Skip to content

Allow for solving multi-domain problems involving codim-0 submeshes#3478

Merged
ksagiyam merged 1 commit intomainfrom
ksagiyam/submesh_core
Oct 15, 2025
Merged

Allow for solving multi-domain problems involving codim-0 submeshes#3478
ksagiyam merged 1 commit intomainfrom
ksagiyam/submesh_core

Conversation

@ksagiyam
Copy link
Contributor

@ksagiyam ksagiyam commented Mar 27, 2024

Depends on:
UFL: FEniCS/ufl#264 Merged.

Allow for solving multi-domain problems involving codim-0 submeshes.

@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch 3 times, most recently from 9b8f70c to 1e7c035 Compare April 4, 2024 01:07
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch 10 times, most recently from 219240f to d555615 Compare April 11, 2024 12:19
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch 2 times, most recently from 9b1d48b to 23caf2e Compare April 17, 2024 21:14
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch 7 times, most recently from f5afedb to 824f2a5 Compare May 7, 2024 14:57
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch 2 times, most recently from 76e89ef to 7e3c248 Compare May 15, 2024 22:16
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch from b6a41e7 to 9c839e0 Compare May 27, 2024 13:20
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch 2 times, most recently from 1167181 to fc6545c Compare June 4, 2024 19:41
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch from a76cca5 to 630bfb4 Compare June 10, 2024 21:49
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch from 2fe02f9 to 8ba65d6 Compare June 26, 2024 21:36
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch from e204069 to b8cc6f6 Compare July 12, 2024 09:49
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch 4 times, most recently from 9608d6e to 654d56a Compare August 20, 2024 15:04
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch 5 times, most recently from 9d39ea2 to 6972622 Compare August 22, 2024 14:42
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch from 6972622 to a6335d4 Compare August 22, 2024 21:23
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch 2 times, most recently from c9497b3 to 435fc60 Compare September 12, 2024 02:32
@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch from 435fc60 to a9ce114 Compare November 15, 2024 10:19
@github-actions
Copy link

github-actions bot commented Nov 15, 2024

TestsPassed ✅Skipped ⏭️Failed ❌
Firedrake complex8354 ran6710 passed1644 skipped0 failed

@github-actions
Copy link

github-actions bot commented Nov 15, 2024

TestsPassed ✅Skipped ⏭️Failed ❌
Firedrake real8315 ran7601 passed714 skipped0 failed

@ksagiyam ksagiyam force-pushed the ksagiyam/submesh_core branch 2 times, most recently from a683850 to ed0e3b1 Compare November 16, 2024 12:01
Comment on lines +288 to +290
# 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_())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this key should not depend on the mesh. We just need to call finat once, independently of mt.terminal (and its domain).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But internally it only cares about the element

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably make CoordinateMapping only depend on the UFL element

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@github-actions
Copy link

github-actions bot commented Mar 7, 2025

TestsPassed ✅Skipped ⏭️Failed ❌
Firedrake default8267 ran7568 passed699 skipped0 failed

print(mesh, mesh_l, mesh_r, mesh_rl)
dS = Measure(
"dS", domain=mesh,
additional_domain_integral_type_map={
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
additional_domain_integral_type_map={
additional_domain_integral_type_map={
Suggested change
additional_domain_integral_type_map={
extra_measures={

Comment on lines +2269 to +2274
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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Make GlocalKernel args and Parloop args only for the active coordinates (and so on).

Comment on lines +246 to +253
dS = Measure(
"dS", domain=mesh,
extra_measures={
mesh_l: "dS",
mesh_r: "ds",
mesh_rl: "ds",
}
)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Define Measures like this.

Comment on lines +89 to +93
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]
Copy link
Contributor Author

@ksagiyam ksagiyam Jun 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Define these gem.Variable(s) per domain. When we grab these from tsfc/fem.py, we need to use the domain as key.

Comment on lines +28 to +38
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.

"""
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: ActiveDomainNumbers.

Comment on lines +100 to +115
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}")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: We do these things for each domain.

Comment on lines +423 to +426
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_)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the value here should be a Measure

@ksagiyam
Copy link
Contributor Author

Reviewed multiple times. Merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants