ddfem 1.0.0__py3-none-any.whl → 1.0.1__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 +4 -0
  2. ddfem/boundary.py +12 -3
  3. ddfem/examples/__init__.py +0 -0
  4. ddfem/examples/advection_diffusion.py +74 -0
  5. ddfem/examples/beam.py +147 -0
  6. ddfem/examples/cahn_hilliard.py +67 -0
  7. ddfem/examples/chemical_reaction.py +88 -0
  8. ddfem/examples/constant.py +46 -0
  9. ddfem/examples/five_circle_flat.py +197 -0
  10. ddfem/examples/forchheimer.py +48 -0
  11. ddfem/examples/hyperelasticity.py +88 -0
  12. ddfem/examples/linear_elasticity.py +45 -0
  13. ddfem/examples/plaplace.py +29 -0
  14. ddfem/examples/single_circle.py +135 -0
  15. ddfem/examples/triple_circle.py +217 -0
  16. ddfem/examples/triple_circle_beam.py +208 -0
  17. ddfem/geometry/__init__.py +3 -3
  18. ddfem/geometry/arc.py +10 -8
  19. ddfem/geometry/ball.py +24 -0
  20. ddfem/geometry/box.py +7 -8
  21. ddfem/geometry/domain.py +16 -4
  22. ddfem/geometry/domain_dune.py +16 -0
  23. ddfem/geometry/helpers.py +19 -12
  24. ddfem/geometry/pie.py +7 -7
  25. ddfem/geometry/plane.py +20 -0
  26. ddfem/geometry/primitive_base.py +129 -70
  27. ddfem/geometry/vesica.py +7 -6
  28. ddfem/model2ufl.py +10 -4
  29. ddfem/transformers/DDM1.py +10 -68
  30. ddfem/transformers/Fitted.py +22 -12
  31. ddfem/transformers/Mix0.py +10 -64
  32. ddfem/transformers/NNS.py +11 -72
  33. ddfem/transformers/NS.py +14 -79
  34. ddfem/transformers/__init__.py +1 -0
  35. ddfem/transformers/transformer_base.py +102 -15
  36. {ddfem-1.0.0.dist-info → ddfem-1.0.1.dist-info}/METADATA +2 -6
  37. ddfem-1.0.1.dist-info/RECORD +41 -0
  38. ddfem/base_model.py +0 -200
  39. ddfem/geometry/circle.py +0 -39
  40. ddfem-1.0.0.dist-info/RECORD +0 -27
  41. {ddfem-1.0.0.dist-info → ddfem-1.0.1.dist-info}/WHEEL +0 -0
  42. {ddfem-1.0.0.dist-info → ddfem-1.0.1.dist-info}/licenses/LICENSE +0 -0
  43. {ddfem-1.0.0.dist-info → ddfem-1.0.1.dist-info}/top_level.txt +0 -0
@@ -4,27 +4,33 @@ from ufl import (
4
4
  conditional,
5
5
  cos,
6
6
  grad,
7
+ max_value,
8
+ min_value,
7
9
  pi,
8
- replace,
9
10
  sin,
10
11
  tanh,
11
12
  )
12
- from ufl import max_value as Max
13
- from ufl import min_value as Min
14
13
 
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
14
+ from .helpers import smax_value, smin_value, ufl_length
18
15
 
19
16
  ORIGIN = as_vector([0, 0])
20
17
 
21
18
 
22
19
  class SDF:
23
20
  def __init__(self, epsilon=None, name=None, children=None):
24
- self.name = name
25
21
  self.epsilon = epsilon
26
22
  self.child_sdf = children if children else []
27
23
 
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
+
28
34
  def sdf(self, x):
29
35
  raise NotImplementedError
30
36
 
@@ -48,10 +54,10 @@ class SDF:
48
54
 
49
55
  return None
50
56
 
51
- def propgate_epsilon(self, epsilon):
57
+ def propagate_epsilon(self, epsilon):
52
58
  self.epsilon = epsilon
53
59
  for child in self.child_sdf:
54
- child.propgate_epsilon(epsilon)
60
+ child.propagate_epsilon(epsilon)
55
61
 
56
62
  def phi(self, x, epsilon=None):
57
63
  if not epsilon:
@@ -99,6 +105,23 @@ class SDF:
99
105
  def round(self, sc):
100
106
  return Round(self, sc)
101
107
 
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
+
102
125
  def __or__(self, other):
103
126
  return self.union(other)
104
127
 
@@ -112,29 +135,39 @@ class SDF:
112
135
  return self.xor(other)
113
136
 
114
137
  def __mul__(self, other):
115
- if isinstance(other, (int, float)):
116
- return self.scale(other)
117
- raise TypeError(f"Cannot multiply a SDF with {type(other)}")
138
+ return self.scale(other)
118
139
 
119
140
  def __rmul__(self, other):
120
141
  if isinstance(other, (int, float)):
121
142
  return self.scale(other)
122
143
  raise TypeError(f"Cannot multiply a SDF with {type(other)}")
123
144
 
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
+
124
161
  class BaseOperator(SDF):
125
- def __init__(self, epsilon, children, *args, **kwargs):
162
+ def __init__(self, children, epsilon=None, *args, **kwargs):
126
163
 
127
164
  if not epsilon and all(child.epsilon for child in children):
128
- if len(children) == 1:
129
- epsilon = children[0].epsilon
130
- else:
131
- epsilon = Min(*[child.epsilon for child in children])
165
+ epsilon = children[0].epsilon
166
+ for child in children:
167
+ epsilon = max_value(epsilon, child.epsilon)
132
168
 
133
169
  super().__init__(children=children, epsilon=epsilon, *args, **kwargs)
134
170
 
135
- def __repr__(self):
136
- return f"{self.__class__.__name__}({', '.join(map(repr, self.child_sdf))})"
137
-
138
171
  def __getitem__(self, key):
139
172
  return self.child_sdf[key]
140
173
 
@@ -142,60 +175,50 @@ class BaseOperator(SDF):
142
175
  class Union(BaseOperator):
143
176
  """Union of two SDFs (OR) - not perfect(negative)"""
144
177
 
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})"
178
+ def __init__(self, sdf1, sdf2, *args, **kwargs):
179
+ super().__init__(children=[sdf1, sdf2], *args, **kwargs)
149
180
 
150
181
  def sdf(self, x):
151
- return Min(self.child_sdf[0].sdf(x), self.child_sdf[1].sdf(x))
182
+ return SDF.min_value(self.child_sdf[0].sdf(x), self.child_sdf[1].sdf(x))
152
183
 
153
184
 
154
185
  class Subtraction(BaseOperator):
155
186
  """Subtraction of two SDFs (difference) - not perfect"""
156
187
 
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})"
188
+ def __init__(self, sdf1, sdf2, *args, **kwargs):
189
+ super().__init__(children=[sdf1, sdf2], *args, **kwargs)
161
190
 
162
191
  def sdf(self, x):
163
- return Max(self.child_sdf[0].sdf(x), -self.child_sdf[1].sdf(x))
192
+ return SDF.max_value(self.child_sdf[0].sdf(x), -self.child_sdf[1].sdf(x))
164
193
 
165
194
 
166
195
  class Intersection(BaseOperator):
167
196
  """Intersection of two SDFs (AND) - not perfect"""
168
197
 
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})"
198
+ def __init__(self, sdf1, sdf2, *args, **kwargs):
199
+ super().__init__(children=[sdf1, sdf2], *args, **kwargs)
173
200
 
174
201
  def sdf(self, x):
175
- return Max(self.child_sdf[0].sdf(x), self.child_sdf[1].sdf(x))
202
+ return SDF.max_value(self.child_sdf[0].sdf(x), self.child_sdf[1].sdf(x))
176
203
 
177
204
 
178
205
  class Xor(BaseOperator):
179
206
  """Xor of two SDFs (AND) - perfect"""
180
207
 
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})"
208
+ def __init__(self, sdf1, sdf2, *args, **kwargs):
209
+ super().__init__(children=[sdf1, sdf2], *args, **kwargs)
185
210
 
186
211
  def sdf(self, x):
187
212
  a_x = self.child_sdf[0].sdf(x)
188
213
  b_x = self.child_sdf[1].sdf(x)
189
- return Max(Min(a_x, b_x), -Max(a_x, b_x))
214
+ return SDF.max_value(SDF.min_value(a_x, b_x), -SDF.max_value(a_x, b_x))
190
215
 
191
216
 
192
217
  class Invert(BaseOperator):
193
218
  """Inverts SDF"""
194
219
 
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})"
220
+ def __init__(self, sdf1, *args, **kwargs):
221
+ super().__init__(children=[sdf1], *args, **kwargs)
199
222
 
200
223
  def sdf(self, x):
201
224
  return -self.child_sdf[0].sdf(x)
@@ -204,33 +227,33 @@ class Invert(BaseOperator):
204
227
  class Scale(BaseOperator):
205
228
  """Scales SDF"""
206
229
 
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})"
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)
212
239
 
213
240
  def sdf(self, x):
214
241
  return self.child_sdf[0].sdf(x / self.scale) * self.scale
215
242
 
216
243
  def __repr__(self):
217
- return f"Scale({repr(self.child_sdf[0])}, {self.scale})"
244
+ return f"Scale({self.scale}, {self._repr_core()})"
218
245
 
219
246
 
220
247
  class Rotate(BaseOperator):
221
248
  """Rotates SDF, counterclockwise of orgin"""
222
249
 
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
-
250
+ def __init__(self, sdf1, angle, radians=True, *args, **kwargs):
230
251
  if not radians:
231
252
  angle *= pi / 180
232
253
  self.angle = angle
233
254
 
255
+ super().__init__(children=[sdf1], *args, **kwargs)
256
+
234
257
  def sdf(self, x):
235
258
  c = cos(self.angle)
236
259
  s = sin(self.angle)
@@ -239,41 +262,77 @@ class Rotate(BaseOperator):
239
262
  return self.child_sdf[0].sdf(r.T * x)
240
263
 
241
264
  def __repr__(self):
242
- return f"Rotate({repr(self.child_sdf[0])}, {self.angle})"
265
+ return f"Rotate({self.angle}, {self._repr_core()})"
243
266
 
244
267
 
245
268
  class Translate(BaseOperator):
246
269
  """Translates SDF"""
247
270
 
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
-
271
+ def __init__(self, sdf1, vec, *args, **kwargs):
253
272
  if isinstance(vec, (list, tuple)):
254
273
  vec = as_vector(vec)
255
274
  self.vec = vec
256
275
 
276
+ super().__init__(children=[sdf1], *args, **kwargs)
277
+
257
278
  def sdf(self, x):
258
279
  return self.child_sdf[0].sdf(x - self.vec)
259
280
 
260
281
  def __repr__(self):
261
- return f"Translate({repr(self.child_sdf[0])}, {self.vec})"
282
+ return f"Translate({self.vec}, {self._repr_core()})"
262
283
 
263
284
 
264
285
  class Round(BaseOperator):
265
286
  """Rounds SDF"""
266
287
 
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
-
288
+ def __init__(self, sdf1, scale, *args, **kwargs):
272
289
  assert scale > 0
273
290
  self._scale = scale # careful not to overwrite SDF.scale here
274
291
 
292
+ super().__init__(children=[sdf1], *args, **kwargs)
293
+
275
294
  def sdf(self, x):
276
295
  return self.child_sdf[0].sdf(x) - self._scale
277
296
 
278
297
  def __repr__(self):
279
- return f"Round({repr(self.child_sdf[0])}, {self.scale})"
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()})"
ddfem/geometry/vesica.py CHANGED
@@ -15,9 +15,7 @@ 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
- super().__init__(*args, **kwargs)
19
-
20
- assert distance != 0, "This is a circle, use Circle class"
18
+ assert distance != 0, "This is a circle, use Ball class"
21
19
  assert distance < radius, "No shape exists, circles cancel each other out"
22
20
  assert (
23
21
  smooth_radius * distance < 0
@@ -27,21 +25,24 @@ class Vesica(SDF):
27
25
  self.distance = distance
28
26
  self.smooth_radius = smooth_radius
29
27
 
28
+ super().__init__(*args, **kwargs)
29
+
30
30
  def __repr__(self):
31
- return f"Vesica({self.radius}, {self.distance}, {self.smooth_radius})"
31
+ return f"Vesica({self.radius}, {self.distance}, {self.smooth_radius}, {self._repr_core()})"
32
32
 
33
33
  def sdf(self, x):
34
+ # Note: Ignores z
34
35
  x0_abs = abs(x[0])
35
36
  x1_abs = abs(x[1])
36
37
 
37
38
  b = sqrt((self.radius + self.smooth_radius) ** 2 - self.distance**2)
38
39
 
39
- circle_coords = as_vector((x0_abs + self.distance, x[1]))
40
+ circle_coords = as_vector([x0_abs + self.distance, x[1]])
40
41
 
41
42
  return (
42
43
  conditional(
43
44
  (x1_abs - b) * self.distance > x0_abs * b,
44
- ufl_length(as_vector((x0_abs, x1_abs - b))) * ufl_sign(self.distance),
45
+ ufl_length(as_vector([x0_abs, x1_abs - b])) * ufl_sign(self.distance),
45
46
  ufl_length(circle_coords) - self.radius - self.smooth_radius,
46
47
  )
47
48
  + self.smooth_radius
ddfem/model2ufl.py CHANGED
@@ -54,14 +54,16 @@ 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
+
57
58
  t = initialTime
58
59
 
59
60
  f_c_model = None
60
61
  if hasattr(Model, "F_c"):
61
- f_c_model = inner(Model.F_c(t, x, u), grad(v)) * dx # -div F_c v
62
+ f_c_model = inner(Model.F_c(t, x, u), grad(v)) # -div F_c v
62
63
  if hasattr(Model, "S_e"):
64
+ # there is an issue with S_e returning 'zero' and zero*dx leading to UFL error
63
65
  se = (
64
- inner(as_vector(Model.S_e(t, x, u, grad(u))), v) * dx
66
+ inner(as_vector(Model.S_e(t, x, u, grad(u))), v)
65
67
  ) # (-div F_c + S_e) * v
66
68
  if f_c_model is not None:
67
69
  f_c_model += se
@@ -70,10 +72,10 @@ def model_ufl(Model, space, initialTime=0, DirichletBC=DirichletBC):
70
72
 
71
73
  f_v_model = None
72
74
  if hasattr(Model, "F_v"):
73
- f_v_model = inner(Model.F_v(t, x, u, grad(u)), grad(v)) * dx # -div F_v v
75
+ f_v_model = inner(Model.F_v(t, x, u, grad(u)), grad(v)) # -div F_v v
74
76
 
75
77
  if hasattr(Model, "S_i"):
76
- si = inner(as_vector(Model.S_i(t, x, u, grad(u))), v) * dx # (-div F_v + S_i) v
78
+ si = inner(as_vector(Model.S_i(t, x, u, grad(u))), v) # (-div F_v + S_i) v
77
79
  if f_v_model is not None:
78
80
  f_v_model += si
79
81
  else:
@@ -97,6 +99,10 @@ def model_ufl(Model, space, initialTime=0, DirichletBC=DirichletBC):
97
99
  [inner(item[1], v) * ds(item[0]) for item in boundary_flux_cs.items()]
98
100
  ) # keep all forms on left hand side
99
101
 
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
100
106
  return (
101
107
  f_c_model,
102
108
  f_v_model,
@@ -1,45 +1,19 @@
1
1
  from ufl import grad, zero
2
2
 
3
- from .transformer_base import transformer_base
3
+ from .transformer_base import transformer
4
4
 
5
5
 
6
- def DDM1(OriginalModel, domainDescription):
7
- Model = transformer_base(OriginalModel, domainDescription)
8
-
6
+ @transformer
7
+ def DDM1(Model):
9
8
  class DDModel(Model):
10
- def sigma(t, x, U, DU=None):
11
- if DU:
12
- return DU
13
- return grad(U)
14
-
15
9
  def S_e_source(t, x, U, DU):
16
10
  return DDModel.phi(x) * Model.S_e(t, x, U, DDModel.sigma(t, x, U, DU))
17
11
 
18
12
  def S_e_convection(t, x, U, DU):
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)
13
+ return -DDModel.BT.BndFlux_cExt(t, x, U)
40
14
 
41
- def S_i_stability(t, x, U, DU):
42
- return -Model.stabFactor * (
15
+ def S_outside(t, x, U, DU):
16
+ return -(
43
17
  DDModel.BT.jumpV(t, x, U) * (1 - DDModel.phi(x)) / (DDModel.epsilon**3)
44
18
  )
45
19
 
@@ -53,42 +27,10 @@ def DDM1(OriginalModel, domainDescription):
53
27
  diffusion = zero(U.ufl_shape)
54
28
  return diffusion
55
29
 
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")
30
+ def F_c(t, x, U):
31
+ return DDModel.phi(x) * Model.F_c(t, x, U)
90
32
 
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))
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))
93
35
 
94
36
  return DDModel
@@ -1,27 +1,41 @@
1
1
  from functools import reduce
2
2
 
3
- from ufl import Min, conditional, eq, grad
3
+ from ufl import conditional, eq, grad, min_value
4
4
 
5
5
  from ..boundary import BndFlux_c, BndFlux_v, BndValue, boundary_validation
6
- from .transformer_base import transformer_base
6
+ from ..geometry.domain import Domain
7
+ from ..geometry.primitive_base import SDF
8
+ from .transformer_base import pretransformer
7
9
 
8
10
 
9
11
  def Fitted(OriginalModel, domainDescription):
10
- Model = transformer_base(OriginalModel, domainDescription)
11
12
 
12
- class Fitted(Model):
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):
13
21
  def sigma(t, x, U, DU=None):
14
22
  if DU:
15
23
  return DU
16
24
  return grad(U)
17
25
 
18
- boundary = Model.BT.physical
19
- bndSDFs = {k: Model.domain.bndSDFs(k) for k in Model.BT.diffuse.keys()}
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
+ )
20
34
 
21
35
  def make_boundary_function(key, mv, bndSDFs=bndSDFs):
22
36
  sdf = bndSDFs[key]
23
37
  closest_sdf = lambda x: reduce(
24
- Min,
38
+ min_value,
25
39
  ([abs(v(x)) for b, v in bndSDFs.items()]),
26
40
  )
27
41
 
@@ -37,11 +51,7 @@ def Fitted(OriginalModel, domainDescription):
37
51
  lambda t, x, u, n: boundary_map(x) * mv(t, x, u, n),
38
52
  )
39
53
 
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):
54
+ def make_boundary_conditional(key, bndSDFs=bndSDFs, tol=1e-2):
45
55
  sdf = bndSDFs[key]
46
56
  return lambda x: abs(sdf(x)) < tol
47
57
 
@@ -1,6 +1,6 @@
1
1
  from ufl import grad, outer
2
2
 
3
- from .transformer_base import transformer_base
3
+ from .transformer_base import transformer
4
4
 
5
5
  """
6
6
  Diffusion:
@@ -45,8 +45,8 @@ paper = phi b . sigma v
45
45
  """
46
46
 
47
47
 
48
- def Mix0DDM(OriginalModel, domainDescription):
49
- Model = transformer_base(OriginalModel, domainDescription)
48
+ @transformer
49
+ def Mix0DDM(Model):
50
50
 
51
51
  class DDModel(Model):
52
52
  def sigma(t, x, U, DU=None):
@@ -68,31 +68,11 @@ def Mix0DDM(OriginalModel, domainDescription):
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
- 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 * (
74
+ def S_outside(t, x, U, DU):
75
+ return -(
96
76
  DDModel.BT.jumpV(t, x, U)
97
77
  * (1 - DDModel.phi(x)) ** 2
98
78
  / (DDModel.epsilon**2)
@@ -118,44 +98,10 @@ def Mix0DDM(OriginalModel, domainDescription):
118
98
  diffusion += DDModel.phi(x) * DDModel.BT.jumpFv(t, x, U, DU, Fv)
119
99
  return -diffusion
120
100
 
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")
101
+ def F_c(t, x, U):
102
+ return DDModel.phi(x) ** 2 * Model.F_c(t, x, U)
155
103
 
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
- )
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))
160
106
 
161
107
  return DDModel