|
11 | 11 | # Modified by Cecile Daversin-Catty, 2018.
|
12 | 12 | # Modified by Ignacia Fierro-Piccardo 2023.
|
13 | 13 |
|
| 14 | +import numpy as np |
14 | 15 | from ufl.argument import Argument
|
15 | 16 | from ufl.core.terminal import FormArgument
|
16 | 17 | from ufl.core.ufl_type import ufl_type
|
|
20 | 21 | from ufl.split_functions import split
|
21 | 22 | from ufl.utils.counted import Counted
|
22 | 23 |
|
| 24 | + |
23 | 25 | # --- The Coefficient class represents a coefficient in a form ---
|
24 | 26 |
|
25 | 27 |
|
@@ -201,6 +203,82 @@ def __repr__(self):
|
201 | 203 | """Representation."""
|
202 | 204 | return self._repr
|
203 | 205 |
|
| 206 | + def traverse_dag_apply_coefficient_split( |
| 207 | + self, |
| 208 | + coefficient_split, |
| 209 | + reference_value=False, |
| 210 | + reference_grad=0, |
| 211 | + restricted=None, |
| 212 | + cache=None, |
| 213 | + ): |
| 214 | + from ufl.classes import ( |
| 215 | + ComponentTensor, |
| 216 | + MultiIndex, |
| 217 | + NegativeRestricted, |
| 218 | + PositiveRestricted, |
| 219 | + ReferenceGrad, |
| 220 | + ReferenceValue, |
| 221 | + Zero, |
| 222 | + ) |
| 223 | + from ufl.core.multiindex import indices |
| 224 | + from ufl.checks import is_cellwise_constant |
| 225 | + from ufl.domain import extract_unique_domain |
| 226 | + from ufl.tensors import as_tensor |
| 227 | + |
| 228 | + if self not in coefficient_split: |
| 229 | + c = self |
| 230 | + if reference_value: |
| 231 | + c = ReferenceValue(c) |
| 232 | + for _ in range(reference_grad): |
| 233 | + # Return zero if expression is trivially constant. This has to |
| 234 | + # happen here because ReferenceGrad has no access to the |
| 235 | + # topological dimension of a literal zero. |
| 236 | + if is_cellwise_constant(c): |
| 237 | + dim = extract_unique_domain(subcoeff).topological_dimension() |
| 238 | + c = Zero(c.ufl_shape + (dim,), c.ufl_free_indices, c.ufl_index_dimensions) |
| 239 | + else: |
| 240 | + c = ReferenceGrad(c) |
| 241 | + if restricted == "+": |
| 242 | + c = PositiveRestricted(c) |
| 243 | + elif restricted == "-": |
| 244 | + c = NegativeRestricted(c) |
| 245 | + elif restricted is not None: |
| 246 | + raise RuntimeError(f"Got unknown restriction: {restricted}") |
| 247 | + return c |
| 248 | + # Reference value expected |
| 249 | + if not reference_value: |
| 250 | + raise RuntimeError(f"ReferenceValue expected: got {o}") |
| 251 | + # Derivative indices |
| 252 | + beta = indices(reference_grad) |
| 253 | + components = [] |
| 254 | + for subcoeff in coefficient_split[self]: |
| 255 | + c = subcoeff |
| 256 | + # Apply terminal modifiers onto the subcoefficient |
| 257 | + if reference_value: |
| 258 | + c = ReferenceValue(c) |
| 259 | + for _ in range(reference_grad): |
| 260 | + # Return zero if expression is trivially constant. This has to |
| 261 | + # happen here because ReferenceGrad has no access to the |
| 262 | + # topological dimension of a literal zero. |
| 263 | + if is_cellwise_constant(c): |
| 264 | + dim = extract_unique_domain(subcoeff).topological_dimension() |
| 265 | + c = Zero(c.ufl_shape + (dim,), c.ufl_free_indices, c.ufl_index_dimensions) |
| 266 | + else: |
| 267 | + c = ReferenceGrad(c) |
| 268 | + if restricted == "+": |
| 269 | + c = PositiveRestricted(c) |
| 270 | + elif restricted == "-": |
| 271 | + c = NegativeRestricted(c) |
| 272 | + elif restricted is not None: |
| 273 | + raise RuntimeError(f"Got unknown restriction: {restricted}") |
| 274 | + # Collect components of the subcoefficient |
| 275 | + for alpha in np.ndindex(subcoeff.ufl_element().reference_value_shape): |
| 276 | + # New modified terminal: component[alpha + beta] |
| 277 | + components.append(c[alpha + beta]) |
| 278 | + # Repack derivative indices to shape |
| 279 | + i, = indices(1) |
| 280 | + return ComponentTensor(as_tensor(components)[i], MultiIndex((i,) + beta)) |
| 281 | + |
204 | 282 |
|
205 | 283 | # --- Helper functions for subfunctions on mixed elements ---
|
206 | 284 |
|
|
0 commit comments