Allow for solving multi-domain problems involving codim-0 submeshes#3478
Allow for solving multi-domain problems involving codim-0 submeshes#3478
Conversation
9b8f70c to
1e7c035
Compare
219240f to
d555615
Compare
9b1d48b to
23caf2e
Compare
f5afedb to
824f2a5
Compare
76e89ef to
7e3c248
Compare
b6a41e7 to
9c839e0
Compare
1167181 to
fc6545c
Compare
a76cca5 to
630bfb4
Compare
2fe02f9 to
8ba65d6
Compare
e204069 to
b8cc6f6
Compare
9608d6e to
654d56a
Compare
9d39ea2 to
6972622
Compare
6972622 to
a6335d4
Compare
c9497b3 to
435fc60
Compare
435fc60 to
a9ce114
Compare
|
|
a683850 to
ed0e3b1
Compare
| # This way of caching is fragile. | ||
| # Should Implement _hash_key_() for ModifiedTerminal and use the entire mt as key. | ||
| return (ufl_element, mt.local_derivatives, ctx.point_set, ctx.integration_dim, entity_id, coordinate_element, mt.restriction, domain._ufl_hash_data_()) |
There was a problem hiding this comment.
I believe this key should not depend on the mesh. We just need to call finat once, independently of mt.terminal (and its domain).
There was a problem hiding this comment.
CoordinateMapping uses mt.terminal:
@serial_cache(hashkey=make_basis_evaluation_key)
def basis_evaluation(self, finat_element, mt, entity_id):
return finat_element.basis_evaluation(mt.local_derivatives,
self.point_set,
(self.integration_dim, entity_id),
coordinate_mapping=CoordinateMapping(mt, self))
There was a problem hiding this comment.
But internally it only cares about the element
There was a problem hiding this comment.
We should probably make CoordinateMapping only depend on the UFL element
There was a problem hiding this comment.
In concept that might be true, but we probably need refactoring. CoordinateMapping also has:
def cell_size(self):
return self.interface.cell_size(self.mt.restriction)
which implicitly depends on domain.
There was a problem hiding this comment.
Either way, as long as we pass mt to basis_evaluation, we need to use the entire mt in the cache key to ensure that we can safely use mt.something_new in the relevant parts of the code.
|
| print(mesh, mesh_l, mesh_r, mesh_rl) | ||
| dS = Measure( | ||
| "dS", domain=mesh, | ||
| additional_domain_integral_type_map={ |
There was a problem hiding this comment.
| additional_domain_integral_type_map={ | |
| additional_domain_integral_type_map={ |
| additional_domain_integral_type_map={ | |
| extra_measures={ |
| def iter_active_coordinates(form, kinfo): | ||
| """Yield the form coordinates referenced in ``kinfo``.""" | ||
| all_meshes = extract_domains(form) | ||
| for i in kinfo.active_domain_numbers.coordinates: | ||
| yield all_meshes[i].coordinates | ||
|
|
There was a problem hiding this comment.
Note: Make GlocalKernel args and Parloop args only for the active coordinates (and so on).
| dS = Measure( | ||
| "dS", domain=mesh, | ||
| extra_measures={ | ||
| mesh_l: "dS", | ||
| mesh_r: "ds", | ||
| mesh_rl: "ds", | ||
| } | ||
| ) |
There was a problem hiding this comment.
Note: Define Measures like this.
| def entity_number(self, domain, restriction): | ||
| """Facet or vertex number as a GEM index.""" | ||
| # Assume self._entity_number dict is set up at this point. | ||
| return self._entity_number[restriction] | ||
| if not hasattr(self, "_entity_numbers"): | ||
| raise RuntimeError("Haven't called set_entity_numbers") | ||
| return self._entity_numbers[domain][restriction] |
There was a problem hiding this comment.
Note: Define these gem.Variable(s) per domain. When we grab these from tsfc/fem.py, we need to use the domain as key.
| ActiveDomainNumbers = namedtuple('ActiveDomainNumbers', ['coordinates', | ||
| 'cell_orientations', | ||
| 'cell_sizes', | ||
| 'exterior_facets', | ||
| 'interior_facets', | ||
| 'exterior_facet_orientations', | ||
| 'interior_facet_orientations']) | ||
| ActiveDomainNumbers.__doc__ = """ | ||
| Active domain numbers collected for each key. | ||
|
|
||
| """ |
There was a problem hiding this comment.
Note: ActiveDomainNumbers.
| def set_coordinates(self, domains): | ||
| """Set coordinates for each domain. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| domains : list or tuple | ||
| All domains in the form. | ||
|
|
||
| :arg domain: :class:`ufl.Domain` | ||
| """ | ||
| # Create a fake coordinate coefficient for a domain. | ||
| f = Coefficient(FunctionSpace(domain, domain.ufl_coordinate_element())) | ||
| self.domain_coordinate[domain] = f | ||
| self._coefficient(f, "coords") | ||
| for i, domain in enumerate(domains): | ||
| if isinstance(domain, MeshSequence): | ||
| raise RuntimeError("Found a MeshSequence") | ||
| f = Coefficient(FunctionSpace(domain, domain.ufl_coordinate_element())) | ||
| self.domain_coordinate[domain] = f | ||
| self._coefficient(f, f"coords_{i}") |
There was a problem hiding this comment.
Note: We do these things for each domain.
| active_domain_numbers_coordinates, args_ = self.make_active_domain_numbers({d: self.coefficient_map[c] for d, c in self.domain_coordinate.items()}, | ||
| active_variables, | ||
| kernel_args.CoordinatesKernelArg) | ||
| args.extend(args_) |
There was a problem hiding this comment.
Note: After calling self.compile_gem(), we use self.make_active_domain_numbers() to get indices of the active domains.
| dS = Measure( | ||
| "dS", domain=mesh, | ||
| extra_measures={ | ||
| mesh_l: "dS", |
There was a problem hiding this comment.
I think the value here should be a Measure
|
Reviewed multiple times. Merging. |
Depends on:
UFL: FEniCS/ufl#264Merged.Allow for solving multi-domain problems involving codim-0 submeshes.