Skip to content

Add mixed-topology support to locate_dofs_topological#4167

Open
jpdean wants to merge 26 commits intomainfrom
jpdean/mixed_locate_dofs_topo
Open

Add mixed-topology support to locate_dofs_topological#4167
jpdean wants to merge 26 commits intomainfrom
jpdean/mixed_locate_dofs_topo

Conversation

@jpdean
Copy link
Copy Markdown
Member

@jpdean jpdean commented Apr 21, 2026

This PR adds mixed-topology support tolocate_dofs_topological.

Comment on lines +72 to +74
throw std::runtime_error("Cell-to-entity connectivity of dimension "
+ std::to_string(tdim) + "->"
+ std::to_string(dim) + " doesn't exist");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
throw std::runtime_error("Cell-to-entity connectivity of dimension "
+ std::to_string(tdim) + "->"
+ std::to_string(dim) + " doesn't exist");
throw std::runtime_error(std::format("Cell-to-entity connectivity of dimension {}->{} doesn't exist", tdim, dim));

/// `topology.entity_types(dim)`
/// @returns A list of `(cell_index, entity_index, cell_type_index)` tuples
/// for each input entity. `cell_type_index` is the index of the cell type in
/// `topology.cell_types()`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Heads up, @chrisrichardson is rewriting all of these to have i inputs, as in: #4169

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

but not in Topology just yet, so get this merged first!

const int tdim = topology.dim();
auto e_to_c = topology.connectivity(dim, tdim);
if (!e_to_c)
std::vector<mesh::CellType> cell_types = topology.cell_types();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
std::vector<mesh::CellType> cell_types = topology.cell_types();
const std::vector<mesh::CellType>& cell_types = topology.cell_types();

c_to_e_connectivities[i]
= topology.connectivity({tdim, i}, {dim, entity_type_index});

// NOTE: If e_to_c exists, c_to_e should also exist.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this assumption always true? I didn't think that was the case, i.e. (tdim, 0) exists at construction of a topology, but (0, tdim) does not.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

true - maybe just reword this comment to state that both are required.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think, with the current connectivity implementation in FEniCSx, this statement is always true because of the direction I stated it in. Your example, Jørgen, is assuming that the reverse statement also holds, which is not the case. However, I am happy to clarify the comment! The code doesn't actually rely on it anyway, I've included a check just in case!

// Get connectivities for each cell type.
std::int32_t num_entities_local = 0;
bool any_connectivity = false;
std::vector<std::shared_ptr<const dolfinx::graph::AdjacencyList<int32_t>>>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we rather use a reserve and pushback?

{
auto e_to_c = e_to_c_connectivities[i];

if (e_to_c and e_to_c->num_links(e) > 0)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can it happen that an entity is not connected to a cell?, i.e. e_to_c->num_links(e) == 0?

{
throw std::runtime_error(
"Entity " + std::to_string(e)
+ " is not connected to any cells or is out of bounds.");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Out of bounds is covered in Line 93 to 99?

Comment on lines +126 to +128
throw std::runtime_error(
"Entity " + std::to_string(e)
+ " is not connected to any cells or is out of bounds.");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
throw std::runtime_error(
"Entity " + std::to_string(e)
+ " is not connected to any cells or is out of bounds.");
throw std::runtime_error(std::format("Entity {} is not connected to any cells or is out of bounds.", e));

Comment on lines +255 to +256
const std::size_t num_cell_types = topology.cell_types().size();
if (num_cell_types != 1)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
const std::size_t num_cell_types = topology.cell_types().size();
if (num_cell_types != 1)
if (topology.cell_types().size() != 1)

throw std::runtime_error(
"Cell-to-entity connectivity has not been computed. Missing dims "
+ std::to_string(tdim) + "->" + std::to_string(dim));
throw std::runtime_error("No connectivity from entities of dimension "
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use std::format here as well.

// the index map into account as they can differ
const int bs = dofmap.bs();
const int element_bs = dofmap.element_dof_layout().block_size();
const int bs = dofmaps.front().get().bs();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should probably add a comment here that the block size of either dofmap should be the same, as pointed out by @chrisrichardson in #4165

std::span<const std::int32_t> entities, int entity_type_index, bool remote)
{
std::vector<mesh::CellType> cell_types = topology.cell_types();
const int num_cell_types = cell_types.size();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

See warning from sonarcloud.

{
// Work with blocks
for (auto [cell, entity_local_index] : entity_indices)
for (auto [cell, entity_local_index, cell_type_idx] : entity_indices)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we use c rather than cell to avoid the shadowing warning?

// dofs
std::span<const std::int32_t> cell_dofs = dofmap.cell_dofs(cell);
for (int index : entity_dofs[entity_local_index])
std::span<const std::int32_t> cell_dofs
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Seems like we should call dofmaps[cell_type+idx].get() once rather than twice.

// found by other processes, e.g. a vertex dof on this process that
// has no connected facets on the boundary.
auto map = dofmap.index_map;
auto map = dofmaps.front().get().index_map;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here and below, call dofmaps.front().get() once as a separate variable?

Copy link
Copy Markdown
Member

@jorgensd jorgensd left a comment

Choose a reason for hiding this comment

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

Some minor things. In general it looks good!:)

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