Codebase list fiat / abb3a59
New upstream version 2017.2.0 Drew Parsons 6 years ago
31 changed file(s) with 1002 addition(s) and 202 deletion(s). Raw diff Collapse all Expand all
0 Anders Logg <logg@chalmers.se>
1 Anders Logg <logg@chalmers.se> <ffc@bamse>
2 Anders Logg <logg@chalmers.se> <logg@yavanna>
3 Anders Logg <logg@chalmers.se> <logg@aule>
4 Anders Logg <logg@chalmers.se> logg <logg@localhost.localdomain>
5 Anders Logg <logg@chalmers.se> fenics <devnull@localhost>
6 Anders Logg <logg@chalmers.se> hg <hg@numenor>
7 Anders Logg <logg@chalmers.se> root <root@leja>
8 Anders Logg <logg@chalmers.se> <logg@glaurung>
9 Anders Logg <logg@chalmers.se> <logg@simula.no>
10 Anders Logg <logg@chalmers.se> <anders.logg+bitbucket@gmail.com>
11 Anders Logg <logg@chalmers.se> <logg@olorin>
12 Anders Logg <logg@chalmers.se> <logg@tti-c.org>
13 Anders Logg <logg@chalmers.se> anders <anders@localhost.localdomain>
14 Anders Logg <logg@chalmers.se> logg <devnull@localhost>
15 Anders Logg <logg@chalmers.se> logg <logg@bigblue.simula.no>
16 Anders Logg <logg@chalmers.se> logg <logg@bunjil.simula.no>
17 Anders Logg <logg@chalmers.se> logg <logg@olorin>
18 Andy R. Terrel <andy.terrel@gmail.com>
19 Andy R. Terrel <andy.terrel@gmail.com> <aterrel@uchicago.edu>
20 Andy R. Terrel <andy.terrel@gmail.com> aterrel <devnull@localhost>
21 Andy R. Terrel <andy.terrel@gmail.com> <aterrel@dhcp-11-20.cs.uchicago.edu>
22 Benjamin Kehlet <benjamik@simula.no>
23 Benjamin Kehlet <benjamik@simula.no> <benjamik@benjamik-hp.simula.no>
24 Benjamin Kehlet <benjamik@simula.no> <benjamik@ifi.uio.no>
25 Benjamin Kehlet <benjamik@simula.no> <benjamik@login.ifi.uio.no>
26 Benjamin Kehlet <benjamik@simula.no> <bkehlet@bkehlet-laptop>
27 Chris Richardson <chris@bpi.cam.ac.uk>
28 Chris Richardson <chris@bpi.cam.ac.uk> chris <chris@Lenovo-Edge.(none)>
29 Chris Richardson <chris@bpi.cam.ac.uk> Chris Richardson <bpi.cam.ac.uk>
30 Chris Richardson <chris@bpi.cam.ac.uk> root <root@bpi.cam.ac.uk>
31 Corrado Maurini <corrado.maurini@upmc.fr>
32 Corrado Maurini <corrado.maurini@upmc.fr> <cmaurini@gmail.com>
33 Dag Lindbo <dag@csc.kth.se>
34 Dag Lindbo <dag@csc.kth.se> dag <dag@dag-laptop>
35 Dag Lindbo <dag@csc.kth.se> dag <dag@na55.nada.kth.se>
36 David Ham <david.ham@imperial.ac.uk>
37 David Ham <david.ham@imperial.ac.uk> <David.Ham@imperial.ac.uk>
38 David Ham <david.ham@imperial.ac.uk> david.ham@imperial.ac.uk <>
39 Evan Lezar <evanlezar@gmail.com>
40 Evan Lezar <evanlezar@gmail.com> <mail@evanlezar.com>
41 Evan Lezar <evanlezar@gmail.com> elezar <elezar@labby>
42 Evan Lezar <evanlezar@gmail.com> elezar <elezar@lefauve>
43 Fredrik Valdmanis <fredrik@valdmanis.com>
44 Fredrik Valdmanis <fredrik@valdmanis.com> Fredrik Valdmanis <fredva@ifi.uio.no>
45 Garth N. Wells <gnw20@cam.ac.uk>
46 Garth N. Wells <gnw20@cam.ac.uk> root <root@fornax.esc.cam.ac.uk>
47 Garth N. Wells <gnw20@cam.ac.uk> garth <devnull@localhost>
48 Garth N. Wells <gnw20@cam.ac.uk> <garth@debian.eng.cam.ac.uk>
49 Garth N. Wells <gnw20@cam.ac.uk> <garth@fedora32-virtual>
50 Garth N. Wells <gnw20@cam.ac.uk> <garth@gnw20pc>
51 Garth N. Wells <gnw20@cam.ac.uk> <garth@home-laptop>
52 Garth N. Wells <gnw20@cam.ac.uk> <garth@localhost.localdomain>
53 Garth N. Wells <gnw20@cam.ac.uk> <garth@ubuntu32-virtual>
54 Garth N. Wells <gnw20@cam.ac.uk> <garth@ubuntu.eng.cam.ac.uk>
55 Garth N. Wells <gnw20@cam.ac.uk> <garth@garth-laptop>
56 Garth N. Wells <gnw20@cam.ac.uk> <garth@gnw20pc>
57 Garth N. Wells <gnw20@cam.ac.uk> <g.n.wells@tudelft.nl>
58 Garth N. Wells <gnw20@cam.ac.uk> gnw20@cam.ac.uk <>
59 gideonsimpson <gideonsimpson@dyn-128-59-151-14.dyn.columbia.edu>
60 Gustav Magnus Vikström <gustavv@simula.no>
61 Gustav Magnus Vikström <gustavv@simula.no> <gustavv@ifi.uio.no>
62 Gustav Magnus Vikström <gustavv@simula.no> <gustavv@ifi.uio.no>
63 Gustav Magnus Vikström <gustavv@simula.no> <gustavv@utlaan-laptop-1>
64 Harish Narayanan <hnarayanan@gmail.com>
65 Harish Narayanan <hnarayanan@gmail.com> Harish Narayanan <harish@simula.no>
66 Johan Hoffman <jhoffman@csc.kth.se>
67 Johan Hoffman <jhoffman@csc.kth.se> hoffman <devnull@localhost>
68 Johan Hoffman <jhoffman@csc.kth.se> <jhoffman@na41.nada.kth.se>
69 Johan Hoffman <jhoffman@csc.kth.se> <jhoffman@na42.nada.kth.se>
70 Ilmar Wilbers <ilmarw@simula.no>
71 Ilmar Wilbers <ilmarw@simula.no> <ilmarw@gogmagog.simula.no>
72 Ilmar Wilbers <ilmarw@simula.no> <ilmarw@multiboot.local>
73 Jack S. Hale <jack.hale@uni.lu>
74 Jack S. Hale <jack.hale@uni.lu> <j.hale09@imperial.ac.uk>
75 Johan Hake <hake.dev@gmail.com>
76 Johan Hake <hake.dev@gmail.com> <johan.hake@gmail.com>
77 Johan Hake <hake.dev@gmail.com> <hake@simula.no>
78 Johan Jansson <jjan@csc.kth.se>
79 Johan Jansson <jjan@csc.kth.se> johan <johan@localhost.localdomain>
80 Johan Jansson <jjan@csc.kth.se> johan <johan@nova>
81 Johan Jansson <jjan@csc.kth.se> johanjan <devnull@localhost>
82 Johan Jansson <jjan@csc.kth.se> johanjan <johanjan@localhost.localdomain>
83 Johan Jansson <jjan@csc.kth.se> Johan Jansson <johanjan@math.chalmers.se>
84 Johannes Ring <johannr@simula.no>
85 Johannes Ring <johannr@simula.no> <johannr@communalis.simula.no>
86 Kent-Andre Mardal <kent-and@simula.no>
87 Kent-Andre Mardal <kent-and@simula.no> <kent-and@localhost>
88 Kristian B. Ølgaard <k.b.oelgaard@gmail.com>
89 Kristian B. Ølgaard <k.b.oelgaard@gmail.com> <k.b.oelgaard@tudelft.nl>
90 Kristian B. Ølgaard <k.b.oelgaard@gmail.com> <oelgaard@localhost.localdomain>
91 Magnus Vikstrøm <gustavv@ifi.uio.no>
92 Marco Morandini <marco.morandini@polimi.it>
93 Marco Morandini <marco.morandini@polimi.it> <morandini@aero.polimi.it>
94 Marie E. Rognes <meg@simula.no>
95 Marie E. Rognes <meg@simula.no> <meg@math.uio.no>
96 Marie E. Rognes <meg@simula.no> <meg@meg-laptop>
97 Marie E. Rognes <meg@simula.no> Marie E. Rognes (meg@simula.no) <Marie E. Rognes (meg@simula.no)>
98 Marie E. Rognes <meg@simula.no> meg@simula.no <>
99 Martin Sandve Alnæs <martinal@simula.no>
100 Martin Sandve Alnæs <martinal@simula.no> <martinal@localhost>
101 Martin Sandve Alnæs <martinal@simula.no> <martinal@martinal-desktop>
102 Michele Zaffalon <michele.zaffalon@gmail.com>
103 Mikael Mortensen <mikaem@math.uio.no>
104 Mikael Mortensen <mikaem@math.uio.no> <mikael.mortensen@gmail.com>
105 Nate Sime <njcs4@cam.ac.uk>
106 Nate Sime <njcs4@cam.ac.uk> <njcs4@galah.bpi.cam.ac.uk>
107 Nuno Lopes <ndl@ptmat.fc.ul.pt>
108 Nuno Lopes <ndl@ptmat.fc.ul.pt> N.Lopes <devnull@localhost>
109 Patrick Farrell <patrick.farrell@maths.ox.ac.uk>
110 Patrick Farrell <patrick.farrell@maths.ox.ac.uk> <patrick.farrell06@imperial.ac.uk>
111 Patrick Farrell <patrick.farrell@maths.ox.ac.uk> <patrick.farrell@imperial.ac.uk>
112 Quang Ha <qth20@cam.ac.uk>
113 Kristoffer Selim <selim@simula.no>
114 Kristoffer Selim <selim@simula.no> <selim@selim-laptop>
115 Simon Funke <simon@simula.no>
116 Simon Funke <simon@simula.no> <simon.funke@gmail.com>
117 Simon Funke <simon@simula.no> <s.funke09@imperial.ac.uk>
118 Solveig Bruvoll <solveio@ifi.uio.no>
119 Solveig Masvie <smasvie@gmail.com>
120 Steven Vandekerckhove <steven.vandekerckhove@kuleuven-kulak.be>
121 Steven Vandekerckhove <steven.vandekerckhove@kuleuven-kulak.be> <Steven.Vandekerckhove@kuleuven-kulak.be>
122 stockli <stockli@carleman.nada.kth.se>
123 stockli <stockli@carleman.nada.kth.se> <stockli@localhost>
124 Tianyi Li <tianyikillua@gmail.com>
125 Steffen Müthing <steffen.muething@ipvs.uni-stuttgart.de>
126 Steffen Müthing <steffen.muething@ipvs.uni-stuttgart.de> Steffen Müthing steffen.muething@ipvs.uni-stuttgart.de <>
127 Miklós Homolya <m.homolya14@imperial.ac.uk>
128 Åsmund Ødegård <aasmund@simula.no>
129 Åsmund Ødegård <aasmund@simula.no> <aasmundo@manpower.local>
130 Ola Skavhaug <skavhaug@simula.no>
131 Andre Massing <massing@simula.no>
132 Andrew McRae <a.mcrae12@imperial.ac.uk>
133 Andrew McRae <a.t.t.mcrae@bath.ac.uk> <a.mcrae12@imperial.ac.uk>
134 Lawrence Mitchell <wence@gmx.li> Lawrence Mitchell <lawrence.mitchell@imperial.ac.uk>
135 Robert Kirby <robert.c.kirby@gmail.com> Robert C. Kirby <kirby@uchicago.edu>
136 Robert Kirby <robert.c.kirby@gmail.com> Robert C. Kirby <robert.c.kirby@gmail.com>
137 Robert Kirby <robert.c.kirby@gmail.com> kirby <devnull@localhost>
138 Robert Kirby <robert.c.kirby@gmail.com> kirby <kirby@LittleMy.local>
139 Robert Kirby <robert.c.kirby@gmail.com> kirby <kirby@localhost>
140 Robert Kirby <robert.c.kirby@gmail.com> kirby <kirby@ma072.dhcp.ttu.edu>
141 Robert Kirby <robert.c.kirby@gmail.com> kirby <kirby@ma251.dhcp.ttu.edu>
142 Robert Kirby <robert.c.kirby@gmail.com> kirby <kirby@zortzi.math.ttu.edu>
143 Matthew Knepley <knepley@gmail.com> knepley <knepley@knepley-laptop>
0 sudo: false
1 notifications:
2 irc:
3 channels: "chat.freenode.net#firedrake"
4 skip_join: true
5 on_success: change
6 on_failure: always
7 template: "%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message} | %{build_url}"
8 language: python
9 python:
10 - "2.7"
11 - "3.4"
12
13 before_install:
14 - pip install --upgrade pip
15 - pip install flake8
16 - pip install flake8-future-import
17 - pip install pytest
18 - pip install six
19
20 install:
21 - pip install .
22
23 script:
24 - flake8 .
25 - DATA_REPO_GIT="" py.test test/
6666
6767 Matthias Liertzer
6868 email: matthias@liertzer.at
69
70 Ivan Yashchuk
71 email: ivan.yashchuk@aalto.fi
00 Changelog
11 =========
2
3 2017.2.0 (2017-09-19)
4 ---------------------
5
6 - Add quadrilateral and hexahedron reference cells
7 - Add quadrilateral and hexahedron elements (with a wrapping class for TensorProductElement)
8
9 2017.1.0.post1 (2017-09-12)
10 ---------------------------
11
12 - Change PyPI package name to fenics-fiat.
213
314 2017.1.0 (2017-05-09)
415 ---------------------
3232 from FIAT.nodal_enriched import NodalEnrichedElement
3333 from FIAT.discontinuous import DiscontinuousElement
3434 from FIAT.hdiv_trace import HDivTrace
35 from FIAT.mixed import MixedElement # noqa: F401
3536 from FIAT.restricted import RestrictedElement # noqa: F401
37 from FIAT.quadrature_element import QuadratureElement # noqa: F401
3638
3739 # Important functionality
3840 from FIAT.quadrature import make_quadrature # noqa: F401
4042 from FIAT.reference_element import ufc_cell, ufc_simplex # noqa: F401
4143 from FIAT.hdivcurl import Hdiv, Hcurl # noqa: F401
4244
43 __version__ = pkg_resources.get_distribution("FIAT").version
45 __version__ = pkg_resources.get_distribution("fenics-fiat").version
4446
4547 # List of supported elements and mapping to element classes
4648 supported_elements = {"Argyris": Argyris,
1717 from __future__ import absolute_import, print_function, division
1818
1919 from FIAT import finite_element, polynomial_set, dual_set, functional
20 from FIAT.reference_element import TRIANGLE
2021
2122
2223 class ArgyrisDualSet(dual_set.DualSet):
2930 verts = ref_el.get_vertices()
3031 sd = ref_el.get_spatial_dimension()
3132
32 if sd != 2:
33 raise Exception("Illegal spatial dimension")
33 if ref_el.get_shape() != TRIANGLE:
34 raise ValueError("Argyris only defined on triangles")
3435
3536 pe = functional.PointEvaluation
3637 pd = functional.PointDerivative
4950 nodes.append(pd(ref_el, verts[v], alpha))
5051
5152 # second derivatives
52 alphas = [[2, 0], [0, 2], [1, 1]]
53 alphas = [[2, 0], [1, 1], [0, 2]]
5354 for alpha in alphas:
5455 nodes.append(pd(ref_el, verts[v], alpha))
5556
8283 nodes.extend(internalnds)
8384 entity_ids[2][0] = list(range(cur, cur + len(internalpts)))
8485 cur += len(internalpts)
86 else:
87 entity_ids[2] = {0: []}
8588
8689 super(ArgyrisDualSet, self).__init__(nodes, ref_el, entity_ids)
8790
97100 top = ref_el.get_topology()
98101 verts = ref_el.get_vertices()
99102 sd = ref_el.get_spatial_dimension()
100 if sd != 2:
101 raise Exception("Illegal spatial dimension")
103 if ref_el.get_shape() != TRIANGLE:
104 raise ValueError("Argyris only defined on triangles")
102105
103106 pd = functional.PointDerivative
104107
115118 nodes.append(pd(ref_el, verts[v], alpha))
116119
117120 # second derivatives
118 alphas = [[2, 0], [0, 2], [1, 1]]
121 alphas = [[2, 0], [1, 1], [0, 2]]
119122 for alpha in alphas:
120123 nodes.append(pd(ref_el, verts[v], alpha))
121124
130133 nodes.append(n)
131134 entity_ids[1][e] = [cur]
132135 cur += 1
136
137 entity_ids[2] = {0: []}
133138
134139 super(QuinticArgyrisDualSet, self).__init__(nodes, ref_el, entity_ids)
135140
1616
1717 from __future__ import absolute_import, print_function, division
1818
19 import numpy as np
20 from copy import copy
19 from itertools import chain
20
21 import numpy
2122
2223 from FIAT.finite_element import FiniteElement
2324 from FIAT.dual_set import DualSet
25 from FIAT.mixed import concatenate_entity_dofs
26
2427
2528 __all__ = ['EnrichedElement']
2629
3437 """
3538
3639 def __init__(self, *elements):
37 assert len(elements) == 2, "EnrichedElement only implemented for two subelements"
38 A, B = elements
39
4040 # Firstly, check it makes sense to enrich. Elements must have:
4141 # - same reference element
4242 # - same mapping
4343 # - same value shape
44 if not A.get_reference_element() == B.get_reference_element():
44 if len(set(e.get_reference_element() for e in elements)) > 1:
4545 raise ValueError("Elements must be defined on the same reference element")
46 if not A.mapping()[0] == B.mapping()[0]:
46 if len(set(m for e in elements for m in e.mapping())) > 1:
4747 raise ValueError("Elements must have same mapping")
48 if not A.value_shape() == B.value_shape():
48 if len(set(e.value_shape() for e in elements)) > 1:
4949 raise ValueError("Elements must have the same value shape")
5050
5151 # order is at least max, possibly more, though getting this
5252 # right isn't important AFAIK
53 order = max(A.get_order(), B.get_order())
53 order = max(e.get_order() for e in elements)
5454 # form degree is essentially max (not true for Hdiv/Hcurl,
5555 # but this will raise an error above anyway).
5656 # E.g. an H^1 function enriched with an L^2 is now just L^2.
57 if A.get_formdegree() is None or B.get_formdegree() is None:
57 if any(e.get_formdegree() is None for e in elements):
5858 formdegree = None
5959 else:
60 formdegree = max(A.get_formdegree(), B.get_formdegree())
60 formdegree = max(e.get_formdegree() for e in elements)
6161
6262 # set up reference element and mapping, following checks above
63 ref_el = A.get_reference_element()
64 mapping = A.mapping()[0]
63 ref_el, = set(e.get_reference_element() for e in elements)
64 mapping, = set(m for e in elements for m in e.mapping())
6565
6666 # set up entity_ids - for each geometric entity, just concatenate
6767 # the entities of the constituent elements
68 Adofs = A.entity_dofs()
69 Bdofs = B.entity_dofs()
70 offset = A.space_dimension() # number of entities belonging to A
71 entity_ids = {}
72
73 for ent_dim in Adofs:
74 entity_ids[ent_dim] = {}
75 for ent_dim_index in Adofs[ent_dim]:
76 entlist = copy(Adofs[ent_dim][ent_dim_index])
77 entlist += [c + offset for c in Bdofs[ent_dim][ent_dim_index]]
78 entity_ids[ent_dim][ent_dim_index] = entlist
68 entity_ids = concatenate_entity_dofs(ref_el, elements)
7969
8070 # set up dual basis - just concatenation
81 nodes = A.dual_basis() + B.dual_basis()
71 nodes = list(chain.from_iterable(e.dual_basis() for e in elements))
8272 dual = DualSet(nodes, ref_el, entity_ids)
8373
8474 super(EnrichedElement, self).__init__(ref_el, dual, order, formdegree, mapping)
8575
86 # Set up constituent elements
87 self.A = A
88 self.B = B
89
9076 # required degree (for quadrature) is definitely max
91 self.polydegree = max(A.degree(), B.degree())
77 self.polydegree = max(e.degree() for e in elements)
9278
9379 # Store subelements
9480 self._elements = elements
115101 """Return tabulated values of derivatives up to given order of
116102 basis functions at given points."""
117103
118 # Again, simply concatenate at the basis-function level
119 # Number of array dimensions depends on whether the space
120 # is scalar- or vector-valued, so treat these separately.
104 num_components = numpy.prod(self.value_shape())
105 table_shape = (self.space_dimension(), num_components, len(points))
121106
122 Asd = self.A.space_dimension()
123 Bsd = self.B.space_dimension()
124 Atab = self.A.tabulate(order, points, entity)
125 Btab = self.B.tabulate(order, points, entity)
126 npoints = len(points)
127 vs = self.A.value_shape()
128 rank = len(vs) # scalar: 0, vector: 1
107 table = {}
108 irange = slice(0)
109 for element in self._elements:
129110
130 result = {}
131 for index in Atab:
132 if rank == 0:
133 # scalar valued
134 # Atab[index] and Btab[index] look like
135 # array[basis_fn][point]
136 # We build a new array, which will be the concatenation
137 # of the two subarrays, in the first index.
111 etable = element.tabulate(order, points, entity)
112 irange = slice(irange.stop, irange.stop + element.space_dimension())
138113
139 temp = np.zeros((Asd + Bsd, npoints),
140 dtype=Atab[index].dtype)
141 temp[:Asd, :] = Atab[index][:, :]
142 temp[Asd:, :] = Btab[index][:, :]
114 # Insert element table into table
115 for dtuple in etable.keys():
143116
144 result[index] = temp
145 elif rank == 1:
146 # vector valued
147 # Atab[index] and Btab[index] look like
148 # array[basis_fn][x/y/z][point]
149 # We build a new array, which will be the concatenation
150 # of the two subarrays, in the first index.
117 if dtuple not in table:
118 if num_components == 1:
119 table[dtuple] = numpy.zeros((self.space_dimension(), len(points)),
120 dtype=etable[dtuple].dtype)
121 else:
122 table[dtuple] = numpy.zeros(table_shape,
123 dtype=etable[dtuple].dtype)
151124
152 temp = np.zeros((Asd + Bsd, vs[0], npoints),
153 dtype=Atab[index].dtype)
154 temp[:Asd, :, :] = Atab[index][:, :, :]
155 temp[Asd:, :, :] = Btab[index][:, :, :]
125 table[dtuple][irange][:] = etable[dtuple]
156126
157 result[index] = temp
158 else:
159 raise NotImplementedError("must be scalar- or vector-valued")
160 return result
127 return table
161128
162129 def value_shape(self):
163130 """Return the value shape of the finite element functions."""
164 return self.A.value_shape()
131 result, = set(e.value_shape() for e in self._elements)
132 return result
165133
166134 def dmats(self):
167135 """Return dmats: expansion coefficients for basis function
5555 return self.dual
5656
5757 def get_order(self):
58 """Return the order of the element (may be different from the degree."""
58 """Return the order of the element (may be different from the degree)."""
5959 return self.order
6060
6161 def dual_basis(self):
227227 dpt_dict = {pt: [(n[i], alphas[i], tuple()) for i in range(sd)]}
228228
229229 Functional.__init__(self, ref_el, tuple(), {}, dpt_dict, "PointNormalDeriv")
230
231 def to_riesz(self, poly_set):
232 x = list(self.deriv_dict.keys())[0]
233
234 X = sympy.DeferredVector('x')
235 dx = numpy.asarray([X[i] for i in range(len(x))])
236
237 es = poly_set.get_expansion_set()
238 ed = poly_set.get_embedded_degree()
239
240 bfs = es.tabulate(ed, [dx])[:, 0]
241
242 # We need the gradient dotted with the normal.
243 return numpy.asarray(
244 [sympy.lambdify(
245 X, sum([sympy.diff(b, dxi)*ni
246 for dxi, ni in zip(dx, self.n)]))(x)
247 for b in bfs])
230248
231249
232250 class IntegralMoment(Functional):
203203 # If not successful, return NaNs
204204 if not success:
205205 for key in phivals:
206 phivals[key] = np.full(shape=(sd, len(points)), fill_value=np.nan)
206 phivals[key] = np.full(shape=(self.space_dimension(), len(points)), fill_value=np.nan)
207207
208208 return phivals
209209
00 # Copyright (C) 2008 Robert C. Kirby (Texas Tech University)
1 # Modified 2017 by RCK
12 #
23 # This file is part of FIAT.
34 #
5051 entity_ids[0][v] = list(range(cur, cur + 1 + sd))
5152 cur += sd + 1
5253
54 # now only have dofs at the barycenter, which is the
55 # maximal dimension
5356 # no edge dof
57
5458 entity_ids[1] = {}
59 for i in top[1]:
60 entity_ids
61 entity_ids[1][i] = []
5562
56 # face dof
57 # point evaluation at barycenter
58 entity_ids[2] = {}
59 for f in sorted(top[2]):
60 pt = ref_el.make_points(2, f, 3)[0]
61 n = functional.PointEvaluation(ref_el, pt)
62 nodes.append(n)
63 entity_ids[2] = list(range(cur, cur + 1))
64 cur += 1
63 if sd > 1:
64 # face dof
65 # point evaluation at barycenter
66 entity_ids[2] = {}
67 for f in sorted(top[2]):
68 pt = ref_el.make_points(2, f, 3)[0]
69 n = functional.PointEvaluation(ref_el, pt)
70 nodes.append(n)
71 entity_ids[2][f] = list(range(cur, cur + 1))
72 cur += 1
6573
66 for dim in range(3, sd + 1):
67 entity_ids[dim] = {}
68 for facet in top[dim]:
69 entity_ids[dim][facet] = []
74 for dim in range(3, sd + 1):
75 entity_ids[dim] = {}
76 for facet in top[dim]:
77 entity_ids[dim][facet] = []
7078
7179 super(CubicHermiteDualSet, self).__init__(nodes, ref_el, entity_ids)
7280
0 # -*- coding: utf-8 -*-
1 #
2 # Copyright (C) 2005-2010 Anders Logg
3 #
4 # This file is part of FIAT.
5 #
6 # FIAT is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU Lesser General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # FIAT is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU Lesser General Public License for more details.
15 #
16 # You should have received a copy of the GNU Lesser General Public License
17 # along with FIAT. If not, see <http://www.gnu.org/licenses/>.
18
19 from __future__ import absolute_import, print_function, division
20 from six import iteritems
21 from six.moves import map
22
23 import numpy
24
25 from operator import add
26 from functools import partial
27
28 from FIAT.dual_set import DualSet
29 from FIAT.finite_element import FiniteElement
30
31
32 class MixedElement(FiniteElement):
33 """A FIAT-like representation of a mixed element.
34
35 :arg elements: An iterable of FIAT elements.
36 :arg ref_el: The reference element (optional).
37
38 This object offers tabulation of the concatenated basis function
39 tables along with an entity_dofs dict."""
40 def __init__(self, elements, ref_el=None):
41 elements = tuple(elements)
42
43 cells = set(e.get_reference_element() for e in elements)
44 if ref_el is not None:
45 cells.add(ref_el)
46 ref_el, = cells
47
48 # These functionals are absolutely wrong, they all map from
49 # functions of the wrong shape, and potentially of different
50 # shapes. However, they are wrong precisely as FFC hacks
51 # expect them to be. :(
52 nodes = [L for e in elements for L in e.dual_basis()]
53
54 entity_dofs = concatenate_entity_dofs(ref_el, elements)
55
56 dual = DualSet(nodes, ref_el, entity_dofs)
57 super(MixedElement, self).__init__(ref_el, dual, None, mapping=None)
58 self._elements = elements
59
60 def elements(self):
61 return self._elements
62
63 def num_sub_elements(self):
64 return len(self._elements)
65
66 def value_shape(self):
67 return (sum(numpy.prod(e.value_shape(), dtype=int) for e in self.elements()), )
68
69 def mapping(self):
70 return [m for e in self._elements for m in e.mapping()]
71
72 def get_nodal_basis(self):
73 raise NotImplementedError("get_nodal_basis not implemented")
74
75 def tabulate(self, order, points, entity=None):
76 """Tabulate a mixed element by appropriately splatting
77 together the tabulation of the individual elements.
78 """
79 shape = (self.space_dimension(),) + self.value_shape() + (len(points),)
80
81 output = {}
82
83 sub_dims = [0] + list(e.space_dimension() for e in self.elements())
84 sub_cmps = [0] + list(numpy.prod(e.value_shape(), dtype=int)
85 for e in self.elements())
86 irange = numpy.cumsum(sub_dims)
87 crange = numpy.cumsum(sub_cmps)
88
89 for i, e in enumerate(self.elements()):
90 table = e.tabulate(order, points, entity)
91
92 for d, tab in iteritems(table):
93 try:
94 arr = output[d]
95 except KeyError:
96 arr = numpy.zeros(shape, dtype=tab.dtype)
97 output[d] = arr
98
99 ir = irange[i:i+2]
100 cr = crange[i:i+2]
101 tab = tab.reshape(ir[1] - ir[0], cr[1] - cr[0], -1)
102 arr[slice(*ir), slice(*cr)] = tab
103
104 return output
105
106 def is_nodal(self):
107 """True if primal and dual bases are orthogonal."""
108 return all(e.is_nodal() for e in self._elements)
109
110
111 def concatenate_entity_dofs(ref_el, elements):
112 """Combine the entity_dofs from a list of elements into a combined
113 entity_dof containing the information for the concatenated DoFs of
114 all the elements."""
115 entity_dofs = {dim: {i: [] for i in entities}
116 for dim, entities in iteritems(ref_el.get_topology())}
117 offsets = numpy.cumsum([0] + list(e.space_dimension()
118 for e in elements), dtype=int)
119 for i, d in enumerate(e.entity_dofs() for e in elements):
120 for dim, dofs in iteritems(d):
121 for ent, off in iteritems(dofs):
122 entity_dofs[dim][ent] += list(map(partial(add, offsets[i]), off))
123 return entity_dofs
1717 from __future__ import absolute_import, print_function, division
1818
1919 from FIAT import finite_element, polynomial_set, dual_set, functional
20 from FIAT.reference_element import TRIANGLE
2021
2122
2223 class MorleyDualSet(dual_set.DualSet):
3334 # need to do this dimension-by-dimension, facet-by-facet
3435 top = ref_el.get_topology()
3536 verts = ref_el.get_vertices()
36 sd = ref_el.get_spatial_dimension()
37 if sd != 2:
38 raise Exception("Illegal spatial dimension")
37 if ref_el.get_shape() != TRIANGLE:
38 raise ValueError("Morley only defined on triangles")
3939
4040 # vertex point evaluations
4141
5555 entity_ids[1][e] = [cur]
5656 cur += 1
5757
58 entity_ids[2] = {0: []}
59
5860 super(MorleyDualSet, self).__init__(nodes, ref_el, entity_ids)
5961
6062
0 # -*- coding: utf-8 -*-
1
2 # Copyright (C) 2007-2016 Kristian B. Oelgaard
3 # Copyright (C) 2017 Miklós Homolya
4 #
5 # This file is part of FIAT.
6 #
7 # FIAT is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Lesser General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # FIAT is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Lesser General Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public License
18 # along with FIAT. If not, see <http://www.gnu.org/licenses/>.
19 #
20 # Modified by Garth N. Wells 2006-2009
21
22 from __future__ import absolute_import, print_function, division
23 from six.moves import range
24
25 # Python modules.
26 import numpy
27 import six
28
29 # FIAT modules.
30 from FIAT.dual_set import DualSet
31 from FIAT.finite_element import FiniteElement
32 from FIAT.functional import PointEvaluation
33
34
35 class QuadratureElement(FiniteElement):
36 """A set of quadrature points pretending to be a finite element."""
37
38 def __init__(self, ref_el, points):
39 # Create entity dofs.
40 entity_dofs = {dim: {entity: [] for entity in entities}
41 for dim, entities in six.iteritems(ref_el.get_topology())}
42 entity_dofs[ref_el.get_dimension()] = {0: list(range(len(points)))}
43
44 # The dual nodes are PointEvaluations at the quadrature points.
45 # FIXME: KBO: Check if this gives expected results for code like evaluate_dof.
46 nodes = [PointEvaluation(ref_el, tuple(point)) for point in points]
47
48 # Construct the dual set
49 dual = DualSet(nodes, ref_el, entity_dofs)
50
51 super(QuadratureElement, self).__init__(ref_el, dual, order=None)
52 self._points = points # save the quadrature points
53
54 def value_shape(self):
55 "The QuadratureElement is scalar valued"
56 return ()
57
58 def tabulate(self, order, points, entity=None):
59 """Return the identity matrix of size (num_quad_points, num_quad_points),
60 in a format that monomialintegration and monomialtabulation understands."""
61
62 if entity is not None and entity != (self.ref_el.get_dimension(), 0):
63 raise ValueError('QuadratureElement does not "tabulate" on subentities.')
64
65 # Derivatives are not defined on a QuadratureElement
66 if order:
67 raise ValueError("Derivatives are not defined on a QuadratureElement.")
68
69 # Check that incoming points are equal to the quadrature points.
70 if len(points) != len(self._points) or abs(numpy.array(points) - self._points).max() > 1e-12:
71 raise AssertionError("Mismatch of quadrature points!")
72
73 # Return the identity matrix of size len(self._points).
74 values = numpy.eye(len(self._points))
75 dim = self.ref_el.get_spatial_dimension()
76 return {(0,) * dim: values}
77
78 @staticmethod
79 def is_nodal():
80 # No polynomial basis, but still nodal.
81 return True
4343 from numpy import array, arange, float64
4444
4545 # FIAT
46 from FIAT.reference_element import QUADRILATERAL, TENSORPRODUCT, UFCTriangle, UFCTetrahedron
46 from FIAT.reference_element import QUADRILATERAL, HEXAHEDRON, TENSORPRODUCT, UFCTriangle, UFCTetrahedron
4747 from FIAT.quadrature import QuadratureRule, make_quadrature, make_tensor_product_quadrature
4848
4949
7272 for c, d in zip(ref_el.cells, degree)]
7373 return make_tensor_product_quadrature(*quad_rules)
7474
75 if ref_el.get_shape() == QUADRILATERAL:
75 if ref_el.get_shape() in [QUADRILATERAL, HEXAHEDRON]:
7676 return create_quadrature(ref_el.product, degree, scheme)
7777
7878 if degree < 0:
9898
9999 # Number of points per axis for exact integration
100100 num_points_per_axis = (degree + 1 + 1) // 2
101
102 # Check for excess
103 if num_points_per_axis > 30:
104 dim = ref_el.get_spatial_dimension()
105 raise RuntimeError("Requested a quadrature rule with %d points per direction (%d points)" %
106 (num_points_per_axis, num_points_per_axis**dim))
107101
108102 # Create and return FIAT quadrature rule
109103 return make_quadrature(ref_el, num_points_per_axis)
3030 """
3131 from __future__ import absolute_import, print_function, division
3232
33 from itertools import chain, product
33 from itertools import chain, product, count
3434 import operator
3535 from math import factorial
3636
37 from six import iteritems, itervalues
37 from six import iteritems
3838 from six import string_types
39 from six.moves import reduce
39 from six.moves import reduce, range
4040 import numpy
4141 from numpy import ravel_multi_index, transpose
42 from collections import defaultdict
4243
4344
4445 POINT = 0
4647 TRIANGLE = 2
4748 TETRAHEDRON = 3
4849 QUADRILATERAL = 11
50 HEXAHEDRON = 111
4951 TENSORPRODUCT = 99
5052
5153
392394 n = Simplex.compute_normal(self, facet_i) # skip UFC overrides
393395 return n / numpy.linalg.norm(n, numpy.inf)
394396
395 def get_facet_transform(self, facet_i):
396 """Return a function f such that for a point with facet coordinates
397 x_f on facet_i, x_c = f(x_f) is the corresponding cell coordinates.
397 def get_entity_transform(self, dim, entity):
398 """Returns a mapping of point coordinates from the
399 `entity`-th subentity of dimension `dim` to the cell.
400
401 :arg dim: subentity dimension (integer)
402 :arg entity: entity number (integer)
398403 """
399 t = self.get_topology()
404 topology = self.get_topology()
405 celldim = self.get_spatial_dimension()
406 codim = celldim - dim
407 if dim == 0:
408 # Special case vertices.
409 i, = topology[dim][entity]
410 vertex = self.get_vertices()[i]
411 return lambda point: vertex
412 elif dim == celldim:
413 assert entity == 0
414 return lambda point: point
400415
401416 try:
402 f_el = self.get_facet_element()
417 subcell = self.construct_subelement(dim)
403418 except NotImplementedError:
404419 # Special case for 1D elements.
405 x_c = self.get_vertices_of_subcomplex(t[0][facet_i])[0]
406
420 x_c, = self.get_vertices_of_subcomplex(topology[0][entity])
407421 return lambda x: x_c
408422
409 sd_c = self.get_spatial_dimension()
410 sd_f = f_el.get_spatial_dimension()
411
412 # Facet vertices in facet space.
413 v_f = numpy.array(f_el.get_vertices())
414
415 A = numpy.zeros([sd_f, sd_f])
416
417 for i in range(A.shape[0]):
418 A[i, :] = (v_f[i + 1] - v_f[0])
423 subdim = subcell.get_spatial_dimension()
424
425 assert subdim == celldim - codim
426
427 # Entity vertices in entity space.
428 v_e = numpy.asarray(subcell.get_vertices())
429
430 A = numpy.zeros([subdim, subdim])
431
432 for i in range(subdim):
433 A[i, :] = (v_e[i + 1] - v_e[0])
419434 A[i, :] /= A[i, :].dot(A[i, :])
420435
421 # Facet vertices in cell space.
422 v_c = numpy.array(self.get_vertices_of_subcomplex(t[sd_c - 1][facet_i]))
423
424 B = numpy.zeros([sd_c, sd_f])
425
426 for j in range(B.shape[1]):
436 # Entity vertices in cell space.
437 v_c = numpy.asarray(self.get_vertices_of_subcomplex(topology[dim][entity]))
438
439 B = numpy.zeros([celldim, subdim])
440
441 for j in range(subdim):
427442 B[:, j] = (v_c[j + 1] - v_c[0])
428443
429444 C = B.dot(A)
430445
431 offset = v_c[0] - C.dot(v_f[0])
446 offset = v_c[0] - C.dot(v_e[0])
432447
433448 return lambda x: offset + C.dot(x)
434449
436451 """Returns the subelement dimension of the cell. Same as the
437452 spatial dimension."""
438453 return self.get_spatial_dimension()
439
440 def get_entity_transform(self, dim, entity_i):
441 """Returns a mapping of point coordinates from the
442 `entity_i`-th subentity of dimension `dim` to the cell.
443
444 :arg dim: subentity dimension (integer)
445 :arg entity_i: entity number (integer)
446 """
447 space_dim = self.get_spatial_dimension()
448 if dim == space_dim: # cell points
449 assert entity_i == 0
450 return lambda point: point
451 elif dim == space_dim - 1: # facet points
452 return self.get_facet_transform(entity_i)
453 elif dim == 0: # vertex point
454 i, = self.get_topology()[dim][entity_i]
455 vertex = self.get_vertices()[i]
456 return lambda point: vertex
457 else:
458 raise NotImplementedError("Co-dimension >1 not implemented.")
459454
460455
461456 # Backwards compatible name
772767 True)
773768
774769
775 class FiredrakeQuadrilateral(Cell):
770 class UFCQuadrilateral(Cell):
776771 """This is the reference quadrilateral with vertices
777772 (0.0, 0.0), (0.0, 1.0), (1.0, 0.0) and (1.0, 1.0)."""
778773
781776 pt = product.get_topology()
782777
783778 verts = product.get_vertices()
784 topology = {0: pt[(0, 0)],
785 1: dict(enumerate(list(itervalues(pt[(0, 1)])) + list(itervalues(pt[(1, 0)])))),
786 2: pt[(1, 1)]}
787 super(FiredrakeQuadrilateral, self).__init__(QUADRILATERAL, verts, topology)
779 topology = flatten_entities(pt)
780
781 super(UFCQuadrilateral, self).__init__(QUADRILATERAL, verts, topology)
782
788783 self.product = product
784 self.unflattening_map = compute_unflattening_map(pt)
789785
790786 def get_dimension(self):
791787 """Returns the subelement dimension of the cell. Same as the
814810 :arg dim: entity dimension (integer)
815811 :arg entity_i: entity number (integer)
816812 """
817 d, e = {0: lambda e: ((0, 0), e),
818 1: lambda e: {0: ((0, 1), 0),
819 1: ((0, 1), 1),
820 2: ((1, 0), 0),
821 3: ((1, 0), 1)}[e],
822 2: lambda e: ((1, 1), e)}[dim](entity_i)
813 d, e = self.unflattening_map[(dim, entity_i)]
823814 return self.product.get_entity_transform(d, e)
824815
825816 def volume(self):
829820 def compute_reference_normal(self, facet_dim, facet_i):
830821 """Returns the unit normal in infinity norm to facet_i."""
831822 assert facet_dim == 1
832 d, i = {0: ((0, 1), 0),
833 1: ((0, 1), 1),
834 2: ((1, 0), 0),
835 3: ((1, 0), 1)}[facet_i]
823 d, i = self.unflattening_map[(facet_dim, facet_i)]
824 return self.product.compute_reference_normal(d, i)
825
826 def contains_point(self, point, epsilon=0):
827 """Checks if reference cell contains given point
828 (with numerical tolerance)."""
829 return self.product.contains_point(point, epsilon=epsilon)
830
831
832 class UFCHexahedron(Cell):
833 """This is the reference hexahedron with vertices
834 (0.0, 0.0, 0.0), (0.0, 0.0, 1.0), (0.0, 1.0, 0.0), (0.0, 1.0, 1.0),
835 (1.0, 0.0, 0.0), (1.0, 0.0, 1.0), (1.0, 1.0, 0.0) and (1.0, 1.0, 1.0)."""
836
837 def __init__(self):
838 product = TensorProductCell(UFCInterval(), UFCInterval(), UFCInterval())
839 pt = product.get_topology()
840
841 verts = product.get_vertices()
842 topology = flatten_entities(pt)
843
844 super(UFCHexahedron, self).__init__(HEXAHEDRON, verts, topology)
845
846 self.product = product
847 self.unflattening_map = compute_unflattening_map(pt)
848
849 def get_dimension(self):
850 """Returns the subelement dimension of the cell. Same as the
851 spatial dimension."""
852 return self.get_spatial_dimension()
853
854 def construct_subelement(self, dimension):
855 """Constructs the reference element of a cell subentity
856 specified by subelement dimension.
857
858 :arg dimension: subentity dimension (integer)
859 """
860 if dimension == 3:
861 return self
862 elif dimension == 2:
863 return UFCQuadrilateral()
864 elif dimension == 1:
865 return UFCInterval()
866 elif dimension == 0:
867 return Point()
868 else:
869 raise ValueError("Invalid dimension: %d" % (dimension,))
870
871 def get_entity_transform(self, dim, entity_i):
872 """Returns a mapping of point coordinates from the
873 `entity_i`-th subentity of dimension `dim` to the cell.
874
875 :arg dim: entity dimension (integer)
876 :arg entity_i: entity number (integer)
877 """
878 d, e = self.unflattening_map[(dim, entity_i)]
879 return self.product.get_entity_transform(d, e)
880
881 def volume(self):
882 """Computes the volume in the appropriate dimensional measure."""
883 return self.product.volume()
884
885 def compute_reference_normal(self, facet_dim, facet_i):
886 """Returns the unit normal in infinity norm to facet_i."""
887 assert facet_dim == 2
888 d, i = self.unflattening_map[(facet_dim, facet_i)]
836889 return self.product.compute_reference_normal(d, i)
837890
838891 def contains_point(self, point, epsilon=0):
918971 # Tensor product cell
919972 return TensorProductCell(*map(ufc_cell, celltype.split(" * ")))
920973 elif celltype == "quadrilateral":
921 return FiredrakeQuadrilateral()
974 return UFCQuadrilateral()
975 elif celltype == "hexahedron":
976 return UFCHexahedron()
922977 elif celltype == "interval":
923978 return ufc_simplex(1)
924979 elif celltype == "triangle":
9511006 p = numpy.prod([si for si in s if (si) > 1.e-10])
9521007
9531008 return p / factorial(sd)
1009
1010
1011 def tuple_sum(tree):
1012 """
1013 This function calculates the sum of elements in a tuple, it is needed to handle nested tuples in TensorProductCell.
1014 Example: tuple_sum(((1, 0), 1)) returns 2
1015 If input argument is not the tuple, returns input.
1016 """
1017 if isinstance(tree, tuple):
1018 return sum(map(tuple_sum, tree))
1019 else:
1020 return tree
1021
1022
1023 def flatten_entities(topology_dict):
1024 """This function flattens topology dict of TensorProductCell and entity_dofs dict of TensorProductElement"""
1025
1026 flattened_entities = defaultdict(list)
1027 for dim in sorted(topology_dict.keys()):
1028 flat_dim = tuple_sum(dim)
1029 flattened_entities[flat_dim] += [v for k, v in sorted(topology_dict[dim].items())]
1030
1031 return {dim: dict(enumerate(entities))
1032 for dim, entities in iteritems(flattened_entities)}
1033
1034
1035 def compute_unflattening_map(topology_dict):
1036 """This function returns unflattening map for the given tensor product topology dict."""
1037
1038 counter = defaultdict(count)
1039 unflattening_map = {}
1040
1041 for dim, entities in sorted(iteritems(topology_dict)):
1042 flat_dim = tuple_sum(dim)
1043 for entity in entities:
1044 flat_entity = next(counter[flat_dim])
1045 unflattening_map[(flat_dim, flat_entity)] = (dim, entity)
1046
1047 return unflattening_map
2020
2121 import numpy
2222 from FIAT.finite_element import FiniteElement
23 from FIAT.reference_element import TensorProductCell
23 from FIAT.reference_element import TensorProductCell, UFCQuadrilateral, UFCHexahedron, flatten_entities, compute_unflattening_map
24 from FIAT.dual_set import DualSet
2425 from FIAT.polynomial_set import mis
2526 from FIAT import dual_set
2627 from FIAT import functional
365366 def get_num_members(self, arg):
366367 """Return number of members of the expansion set."""
367368 raise NotImplementedError("get_num_members not implemented")
369
370 def is_nodal(self):
371 # This element is nodal iff all factor elements are nodal.
372 return all([self.A.is_nodal(), self.B.is_nodal()])
373
374
375 class FlattenedDimensions(FiniteElement):
376 """A wrapper class that flattens entity dimensions of a FIAT element defined
377 on a TensorProductCell to one with quadrilateral/hexahedron entities.
378 TensorProductCell has dimension defined as a tuple of factor element dimensions
379 (i, j) in 2D and (i, j, k) in 3D.
380 Flattened dimension is a sum of the tuple elements."""
381
382 def __init__(self, element):
383
384 nodes = element.dual.nodes
385 dim = element.ref_el.get_spatial_dimension()
386
387 if dim == 2:
388 ref_el = UFCQuadrilateral()
389 elif dim == 3:
390 ref_el = UFCHexahedron()
391 else:
392 raise ValueError("Illegal element dimension %s" % dim)
393
394 entity_ids = element.dual.entity_ids
395
396 flat_entity_ids = flatten_entities(entity_ids)
397 dual = DualSet(nodes, ref_el, flat_entity_ids)
398 super(FlattenedDimensions, self).__init__(ref_el, dual, element.get_order(), element.get_formdegree(), element._mapping)
399 self.element = element
400
401 # Construct unflattening map for passing correct values to tabulate()
402 self.unflattening_map = compute_unflattening_map(self.element.ref_el.get_topology())
403
404 def degree(self):
405 """Return the degree of the (embedding) polynomial space."""
406 return self.element.degree()
407
408 def tabulate(self, order, points, entity=None):
409 """Return tabulated values of derivatives up to given order of
410 basis functions at given points."""
411 if entity is None:
412 entity = (self.get_reference_element().get_spatial_dimension(), 0)
413
414 # Entity is provided in flattened form (d, i)
415 # Appropriate product entity is taken from the unflattening_map dict
416 entity_dim, entity_id = entity
417 product_entity = self.unflattening_map[(entity_dim, entity_id)]
418
419 return self.element.tabulate(order, points, product_entity)
420
421 def value_shape(self):
422 """Return the value shape of the finite element functions."""
423 return self.element.value_shape()
424
425 def get_nodal_basis(self):
426 """Return the nodal basis, encoded as a PolynomialSet object,
427 for the finite element."""
428 raise self.element.get_nodal_basis()
429
430 def get_coeffs(self):
431 """Return the expansion coefficients for the basis of the
432 finite element."""
433 raise self.element.get_coeffs()
434
435 def dmats(self):
436 """Return dmats: expansion coefficients for basis function
437 derivatives."""
438 raise self.element.dmats()
439
440 def get_num_members(self, arg):
441 """Return number of members of the expansion set."""
442 raise self.element.get_num_members(arg)
443
444 def is_nodal(self):
445 # This element is nodal iff unflattened element is nodal.
446 return self.element.is_nodal()
0 image: ubuntu:16.04
1
2 pipelines:
3 default:
4 - step:
5 script:
6 - apt-get update
7 - apt-get install -y
8 git
9 python-minimal python-pip python-pytest python-setuptools python-wheel
10 python3-minimal python3-pip python3-pytest python3-setuptools python3-wheel
11 --no-install-recommends
12 - pip2 install flake8 flake8-future-import
13 - pip3 install flake8 flake8-future-import
14 - pip2 install .
15 - pip3 install .
16 - python2 -m flake8
17 - python3 -m flake8
18 - DATA_REPO_GIT="" python2 -m pytest -v test/
19 - DATA_REPO_GIT="" python3 -m pytest -v test/
5555 project = u'FInite element Automatic Tabulator (FIAT)'
5656 this_year = datetime.date.today().year
5757 copyright = u'%s, FEniCS Project' % this_year
58 version = pkg_resources.get_distribution("FIAT").version
58 version = pkg_resources.get_distribution("fenics-fiat").version
5959 release = version
6060
6161 # The language for content autogenerated by Sphinx. Refer to documentation
0 =================================
1 Changes in version 2017.1.0.post1
2 =================================
3
4 FIAT 2017.1.0.post1 was released on 2017-09-12.
5
6 Summary of changes
7 ==================
8
9 - Change PyPI package name to fenics-fiat.
0 ===========================
1 Changes in version 2017.2.0
2 ===========================
3
4 FIAT 2017.2.0 was released on 2017-09-19.
5
6 Summary of changes
7 ==================
8
9 - Add quadrilateral and hexahedron reference cells
10 - Add quadrilateral and hexahedron elements (with a wrapping class for TensorProductElement)
88 :maxdepth: 2
99
1010 releases/next
11 releases/v2017.1.0.post1
1112 releases/v2017.1.0
1213 releases/v2016.2.0
1314 releases/v2016.1.0
0 # Configuration file for fenics-release
1
2 PACKAGE="fiat"
3 BRANCH="master"
4 FILES="ChangeLog.rst \
5 setup.py \
6 doc/sphinx/source/releases/next.rst \
7 doc/sphinx/source/releases.rst"
1212 print("Python 2.7 or higher required, please upgrade.")
1313 sys.exit(1)
1414
15 version = "2017.1.0"
15 version = "2017.2.0"
1616
1717 url = "https://bitbucket.org/fenics-project/fiat/"
1818 tarball = None
1919 if 'dev' not in version:
20 tarball = url + "downloads/fiat-%s.tar.gz" % version
20 tarball = url + "downloads/fenics-fiat-%s.tar.gz" % version
2121
22 setup(name="FIAT",
22 setup(name="fenics-fiat",
2323 description="FInite element Automatic Tabulator",
2424 version=version,
2525 author="Robert C. Kirby et al.",
0 language: python
1 python:
2 - 2.7
3 - 3.6
4
5 env:
6 - DATA_REPO_GIT=""
7
8 build:
9 ci:
10 - pip install --upgrade pip
11 - pip install flake8 flake8-future-import pytest
12 - pip install .
13 - python -m flake8 .
14 - python -m pytest -v test/
0 fiat-reference-data/
3030 from FIAT.raviart_thomas import RaviartThomas # noqa: F401
3131 from FIAT.discontinuous_raviart_thomas import DiscontinuousRaviartThomas # noqa: F401
3232 from FIAT.brezzi_douglas_marini import BrezziDouglasMarini # noqa: F401
33 from FIAT.mixed import MixedElement
3334 from FIAT.nedelec import Nedelec # noqa: F401
3435 from FIAT.nedelec_second_kind import NedelecSecondKind # noqa: F401
3536 from FIAT.regge import Regge # noqa: F401
4041 from FIAT.gauss_lobatto_legendre import GaussLobattoLegendre # noqa: F401
4142 from FIAT.restricted import RestrictedElement # noqa: F401
4243 from FIAT.tensor_product import TensorProductElement # noqa: F401
44 from FIAT.tensor_product import FlattenedDimensions # noqa: F401
4345 from FIAT.hdivcurl import Hdiv, Hcurl # noqa: F401
4446 from FIAT.argyris import Argyris, QuinticArgyris # noqa: F401
4547 from FIAT.hermite import CubicHermite # noqa: F401
194196 " Regge(S, 1),"
195197 " RestrictedElement(Regge(S, 2), restriction_domain='interior')"
196198 ")",
199 "Argyris(T, 5)",
200 "QuinticArgyris(T)",
201 "CubicHermite(I)",
202 "CubicHermite(T)",
203 "CubicHermite(S)",
204 "Morley(T)",
205
206 # MixedElement made of nodal elements should be nodal, but its API
207 # is currently just broken.
208 xfail_impl("MixedElement(["
209 " DiscontinuousLagrange(T, 1),"
210 " RaviartThomas(T, 2)"
211 "])"),
197212
198213 # Following element do not bother implementing get_nodal_basis
199214 # so the test would need to be rewritten using tabulate
209224 "Hcurl(TensorProductElement(Lagrange(I, 1), DiscontinuousLagrange(I, 0))), "
210225 "Hcurl(TensorProductElement(DiscontinuousLagrange(I, 0), Lagrange(I, 1)))"
211226 ")"),
212
213 # These elements have broken constructor
214 xfail_key("Argyris(T, 1)",),
215 xfail_key("QuinticArgyris(T)",),
216 xfail_key("CubicHermite(I)",),
217 xfail_key("CubicHermite(T)",),
218 xfail_key("CubicHermite(S)",),
219 xfail_key("Morley(T)",),
227 # Following elements are checked using tabulate
228 xfail_impl("TensorProductElement(Lagrange(I, 1), Lagrange(I, 1))"),
229 xfail_impl("TensorProductElement(Lagrange(I, 2), Lagrange(I, 2))"),
230 xfail_impl("TensorProductElement(TensorProductElement(Lagrange(I, 1), Lagrange(I, 1)), Lagrange(I, 1))"),
231 xfail_impl("TensorProductElement(TensorProductElement(Lagrange(I, 2), Lagrange(I, 2)), Lagrange(I, 2))"),
232 xfail_impl("FlattenedDimensions(TensorProductElement(Lagrange(I, 1), Lagrange(I, 1)))"),
233 xfail_impl("FlattenedDimensions(TensorProductElement(Lagrange(I, 2), Lagrange(I, 2)))"),
234 xfail_impl("FlattenedDimensions(TensorProductElement(FlattenedDimensions(TensorProductElement(Lagrange(I, 1), Lagrange(I, 1))), Lagrange(I, 1)))"),
235 xfail_impl("FlattenedDimensions(TensorProductElement(FlattenedDimensions(TensorProductElement(Lagrange(I, 2), Lagrange(I, 2))), Lagrange(I, 2)))"),
220236 ]
221237
222238
302318 e1.get_dual_set().to_riesz(e1.get_nodal_basis()))
303319
304320
321 def test_mixed_is_nodal():
322 element = MixedElement([DiscontinuousLagrange(T, 1), RaviartThomas(T, 2)])
323
324 assert element.is_nodal()
325
326
327 def test_mixed_is_not_nodal():
328 element = MixedElement([
329 EnrichedElement(
330 RaviartThomas(T, 1),
331 RestrictedElement(RaviartThomas(T, 2), restriction_domain="interior")
332 ),
333 DiscontinuousLagrange(T, 1)
334 ])
335
336 assert not element.is_nodal()
337
338
339 @pytest.mark.parametrize('element', [
340 "TensorProductElement(Lagrange(I, 1), Lagrange(I, 1))",
341 "TensorProductElement(Lagrange(I, 2), Lagrange(I, 2))",
342 "TensorProductElement(TensorProductElement(Lagrange(I, 1), Lagrange(I, 1)), Lagrange(I, 1))",
343 "TensorProductElement(TensorProductElement(Lagrange(I, 2), Lagrange(I, 2)), Lagrange(I, 2))",
344 "FlattenedDimensions(TensorProductElement(Lagrange(I, 1), Lagrange(I, 1)))",
345 "FlattenedDimensions(TensorProductElement(Lagrange(I, 2), Lagrange(I, 2)))",
346 "FlattenedDimensions(TensorProductElement(FlattenedDimensions(TensorProductElement(Lagrange(I, 1), Lagrange(I, 1))), Lagrange(I, 1)))",
347 "FlattenedDimensions(TensorProductElement(FlattenedDimensions(TensorProductElement(Lagrange(I, 2), Lagrange(I, 2))), Lagrange(I, 2)))",
348 ])
349 def test_nodality_tpe(element):
350 """Check that generated TensorProductElements are nodal, i.e. nodes evaluated
351 on basis functions give Kronecker delta
352 """
353 # Instantiate element
354 element = eval(element)
355
356 # Get nodes coordinates
357 nodes_coord = list(next(iter(f.get_point_dict().keys())) for f in element.dual_basis())
358
359 # Check nodality
360 for j, x in enumerate(nodes_coord):
361 table = element.tabulate(0, (x,))
362 basis = table[list(table.keys())[0]]
363 for i in range(len(basis)):
364 assert np.isclose(basis[i], 1.0 if i == j else 0.0)
365
366
305367 if __name__ == '__main__':
306368 import os
307369 pytest.main(os.path.abspath(__file__))
2222 import pytest
2323 import FIAT
2424 from FIAT.reference_element import UFCInterval, UFCTriangle, UFCTetrahedron
25 from FIAT.reference_element import FiredrakeQuadrilateral, TensorProductCell
25 from FIAT.reference_element import UFCQuadrilateral, UFCHexahedron, TensorProductCell
2626
2727
2828 @pytest.fixture(scope='module')
4242
4343 @pytest.fixture(scope='module')
4444 def quadrilateral():
45 return FiredrakeQuadrilateral()
45 return UFCQuadrilateral()
46
47
48 @pytest.fixture(scope='module')
49 def hexahedron():
50 return UFCHexahedron()
4651
4752
4853 @pytest.fixture(scope='module')
6065 @pytest.fixture(scope='module')
6166 def extr_quadrilateral():
6267 """Extruded quadrilateral = quadrilateral x interval"""
63 return TensorProductCell(FiredrakeQuadrilateral(), UFCInterval())
68 return TensorProductCell(UFCQuadrilateral(), UFCInterval())
6469
6570
6671 @pytest.fixture(params=["canonical", "default"])
115120 (2**(degree + 2) - 2) / ((degree + 1)*(degree + 2)))
116121
117122
123 @pytest.mark.parametrize("degree", range(8))
124 def test_create_quadrature_hexahedron(hexahedron, degree, scheme):
125 q = FIAT.create_quadrature(hexahedron, degree, scheme)
126 assert numpy.allclose(q.integrate(lambda x: sum(x)**degree),
127 -3 * (2**(degree + 3) - 3**(degree + 2) - 1) / ((degree + 1)*(degree + 2)*(degree + 3)))
128
129
118130 @pytest.mark.parametrize("extrdeg", range(4))
119131 @pytest.mark.parametrize("basedeg", range(5))
120132 def test_create_quadrature_extr_quadrilateral(extr_quadrilateral, basedeg, extrdeg, scheme):
138150 def test_invalid_quadrature_degree_tensor_prod(cell):
139151 with pytest.raises(ValueError):
140152 FIAT.create_quadrature(cell, (-1, -1))
141
142
143 @pytest.mark.parametrize("cell", [interval(),
144 triangle(),
145 tetrahedron(),
146 quadrilateral()])
147 def test_high_degree_runtime_error(cell):
148 with pytest.raises(RuntimeError):
149 FIAT.create_quadrature(cell, 60)
150
151
152 @pytest.mark.parametrize("cell", [extr_interval(),
153 extr_triangle(),
154 extr_quadrilateral()])
155 def test_high_degree_runtime_error_tensor_prod(cell):
156 with pytest.raises(RuntimeError):
157 FIAT.create_quadrature(cell, (60, 60))
158153
159154
160155 def test_tensor_product_composition(interval, triangle, extr_triangle, scheme):
0 # Copyright (C) 2017 Miklos Homolya
1 #
2 # This file is part of FIAT.
3 #
4 # FIAT is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Lesser General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # FIAT is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public License
15 # along with FIAT. If not, see <http://www.gnu.org/licenses/>.
16
17 from __future__ import absolute_import, print_function, division
18
19 import pytest
20 import numpy as np
21
22 from FIAT import QuadratureElement, make_quadrature, ufc_simplex
23
24
25 @pytest.fixture(params=[1, 2, 3])
26 def cell(request):
27 return ufc_simplex(request.param)
28
29
30 @pytest.fixture
31 def quadrature(cell):
32 return make_quadrature(cell, 2)
33
34
35 @pytest.fixture
36 def element(cell, quadrature):
37 return QuadratureElement(cell, quadrature.get_points())
38
39
40 def test_order(element, quadrature):
41 with pytest.raises(ValueError):
42 element.tabulate(1, quadrature.get_points())
43
44
45 def test_points(element, quadrature):
46 points = quadrature.get_points()
47 wrong_points = np.linspace(0.0, 1.0, points.size).reshape(points.shape)
48 with pytest.raises(AssertionError):
49 element.tabulate(0, wrong_points)
50
51
52 def test_entity(element, quadrature):
53 dim = element.get_reference_element().get_spatial_dimension()
54 points = make_quadrature(ufc_simplex(dim - 1), 2).get_points()
55 with pytest.raises(ValueError):
56 element.tabulate(0, points, entity=(dim - 1, 1))
57
58
59 def test_result(element, quadrature):
60 dim = element.get_reference_element().get_spatial_dimension()
61 points = quadrature.get_points()
62 actual = element.tabulate(0, points)[(0,) * dim]
63 assert np.allclose(np.eye(len(points)), actual)
64
65
66 if __name__ == '__main__':
67 import os
68 pytest.main(os.path.abspath(__file__))
2020 import numpy as np
2121
2222 from FIAT.reference_element import UFCInterval, UFCTriangle, UFCTetrahedron
23 from FIAT.reference_element import Point, FiredrakeQuadrilateral, TensorProductCell
23 from FIAT.reference_element import Point, TensorProductCell, UFCQuadrilateral, UFCHexahedron
2424
2525 point = Point()
2626 interval = UFCInterval()
2727 triangle = UFCTriangle()
28 quadrilateral = FiredrakeQuadrilateral()
28 quadrilateral = UFCQuadrilateral()
29 hexahedron = UFCHexahedron()
2930 tetrahedron = UFCTetrahedron()
3031 interval_x_interval = TensorProductCell(interval, interval)
3132 triangle_x_interval = TensorProductCell(triangle, interval)
4041 (tetrahedron, 1/6),
4142 (interval_x_interval, 1),
4243 (triangle_x_interval, 1/2),
43 (quadrilateral_x_interval, 1)])
44 (quadrilateral_x_interval, 1),
45 (hexahedron, 1)])
4446 def test_volume(cell, volume):
4547 assert np.allclose(volume, cell.volume())
4648
5860 (tetrahedron, [[1, 1, 1],
5961 [-1, 0, 0],
6062 [0, -1, 0],
61 [0, 0, -1]])])
63 [0, 0, -1]]),
64 (hexahedron, [[-1, 0, 0],
65 [1, 0, 0],
66 [0, -1, 0],
67 [0, 1, 0],
68 [0, 0, -1],
69 [0, 0, 1]])])
6270 def test_reference_normal(cell, normals):
6371 facet_dim = cell.get_spatial_dimension() - 1
6472 for facet_number in range(len(cell.get_topology()[facet_dim])):
2828 from FIAT.discontinuous_lagrange import DiscontinuousLagrange
2929 from FIAT.nedelec import Nedelec
3030 from FIAT.raviart_thomas import RaviartThomas
31 from FIAT.tensor_product import TensorProductElement
31 from FIAT.tensor_product import TensorProductElement, FlattenedDimensions
3232 from FIAT.hdivcurl import Hdiv, Hcurl
3333 from FIAT.enriched import EnrichedElement
3434
521521 assert tab[dd][7][2][0] == 0.0
522522
523523
524 def test_flattened_against_tpe_quad():
525 T = UFCInterval()
526 P1 = Lagrange(T, 1)
527 tpe_quad = TensorProductElement(P1, P1)
528 flattened_quad = FlattenedDimensions(tpe_quad)
529 assert tpe_quad.value_shape() == ()
530 tpe_tab = tpe_quad.tabulate(1, [(0.1, 0.2)])
531 flattened_tab = flattened_quad.tabulate(1, [(0.1, 0.2)])
532
533 for da, db in [[(0,), (0,)], [(1,), (0,)], [(0,), (1,)]]:
534 dc = da + db
535 assert np.isclose(tpe_tab[dc][0][0], flattened_tab[dc][0][0])
536 assert np.isclose(tpe_tab[dc][1][0], flattened_tab[dc][1][0])
537 assert np.isclose(tpe_tab[dc][2][0], flattened_tab[dc][2][0])
538 assert np.isclose(tpe_tab[dc][3][0], flattened_tab[dc][3][0])
539
540
541 def test_flattened_against_tpe_hex():
542 T = UFCInterval()
543 P1 = Lagrange(T, 1)
544 tpe_quad = TensorProductElement(P1, P1)
545 tpe_hex = TensorProductElement(tpe_quad, P1)
546 flattened_quad = FlattenedDimensions(tpe_quad)
547 flattened_hex = FlattenedDimensions(TensorProductElement(flattened_quad, P1))
548 assert tpe_quad.value_shape() == ()
549 tpe_tab = tpe_hex.tabulate(1, [(0.1, 0.2, 0.3)])
550 flattened_tab = flattened_hex.tabulate(1, [(0.1, 0.2, 0.3)])
551
552 for da, db, dc in [[(0,), (0,), (0,)], [(1,), (0,), (0,)], [(0,), (1,), (0,)], [(0,), (0,), (1,)]]:
553 dd = da + db + dc
554 assert np.isclose(tpe_tab[dd][0][0], flattened_tab[dd][0][0])
555 assert np.isclose(tpe_tab[dd][1][0], flattened_tab[dd][1][0])
556 assert np.isclose(tpe_tab[dd][2][0], flattened_tab[dd][2][0])
557 assert np.isclose(tpe_tab[dd][3][0], flattened_tab[dd][3][0])
558 assert np.isclose(tpe_tab[dd][4][0], flattened_tab[dd][4][0])
559 assert np.isclose(tpe_tab[dd][5][0], flattened_tab[dd][5][0])
560 assert np.isclose(tpe_tab[dd][6][0], flattened_tab[dd][6][0])
561 assert np.isclose(tpe_tab[dd][7][0], flattened_tab[dd][7][0])
562
563
524564 if __name__ == '__main__':
525565 import os
526566 pytest.main(os.path.abspath(__file__))