Skip to content

Support MatIS and BDDC #4405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 42 commits into
base: release
Choose a base branch
from
Open

Support MatIS and BDDC #4405

wants to merge 42 commits into from

Conversation

pbrubeck
Copy link
Contributor

Description

Support assemble(a, mat_type="is")

if mat_type == "is":
rlgmap = unghosted_lgmap(sparsity._dsets[0].lgmap, test.function_space())
clgmap = unghosted_lgmap(sparsity._dsets[1].lgmap, trial.function_space())
sparsity._lgmaps = (rlgmap, clgmap)
Copy link
Contributor

Choose a reason for hiding this comment

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

This encodes the boundary conditions into the definition of the matrix, which is a bit bizarre. Why can't MATIS set lgmaps after the fact?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This does not encode BCs, just the removal of repeated ghost dofs. This is the correct way of using MatIS

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The way we handle BCs on matrices requires changing the LGmap after creating the matrix. This is not possible for a MatIS, as the LGMap is what defines it. If you change the LGMap then the matrix is destroyed.

For MatIS, BCs are never imposed on the LGMap. Instead we assemble the matrix without BCs, and we zero out the BC rows and columns.

Copy link
Contributor

@wence- wence- left a comment

Choose a reason for hiding this comment

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

I think a bunch of the indexing is wrong when constructing the masked lgmaps?

Comment on lines 2202 to 2203
depth = mesh_dm.getDepth()
start, end = mesh_dm.getDepthStratum(depth)
Copy link
Contributor

Choose a reason for hiding this comment

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

AKA getHeightStratum(0)

continue
off = section.getOffset(p)
# Local indices within W
W_indices = slice(block_size * off, block_size * (off + dof))
Copy link
Contributor

Choose a reason for hiding this comment

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

If block is True and lgmap has block_size > 1 then this produces out of bounds indices.

Copy link
Contributor

Choose a reason for hiding this comment

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

Or conversely, if this is a mixed space where one component has block size > 1, then this masks out dofs even when running on a single process (which seems wrong).

W_indices = slice(block_size * off, block_size * (off + dof))
own.extend(W_local_ises_indices[W_indices])

mask = numpy.setdiff1d(range(len(lgmap.indices)), own)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you're trying to mask out those entries in lgmap.indices which belong to dofs that are not reachable from owned cells?

I think for a non-mixed space, this is (if block=True):

cmap = V.cell_node_map()
mask = np.setdiff1d(
    cmap.values_with_halo[cmap.iterset.size:], 
    cmap.values[:cmap.iterset.size],
)

For a mixed space, you need to index through to local_ises, I think like this?

mask_pieces = []
for i, W in enumerate(V):
    iset = V.dof_dset.local_ises[i]
    cmap = W.cell_node_map()
    to_mask = np.setdiff1d(cmap.values_with_halo[cmap.iterset.size:], cmap.values[:cmap.iterset.size])
    bs = iset.block_size
    if bs > 1:
        to_mask = np.concatenate([i + bs * to_mask for i in range(bs)])
    mask_pieces.append(iset.indices[to_mask])
mask = np.concatenate(mask_pieces)

Copy link
Contributor Author

@pbrubeck pbrubeck Jun 26, 2025

Choose a reason for hiding this comment

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

cell_node_map is not defined for extruded meshes, but also there is no DM for extruded. The correct thing is to execute a pyop2 kernel that visits only the dofs that are reachable from owned cells.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Only VectorElements or TensorElements can have blocksize != 1. Any MixedElement has blocksize = 1

@@ -1366,6 +1369,18 @@ def _make_sparsity(test, trial, mat_type, sub_mat_type, maps_and_regions):
except SparsityFormatError:
raise ValueError("Monolithic matrix assembly not supported for systems "
"with R-space blocks")

# TODO reconstruct dof_dset with the unghosted lgmap
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ksagiyam is it possible to get a RestrictedFunctionSpace with the unghosted FunctionSpace (the space that corresponds to DistributedMeshOverlapType.None)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alternatively, if I reconstruct the FunctionSpace with the mesh without the overlap, would I get consistent dof orderings? How do I recover the mesh without overlap?

Copy link
Contributor

Choose a reason for hiding this comment

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

You can make a RestrictedFunctionSpace with boundary_set=ghost entities.

DoF ordering on each entity is the same only for CG and DG spaces (assuming that cone orderings are preserved). Otherwise DoFs depend on the global vertex numbers, which are arbitrary.

I think what we want is to be able to pass ignore_halos=True to op2.Sparsity and have op2.DataSet.lgmap (and similar) return the correct lgmap in the first place depending on the value of ignore_halos?

@pbrubeck pbrubeck force-pushed the pbrubeck/matis branch 2 times, most recently from 76c9a91 to f4a86f7 Compare August 1, 2025 16:15
bsize=1,
comm=self.comm)
if self.mat_type == "is":
# FIXME monolithic lgmaps
Copy link
Contributor

Choose a reason for hiding this comment

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

@pbrubeck Is this still broken? We can do mixed Poisson H(div) x L2 if we have monolithic l2gmaps

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.

5 participants