ddfem 0.9.0__py3-none-any.whl → 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. ddfem/__init__.py +0 -4
  2. ddfem/base_model.py +200 -0
  3. ddfem/boundary.py +3 -12
  4. ddfem/geometry/__init__.py +3 -3
  5. ddfem/geometry/arc.py +8 -10
  6. ddfem/geometry/box.py +8 -7
  7. ddfem/geometry/circle.py +39 -0
  8. ddfem/geometry/domain.py +4 -16
  9. ddfem/geometry/domain_dune.py +0 -16
  10. ddfem/geometry/helpers.py +12 -19
  11. ddfem/geometry/pie.py +7 -7
  12. ddfem/geometry/primitive_base.py +70 -129
  13. ddfem/geometry/vesica.py +6 -7
  14. ddfem/model2ufl.py +4 -10
  15. ddfem/transformers/DDM1.py +68 -10
  16. ddfem/transformers/Fitted.py +12 -22
  17. ddfem/transformers/Mix0.py +64 -10
  18. ddfem/transformers/NNS.py +72 -11
  19. ddfem/transformers/NS.py +79 -14
  20. ddfem/transformers/__init__.py +0 -1
  21. ddfem/transformers/transformer_base.py +15 -102
  22. {ddfem-0.9.0.dist-info → ddfem-1.0.0.dist-info}/METADATA +1 -2
  23. ddfem-1.0.0.dist-info/RECORD +27 -0
  24. ddfem/examples/__init__.py +0 -0
  25. ddfem/examples/advection_diffusion.py +0 -74
  26. ddfem/examples/beam.py +0 -147
  27. ddfem/examples/cahn_hilliard.py +0 -67
  28. ddfem/examples/chemical_reaction.py +0 -88
  29. ddfem/examples/constant.py +0 -46
  30. ddfem/examples/five_circle_flat.py +0 -197
  31. ddfem/examples/forchheimer.py +0 -48
  32. ddfem/examples/hyperelasticity.py +0 -88
  33. ddfem/examples/linear_elasticity.py +0 -45
  34. ddfem/examples/plaplace.py +0 -29
  35. ddfem/examples/single_circle.py +0 -135
  36. ddfem/examples/triple_circle.py +0 -217
  37. ddfem/examples/triple_circle_beam.py +0 -208
  38. ddfem/geometry/ball.py +0 -24
  39. ddfem/geometry/plane.py +0 -20
  40. ddfem-0.9.0.dist-info/RECORD +0 -41
  41. {ddfem-0.9.0.dist-info → ddfem-1.0.0.dist-info}/WHEEL +0 -0
  42. {ddfem-0.9.0.dist-info → ddfem-1.0.0.dist-info}/licenses/LICENSE +0 -0
  43. {ddfem-0.9.0.dist-info → ddfem-1.0.0.dist-info}/top_level.txt +0 -0
@@ -4,33 +4,27 @@ from ufl import (
4
4
  conditional,
5
5
  cos,
6
6
  grad,
7
- max_value,
8
- min_value,
9
7
  pi,
8
+ replace,
10
9
  sin,
11
10
  tanh,
12
11
  )
12
+ from ufl import max_value as Max
13
+ from ufl import min_value as Min
13
14
 
14
- from .helpers import smax_value, smin_value, ufl_length
15
+ from ufl.algorithms import expand_indices
16
+ from ufl.algorithms.apply_algebra_lowering import apply_algebra_lowering
17
+ from ufl.algorithms.apply_derivatives import apply_derivatives
15
18
 
16
19
  ORIGIN = as_vector([0, 0])
17
20
 
18
21
 
19
22
  class SDF:
20
23
  def __init__(self, epsilon=None, name=None, children=None):
24
+ self.name = name
21
25
  self.epsilon = epsilon
22
26
  self.child_sdf = children if children else []
23
27
 
24
- self.name = name
25
- if self.name is None:
26
- self.name = repr(self)
27
-
28
- def _repr_core(self):
29
- return f"epsilon={self.epsilon}, name={self.name}, children={self.child_sdf}"
30
-
31
- def __repr__(self):
32
- return f"{self.__class__.__name__}({self._repr_core()})"
33
-
34
28
  def sdf(self, x):
35
29
  raise NotImplementedError
36
30
 
@@ -54,10 +48,10 @@ class SDF:
54
48
 
55
49
  return None
56
50
 
57
- def propagate_epsilon(self, epsilon):
51
+ def propgate_epsilon(self, epsilon):
58
52
  self.epsilon = epsilon
59
53
  for child in self.child_sdf:
60
- child.propagate_epsilon(epsilon)
54
+ child.propgate_epsilon(epsilon)
61
55
 
62
56
  def phi(self, x, epsilon=None):
63
57
  if not epsilon:
@@ -105,23 +99,6 @@ class SDF:
105
99
  def round(self, sc):
106
100
  return Round(self, sc)
107
101
 
108
- def extrude(self, length, split_ends=False):
109
- if split_ends:
110
- from .plane import Plane
111
-
112
- ext = Extrusion(self, length * 2, name=f"{self.name}_ext")
113
- ext = Translate(ext, [0, 0, -length / 2], name=f"{self.name}_sides")
114
- bot = Plane([0, 0, -1], 0, name=f"{self.name}_bot")
115
- top = Plane([0, 0, 1], -length, name=f"{self.name}_top")
116
- z_interval = bot & top
117
- ext = ext & z_interval
118
- else:
119
- return Extrusion(self, length, name=f"{self.name}_ext")
120
- return ext
121
-
122
- def revolve(self, offset=0, axis="x"):
123
- return Revolution(self, offset, axis)
124
-
125
102
  def __or__(self, other):
126
103
  return self.union(other)
127
104
 
@@ -135,39 +112,29 @@ class SDF:
135
112
  return self.xor(other)
136
113
 
137
114
  def __mul__(self, other):
138
- return self.scale(other)
115
+ if isinstance(other, (int, float)):
116
+ return self.scale(other)
117
+ raise TypeError(f"Cannot multiply a SDF with {type(other)}")
139
118
 
140
119
  def __rmul__(self, other):
141
120
  if isinstance(other, (int, float)):
142
121
  return self.scale(other)
143
122
  raise TypeError(f"Cannot multiply a SDF with {type(other)}")
144
123
 
145
- # possibly use a 'Constant' but then multiple changes will influence previous usage?
146
- smoothing = None
147
-
148
- def max_value(a, b):
149
- if SDF.smoothing is None:
150
- return max_value(a, b)
151
- else:
152
- return smax_value(a, b, SDF.smoothing)
153
-
154
- def min_value(a, b):
155
- if SDF.smoothing is None:
156
- return min_value(a, b)
157
- else:
158
- return smin_value(a, b, SDF.smoothing)
159
-
160
-
161
124
  class BaseOperator(SDF):
162
- def __init__(self, children, epsilon=None, *args, **kwargs):
125
+ def __init__(self, epsilon, children, *args, **kwargs):
163
126
 
164
127
  if not epsilon and all(child.epsilon for child in children):
165
- epsilon = children[0].epsilon
166
- for child in children:
167
- epsilon = max_value(epsilon, child.epsilon)
128
+ if len(children) == 1:
129
+ epsilon = children[0].epsilon
130
+ else:
131
+ epsilon = Min(*[child.epsilon for child in children])
168
132
 
169
133
  super().__init__(children=children, epsilon=epsilon, *args, **kwargs)
170
134
 
135
+ def __repr__(self):
136
+ return f"{self.__class__.__name__}({', '.join(map(repr, self.child_sdf))})"
137
+
171
138
  def __getitem__(self, key):
172
139
  return self.child_sdf[key]
173
140
 
@@ -175,50 +142,60 @@ class BaseOperator(SDF):
175
142
  class Union(BaseOperator):
176
143
  """Union of two SDFs (OR) - not perfect(negative)"""
177
144
 
178
- def __init__(self, sdf1, sdf2, *args, **kwargs):
179
- super().__init__(children=[sdf1, sdf2], *args, **kwargs)
145
+ def __init__(self, sdf1, sdf2, epsilon=None, name=None, *args, **kwargs):
146
+ super().__init__(epsilon=epsilon, children=[sdf1, sdf2], *args, **kwargs)
147
+ if self.name is None:
148
+ self.name = f"({sdf1.name}|{sdf2.name})"
180
149
 
181
150
  def sdf(self, x):
182
- return SDF.min_value(self.child_sdf[0].sdf(x), self.child_sdf[1].sdf(x))
151
+ return Min(self.child_sdf[0].sdf(x), self.child_sdf[1].sdf(x))
183
152
 
184
153
 
185
154
  class Subtraction(BaseOperator):
186
155
  """Subtraction of two SDFs (difference) - not perfect"""
187
156
 
188
- def __init__(self, sdf1, sdf2, *args, **kwargs):
189
- super().__init__(children=[sdf1, sdf2], *args, **kwargs)
157
+ def __init__(self, sdf1, sdf2, epsilon=None, name=None, *args, **kwargs):
158
+ super().__init__(epsilon=epsilon, children=[sdf1, sdf2], *args, **kwargs)
159
+ if self.name is None:
160
+ self.name = f"({sdf1.name}-{sdf2.name})"
190
161
 
191
162
  def sdf(self, x):
192
- return SDF.max_value(self.child_sdf[0].sdf(x), -self.child_sdf[1].sdf(x))
163
+ return Max(self.child_sdf[0].sdf(x), -self.child_sdf[1].sdf(x))
193
164
 
194
165
 
195
166
  class Intersection(BaseOperator):
196
167
  """Intersection of two SDFs (AND) - not perfect"""
197
168
 
198
- def __init__(self, sdf1, sdf2, *args, **kwargs):
199
- super().__init__(children=[sdf1, sdf2], *args, **kwargs)
169
+ def __init__(self, sdf1, sdf2, epsilon=None, name=None, *args, **kwargs):
170
+ super().__init__(epsilon=epsilon, children=[sdf1, sdf2], *args, **kwargs)
171
+ if self.name is None:
172
+ self.name = f"({sdf1.name}&{sdf2.name})"
200
173
 
201
174
  def sdf(self, x):
202
- return SDF.max_value(self.child_sdf[0].sdf(x), self.child_sdf[1].sdf(x))
175
+ return Max(self.child_sdf[0].sdf(x), self.child_sdf[1].sdf(x))
203
176
 
204
177
 
205
178
  class Xor(BaseOperator):
206
179
  """Xor of two SDFs (AND) - perfect"""
207
180
 
208
- def __init__(self, sdf1, sdf2, *args, **kwargs):
209
- super().__init__(children=[sdf1, sdf2], *args, **kwargs)
181
+ def __init__(self, sdf1, sdf2, epsilon=None, name=None, *args, **kwargs):
182
+ super().__init__(epsilon=epsilon, children=[sdf1, sdf2], *args, **kwargs)
183
+ if self.name is None:
184
+ self.name = f"({sdf1.name}^{sdf2.name})"
210
185
 
211
186
  def sdf(self, x):
212
187
  a_x = self.child_sdf[0].sdf(x)
213
188
  b_x = self.child_sdf[1].sdf(x)
214
- return SDF.max_value(SDF.min_value(a_x, b_x), -SDF.max_value(a_x, b_x))
189
+ return Max(Min(a_x, b_x), -Max(a_x, b_x))
215
190
 
216
191
 
217
192
  class Invert(BaseOperator):
218
193
  """Inverts SDF"""
219
194
 
220
- def __init__(self, sdf1, *args, **kwargs):
221
- super().__init__(children=[sdf1], *args, **kwargs)
195
+ def __init__(self, sdf1, epsilon=None, name=None, *args, **kwargs):
196
+ super().__init__(epsilon=epsilon, children=[sdf1], *args, **kwargs)
197
+ if self.name is None:
198
+ self.name = f"(-{sdf1.name})"
222
199
 
223
200
  def sdf(self, x):
224
201
  return -self.child_sdf[0].sdf(x)
@@ -227,33 +204,33 @@ class Invert(BaseOperator):
227
204
  class Scale(BaseOperator):
228
205
  """Scales SDF"""
229
206
 
230
- def __init__(self, sdf1, scale, *args, **kwargs):
231
- if not isinstance(scale, (int, float)):
232
- raise TypeError(f"Cannot scale a SDF with {type(scale)}")
233
- elif not scale > 0:
234
- raise ValueError("Cannot scale a SDF with nonpositive")
235
- else:
236
- self.scale = scale
237
-
238
- super().__init__(children=[sdf1], *args, **kwargs)
207
+ def __init__(self, sdf1, scale, epsilon=None, name=None, *args, **kwargs):
208
+ super().__init__(epsilon=epsilon, children=[sdf1], *args, **kwargs)
209
+ self.scale = scale
210
+ if self.name is None:
211
+ self.name = f"({scale}*{sdf1.name})"
239
212
 
240
213
  def sdf(self, x):
241
214
  return self.child_sdf[0].sdf(x / self.scale) * self.scale
242
215
 
243
216
  def __repr__(self):
244
- return f"Scale({self.scale}, {self._repr_core()})"
217
+ return f"Scale({repr(self.child_sdf[0])}, {self.scale})"
245
218
 
246
219
 
247
220
  class Rotate(BaseOperator):
248
221
  """Rotates SDF, counterclockwise of orgin"""
249
222
 
250
- def __init__(self, sdf1, angle, radians=True, *args, **kwargs):
223
+ def __init__(
224
+ self, sdf1, angle, radians=True, epsilon=None, name=None, *args, **kwargs
225
+ ):
226
+ super().__init__(epsilon=epsilon, children=[sdf1], *args, **kwargs)
227
+ if self.name is None:
228
+ self.name = f"({angle}@{sdf1.name})"
229
+
251
230
  if not radians:
252
231
  angle *= pi / 180
253
232
  self.angle = angle
254
233
 
255
- super().__init__(children=[sdf1], *args, **kwargs)
256
-
257
234
  def sdf(self, x):
258
235
  c = cos(self.angle)
259
236
  s = sin(self.angle)
@@ -262,77 +239,41 @@ class Rotate(BaseOperator):
262
239
  return self.child_sdf[0].sdf(r.T * x)
263
240
 
264
241
  def __repr__(self):
265
- return f"Rotate({self.angle}, {self._repr_core()})"
242
+ return f"Rotate({repr(self.child_sdf[0])}, {self.angle})"
266
243
 
267
244
 
268
245
  class Translate(BaseOperator):
269
246
  """Translates SDF"""
270
247
 
271
- def __init__(self, sdf1, vec, *args, **kwargs):
248
+ def __init__(self, sdf1, vec, epsilon=None, name=None, *args, **kwargs):
249
+ super().__init__(epsilon=epsilon, children=[sdf1], *args, **kwargs)
250
+ if self.name is None:
251
+ self.name = f"({vec}+{sdf1.name})"
252
+
272
253
  if isinstance(vec, (list, tuple)):
273
254
  vec = as_vector(vec)
274
255
  self.vec = vec
275
256
 
276
- super().__init__(children=[sdf1], *args, **kwargs)
277
-
278
257
  def sdf(self, x):
279
258
  return self.child_sdf[0].sdf(x - self.vec)
280
259
 
281
260
  def __repr__(self):
282
- return f"Translate({self.vec}, {self._repr_core()})"
261
+ return f"Translate({repr(self.child_sdf[0])}, {self.vec})"
283
262
 
284
263
 
285
264
  class Round(BaseOperator):
286
265
  """Rounds SDF"""
287
266
 
288
- def __init__(self, sdf1, scale, *args, **kwargs):
267
+ def __init__(self, sdf1, scale, epsilon=None, name=None, *args, **kwargs):
268
+ super().__init__(epsilon=epsilon, children=[sdf1], *args, **kwargs)
269
+ if self.name is None:
270
+ self.name = f"({scale}~{sdf1.name})"
271
+
289
272
  assert scale > 0
290
273
  self._scale = scale # careful not to overwrite SDF.scale here
291
274
 
292
- super().__init__(children=[sdf1], *args, **kwargs)
293
-
294
275
  def sdf(self, x):
295
276
  return self.child_sdf[0].sdf(x) - self._scale
296
277
 
297
278
  def __repr__(self):
298
- return f"Round({self._scale}, {self._repr_core()})"
299
-
300
-
301
- class Extrusion(BaseOperator):
302
- """Extrude SDF"""
303
-
304
- def __init__(self, sdf1, extrude_length, *args, **kwargs):
305
- self.extrude_length = extrude_length
306
-
307
- super().__init__(children=[sdf1], *args, **kwargs)
308
-
309
- def sdf(self, x):
310
- d = self.child_sdf[0].sdf(as_vector([x[0], x[1]]))
311
- w = abs(x[2]) - self.extrude_length
312
- return SDF.min_value(SDF.max_value(d, w), 0) + ufl_length(
313
- as_vector([SDF.max_value(d, 0), SDF.max_value(w, 0)])
314
- )
315
-
316
- def __repr__(self):
317
- return f"Extrusion({self.extrude_length}, {self._repr_core()})"
318
-
319
-
320
- class Revolution(BaseOperator):
321
- """Revolve SDF"""
322
-
323
- def __init__(self, sdf1, offset, axis, *args, **kwargs):
324
- self.offset = offset
325
- assert axis in ["x", "y"], "Can only revolve around the x or y axis"
326
- self.axis = axis
327
-
328
- super().__init__(children=[sdf1], *args, **kwargs)
329
-
330
- def sdf(self, x):
331
- if self.axis == "x":
332
- q = as_vector([x[0], ufl_length(as_vector([x[1], x[2]])) - self.offset])
333
- elif self.axis == "y":
334
- q = as_vector([ufl_length(as_vector([x[0], x[2]])) - self.offset, x[1]])
335
- return self.child_sdf[0].sdf(q)
336
-
337
- def __repr__(self):
338
- return f"Revolution({self.offset}, {self._repr_core()})"
279
+ return f"Round({repr(self.child_sdf[0])}, {self.scale})"
ddfem/geometry/vesica.py CHANGED
@@ -15,7 +15,9 @@ class Vesica(SDF):
15
15
  distance (float): Distance of circle center from y-axis.
16
16
  smooth_radius (float): Smoothing of domain,so no sharp corner when circles connection.
17
17
  """
18
- assert distance != 0, "This is a circle, use Ball class"
18
+ super().__init__(*args, **kwargs)
19
+
20
+ assert distance != 0, "This is a circle, use Circle class"
19
21
  assert distance < radius, "No shape exists, circles cancel each other out"
20
22
  assert (
21
23
  smooth_radius * distance < 0
@@ -25,24 +27,21 @@ class Vesica(SDF):
25
27
  self.distance = distance
26
28
  self.smooth_radius = smooth_radius
27
29
 
28
- super().__init__(*args, **kwargs)
29
-
30
30
  def __repr__(self):
31
- return f"Vesica({self.radius}, {self.distance}, {self.smooth_radius}, {self._repr_core()})"
31
+ return f"Vesica({self.radius}, {self.distance}, {self.smooth_radius})"
32
32
 
33
33
  def sdf(self, x):
34
- # Note: Ignores z
35
34
  x0_abs = abs(x[0])
36
35
  x1_abs = abs(x[1])
37
36
 
38
37
  b = sqrt((self.radius + self.smooth_radius) ** 2 - self.distance**2)
39
38
 
40
- circle_coords = as_vector([x0_abs + self.distance, x[1]])
39
+ circle_coords = as_vector((x0_abs + self.distance, x[1]))
41
40
 
42
41
  return (
43
42
  conditional(
44
43
  (x1_abs - b) * self.distance > x0_abs * b,
45
- ufl_length(as_vector([x0_abs, x1_abs - b])) * ufl_sign(self.distance),
44
+ ufl_length(as_vector((x0_abs, x1_abs - b))) * ufl_sign(self.distance),
46
45
  ufl_length(circle_coords) - self.radius - self.smooth_radius,
47
46
  )
48
47
  + self.smooth_radius
ddfem/model2ufl.py CHANGED
@@ -54,16 +54,14 @@ def model_ufl(Model, space, initialTime=0, DirichletBC=DirichletBC):
54
54
  u = TrialFunction(space)
55
55
  v = TestFunction(space)
56
56
  x = SpatialCoordinate(space.cell())
57
-
58
57
  t = initialTime
59
58
 
60
59
  f_c_model = None
61
60
  if hasattr(Model, "F_c"):
62
- f_c_model = inner(Model.F_c(t, x, u), grad(v)) # -div F_c v
61
+ f_c_model = inner(Model.F_c(t, x, u), grad(v)) * dx # -div F_c v
63
62
  if hasattr(Model, "S_e"):
64
- # there is an issue with S_e returning 'zero' and zero*dx leading to UFL error
65
63
  se = (
66
- inner(as_vector(Model.S_e(t, x, u, grad(u))), v)
64
+ inner(as_vector(Model.S_e(t, x, u, grad(u))), v) * dx
67
65
  ) # (-div F_c + S_e) * v
68
66
  if f_c_model is not None:
69
67
  f_c_model += se
@@ -72,10 +70,10 @@ def model_ufl(Model, space, initialTime=0, DirichletBC=DirichletBC):
72
70
 
73
71
  f_v_model = None
74
72
  if hasattr(Model, "F_v"):
75
- f_v_model = inner(Model.F_v(t, x, u, grad(u)), grad(v)) # -div F_v v
73
+ f_v_model = inner(Model.F_v(t, x, u, grad(u)), grad(v)) * dx # -div F_v v
76
74
 
77
75
  if hasattr(Model, "S_i"):
78
- si = inner(as_vector(Model.S_i(t, x, u, grad(u))), v) # (-div F_v + S_i) v
76
+ si = inner(as_vector(Model.S_i(t, x, u, grad(u))), v) * dx # (-div F_v + S_i) v
79
77
  if f_v_model is not None:
80
78
  f_v_model += si
81
79
  else:
@@ -99,10 +97,6 @@ def model_ufl(Model, space, initialTime=0, DirichletBC=DirichletBC):
99
97
  [inner(item[1], v) * ds(item[0]) for item in boundary_flux_cs.items()]
100
98
  ) # keep all forms on left hand side
101
99
 
102
- if f_c_model:
103
- f_c_model = f_c_model * dx
104
- if f_v_model:
105
- f_v_model = f_v_model * dx
106
100
  return (
107
101
  f_c_model,
108
102
  f_v_model,
@@ -1,19 +1,45 @@
1
1
  from ufl import grad, zero
2
2
 
3
- from .transformer_base import transformer
3
+ from .transformer_base import transformer_base
4
4
 
5
5
 
6
- @transformer
7
- def DDM1(Model):
6
+ def DDM1(OriginalModel, domainDescription):
7
+ Model = transformer_base(OriginalModel, domainDescription)
8
+
8
9
  class DDModel(Model):
10
+ def sigma(t, x, U, DU=None):
11
+ if DU:
12
+ return DU
13
+ return grad(U)
14
+
9
15
  def S_e_source(t, x, U, DU):
10
16
  return DDModel.phi(x) * Model.S_e(t, x, U, DDModel.sigma(t, x, U, DU))
11
17
 
12
18
  def S_e_convection(t, x, U, DU):
13
- return -DDModel.BT.BndFlux_cExt(t, x, U)
19
+ return DDModel.BT.BndFlux_cExt(t, x, U)
20
+
21
+ if hasattr(Model, "S_e") and hasattr(Model, "F_c"):
22
+ print("DDM1: S_e and F_c")
23
+
24
+ def S_e(t, x, U, DU):
25
+ return DDModel.S_e_source(t, x, U, DU) + DDModel.S_e_convection(
26
+ t, x, U, DU
27
+ )
28
+
29
+ elif hasattr(Model, "S_e"):
30
+ print("DDM1: S_e")
31
+
32
+ def S_e(t, x, U, DU):
33
+ return DDModel.S_e_source(t, x, U, DU)
34
+
35
+ elif hasattr(Model, "F_c"):
36
+ print("DDM1: F_c")
37
+
38
+ def S_e(t, x, U, DU):
39
+ return DDModel.S_e_convection(t, x, U, DU)
14
40
 
15
- def S_outside(t, x, U, DU):
16
- return -(
41
+ def S_i_stability(t, x, U, DU):
42
+ return -Model.stabFactor * (
17
43
  DDModel.BT.jumpV(t, x, U) * (1 - DDModel.phi(x)) / (DDModel.epsilon**3)
18
44
  )
19
45
 
@@ -27,10 +53,42 @@ def DDM1(Model):
27
53
  diffusion = zero(U.ufl_shape)
28
54
  return diffusion
29
55
 
30
- def F_c(t, x, U):
31
- return DDModel.phi(x) * Model.F_c(t, x, U)
56
+ if hasattr(Model, "S_i") and hasattr(Model, "F_v"):
57
+ print("DDM1: S_i and F_v")
58
+
59
+ def S_i(t, x, U, DU):
60
+ return (
61
+ DDModel.S_i_stability(t, x, U, DU)
62
+ + DDModel.S_i_source(t, x, U, DU)
63
+ + DDModel.S_i_diffusion(t, x, U, DU)
64
+ )
65
+
66
+ elif hasattr(Model, "F_v"):
67
+ print("DDM1: F_v")
68
+
69
+ def S_i(t, x, U, DU):
70
+ return DDModel.S_i_stability(t, x, U, DU) + DDModel.S_i_diffusion(
71
+ t, x, U, DU
72
+ )
73
+
74
+ elif hasattr(Model, "S_i"):
75
+ print("DDM1: S_i")
76
+
77
+ def S_i(t, x, U, DU):
78
+ return DDModel.S_i_stability(t, x, U, DU) + DDModel.S_i_source(
79
+ t, x, U, DU
80
+ )
81
+
82
+ if hasattr(Model, "F_c"):
83
+ print("DDM1: F_c")
84
+
85
+ def F_c(t, x, U):
86
+ return DDModel.phi(x) * Model.F_c(t, x, U)
87
+
88
+ if hasattr(Model, "F_v"):
89
+ print("DDM1: F_v")
32
90
 
33
- def F_v(t, x, U, DU):
34
- return DDModel.phi(x) * Model.F_v(t, x, U, DDModel.sigma(t, x, U, DU))
91
+ def F_v(t, x, U, DU):
92
+ return DDModel.phi(x) * Model.F_v(t, x, U, DDModel.sigma(t, x, U, DU))
35
93
 
36
94
  return DDModel
@@ -1,41 +1,27 @@
1
1
  from functools import reduce
2
2
 
3
- from ufl import conditional, eq, grad, min_value
3
+ from ufl import Min, conditional, eq, grad
4
4
 
5
5
  from ..boundary import BndFlux_c, BndFlux_v, BndValue, boundary_validation
6
- from ..geometry.domain import Domain
7
- from ..geometry.primitive_base import SDF
8
- from .transformer_base import pretransformer
6
+ from .transformer_base import transformer_base
9
7
 
10
8
 
11
9
  def Fitted(OriginalModel, domainDescription):
10
+ Model = transformer_base(OriginalModel, domainDescription)
12
11
 
13
- if isinstance(domainDescription, Domain):
14
- domain = domainDescription
15
- else:
16
- domain = Domain(domainDescription)
17
-
18
- condition = lambda k: isinstance(k, str) or isinstance(k, SDF)
19
-
20
- class Fitted(OriginalModel):
12
+ class Fitted(Model):
21
13
  def sigma(t, x, U, DU=None):
22
14
  if DU:
23
15
  return DU
24
16
  return grad(U)
25
17
 
26
- diffuse = {k: v for k, v in OriginalModel.boundary.items() if condition(k)}
27
- boundary = {k: v for k, v in OriginalModel.boundary.items() if not condition(k)}
28
-
29
- bndSDFs = {k: domain.bndSDFs(k) for k in diffuse.keys()}
30
-
31
- boundary_flux_cs, boundary_flux_vs, boundary_values = boundary_validation(
32
- OriginalModel, override_boundary_dict=diffuse
33
- )
18
+ boundary = Model.BT.physical
19
+ bndSDFs = {k: Model.domain.bndSDFs(k) for k in Model.BT.diffuse.keys()}
34
20
 
35
21
  def make_boundary_function(key, mv, bndSDFs=bndSDFs):
36
22
  sdf = bndSDFs[key]
37
23
  closest_sdf = lambda x: reduce(
38
- min_value,
24
+ Min,
39
25
  ([abs(v(x)) for b, v in bndSDFs.items()]),
40
26
  )
41
27
 
@@ -51,7 +37,11 @@ def Fitted(OriginalModel, domainDescription):
51
37
  lambda t, x, u, n: boundary_map(x) * mv(t, x, u, n),
52
38
  )
53
39
 
54
- def make_boundary_conditional(key, bndSDFs=bndSDFs, tol=1e-2):
40
+ boundary_flux_cs, boundary_flux_vs, boundary_values = boundary_validation(
41
+ Model, override_boundary_dict=Model.BT.diffuse
42
+ )
43
+
44
+ def make_boundary_conditional(key, bndSDFs=bndSDFs, tol=0.01):
55
45
  sdf = bndSDFs[key]
56
46
  return lambda x: abs(sdf(x)) < tol
57
47
 
@@ -1,6 +1,6 @@
1
1
  from ufl import grad, outer
2
2
 
3
- from .transformer_base import transformer
3
+ from .transformer_base import transformer_base
4
4
 
5
5
  """
6
6
  Diffusion:
@@ -45,8 +45,8 @@ paper = phi b . sigma v
45
45
  """
46
46
 
47
47
 
48
- @transformer
49
- def Mix0DDM(Model):
48
+ def Mix0DDM(OriginalModel, domainDescription):
49
+ Model = transformer_base(OriginalModel, domainDescription)
50
50
 
51
51
  class DDModel(Model):
52
52
  def sigma(t, x, U, DU=None):
@@ -68,11 +68,31 @@ def Mix0DDM(Model):
68
68
  * grad(DDModel.phi(x))
69
69
  )
70
70
 
71
- convec -= DDModel.phi(x) * DDModel.BT.BndFlux_cExt(t, x, U)
71
+ convec += DDModel.phi(x) * DDModel.BT.BndFlux_cExt(t, x, U)
72
72
  return convec
73
73
 
74
- def S_outside(t, x, U, DU):
75
- return -(
74
+ if hasattr(Model, "S_e") and hasattr(Model, "F_c"):
75
+ print("Mix0DDM: S_e and F_c")
76
+
77
+ def S_e(t, x, U, DU):
78
+ return DDModel.S_e_source(t, x, U, DU) + DDModel.S_e_convection(
79
+ t, x, U, DU
80
+ )
81
+
82
+ elif hasattr(Model, "S_e"):
83
+ print("Mix0DDM: S_e")
84
+
85
+ def S_e(t, x, U, DU):
86
+ return DDModel.S_e_source(t, x, U, DU)
87
+
88
+ elif hasattr(Model, "F_c"):
89
+ print("Mix0DDM: F_c")
90
+
91
+ def S_e(t, x, U, DU):
92
+ return DDModel.S_e_convection(t, x, U, DU)
93
+
94
+ def S_i_stability(t, x, U, DU):
95
+ return -Model.stabFactor * (
76
96
  DDModel.BT.jumpV(t, x, U)
77
97
  * (1 - DDModel.phi(x)) ** 2
78
98
  / (DDModel.epsilon**2)
@@ -98,10 +118,44 @@ def Mix0DDM(Model):
98
118
  diffusion += DDModel.phi(x) * DDModel.BT.jumpFv(t, x, U, DU, Fv)
99
119
  return -diffusion
100
120
 
101
- def F_c(t, x, U):
102
- return DDModel.phi(x) ** 2 * Model.F_c(t, x, U)
121
+ if hasattr(Model, "S_i") and hasattr(Model, "F_v"):
122
+ print("Mix0DDM: S_i and F_v")
123
+
124
+ def S_i(t, x, U, DU):
125
+ return (
126
+ DDModel.S_i_stability(t, x, U, DU)
127
+ + DDModel.S_i_source(t, x, U, DU)
128
+ + DDModel.S_i_diffusion(t, x, U, DU)
129
+ )
130
+
131
+ elif hasattr(Model, "F_v"):
132
+ print("Mix0DDM: F_v")
133
+
134
+ def S_i(t, x, U, DU):
135
+ return DDModel.S_i_stability(t, x, U, DU) + DDModel.S_i_diffusion(
136
+ t, x, U, DU
137
+ )
138
+
139
+ elif hasattr(Model, "S_i"):
140
+ print("Mix0DDM: S_i")
141
+
142
+ def S_i(t, x, U, DU):
143
+ return DDModel.S_i_stability(t, x, U, DU) + DDModel.S_i_source(
144
+ t, x, U, DU
145
+ )
146
+
147
+ if hasattr(Model, "F_c"):
148
+ print("Mix0DDM: F_c")
149
+
150
+ def F_c(t, x, U):
151
+ return DDModel.phi(x) ** 2 * Model.F_c(t, x, U)
152
+
153
+ if hasattr(Model, "F_v"):
154
+ print("Mix0DDM: F_v")
103
155
 
104
- def F_v(t, x, U, DU):
105
- return DDModel.phi(x) ** 2 * Model.F_v(t, x, U, DDModel.sigma(t, x, U, DU))
156
+ def F_v(t, x, U, DU):
157
+ return DDModel.phi(x) ** 2 * Model.F_v(
158
+ t, x, U, DDModel.sigma(t, x, U, DU)
159
+ )
106
160
 
107
161
  return DDModel