Skip to content

Commit 55e3630

Browse files
authored
Merge pull request #21 from mscroggs/more-elements
More elements
2 parents f79a9ef + f97c941 commit 55e3630

26 files changed

+385
-75
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2021.1.1
1+
2021.1.2

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[flake8]
2-
ignore = E501
2+
max-line-length = 100
33
exclude = __init__.py
44
min-version = 3.0
55

symfem/__init__.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
with open(_os.path.join(_v_folder, "VERSION")) as _f:
1717
__version__ = _f.read().strip()
1818

19-
_elementlist = {}
20-
19+
_elementmap = {}
20+
_elementlist = []
2121

2222
for _file in _os.listdir(_os.path.join(_folder, "elements")):
2323
if _file.endswith(".py") and "__init__" not in _file:
@@ -31,10 +31,11 @@
3131
and issubclass(_element, _FiniteElement)
3232
and _element != _FiniteElement
3333
):
34+
_elementlist.append(_element)
3435
for _n in _element.names:
35-
if _n in _elementlist:
36-
assert _element == _elementlist[_n]
37-
_elementlist[_n] = _element
36+
if _n in _elementmap:
37+
assert _element == _elementmap[_n]
38+
_elementmap[_n] = _element
3839

3940

4041
def create_reference(cell_type, vertices=None):
@@ -89,13 +90,15 @@ def create_element(cell_type, element_type, order):
8990
vector Lagrange, vP, Regge, Nedelec, Nedelec1, N1curl,
9091
Nedelec2, N2curl, Raviart-Thomas, RT, N1div, dQ, NCE, RTCE,
9192
Qcurl, Q, NCF, RTCF, Qdiv, vector Q, vQ,
92-
Brezzi-Douglas-Marini, BDM, N2div
93+
Brezzi-Douglas-Marini, BDM, N2div, Morley, Hermite,
94+
Mardal-Tai-Winther, MTW, Argyris
9395
order : int
9496
The order of the element.
9597
"""
9698
reference = create_reference(cell_type)
9799

98-
if element_type in _elementlist:
99-
return _elementlist[element_type](reference, order)
100+
if element_type in _elementmap:
101+
assert cell_type in _elementmap[element_type].references
102+
return _elementmap[element_type](reference, order)
100103

101104
raise ValueError(f"Unsupported element type: {element_type}")

symfem/core/calculus.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""Functions to handle derivatives."""
2+
3+
from .vectors import vdot
4+
from .symbolic import x, sym_sum
5+
6+
7+
def derivative(f, dir):
8+
"""Find the directional derivative of a function."""
9+
return vdot(grad(f, len(dir)), dir)
10+
11+
12+
def grad(f, dim):
13+
"""Find the gradient of a scalar function."""
14+
return tuple(f.diff(x[i]) for i in range(dim))
15+
16+
17+
def jacobian_component(f, component):
18+
"""Find a component of the Jacobian."""
19+
return f.diff(x[component[0]]).diff(x[component[1]])
20+
21+
22+
def jacobian(f, dim):
23+
"""Find the Jacobian."""
24+
return [[f.diff(x[i]).diff(x[j]) for i in range(dim)] for j in range(dim)]
25+
26+
27+
def div(f):
28+
"""Find the divergence of a vector function."""
29+
return sym_sum(j.diff(x[i]) for i, j in enumerate(f))
30+
31+
32+
def curl(f):
33+
"""Find the curl of a 3D vector function."""
34+
return (
35+
f[2].diff(x[1]) - f[1].diff(x[2]),
36+
f[0].diff(x[2]) - f[2].diff(x[0]),
37+
f[1].diff(x[0]) - f[0].diff(x[1])
38+
)

symfem/core/finite_element.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,8 @@ def name(self):
118118

119119
def make_integral_moment_dofs(
120120
reference,
121-
vertices=None,
122-
edges=None,
123-
faces=None,
124-
volumes=None,
125-
cells=None,
126-
facets=None,
127-
ridges=None,
128-
peaks=None,
121+
vertices=None, edges=None, faces=None, volumes=None,
122+
cells=None, facets=None, ridges=None, peaks=None
129123
):
130124
"""Generate DOFs due to integral moments on sub entities.
131125

symfem/core/functionals.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Functionals used to define the dual sets."""
22
from .symbolic import subs, x, t
33
from .vectors import vdot
4+
from .calculus import derivative, jacobian_component
45

56

67
class BaseFunctional:
@@ -47,6 +48,66 @@ def entity_dim(self):
4748
name = "Point evaluation"
4849

4950

51+
class PointDirectionalDerivativeEvaluation(BaseFunctional):
52+
"""A point evaluation of a derivative in a fixed direction."""
53+
54+
def __init__(self, point, direction, entity_dim=None):
55+
self.point = point
56+
self.dir = direction
57+
self._entity_dim = entity_dim
58+
59+
def eval(self, function):
60+
"""Apply to the functional to a function."""
61+
return subs(derivative(function, self.dir), x, self.point)
62+
63+
def dof_point(self):
64+
"""Get the location of the DOF in the cell."""
65+
return self.point
66+
67+
def dof_direction(self):
68+
"""Get the direction of the DOF."""
69+
return self.dir
70+
71+
def entity_dim(self):
72+
"""Get the dimension of the entitiy this DOF is associated with."""
73+
return self._entity_dim
74+
75+
name = "Point evaluation of directional derivative"
76+
77+
78+
class PointNormalDerivativeEvaluation(PointDirectionalDerivativeEvaluation):
79+
"""A point evaluation of a normal derivative."""
80+
81+
def __init__(self, point, edge):
82+
super().__init__(point, edge.normal(), entity_dim=edge.tdim)
83+
self.reference = edge
84+
85+
name = "Point evaluation of normal derivative"
86+
87+
88+
class PointComponentSecondDerivativeEvaluation(BaseFunctional):
89+
"""A point evaluation of a component of a second derivative."""
90+
91+
def __init__(self, point, component, entity_dim=None):
92+
self.point = point
93+
self.component = component
94+
self._entity_dim = entity_dim
95+
96+
def eval(self, function):
97+
"""Apply to the functional to a function."""
98+
return subs(jacobian_component(function, self.component), x, self.point)
99+
100+
def dof_point(self):
101+
"""Get the location of the DOF in the cell."""
102+
return self.point
103+
104+
def entity_dim(self):
105+
"""Get the dimension of the entitiy this DOF is associated with."""
106+
return self._entity_dim
107+
108+
name = "Point evaluation of Jacobian component"
109+
110+
50111
class PointInnerProduct(BaseFunctional):
51112
"""An evaluation of an inner product at a point."""
52113

symfem/core/symbolic.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,11 @@ def subs(f, vars, values):
2222
return (
2323
f.subs(vars[0], values[0]).subs(vars[1], values[1]).subs(vars[2], values[2])
2424
)
25+
26+
27+
def sym_sum(ls):
28+
"""Symbolically computes the sum of a list."""
29+
out = zero
30+
for i in ls:
31+
out += i
32+
return out

symfem/core/vectors.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ def vsub(v, w):
1111
return v - w
1212

1313

14+
def vadd(v, w):
15+
"""Add two vectors."""
16+
try:
17+
return tuple(i + j for i, j in zip(v, w))
18+
except TypeError:
19+
return v + w
20+
21+
1422
def vdiv(v, a):
1523
"""Divide a vector by a scalar."""
1624
try:

symfem/elements/argyris.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""Argyris elements on simplices."""
2+
3+
from ..core.finite_element import FiniteElement
4+
from ..core.polynomials import polynomial_set
5+
from ..core.functionals import (PointEvaluation, PointDirectionalDerivativeEvaluation,
6+
PointNormalDerivativeEvaluation,
7+
PointComponentSecondDerivativeEvaluation)
8+
from ..core.symbolic import sym_sum
9+
10+
11+
class Argyris(FiniteElement):
12+
"""Argyris finite element."""
13+
14+
def __init__(self, reference, order):
15+
from symfem import create_reference
16+
assert order == 5
17+
assert reference.name == "triangle"
18+
dofs = []
19+
for vs in reference.sub_entities(0):
20+
dofs.append(PointEvaluation(vs, entity_dim=0))
21+
for i in range(reference.tdim):
22+
dir = tuple(1 if i == j else 0 for j in range(reference.tdim))
23+
dofs.append(PointDirectionalDerivativeEvaluation(vs, dir, entity_dim=0))
24+
for i in range(reference.tdim):
25+
for j in range(i + 1):
26+
dofs.append(PointComponentSecondDerivativeEvaluation(
27+
vs, (i, j), entity_dim=0))
28+
for vs in reference.sub_entities(1):
29+
sub_ref = create_reference(
30+
reference.sub_entity_types[1],
31+
vertices=[reference.reference_vertices[v] for v in vs])
32+
midpoint = tuple(sym_sum(i) / len(i)
33+
for i in zip(*[reference.vertices[i] for i in vs]))
34+
dofs.append(PointNormalDerivativeEvaluation(midpoint, sub_ref))
35+
36+
super().__init__(
37+
reference, polynomial_set(reference.tdim, 1, order), dofs, reference.tdim, 1
38+
)
39+
40+
names = ["Argyris"]
41+
references = ["triangle"]
42+
min_order = 5
43+
max_order = 5

symfem/elements/bdm.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ def __init__(self, reference, order):
2222
super().__init__(reference, poly, dofs, reference.tdim, reference.tdim)
2323

2424
names = ["Brezzi-Douglas-Marini", "BDM", "N2div"]
25+
references = ["triangle", "tetrahedron"]
2526
min_order = 1

0 commit comments

Comments
 (0)