Skip to content

Commit 19d8448

Browse files
committed
Propagate sub_mat_type, fix MatNest + MatIS
1 parent 6c74a50 commit 19d8448

File tree

3 files changed

+86
-14
lines changed

3 files changed

+86
-14
lines changed

firedrake/assemble.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,9 @@ def allocate(self):
353353
else:
354354
test, trial = self._form.arguments()
355355
sparsity = ExplicitMatrixAssembler._make_sparsity(test, trial, self._mat_type, self._sub_mat_type, self.maps_and_regions)
356-
return matrix.Matrix(self._form, self._bcs, self._mat_type, sparsity, ScalarType, options_prefix=self._options_prefix)
356+
return matrix.Matrix(self._form, self._bcs, self._mat_type, sparsity, ScalarType,
357+
sub_mat_type=self._sub_mat_type,
358+
options_prefix=self._options_prefix)
357359
else:
358360
raise NotImplementedError("Only implemented for rank = 2 and diagonal = False")
359361

@@ -1344,6 +1346,7 @@ def allocate(self):
13441346
self._sub_mat_type,
13451347
self._make_maps_and_regions())
13461348
return matrix.Matrix(self._form, self._bcs, self._mat_type, sparsity, ScalarType,
1349+
sub_mat_type=self._sub_mat_type,
13471350
options_prefix=self._options_prefix,
13481351
fc_params=self._form_compiler_params)
13491352

@@ -1366,10 +1369,21 @@ def _make_sparsity(test, trial, mat_type, sub_mat_type, maps_and_regions):
13661369
except SparsityFormatError:
13671370
raise ValueError("Monolithic matrix assembly not supported for systems "
13681371
"with R-space blocks")
1372+
1373+
# TODO reconstruct dof_dset with the unghosted lgmap
13691374
if mat_type == "is":
1370-
rlgmap = unghosted_lgmap(sparsity._dsets[0].lgmap, test.function_space())
1371-
clgmap = unghosted_lgmap(sparsity._dsets[1].lgmap, trial.function_space())
1372-
sparsity._lgmaps = (rlgmap, clgmap)
1375+
rmap = unghosted_lgmap(sparsity._dsets[0].lgmap, test.function_space())
1376+
cmap = unghosted_lgmap(sparsity._dsets[1].lgmap, trial.function_space())
1377+
sparsity._lgmaps = (rmap, cmap)
1378+
1379+
elif mat_type == "nest" and sub_mat_type == "is":
1380+
Vrow = test.function_space()
1381+
Vcol = trial.function_space()
1382+
for i, j in numpy.ndindex((len(Vrow), len(Vcol))):
1383+
block = sparsity[i, j]
1384+
rmap = unghosted_lgmap(block._dsets[0].lgmap, Vrow[i])
1385+
cmap = unghosted_lgmap(block._dsets[1].lgmap, Vcol[j])
1386+
block._lgmaps = (rmap, cmap)
13731387
return sparsity
13741388

13751389
def _make_maps_and_regions(self):
@@ -1465,6 +1479,15 @@ def _apply_bc(self, tensor, bc, u=None):
14651479
# block is on the matrix diagonal and its index matches the
14661480
# index of the function space the bc is defined on.
14671481
op2tensor[index, index].set_local_diagonal_entries(bc.nodes, idx=component, diag_val=self.weight)
1482+
if self._mat_type == "nest" and self._sub_mat_type == "is":
1483+
for i in range(len(tensor.arguments()[1].function_space())):
1484+
if i == index:
1485+
continue
1486+
op2tensor[index, i].zero_rows(bc.nodes, idx=component, diag_val=0)
1487+
for i in range(len(tensor.arguments()[0].function_space())):
1488+
if i == index:
1489+
continue
1490+
op2tensor[i, index].zero_columns(bc.nodes, idx=component, diag_val=0)
14681491

14691492
# Handle off-diagonal block involving real function space.
14701493
# "lgmaps" is correctly constructed in _matrix_arg, but

pyop2/types/mat.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ class Mat(AbstractMat):
561561

562562
def __init__(self, *args, **kwargs):
563563
self.mat_type = kwargs.pop("mat_type", None)
564+
self.sub_mat_type = kwargs.pop("sub_mat_type", None)
564565
super().__init__(*args, **kwargs)
565566
self._init()
566567
self.assembly_state = Mat.ASSEMBLED
@@ -620,7 +621,7 @@ def _init_monolithic(self):
620621
rlgmap = rset.unblocked_lgmap
621622
clgmap = cset.unblocked_lgmap
622623
if self.mat_type == "is":
623-
# TODO monolithic lgmaps
624+
# FIXME monolithic lgmaps
624625
rlgmap, clgmap = self.sparsity._lgmaps
625626
create = mat.createIS
626627
else:
@@ -671,7 +672,8 @@ def _init_nest(self):
671672
row = []
672673
for j in range(cols):
673674
row.append(Mat(self.sparsity[i, j], self.dtype,
674-
'_'.join([self.name, str(i), str(j)])))
675+
'_'.join([self.name, str(i), str(j)]),
676+
mat_type=self.sub_mat_type))
675677
self._blocks.append(row)
676678
# PETSc Mat.createNest wants a flattened list of Mats
677679
mat.createNest([[m.handle for m in row_] for row_ in self._blocks],
@@ -794,15 +796,43 @@ def zero(self):
794796
self.handle.zeroEntries()
795797

796798
@mpi.collective
797-
def zero_rows(self, rows, diag_val=1.0):
799+
def zero_rows(self, rows, diag_val=1.0, idx=None):
798800
"""Zeroes the specified rows of the matrix, with the exception of the
799801
diagonal entry, which is set to diag_val. May be used for applying
800802
strong boundary conditions.
801803
802804
:param rows: a :class:`Subset` or an iterable"""
805+
rows = rows.indices if isinstance(rows, Subset) else rows
806+
rows = np.asarray(rows, dtype=dtypes.IntType)
807+
rbs, _ = self.dims[0][0]
808+
if rbs > 1:
809+
if idx is not None:
810+
rows = rbs * rows + idx
811+
else:
812+
rows = np.dstack([rbs*rows + i for i in range(rbs)]).flatten()
803813
self.assemble()
814+
self.handle.zeroRowsLocal(rows, diag_val)
815+
816+
@mpi.collective
817+
def zero_columns(self, rows, diag_val=1.0, idx=None):
818+
"""Zeroes the specified columns of the matrix, with the exception of the
819+
diagonal entry, which is set to diag_val. May be used for applying
820+
strong boundary conditions.
821+
822+
:param rows: a :class:`Subset` or an iterable"""
804823
rows = rows.indices if isinstance(rows, Subset) else rows
824+
rows = np.asarray(rows, dtype=dtypes.IntType)
825+
rbs, _ = self.dims[0][0]
826+
if rbs > 1:
827+
if idx is not None:
828+
rows = rbs * rows + idx
829+
else:
830+
rows = np.dstack([rbs*rows + i for i in range(rbs)]).flatten()
831+
self.assemble()
832+
# FIXME implement zeroColumnsLocal
833+
self.handle.transpose()
805834
self.handle.zeroRowsLocal(rows, diag_val)
835+
self.handle.transpose()
806836

807837
def _flush_assembly(self):
808838
self.handle.assemble(assembly=PETSc.Mat.AssemblyType.FLUSH)

tests/firedrake/regression/test_assemble.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,27 +152,46 @@ def test_assemble_matis(mesh, shape, mat_type, dirichlet_bcs):
152152
V = FunctionSpace(mesh, "CG", 1)
153153
if shape == "mixed":
154154
V = V * V
155-
156155
if V.value_size == 1:
157156
A = 1
158157
else:
159158
A = as_matrix([[2, -1], [-1, 2]])
160159

161160
u = TrialFunction(V)
162161
v = TestFunction(V)
163-
a = inner(A*grad(u), grad(v))*dx
162+
a = inner(A * grad(u), grad(v))*dx
164163
if dirichlet_bcs:
165164
bcs = [DirichletBC(V.sub(i), 0, (i % 4+1, (i+2) % 4+1)) for i in range(V.value_size)]
166165
else:
167166
bcs = None
168167

169168
ais = assemble(a, bcs=bcs, mat_type=mat_type, sub_mat_type="is").petscmat
170-
aijnew = PETSc.Mat()
171-
ais.convert("aij", aijnew)
172169

173-
aij = assemble(a, bcs=bcs, mat_type="aij").petscmat
174-
aij.axpy(-1, aijnew)
175-
assert np.allclose(aij[:, :], 0)
170+
aij = PETSc.Mat()
171+
if ais.type == "nest":
172+
blocks = []
173+
for i in range(len(V)):
174+
row = []
175+
for j in range(len(V)):
176+
bis = ais.getNestSubMatrix(i, j)
177+
assert bis.type == "is"
178+
bij = PETSc.Mat()
179+
bis.convert("aij", bij)
180+
row.append(bij)
181+
blocks.append(row)
182+
anest = PETSc.Mat()
183+
anest.createNest(blocks,
184+
isrows=V.dof_dset.field_ises,
185+
iscols=V.dof_dset.field_ises,
186+
comm=ais.comm)
187+
anest.convert("aij", aij)
188+
else:
189+
assert ais.type == "is"
190+
ais.convert("aij", aij)
191+
192+
aij_ref = assemble(a, bcs=bcs, mat_type="aij").petscmat
193+
aij_ref.axpy(-1, aij)
194+
assert np.allclose(aij_ref[:, :], 0)
176195

177196

178197
def test_assemble_diagonal(mesh):

0 commit comments

Comments
 (0)