Skip to content

Commit 273d02f

Browse files
authored
Merge pull request thelfer#99 from thelfer/tensor-vec-repr
Fixes thelfer#98
2 parents 42609e3 + 348c733 commit 273d02f

6 files changed

+293
-188
lines changed

bindings/python/mgis/fenics/gradient_flux.py

+26-17
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
get_quadrature_element,
1818
vector_to_tensor,
1919
)
20+
import mgis.behaviour as mgis_bv
2021

2122

2223
class QuadratureFunction:
2324
"""An abstract class for functions defined at quadrature points"""
24-
def __init__(self, name, shape):
25+
def __init__(self, name, shape, hypothesis):
2526
self.shape = shape
2627
self.name = name
28+
self.hypothesis = hypothesis
2729

2830
def initialize_function(self, mesh, quadrature_degree):
2931
self.quadrature_degree = quadrature_degree
@@ -87,26 +89,32 @@ class Gradient(QuadratureFunction):
8789
This class is intended for internal use only. Gradient objects must be
8890
declared by the user using the registration concept.
8991
"""
90-
def __init__(self, variable, expression, name, symmetric=None):
92+
def __init__(self, variable, expression, name, hypothesis, symmetric=None):
9193
self.variable = variable
9294
if symmetric is None:
9395
self.expression = expression
9496
# TODO: treat axisymmetric case
95-
elif symmetric:
96-
if ufl.shape(expression) == (2, 2):
97-
self.expression = as_vector([
98-
symmetric_tensor_to_vector(expression)[i] for i in range(4)
99-
])
100-
else:
101-
self.expression = symmetric_tensor_to_vector(expression)
10297
else:
103-
if ufl.shape(expression) == (2, 2):
104-
self.expression = as_vector([
105-
nonsymmetric_tensor_to_vector(expression)[i]
106-
for i in range(5)
107-
])
98+
if symmetric:
99+
converter = symmetric_tensor_to_vector
100+
else:
101+
converter = nonsymmetric_tensor_to_vector
102+
if hypothesis in [
103+
mgis_bv.Hypothesis.PlaneStrain,
104+
mgis_bv.Hypothesis.Axisymmetrical,
105+
]:
106+
if ufl.shape(expression) == (2, 2):
107+
T22 = 0
108+
expression_2d = expression
109+
elif ufl.shape(expression) == (3, 3):
110+
T22 = expression[2, 2]
111+
expression_2d = ufl.as_tensor(
112+
[[expression[i, j] for j in range(2)]
113+
for i in range(2)])
114+
self.expression = converter(expression_2d, T22)
108115
else:
109-
self.expression = nonsymmetric_tensor_to_vector(expression)
116+
self.expression = converter(expression)
117+
110118
shape = ufl.shape(self.expression)
111119
if len(shape) == 1:
112120
self.shape = shape[0]
@@ -115,6 +123,7 @@ def __init__(self, variable, expression, name, symmetric=None):
115123
else:
116124
self.shape = shape
117125
self.name = name
126+
self.hypothesis = hypothesis
118127

119128
def __call__(self, v):
120129
return ufl.replace(self.expression, {self.variable: v})
@@ -148,8 +157,8 @@ def _evaluate_at_quadrature_points(self, x):
148157

149158
class Var(Gradient):
150159
""" A simple variable """
151-
def __init__(self, variable, expression, name):
152-
Gradient.__init__(self, variable, expression, name)
160+
def __init__(self, variable, expression, name, hypothesis):
161+
Gradient.__init__(self, variable, expression, name, hypothesis)
153162

154163
def _evaluate_at_quadrature_points(self, x):
155164
local_project(x, self.function_space, self.dx, self.function)

bindings/python/mgis/fenics/nonlinear_problem.py

+15-6
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
}
2626
Id_Grad = {
2727
mgis_bv.Hypothesis.Tridimensional: lambda u: Identity(3) + grad(u),
28-
mgis_bv.Hypothesis.PlaneStrain: lambda u: Identity(2) + grad(u),
28+
mgis_bv.Hypothesis.PlaneStrain: lambda u: Identity(3) + grad_3d(u),
2929
mgis_bv.Hypothesis.Axisymmetrical:
3030
lambda r, u: Identity(3) + axi_grad(r, u),
3131
}
@@ -222,8 +222,16 @@ def register_gradient(self, name, expression):
222222
symmetric = True
223223
else:
224224
symmetric = None
225-
self.gradients.update(
226-
{name: Gradient(self.u, expression, name, symmetric=symmetric)})
225+
self.gradients.update({
226+
name:
227+
Gradient(
228+
self.u,
229+
expression,
230+
name,
231+
self.material.hypothesis,
232+
symmetric=symmetric,
233+
)
234+
})
227235

228236
def register_external_state_variable(self, name, expression):
229237
"""
@@ -245,7 +253,7 @@ def register_external_state_variable(self, name, expression):
245253
if type(expression) == float:
246254
expression = Constant(expression)
247255
self.state_variables["external"].update(
248-
{name: Var(self.u, expression, name)})
256+
{name: Var(self.u, expression, name, self.material.hypothesis)})
249257

250258
def set_loading(self, Fext):
251259
"""
@@ -307,7 +315,7 @@ def initialize_fluxes(self):
307315
fluxes = []
308316
for (f, size) in zip(self.material.get_flux_names(),
309317
self.material.get_flux_sizes()):
310-
flux = Flux(f, size)
318+
flux = Flux(f, size, self.material.hypothesis)
311319
flux.initialize_function(self.mesh, self.quadrature_degree)
312320
fluxes.append(flux)
313321
self.fluxes = dict(zip(self.material.get_flux_names(), fluxes))
@@ -318,7 +326,8 @@ def initialize_internal_state_variables(self):
318326
self.material.get_internal_state_variable_names(),
319327
self.material.get_internal_state_variable_sizes(),
320328
):
321-
state_variable = InternalStateVariable(s, size)
329+
state_variable = InternalStateVariable(s, size,
330+
self.material.hypothesis)
322331
state_variable.initialize_function(self.mesh,
323332
self.quadrature_degree)
324333
state_variables.append(state_variable)

bindings/python/mgis/fenics/utils.py

+56-34
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,18 @@ def local_project(v, V, dx, u=None):
3232

3333

3434
def symmetric_tensor_to_vector(T, T22=0):
35-
""" Return symmetric tensor components in vector form notation following MFront conventions
36-
T22 can be specified when T is only (2,2)"""
35+
"""Return symmetric tensor components in vector form notation following MFront conventions
36+
T22 can be specified when T is only (2,2)"""
3737
if ufl.shape(T) == (2, 2):
3838
return as_vector([T[0, 0], T[1, 1], T22, sqrt(2) * T[0, 1]])
3939
elif ufl.shape(T) == (3, 3):
4040
return as_vector([
41-
T[0, 0], T[1, 1], T[2, 2],
41+
T[0, 0],
42+
T[1, 1],
43+
T[2, 2],
4244
sqrt(2) * T[0, 1],
4345
sqrt(2) * T[0, 2],
44-
sqrt(2) * T[1, 2]
46+
sqrt(2) * T[1, 2],
4547
])
4648
elif len(ufl.shape(T)) == 1:
4749
return T
@@ -50,14 +52,21 @@ def symmetric_tensor_to_vector(T, T22=0):
5052

5153

5254
def nonsymmetric_tensor_to_vector(T, T22=0):
53-
""" Return nonsymmetric tensor components in vector form notation following MFront conventions
54-
T22 can be specified when T is only (2,2) """
55+
"""Return nonsymmetric tensor components in vector form notation following MFront conventions
56+
T22 can be specified when T is only (2,2)"""
5557
if ufl.shape(T) == (2, 2):
5658
return as_vector([T[0, 0], T[1, 1], T22, T[0, 1], T[1, 0]])
5759
elif ufl.shape(T) == (3, 3):
5860
return as_vector([
59-
T[0, 0], T[1, 1], T[2, 2], T[0, 1], T[1, 0], T[0, 2], T[2, 0],
60-
T[1, 2], T[2, 1]
61+
T[0, 0],
62+
T[1, 1],
63+
T[2, 2],
64+
T[0, 1],
65+
T[1, 0],
66+
T[0, 2],
67+
T[2, 0],
68+
T[1, 2],
69+
T[2, 1],
6170
])
6271
elif len(ufl.shape(T)) == 1:
6372
return T
@@ -70,9 +79,11 @@ def vector_to_tensor(T):
7079
if ufl.shape(T) == (4, ):
7180
return as_tensor([[T[0], T[3] / sqrt(2)], T[3] / sqrt(2), T[1]])
7281
elif ufl.shape(T) == (6, ):
73-
return as_tensor([[T[0], T[3] / sqrt(2), T[4] / sqrt(2)],
74-
[T[3] / sqrt(2), T[1], T[5] / sqrt(2)],
75-
[T[4] / sqrt(2), T[5] / sqrt(2), T[2]]])
82+
return as_tensor([
83+
[T[0], T[3] / sqrt(2), T[4] / sqrt(2)],
84+
[T[3] / sqrt(2), T[1], T[5] / sqrt(2)],
85+
[T[4] / sqrt(2), T[5] / sqrt(2), T[2]],
86+
])
7687
elif ufl.shape(T) == (5, ):
7788
return as_tensor([[T[0], T[3]], T[4], T[1]])
7889
elif ufl.shape(T) == (9, ):
@@ -84,15 +95,17 @@ def vector_to_tensor(T):
8495

8596
def axi_grad(r, v):
8697
"""
87-
Axisymmetric gradient in cylindrical coordinate (er, etheta, ez) for:
88-
* a scalar v(r, z)
89-
* a 2d-vectorial (vr(r,z), vz(r, z))
90-
* a 3d-vectorial (vr(r,z), 0, vz(r, z))
98+
Axisymmetric gradient in cylindrical coordinate (er, etheta, ez) for:
99+
* a scalar v(r, z)
100+
* a 2d-vectorial (vr(r,z), vz(r, z))
101+
* a 3d-vectorial (vr(r,z), 0, vz(r, z))
91102
"""
92103
if ufl.shape(v) == (3, ):
93-
return as_matrix([[v[0].dx(0), -v[1] / r, v[0].dx(1)],
94-
[v[1].dx(0), v[0] / r, v[1].dx(1)],
95-
[v[2].dx(0), 0, v[2].dx(1)]])
104+
return as_matrix([
105+
[v[0].dx(0), -v[1] / r, v[0].dx(1)],
106+
[v[1].dx(0), v[0] / r, v[1].dx(1)],
107+
[v[2].dx(0), 0, v[2].dx(1)],
108+
])
96109
elif ufl.shape(v) == (2, ):
97110
return as_matrix([[v[0].dx(0), v[0].dx(1), 0],
98111
[v[1].dx(0), v[1].dx(1), 0], [0, 0, v[0] / r]])
@@ -102,6 +115,11 @@ def axi_grad(r, v):
102115
raise NotImplementedError
103116

104117

118+
def grad_3d(u):
119+
return as_matrix([[u[0].dx(0), u[0].dx(1), 0], [u[1].dx(0), u[1].dx(1), 0],
120+
[0, 0, 0]])
121+
122+
105123
def symmetric_gradient(g):
106124
""" Return symmetric gradient components in vector form"""
107125
return symmetric_tensor_to_vector(sym(g))
@@ -122,26 +140,26 @@ def get_quadrature_element(cell, degree, dim=0):
122140
return FiniteElement("Quadrature",
123141
cell,
124142
degree=degree,
125-
quad_scheme='default')
143+
quad_scheme="default")
126144
elif type(dim) == int:
127145
return VectorElement("Quadrature",
128146
cell,
129147
degree=degree,
130148
dim=dim,
131-
quad_scheme='default')
149+
quad_scheme="default")
132150
elif len(dim) == 1 or (len(dim) == 2 and 0 in dim):
133151
d = [dd for dd in list(dim) if dd != 0][0]
134152
return VectorElement("Quadrature",
135153
cell,
136154
degree=degree,
137155
dim=d,
138-
quad_scheme='default')
156+
quad_scheme="default")
139157
elif type(dim) == tuple:
140158
return TensorElement("Quadrature",
141159
cell,
142160
degree=degree,
143161
shape=dim,
144-
quad_scheme='default')
162+
quad_scheme="default")
145163
else:
146164
raise ValueError("Wrong shape for dim=", dim)
147165

@@ -170,12 +188,14 @@ def project_on_quadrature(f, mesh, degree):
170188
shape = f.ufl_shape
171189
Vge = get_quadrature_element(mesh.ufl_cell(), degree, shape)
172190
Vg = FunctionSpace(mesh, Vge)
173-
dx = Measure("dx",
174-
domain=mesh,
175-
metadata={
176-
"quadrature_scheme": "default",
177-
"quadrature_degree": degree
178-
})
191+
dx = Measure(
192+
"dx",
193+
domain=mesh,
194+
metadata={
195+
"quadrature_scheme": "default",
196+
"quadrature_degree": degree
197+
},
198+
)
179199
fg = Function(Vg)
180200
fg.assign(local_project(f, Vg, dx))
181201
return fg
@@ -185,12 +205,14 @@ def compute_on_quadrature(f, mesh, degree):
185205
shape = f.ufl_shape
186206
Vge = get_quadrature_element(mesh.ufl_cell(), degree, shape)
187207
Vg = FunctionSpace(mesh, Vge)
188-
dx = Measure("dx",
189-
domain=mesh,
190-
metadata={
191-
"quadrature_scheme": "default",
192-
"quadrature_degree": degree
193-
})
208+
dx = Measure(
209+
"dx",
210+
domain=mesh,
211+
metadata={
212+
"quadrature_scheme": "default",
213+
"quadrature_degree": degree
214+
},
215+
)
194216
fg = Function(Vg)
195217
if (isinstance(f, function.function.Function)
196218
or isinstance(f, function.function.Constant)

0 commit comments

Comments
 (0)