@@ -380,21 +380,21 @@ def condense(self, A, J, bcs, fcp, pc_type="icc"):
380
380
The matrix to statically condense.
381
381
J : ufl.Form
382
382
The bilinear form to statically condense.
383
- bcs :
384
- An iterable of boundary conditions.
385
- fcp :
386
- A dict with the form compiler parameters.
387
- pc_type :
383
+ bcs : BCBase[]
384
+ An iterable of boundary conditions to apply on ``A`` .
385
+ fcp : dict
386
+ The form compiler parameters.
387
+ pc_type : PETSc.PC.Type
388
388
The preconditioner type for the interior solver.
389
389
390
390
Returns
391
391
-------
392
- Smat :
393
- A :class:`PETSc.Mat` with the original blocks of A , except that
392
+ Smat : PETSc.Mat
393
+ A matrix with the original blocks of ``A`` , except that
394
394
the matrix-free Schur complement replaces the interface-interface block.
395
- Pmat :
396
- A ` dict` mapping pairs of function spaces to the preconditioner blocks
397
- [[inv(A00), A01], [A10, inv(S)]].
395
+ Pmat : dict
396
+ A dict mapping pairs of function spaces to the preconditioner blocks
397
+ `` [[inv(A00), A01], [A10, inv(S)]]`` .
398
398
"""
399
399
Smats = {}
400
400
V = J .arguments ()[0 ].function_space ()
@@ -437,7 +437,7 @@ def condense(self, A, J, bcs, fcp, pc_type="icc"):
437
437
* args_acc ,
438
438
x .dat (op2 .READ , x .cell_node_map ()),
439
439
y .dat (op2 .INC , y .cell_node_map ()))
440
- ctx = ParloopMatrixContext (parloop , x , y , bcs = bcs )
440
+ ctx = PythonMatrixContext (parloop , x , y , bcs = bcs )
441
441
Smats [Vsub , Vsub ] = PETSc .Mat ().createPython (sizes , context = ctx , comm = comm )
442
442
if Vsub == V0 :
443
443
Pmats [Vsub , Vsub ] = Smats [Vsub , Vsub ]
@@ -668,15 +668,22 @@ def _element_mass_matrix(self):
668
668
669
669
@PETSc .Log .EventDecorator ("FDMSetValues" )
670
670
def set_values (self , A , Vrow , Vcol , addv , mat_type = "aij" ):
671
- """
672
- Assemble the auxiliary operator in the FDM basis using sparse reference
673
- tensors and diagonal mass matrices.
674
-
675
- :arg A: the :class:`PETSc.Mat` to assemble
676
- :arg Vrow: the :class:`.FunctionSpace` test space
677
- :arg Vcol: the :class:`.FunctionSpace` trial space
678
- :arg addv: a `PETSc.Mat.InsertMode`
679
- :arg mat_type: the `PETSc.Mat.Type` of the auxiliary operator
671
+ """Assemble the auxiliary operator in the FDM basis using sparse
672
+ reference tensors and diagonal mass matrices.
673
+
674
+ Parameters
675
+ ----------
676
+ A : PETSc.Mat
677
+ The (initialized) matrix to assemble.
678
+ Vrow : FunctionSpace
679
+ The test space.
680
+ Vcol : FunctionSpace
681
+ The trial space.
682
+ addv : PETSc.Mat.InsertMode
683
+ Flag indicating if we want to insert or add matrix values.
684
+ mat_type : PETSc.Mat.Type
685
+ The matrix type of auxiliary operator. This only used when ``A`` is a preallocator
686
+ to determine the nonzeros on the upper triangual part of an ``'sbaij'`` matrix.
680
687
"""
681
688
key = (Vrow .ufl_element (), Vcol .ufl_element ())
682
689
on_diag = Vrow == Vcol
@@ -795,7 +802,7 @@ def kernel(self, mat_type="aij", on_diag=False, addv=None):
795
802
796
803
797
804
class TripleProductKernel (ElementKernel ):
798
- """Kernel builder that inserts a triple product of the form L * C * R,
805
+ """Kernel builder to assemble a triple product of the form L * C * R for each cell ,
799
806
where L, C, R are sparse matrices and the entries of C are updated on each cell."""
800
807
code = dedent ("""
801
808
PetscErrorCode %(name)s(const Mat A, const Mat B,
@@ -810,8 +817,8 @@ class TripleProductKernel(ElementKernel):
810
817
PetscFunctionReturn(PETSC_SUCCESS);
811
818
}""" )
812
819
813
- def __init__ (self , A , B , C , name = None ):
814
- self .product = partial (A .matMatMult , B , C )
820
+ def __init__ (self , L , C , R , name = None ):
821
+ self .product = partial (L .matMatMult , C , R )
815
822
super ().__init__ (self .product (), name = name )
816
823
817
824
@@ -1169,15 +1176,15 @@ def matmult_kernel_code(a, prefix="form", fcp=None, matshell=False):
1169
1176
1170
1177
Returns
1171
1178
-------
1172
- A 4-tuple of C code strings/string generators,
1173
- matmult_struct :
1179
+ matmult_struct : str
1174
1180
The C code to compute the matrix-vector product.
1175
- matmult_call :
1176
- A lambda to call the matrix-vector product on the first argument,
1177
- writing the output on the second argument.
1178
- ctx_struct :
1181
+ matmult_call : callable
1182
+ - ``x``: the pointer name of the input vector (`str`).
1183
+ - ``y``: the pointer name of the output vector (`str`).
1184
+ A lambda to generate the C code calling the matrix-vector product.
1185
+ ctx_struct : str
1179
1186
The signature of the kernel.
1180
- ctx_pack :
1187
+ ctx_pack : str
1181
1188
Code to update the coefficient array pointers to be called before
1182
1189
applying the matshell.
1183
1190
"""
@@ -1193,14 +1200,18 @@ def matmult_kernel_code(a, prefix="form", fcp=None, matshell=False):
1193
1200
kernel = kernels [- 1 ].kinfo .kernel
1194
1201
nargs = len (kernel .arguments ) - len (a .arguments ())
1195
1202
ncoef = nargs - len (extract_firedrake_constants (F ))
1203
+
1204
+ matmult_struct = cache_generate_code (kernel , V ._comm )
1205
+ matmult_struct = matmult_struct .replace ("void " + kernel .name , "static void " + kernel .name )
1206
+
1207
+ ctx_coeff = "" .join (f"appctx[{ i } ], " for i in range (ncoef ))
1208
+ ctx_const = "" .join (f", appctx[{ i } ]" for i in range (ncoef , nargs ))
1209
+ matmult_call = lambda x , y : f"{ kernel .name } ({ y } , { ctx_coeff } { x } { ctx_const } );"
1210
+
1196
1211
ctx_struct = "" .join (f"const PetscScalar *restrict c{ i } , " for i in range (nargs ))
1197
1212
ctx_pointers = ", " .join (f"c{ i } " for i in range (nargs ))
1198
1213
ctx_pack = f"const PetscScalar *appctx[{ nargs } ] = {{ { ctx_pointers } }};"
1199
- ctx_coefficients = "" .join ("appctx[%d], " % i for i in range (ncoef ))
1200
- ctx_constants = "" .join (", appctx[%d]" % i for i in range (ncoef , nargs ))
1201
- matmult_call = lambda x , y : f"{ kernel .name } ({ y } , { ctx_coefficients } { x } { ctx_constants } );"
1202
- matmult_struct = cache_generate_code (kernel , V ._comm )
1203
- matmult_struct = matmult_struct .replace ("void " + kernel .name , "static void " + kernel .name )
1214
+
1204
1215
cache [key ] = (matmult_struct , matmult_call , ctx_struct , ctx_pack )
1205
1216
1206
1217
if matshell :
@@ -1262,24 +1273,20 @@ def __init__(self, kernel, form, name=None, prefix="interior_", fcp=None, pc_typ
1262
1273
A .setSizes (B .getSizes ())
1263
1274
A .setUp ()
1264
1275
1265
- use_cg = False
1266
- if use_cg :
1267
- ksp_type = PETSc .KSP .Type .CG
1268
- norm_type = PETSc .KSP .NormType .NATURAL
1269
- else :
1270
- ksp_type = PETSc .KSP .Type .MINRES
1271
- norm_type = PETSc .KSP .NormType .PRECONDITIONED
1272
- knoll = False
1273
- knoll = True
1276
+ # Set up the local KSP for the cell interiors
1274
1277
ksp = PETSc .KSP ().create (comm = comm )
1275
1278
ksp .setOptionsPrefix (prefix )
1276
1279
ksp .setOperators (A , B )
1280
+
1281
+ # Default solver options, these can be overriden via -interior_ksp_type, etc.
1282
+ rtol = 1E-8
1283
+ atol = 1E-14
1284
+ ksp_type = PETSc .KSP .Type .MINRES
1285
+ norm_type = PETSc .KSP .NormType .PRECONDITIONED
1277
1286
ksp .pc .setType (pc_type )
1278
1287
ksp .setType (ksp_type )
1279
1288
ksp .setNormType (norm_type )
1280
- ksp .setTolerances (rtol = 1E-8 , atol = 0 )
1281
- ksp .setInitialGuessNonzero (knoll )
1282
- ksp .setInitialGuessKnoll (knoll )
1289
+ ksp .setTolerances (rtol = rtol , atol = atol )
1283
1290
ksp .setFromOptions ()
1284
1291
ksp .setUp ()
1285
1292
super ().__init__ (ksp , name = name )
@@ -1352,12 +1359,18 @@ def __init__(self, kernel, name=None):
1352
1359
fdofs = PETSc .IS ().createBlock (V .value_size , restricted_dofs (V1 .finat_element , V .finat_element ), comm = comm )
1353
1360
size = idofs .size + fdofs .size
1354
1361
assert size == V .finat_element .space_dimension () * V .value_size
1362
+ # Bilinear form on the space with interior and interface
1355
1363
a = form if Q == V else form (* (t .reconstruct (function_space = V ) for t in args ))
1356
- a00 = form if Q == V0 else form ( * ( t . reconstruct ( function_space = V0 ) for t in args ))
1364
+ # Generate code to apply the action of A for computing the Schur complement action
1357
1365
A_struct , A_call , ctx_struct , ctx_pack = matmult_kernel_code (a , prefix = "A" , fcp = fcp )
1366
+
1367
+ # Bilinear form on the interior
1368
+ a00 = form if Q == V0 else form (* (t .reconstruct (function_space = V0 ) for t in args ))
1369
+ # Generate code to apply A00 as a PETSc.Mat of type shell within the interior KSP
1358
1370
A00_struct , * _ = matmult_kernel_code (a00 , prefix = "A_interior" , fcp = fcp , matshell = True )
1359
1371
A00_struct = A00_struct .replace ("#include <stdint.h>" , "" )
1360
1372
1373
+ # Replacement rules to use idofs, fdofs, A, and A00 on self.code
1361
1374
rules = dict (A_struct = A_struct , A_call = A_call ("x" , "y" ), ctx_struct = ctx_struct , ctx_pack = ctx_pack ,
1362
1375
A00_struct = A00_struct , size = size , isize = idofs .size , fsize = fdofs .size ,
1363
1376
idofs = ", " .join (map (str , idofs .indices )),
@@ -1367,10 +1380,23 @@ def __init__(self, kernel, name=None):
1367
1380
fdofs .destroy ()
1368
1381
1369
1382
1370
- class ParloopMatrixContext :
1383
+ class PythonMatrixContext :
1384
+ """Python matrix context that handles boundary conditions."""
1371
1385
1372
- def __init__ (self , parloop , x , y , bcs = None ):
1373
- self ._mult_parloop = parloop
1386
+ def __init__ (self , mult_callable , x , y , bcs = None ):
1387
+ """
1388
+ Parameters
1389
+ ----------
1390
+ mult_callable : callable
1391
+ The callable performing the matrix-vector product.
1392
+ x : Function
1393
+ The tensor holding the input to the matrix-vector product.
1394
+ y : Function
1395
+ The tensor holding the output to the matrix-vector product.
1396
+ bcs : BCBase[] or None
1397
+ An iterable of boundary conditions to apply on ``x`` and ``y``.
1398
+ """
1399
+ self ._mult_callable = mult_callable
1374
1400
self ._x = x
1375
1401
self ._y = y
1376
1402
Vrow = y .function_space ()
@@ -1408,11 +1434,11 @@ def _op(self, action, X, Y, W=None):
1408
1434
1409
1435
@PETSc .Log .EventDecorator ()
1410
1436
def mult (self , mat , X , Y ):
1411
- self ._op (self ._mult_parloop , X , Y )
1437
+ self ._op (self ._mult_callable , X , Y )
1412
1438
1413
1439
@PETSc .Log .EventDecorator ()
1414
1440
def multAdd (self , mat , X , Y , W ):
1415
- self ._op (self ._mult_parloop , X , Y , W )
1441
+ self ._op (self ._mult_callable , X , Y , W )
1416
1442
1417
1443
1418
1444
def is_restricted (finat_element ):
@@ -1672,7 +1698,8 @@ def get_base_elements(e):
1672
1698
1673
1699
1674
1700
class SparseAssembler :
1675
-
1701
+ """Class to generate and cache python wrappers to insert sparse element
1702
+ matrices directly with PETSc C code."""
1676
1703
_cache = {}
1677
1704
1678
1705
@staticmethod
@@ -1807,14 +1834,22 @@ def assemble_reference_tensor(self, V):
1807
1834
1808
1835
@PETSc .Log .EventDecorator ("FDMSetValues" )
1809
1836
def set_values (self , A , Vrow , Vcol , addv , mat_type = "aij" ):
1810
- """
1811
- Assemble the stiffness matrix in the FDM basis using Kronecker products of interval matrices
1837
+ """Assemble the stiffness matrix in the FDM basis using Kronecker
1838
+ products of interval matrices.
1812
1839
1813
- :arg A: the :class:`PETSc.Mat` to assemble
1814
- :arg Vrow: the :class:`.FunctionSpace` test space
1815
- :arg Vcol: the :class:`.FunctionSpace` trial space
1816
- :arg addv: a `PETSc.Mat.InsertMode`
1817
- :arg mat_type: a `PETSc.Mat.Type`
1840
+ Parameters
1841
+ ----------
1842
+ A : PETSc.Mat
1843
+ The (initialized) matrix to assemble.
1844
+ Vrow : FunctionSpace
1845
+ The test space.
1846
+ Vcol : FunctionSpace
1847
+ The trial space.
1848
+ addv : PETSc.Mat.InsertMode
1849
+ Flag indicating if we want to insert or add matrix values.
1850
+ mat_type : PETSc.Mat.Type
1851
+ The matrix type of auxiliary operator. This only used when ``A`` is a preallocator
1852
+ to determine the nonzeros on the upper triangual part of an ``'sbaij'`` matrix.
1818
1853
"""
1819
1854
triu = A .getType () == "preallocator" and mat_type .endswith ("sbaij" )
1820
1855
set_submat = SparseAssembler .setSubMatCSR (PETSc .COMM_SELF , triu = triu )
0 commit comments