xref: /petsc/src/mat/utils/gcreate.c (revision 1bd63e3efbce1229b47e2ec5bb1e7d27e9e9b2dd)
1 #include <petsc/private/matimpl.h> /*I "petscmat.h"  I*/
2 
3 #include <../src/mat/impls/aij/seq/aij.h>
4 #include <../src/mat/impls/aij/mpi/mpiaij.h>
5 
6 PETSC_INTERN PetscErrorCode MatSetBlockSizes_Default(Mat mat, PetscInt rbs, PetscInt cbs)
7 {
8   PetscFunctionBegin;
9   if (!mat->preallocated) PetscFunctionReturn(PETSC_SUCCESS);
10   PetscCheck(mat->rmap->bs <= 0 || mat->rmap->bs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot change row block size %" PetscInt_FMT " to %" PetscInt_FMT, mat->rmap->bs, rbs);
11   PetscCheck(mat->cmap->bs <= 0 || mat->cmap->bs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot change column block size %" PetscInt_FMT " to %" PetscInt_FMT, mat->cmap->bs, cbs);
12   PetscFunctionReturn(PETSC_SUCCESS);
13 }
14 
15 PETSC_INTERN PetscErrorCode MatShift_Basic(Mat Y, PetscScalar a)
16 {
17   PetscInt    i, start, end, oldValA = 0, oldValB = 0;
18   PetscScalar alpha = a;
19   PetscBool   prevoption;
20   PetscBool   isSeqAIJDerived, isMPIAIJDerived; // all classes sharing SEQAIJHEADER or MPIAIJHEADER
21   Mat         A = NULL, B = NULL;
22 
23   PetscFunctionBegin;
24   PetscCall(MatGetOption(Y, MAT_NO_OFF_PROC_ENTRIES, &prevoption));
25   PetscCall(MatSetOption(Y, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
26   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isSeqAIJDerived, MATSEQAIJ, MATSEQBAIJ, MATSEQSBAIJ, ""));
27   PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isMPIAIJDerived, MATMPIAIJ, MATMPIBAIJ, MATMPISBAIJ, ""));
28 
29   if (isSeqAIJDerived) A = Y;
30   else if (isMPIAIJDerived) {
31     Mat_MPIAIJ *mpiaij = (Mat_MPIAIJ *)Y->data;
32     A                  = mpiaij->A;
33     B                  = mpiaij->B;
34   }
35 
36   if (A) {
37     oldValA                          = ((Mat_SeqAIJ *)(A->data))->nonew;
38     ((Mat_SeqAIJ *)(A->data))->nonew = 0; // so that new nonzero locations are allowed
39   }
40   if (B) {
41     oldValB                          = ((Mat_SeqAIJ *)(B->data))->nonew;
42     ((Mat_SeqAIJ *)(B->data))->nonew = 0;
43   }
44 
45   PetscCall(MatGetOwnershipRange(Y, &start, &end));
46   for (i = start; i < end; i++) {
47     if (i < Y->cmap->N) PetscCall(MatSetValues(Y, 1, &i, 1, &i, &alpha, ADD_VALUES));
48   }
49   PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
50   PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
51   PetscCall(MatSetOption(Y, MAT_NO_OFF_PROC_ENTRIES, prevoption));
52   if (A) ((Mat_SeqAIJ *)(A->data))->nonew = oldValA;
53   if (B) ((Mat_SeqAIJ *)(B->data))->nonew = oldValB;
54   PetscFunctionReturn(PETSC_SUCCESS);
55 }
56 
57 /*@
58   MatCreate - Creates a matrix where the type is determined
59   from either a call to `MatSetType()` or from the options database
60   with a call to `MatSetFromOptions()`.
61 
62   Collective
63 
64   Input Parameter:
65 . comm - MPI communicator
66 
67   Output Parameter:
68 . A - the matrix
69 
70   Options Database Keys:
71 + -mat_type seqaij   - `MATSEQAIJ` type, uses `MatCreateSeqAIJ()`
72 . -mat_type mpiaij   - `MATMPIAIJ` type, uses `MatCreateAIJ()`
73 . -mat_type seqdense - `MATSEQDENSE`, uses `MatCreateSeqDense()`
74 . -mat_type mpidense - `MATMPIDENSE` type, uses `MatCreateDense()`
75 . -mat_type seqbaij  - `MATSEQBAIJ` type, uses `MatCreateSeqBAIJ()`
76 - -mat_type mpibaij  - `MATMPIBAIJ` type, uses `MatCreateBAIJ()`
77 
78    See the manpages for particular formats (e.g., `MATSEQAIJ`)
79    for additional format-specific options.
80 
81   Level: beginner
82 
83   Notes:
84   The default matrix type is `MATAIJ`, using the routines `MatCreateSeqAIJ()` or
85   `MatCreateAIJ()` if you do not set a type in the options database. If you never call
86   `MatSetType()` or `MatSetFromOptions()` it will generate an error when you try to use the
87   matrix.
88 
89 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatCreateAIJ()`,
90           `MatCreateSeqDense()`, `MatCreateDense()`,
91           `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`,
92           `MatCreateSeqSBAIJ()`, `MatCreateSBAIJ()`,
93           `MatConvert()`
94 @*/
95 PetscErrorCode MatCreate(MPI_Comm comm, Mat *A)
96 {
97   Mat B;
98 
99   PetscFunctionBegin;
100   PetscAssertPointer(A, 2);
101 
102   *A = NULL;
103   PetscCall(MatInitializePackage());
104 
105   PetscCall(PetscHeaderCreate(B, MAT_CLASSID, "Mat", "Matrix", "Mat", comm, MatDestroy, MatView));
106   PetscCall(PetscLayoutCreate(comm, &B->rmap));
107   PetscCall(PetscLayoutCreate(comm, &B->cmap));
108   PetscCall(PetscStrallocpy(VECSTANDARD, &B->defaultvectype));
109   PetscCall(PetscStrallocpy(PETSCRANDER48, &B->defaultrandtype));
110 
111   B->symmetric                   = PETSC_BOOL3_UNKNOWN;
112   B->hermitian                   = PETSC_BOOL3_UNKNOWN;
113   B->structurally_symmetric      = PETSC_BOOL3_UNKNOWN;
114   B->spd                         = PETSC_BOOL3_UNKNOWN;
115   B->symmetry_eternal            = PETSC_FALSE;
116   B->structural_symmetry_eternal = PETSC_FALSE;
117 
118   B->congruentlayouts = PETSC_DECIDE;
119   B->preallocated     = PETSC_FALSE;
120 #if defined(PETSC_HAVE_DEVICE)
121   B->boundtocpu = PETSC_TRUE;
122 #endif
123   *A = B;
124   PetscFunctionReturn(PETSC_SUCCESS);
125 }
126 
127 /*@C
128   MatCreateFromOptions - Creates a matrix whose type is set from the options database
129 
130   Collective
131 
132   Input Parameters:
133 + comm   - MPI communicator
134 . prefix - [optional] prefix for the options database
135 . bs     - the blocksize (commonly 1)
136 . m      - the local number of rows (or `PETSC_DECIDE`)
137 . n      - the local number of columns (or `PETSC_DECIDE` or `PETSC_DETERMINE`)
138 . M      - the global number of rows (or `PETSC_DETERMINE`)
139 - N      - the global number of columns (or `PETSC_DETERMINE`)
140 
141   Output Parameter:
142 . A - the matrix
143 
144   Options Database Key:
145 . -mat_type - see `MatType`, for example `aij`, `aijcusparse`, `baij`, `sbaij`, dense, defaults to `aij`
146 
147   Level: beginner
148 
149 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatCreateAIJ()`,
150           `MatCreateSeqDense()`, `MatCreateDense()`,
151           `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`,
152           `MatCreateSeqSBAIJ()`, `MatCreateSBAIJ()`,
153           `MatConvert()`, `MatCreate()`
154 @*/
155 PetscErrorCode MatCreateFromOptions(MPI_Comm comm, const char *prefix, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, Mat *A)
156 {
157   PetscFunctionBegin;
158   PetscAssertPointer(A, 8);
159   PetscCall(MatCreate(comm, A));
160   if (prefix) PetscCall(MatSetOptionsPrefix(*A, prefix));
161   PetscCall(MatSetBlockSize(*A, bs));
162   PetscCall(MatSetSizes(*A, m, n, M, N));
163   PetscCall(MatSetFromOptions(*A));
164   PetscFunctionReturn(PETSC_SUCCESS);
165 }
166 
167 /*@
168   MatSetErrorIfFailure - Causes `Mat` to generate an immediate error, for example a zero pivot, is detected.
169 
170   Logically Collective
171 
172   Input Parameters:
173 + mat - matrix obtained from `MatCreate()`
174 - flg - `PETSC_TRUE` indicates you want the error generated
175 
176   Level: advanced
177 
178   Note:
179   If this flag is not set then the matrix operation will note the error and continue. The error may cause a later `PC` or `KSP` error
180   or result in a `KSPConvergedReason` indicating the method did not converge.
181 
182 .seealso: [](ch_matrices), `Mat`, `PCSetErrorIfFailure()`, `KSPConvergedReason`, `SNESConvergedReason`
183 @*/
184 PetscErrorCode MatSetErrorIfFailure(Mat mat, PetscBool flg)
185 {
186   PetscFunctionBegin;
187   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
188   PetscValidLogicalCollectiveBool(mat, flg, 2);
189   mat->erroriffailure = flg;
190   PetscFunctionReturn(PETSC_SUCCESS);
191 }
192 
193 /*@
194   MatSetSizes - Sets the local and global sizes, and checks to determine compatibility
195 
196   Collective
197 
198   Input Parameters:
199 + A - the matrix
200 . m - number of local rows (or `PETSC_DECIDE`)
201 . n - number of local columns (or `PETSC_DECIDE`)
202 . M - number of global rows (or `PETSC_DETERMINE`)
203 - N - number of global columns (or `PETSC_DETERMINE`)
204 
205   Level: beginner
206 
207   Notes:
208   `m` (`n`) and `M` (`N`) cannot be both `PETSC_DECIDE`
209   If one processor calls this with `M` (`N`) of `PETSC_DECIDE` then all processors must, otherwise the program will hang.
210 
211   If `PETSC_DECIDE` is not used for the arguments 'm' and 'n', then the
212   user must ensure that they are chosen to be compatible with the
213   vectors. To do this, one first considers the matrix-vector product
214   'y = A x'. The `m` that is used in the above routine must match the
215   local size used in the vector creation routine `VecCreateMPI()` for 'y'.
216   Likewise, the `n` used must match that used as the local size in
217   `VecCreateMPI()` for 'x'.
218 
219   You cannot change the sizes once they have been set.
220 
221   The sizes must be set before `MatSetUp()` or MatXXXSetPreallocation() is called.
222 
223 .seealso: [](ch_matrices), `Mat`, `MatGetSize()`, `PetscSplitOwnership()`
224 @*/
225 PetscErrorCode MatSetSizes(Mat A, PetscInt m, PetscInt n, PetscInt M, PetscInt N)
226 {
227   PetscFunctionBegin;
228   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
229   PetscValidLogicalCollectiveInt(A, M, 4);
230   PetscValidLogicalCollectiveInt(A, N, 5);
231   PetscCheck(M <= 0 || m <= M, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local row size %" PetscInt_FMT " cannot be larger than global row size %" PetscInt_FMT, m, M);
232   PetscCheck(N <= 0 || n <= N, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local column size %" PetscInt_FMT " cannot be larger than global column size %" PetscInt_FMT, n, N);
233   PetscCheck((A->rmap->n < 0 || A->rmap->N < 0) || (A->rmap->n == m && (M <= 0 || A->rmap->N == M)), PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot change/reset row sizes to %" PetscInt_FMT " local %" PetscInt_FMT " global after previously setting them to %" PetscInt_FMT " local %" PetscInt_FMT " global", m, M,
234              A->rmap->n, A->rmap->N);
235   PetscCheck((A->cmap->n < 0 || A->cmap->N < 0) || (A->cmap->n == n && (N <= 0 || A->cmap->N == N)), PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot change/reset column sizes to %" PetscInt_FMT " local %" PetscInt_FMT " global after previously setting them to %" PetscInt_FMT " local %" PetscInt_FMT " global", n, N,
236              A->cmap->n, A->cmap->N);
237   A->rmap->n = m;
238   A->cmap->n = n;
239   A->rmap->N = M > -1 ? M : A->rmap->N;
240   A->cmap->N = N > -1 ? N : A->cmap->N;
241   PetscFunctionReturn(PETSC_SUCCESS);
242 }
243 
244 /*@
245   MatSetFromOptions - Creates a matrix where the type is determined
246   from the options database.
247 
248   Collective
249 
250   Input Parameter:
251 . B - the matrix
252 
253   Options Database Keys:
254 + -mat_type seqaij   - `MATSEQAIJ` type, uses `MatCreateSeqAIJ()`
255 . -mat_type mpiaij   - `MATMPIAIJ` type, uses `MatCreateAIJ()`
256 . -mat_type seqdense - `MATSEQDENSE` type, uses `MatCreateSeqDense()`
257 . -mat_type mpidense - `MATMPIDENSE`, uses `MatCreateDense()`
258 . -mat_type seqbaij  - `MATSEQBAIJ`, uses `MatCreateSeqBAIJ()`
259 - -mat_type mpibaij  - `MATMPIBAIJ`, uses `MatCreateBAIJ()`
260 
261    See the manpages for particular formats (e.g., `MATSEQAIJ`)
262    for additional format-specific options.
263 
264   Level: beginner
265 
266   Notes:
267   Generates a parallel MPI matrix if the communicator has more than one processor.  The default
268   matrix type is `MATAIJ`, using the routines `MatCreateSeqAIJ()` and `MatCreateAIJ()` if you
269   do not select a type in the options database.
270 
271 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatCreateAIJ()`,
272           `MatCreateSeqDense()`, `MatCreateDense()`,
273           `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`,
274           `MatCreateSeqSBAIJ()`, `MatCreateSBAIJ()`,
275           `MatConvert()`
276 @*/
277 PetscErrorCode MatSetFromOptions(Mat B)
278 {
279   const char *deft = MATAIJ;
280   char        type[256];
281   PetscBool   flg, set;
282   PetscInt    bind_below = 0;
283 
284   PetscFunctionBegin;
285   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
286 
287   PetscObjectOptionsBegin((PetscObject)B);
288 
289   if (B->rmap->bs < 0) {
290     PetscInt newbs = -1;
291     PetscCall(PetscOptionsInt("-mat_block_size", "Set the blocksize used to store the matrix", "MatSetBlockSize", newbs, &newbs, &flg));
292     if (flg) {
293       PetscCall(PetscLayoutSetBlockSize(B->rmap, newbs));
294       PetscCall(PetscLayoutSetBlockSize(B->cmap, newbs));
295     }
296   }
297 
298   PetscCall(PetscOptionsFList("-mat_type", "Matrix type", "MatSetType", MatList, deft, type, 256, &flg));
299   if (flg) {
300     PetscCall(MatSetType(B, type));
301   } else if (!((PetscObject)B)->type_name) {
302     PetscCall(MatSetType(B, deft));
303   }
304 
305   PetscCall(PetscOptionsName("-mat_is_symmetric", "Checks if mat is symmetric on MatAssemblyEnd()", "MatIsSymmetric", &B->checksymmetryonassembly));
306   PetscCall(PetscOptionsReal("-mat_is_symmetric", "Checks if mat is symmetric on MatAssemblyEnd()", "MatIsSymmetric", B->checksymmetrytol, &B->checksymmetrytol, NULL));
307   PetscCall(PetscOptionsBool("-mat_null_space_test", "Checks if provided null space is correct in MatAssemblyEnd()", "MatSetNullSpaceTest", B->checknullspaceonassembly, &B->checknullspaceonassembly, NULL));
308   PetscCall(PetscOptionsBool("-mat_error_if_failure", "Generate an error if an error occurs when factoring the matrix", "MatSetErrorIfFailure", B->erroriffailure, &B->erroriffailure, NULL));
309 
310   PetscTryTypeMethod(B, setfromoptions, PetscOptionsObject);
311 
312   flg = PETSC_FALSE;
313   PetscCall(PetscOptionsBool("-mat_new_nonzero_location_err", "Generate an error if new nonzeros are created in the matrix structure (useful to test preallocation)", "MatSetOption", flg, &flg, &set));
314   if (set) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, flg));
315   flg = PETSC_FALSE;
316   PetscCall(PetscOptionsBool("-mat_new_nonzero_allocation_err", "Generate an error if new nonzeros are allocated in the matrix structure (useful to test preallocation)", "MatSetOption", flg, &flg, &set));
317   if (set) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, flg));
318   flg = PETSC_FALSE;
319   PetscCall(PetscOptionsBool("-mat_ignore_zero_entries", "For AIJ/IS matrices this will stop zero values from creating a zero location in the matrix", "MatSetOption", flg, &flg, &set));
320   if (set) PetscCall(MatSetOption(B, MAT_IGNORE_ZERO_ENTRIES, flg));
321 
322   flg = PETSC_FALSE;
323   PetscCall(PetscOptionsBool("-mat_form_explicit_transpose", "Hint to form an explicit transpose for operations like MatMultTranspose", "MatSetOption", flg, &flg, &set));
324   if (set) PetscCall(MatSetOption(B, MAT_FORM_EXPLICIT_TRANSPOSE, flg));
325 
326   /* Bind to CPU if below a user-specified size threshold.
327    * This perhaps belongs in the options for the GPU Mat types, but MatBindToCPU() does nothing when called on non-GPU types,
328    * and putting it here makes is more maintainable than duplicating this for all. */
329   PetscCall(PetscOptionsInt("-mat_bind_below", "Set the size threshold (in local rows) below which the Mat is bound to the CPU", "MatBindToCPU", bind_below, &bind_below, &flg));
330   if (flg && B->rmap->n < bind_below) PetscCall(MatBindToCPU(B, PETSC_TRUE));
331 
332   /* process any options handlers added with PetscObjectAddOptionsHandler() */
333   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)B, PetscOptionsObject));
334   PetscOptionsEnd();
335   PetscFunctionReturn(PETSC_SUCCESS);
336 }
337 
338 /*@C
339   MatXAIJSetPreallocation - set preallocation for serial and parallel `MATAIJ`, `MATBAIJ`, and `MATSBAIJ` matrices and their unassembled versions.
340 
341   Collective
342 
343   Input Parameters:
344 + A     - matrix being preallocated
345 . bs    - block size
346 . dnnz  - number of nonzero column blocks per block row of diagonal part of parallel matrix
347 . onnz  - number of nonzero column blocks per block row of off-diagonal part of parallel matrix
348 . dnnzu - number of nonzero column blocks per block row of upper-triangular part of diagonal part of parallel matrix
349 - onnzu - number of nonzero column blocks per block row of upper-triangular part of off-diagonal part of parallel matrix
350 
351   Level: beginner
352 
353 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`, `MatMPIBAIJSetPreallocation()`,
354           `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`,
355           `PetscSplitOwnership()`
356 @*/
357 PetscErrorCode MatXAIJSetPreallocation(Mat A, PetscInt bs, const PetscInt dnnz[], const PetscInt onnz[], const PetscInt dnnzu[], const PetscInt onnzu[])
358 {
359   PetscInt cbs;
360   void (*aij)(void);
361   void (*is)(void);
362   void (*hyp)(void) = NULL;
363 
364   PetscFunctionBegin;
365   if (bs != PETSC_DECIDE) { /* don't mess with an already set block size */
366     PetscCall(MatSetBlockSize(A, bs));
367   }
368   PetscCall(PetscLayoutSetUp(A->rmap));
369   PetscCall(PetscLayoutSetUp(A->cmap));
370   PetscCall(MatGetBlockSizes(A, &bs, &cbs));
371   /* these routines assumes bs == cbs, this should be checked somehow */
372   PetscCall(MatSeqBAIJSetPreallocation(A, bs, 0, dnnz));
373   PetscCall(MatMPIBAIJSetPreallocation(A, bs, 0, dnnz, 0, onnz));
374   PetscCall(MatSeqSBAIJSetPreallocation(A, bs, 0, dnnzu));
375   PetscCall(MatMPISBAIJSetPreallocation(A, bs, 0, dnnzu, 0, onnzu));
376   /*
377     In general, we have to do extra work to preallocate for scalar (AIJ) or unassembled (IS) matrices so we check whether it will do any
378     good before going on with it.
379   */
380   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatMPIAIJSetPreallocation_C", &aij));
381   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatISSetPreallocation_C", &is));
382 #if defined(PETSC_HAVE_HYPRE)
383   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatHYPRESetPreallocation_C", &hyp));
384 #endif
385   if (!aij && !is && !hyp) PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSeqAIJSetPreallocation_C", &aij));
386   if (aij || is || hyp) {
387     if (bs == cbs && bs == 1) {
388       PetscCall(MatSeqAIJSetPreallocation(A, 0, dnnz));
389       PetscCall(MatMPIAIJSetPreallocation(A, 0, dnnz, 0, onnz));
390       PetscCall(MatISSetPreallocation(A, 0, dnnz, 0, onnz));
391 #if defined(PETSC_HAVE_HYPRE)
392       PetscCall(MatHYPRESetPreallocation(A, 0, dnnz, 0, onnz));
393 #endif
394     } else { /* Convert block-row precallocation to scalar-row */
395       PetscInt i, m, *sdnnz, *sonnz;
396       PetscCall(MatGetLocalSize(A, &m, NULL));
397       PetscCall(PetscMalloc2((!!dnnz) * m, &sdnnz, (!!onnz) * m, &sonnz));
398       for (i = 0; i < m; i++) {
399         if (dnnz) sdnnz[i] = dnnz[i / bs] * cbs;
400         if (onnz) sonnz[i] = onnz[i / bs] * cbs;
401       }
402       PetscCall(MatSeqAIJSetPreallocation(A, 0, dnnz ? sdnnz : NULL));
403       PetscCall(MatMPIAIJSetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL));
404       PetscCall(MatISSetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL));
405 #if defined(PETSC_HAVE_HYPRE)
406       PetscCall(MatHYPRESetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL));
407 #endif
408       PetscCall(PetscFree2(sdnnz, sonnz));
409     }
410   }
411   PetscFunctionReturn(PETSC_SUCCESS);
412 }
413 
414 /*@C
415   MatHeaderMerge - Merges some information from the header of `C` to `A`; the `C` object is then destroyed
416 
417   Collective, No Fortran Support
418 
419   Input Parameters:
420 + A - a `Mat` being merged into
421 - C - the `Mat` providing the merge information
422 
423   Level: developer
424 
425   Developer Note:
426   This is somewhat different from `MatHeaderReplace()`, it would be nice to merge the code
427 
428 .seealso: `Mat`, `MatHeaderReplace()`
429  @*/
430 PetscErrorCode MatHeaderMerge(Mat A, Mat *C)
431 {
432   PetscInt         refct;
433   PetscOps         Abops;
434   struct _MatOps   Aops;
435   char            *mtype, *mname, *mprefix;
436   Mat_Product     *product;
437   Mat_Redundant   *redundant;
438   PetscObjectState state;
439 
440   PetscFunctionBegin;
441   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
442   PetscValidHeaderSpecific(*C, MAT_CLASSID, 2);
443   if (A == *C) PetscFunctionReturn(PETSC_SUCCESS);
444   PetscCheckSameComm(A, 1, *C, 2);
445   /* save the parts of A we need */
446   Abops     = ((PetscObject)A)->bops[0];
447   Aops      = A->ops[0];
448   refct     = ((PetscObject)A)->refct;
449   mtype     = ((PetscObject)A)->type_name;
450   mname     = ((PetscObject)A)->name;
451   state     = ((PetscObject)A)->state;
452   mprefix   = ((PetscObject)A)->prefix;
453   product   = A->product;
454   redundant = A->redundant;
455 
456   /* zero these so the destroy below does not free them */
457   ((PetscObject)A)->type_name = NULL;
458   ((PetscObject)A)->name      = NULL;
459 
460   /*
461      free all the interior data structures from mat
462      cannot use PetscUseTypeMethod(A,destroy); because compiler
463      thinks it may print NULL type_name and name
464   */
465   PetscTryTypeMethod(A, destroy);
466 
467   PetscCall(PetscFree(A->defaultvectype));
468   PetscCall(PetscFree(A->defaultrandtype));
469   PetscCall(PetscLayoutDestroy(&A->rmap));
470   PetscCall(PetscLayoutDestroy(&A->cmap));
471   PetscCall(PetscFunctionListDestroy(&((PetscObject)A)->qlist));
472   PetscCall(PetscObjectListDestroy(&((PetscObject)A)->olist));
473   PetscCall(PetscComposedQuantitiesDestroy((PetscObject)A));
474 
475   /* copy C over to A */
476   PetscCall(PetscFree(A->factorprefix));
477   PetscCall(PetscMemcpy(A, *C, sizeof(struct _p_Mat)));
478 
479   /* return the parts of A we saved */
480   ((PetscObject)A)->bops[0]   = Abops;
481   A->ops[0]                   = Aops;
482   ((PetscObject)A)->refct     = refct;
483   ((PetscObject)A)->type_name = mtype;
484   ((PetscObject)A)->name      = mname;
485   ((PetscObject)A)->prefix    = mprefix;
486   ((PetscObject)A)->state     = state + 1;
487   A->product                  = product;
488   A->redundant                = redundant;
489 
490   /* since these two are copied into A we do not want them destroyed in C */
491   ((PetscObject)*C)->qlist = NULL;
492   ((PetscObject)*C)->olist = NULL;
493 
494   PetscCall(PetscHeaderDestroy(C));
495   PetscFunctionReturn(PETSC_SUCCESS);
496 }
497 
498 /*@
499   MatHeaderReplace - Replaces the internal data of matrix `A` by the internal data of matrix `C` while deleting the outer wrapper of `C`
500 
501   Input Parameters:
502 + A - a `Mat` whose internal data is to be replaced
503 - C - the `Mat` providing new internal data for `A`
504 
505   Level: advanced
506 
507   Example Usage\:
508 .vb
509   Mat C;
510   MatCreateSeqAIJWithArrays(..., &C);
511   MatHeaderReplace(A, &C);
512   // C has been destroyed and A contains the matrix entries of C
513 .ve
514 
515   Note:
516   This can be used inside a function provided to `SNESSetJacobian()`, `TSSetRHSJacobian()`, or `TSSetIJacobian()` in cases where the user code computes an entirely new sparse matrix
517   (generally with a different nonzero pattern) for each Newton update. It is usually better to reuse the matrix structure of `A` instead of constructing an entirely new one.
518 
519   Developer Note:
520   This is somewhat different from `MatHeaderMerge()` it would be nice to merge the code
521 
522 .seealso: `Mat`, `MatHeaderMerge()`
523  @*/
524 PetscErrorCode MatHeaderReplace(Mat A, Mat *C)
525 {
526   PetscInt         refct;
527   PetscObjectState state;
528   struct _p_Mat    buffer;
529   MatStencilInfo   stencil;
530 
531   PetscFunctionBegin;
532   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
533   PetscValidHeaderSpecific(*C, MAT_CLASSID, 2);
534   if (A == *C) PetscFunctionReturn(PETSC_SUCCESS);
535   PetscCheckSameComm(A, 1, *C, 2);
536   PetscCheck(((PetscObject)*C)->refct == 1, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Object C has refct %" PetscInt_FMT " > 1, would leave hanging reference", ((PetscObject)*C)->refct);
537 
538   /* swap C and A */
539   refct   = ((PetscObject)A)->refct;
540   state   = ((PetscObject)A)->state;
541   stencil = A->stencil;
542   PetscCall(PetscMemcpy(&buffer, A, sizeof(struct _p_Mat)));
543   PetscCall(PetscMemcpy(A, *C, sizeof(struct _p_Mat)));
544   PetscCall(PetscMemcpy(*C, &buffer, sizeof(struct _p_Mat)));
545   ((PetscObject)A)->refct = refct;
546   ((PetscObject)A)->state = state + 1;
547   A->stencil              = stencil;
548 
549   ((PetscObject)*C)->refct = 1;
550   PetscCall(MatShellSetOperation(*C, MATOP_DESTROY, (void (*)(void))NULL));
551   PetscCall(MatDestroy(C));
552   PetscFunctionReturn(PETSC_SUCCESS);
553 }
554 
555 /*@
556   MatBindToCPU - marks a matrix to temporarily stay on the CPU and perform computations on the CPU
557 
558   Logically Collective
559 
560   Input Parameters:
561 + A   - the matrix
562 - flg - bind to the CPU if value of `PETSC_TRUE`
563 
564   Level: intermediate
565 
566 .seealso: [](ch_matrices), `Mat`, `MatBoundToCPU()`
567 @*/
568 PetscErrorCode MatBindToCPU(Mat A, PetscBool flg)
569 {
570   PetscFunctionBegin;
571   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
572   PetscValidLogicalCollectiveBool(A, flg, 2);
573 #if defined(PETSC_HAVE_DEVICE)
574   if (A->boundtocpu == flg) PetscFunctionReturn(PETSC_SUCCESS);
575   A->boundtocpu = flg;
576   PetscTryTypeMethod(A, bindtocpu, flg);
577 #endif
578   PetscFunctionReturn(PETSC_SUCCESS);
579 }
580 
581 /*@
582   MatBoundToCPU - query if a matrix is bound to the CPU
583 
584   Input Parameter:
585 . A - the matrix
586 
587   Output Parameter:
588 . flg - the logical flag
589 
590   Level: intermediate
591 
592 .seealso: [](ch_matrices), `Mat`, `MatBindToCPU()`
593 @*/
594 PetscErrorCode MatBoundToCPU(Mat A, PetscBool *flg)
595 {
596   PetscFunctionBegin;
597   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
598   PetscAssertPointer(flg, 2);
599 #if defined(PETSC_HAVE_DEVICE)
600   *flg = A->boundtocpu;
601 #else
602   *flg = PETSC_TRUE;
603 #endif
604   PetscFunctionReturn(PETSC_SUCCESS);
605 }
606 
607 PetscErrorCode MatSetValuesCOO_Basic(Mat A, const PetscScalar coo_v[], InsertMode imode)
608 {
609   IS              is_coo_i, is_coo_j;
610   const PetscInt *coo_i, *coo_j;
611   PetscInt        n, n_i, n_j;
612   PetscScalar     zero = 0.;
613 
614   PetscFunctionBegin;
615   PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_coo_i", (PetscObject *)&is_coo_i));
616   PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_coo_j", (PetscObject *)&is_coo_j));
617   PetscCheck(is_coo_i, PetscObjectComm((PetscObject)A), PETSC_ERR_COR, "Missing coo_i IS");
618   PetscCheck(is_coo_j, PetscObjectComm((PetscObject)A), PETSC_ERR_COR, "Missing coo_j IS");
619   PetscCall(ISGetLocalSize(is_coo_i, &n_i));
620   PetscCall(ISGetLocalSize(is_coo_j, &n_j));
621   PetscCheck(n_i == n_j, PETSC_COMM_SELF, PETSC_ERR_COR, "Wrong local size %" PetscInt_FMT " != %" PetscInt_FMT, n_i, n_j);
622   PetscCall(ISGetIndices(is_coo_i, &coo_i));
623   PetscCall(ISGetIndices(is_coo_j, &coo_j));
624   if (imode != ADD_VALUES) PetscCall(MatZeroEntries(A));
625   for (n = 0; n < n_i; n++) PetscCall(MatSetValue(A, coo_i[n], coo_j[n], coo_v ? coo_v[n] : zero, ADD_VALUES));
626   PetscCall(ISRestoreIndices(is_coo_i, &coo_i));
627   PetscCall(ISRestoreIndices(is_coo_j, &coo_j));
628   PetscFunctionReturn(PETSC_SUCCESS);
629 }
630 
631 PetscErrorCode MatSetPreallocationCOO_Basic(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
632 {
633   Mat         preallocator;
634   IS          is_coo_i, is_coo_j;
635   PetscScalar zero = 0.0;
636 
637   PetscFunctionBegin;
638   PetscCall(PetscLayoutSetUp(A->rmap));
639   PetscCall(PetscLayoutSetUp(A->cmap));
640   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &preallocator));
641   PetscCall(MatSetType(preallocator, MATPREALLOCATOR));
642   PetscCall(MatSetSizes(preallocator, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
643   PetscCall(MatSetLayouts(preallocator, A->rmap, A->cmap));
644   PetscCall(MatSetUp(preallocator));
645   for (PetscCount n = 0; n < ncoo; n++) PetscCall(MatSetValue(preallocator, coo_i[n], coo_j[n], zero, INSERT_VALUES));
646   PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY));
647   PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY));
648   PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, A));
649   PetscCall(MatDestroy(&preallocator));
650   PetscCheck(ncoo <= PETSC_MAX_INT, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "ncoo %" PetscCount_FMT " overflowed PetscInt; configure --with-64-bit-indices or request support", ncoo);
651   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncoo, coo_i, PETSC_COPY_VALUES, &is_coo_i));
652   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncoo, coo_j, PETSC_COPY_VALUES, &is_coo_j));
653   PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_coo_i", (PetscObject)is_coo_i));
654   PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_coo_j", (PetscObject)is_coo_j));
655   PetscCall(ISDestroy(&is_coo_i));
656   PetscCall(ISDestroy(&is_coo_j));
657   PetscFunctionReturn(PETSC_SUCCESS);
658 }
659 
660 /*@C
661   MatSetPreallocationCOO - set preallocation for matrices using a coordinate format of the entries with global indices
662 
663   Collective
664 
665   Input Parameters:
666 + A     - matrix being preallocated
667 . ncoo  - number of entries
668 . coo_i - row indices
669 - coo_j - column indices
670 
671   Level: beginner
672 
673   Notes:
674   The indices `coo_i` and `coo_j` may be modified within this function. The caller should not rely on them
675   having any specific value after this function returns. The arrays can be freed or reused immediately
676   after this function returns.
677 
678   Entries can be repeated, see `MatSetValuesCOO()`. Entries with negative row or column indices are allowed
679   but will be ignored. The corresponding entries in `MatSetValuesCOO()` will be ignored too. Remote entries
680   are allowed and will be properly added or inserted to the matrix, unless the matrix option `MAT_IGNORE_OFF_PROC_ENTRIES`
681   is set, in which case remote entries are ignored, or `MAT_NO_OFF_PROC_ENTRIES` is set, in which case an error will be generated.
682 
683   If you just want to create a sequential AIJ matrix (`MATSEQAIJ`), and your matrix entries in COO format are unique, you can also use
684   `MatCreateSeqAIJFromTriple()`. But that is not recommended for iterative applications.
685 
686 .seealso: [](ch_matrices), `Mat`, `MatSetValuesCOO()`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`,
687           `MatMPIBAIJSetPreallocation()`, `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`, `MatSetPreallocationCOOLocal()`,
688           `DMSetMatrixPreallocateSkip()`, `MatCreateSeqAIJFromTriple()`
689 @*/
690 PetscErrorCode MatSetPreallocationCOO(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
691 {
692   PetscErrorCode (*f)(Mat, PetscCount, PetscInt[], PetscInt[]) = NULL;
693 
694   PetscFunctionBegin;
695   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
696   PetscValidType(A, 1);
697   if (ncoo) PetscAssertPointer(coo_i, 3);
698   if (ncoo) PetscAssertPointer(coo_j, 4);
699   PetscCall(PetscLayoutSetUp(A->rmap));
700   PetscCall(PetscLayoutSetUp(A->cmap));
701   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetPreallocationCOO_C", &f));
702 
703   PetscCall(PetscLogEventBegin(MAT_PreallCOO, A, 0, 0, 0));
704   if (f) {
705     PetscCall((*f)(A, ncoo, coo_i, coo_j));
706   } else { /* allow fallback, very slow */
707     PetscCall(MatSetPreallocationCOO_Basic(A, ncoo, coo_i, coo_j));
708   }
709   PetscCall(PetscLogEventEnd(MAT_PreallCOO, A, 0, 0, 0));
710   A->preallocated = PETSC_TRUE;
711   A->nonzerostate++;
712   PetscFunctionReturn(PETSC_SUCCESS);
713 }
714 
715 /*@C
716   MatSetPreallocationCOOLocal - set preallocation for matrices using a coordinate format of the entries with local indices
717 
718   Collective
719 
720   Input Parameters:
721 + A     - matrix being preallocated
722 . ncoo  - number of entries
723 . coo_i - row indices (local numbering; may be modified)
724 - coo_j - column indices (local numbering; may be modified)
725 
726   Level: beginner
727 
728   Notes:
729   The local indices are translated using the local to global mapping, thus `MatSetLocalToGlobalMapping()` must have been
730   called prior to this function. For matrices created with `DMCreateMatrix()` the local to global mapping is often already provided.
731 
732   The indices `coo_i` and `coo_j` may be modified within this function. They might be translated to corresponding global
733   indices, but the caller should not rely on them having any specific value after this function returns. The arrays
734   can be freed or reused immediately after this function returns.
735 
736   Entries can be repeated, see `MatSetValuesCOO()`. Entries with negative row or column indices are allowed
737   but will be ignored. The corresponding entries in `MatSetValuesCOO()` will be ignored too. Remote entries
738   are allowed and will be properly added or inserted to the matrix.
739 
740 .seealso: [](ch_matrices), `Mat`, `MatSetValuesCOO()`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`,
741           `MatMPIBAIJSetPreallocation()`, `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`, `MatSetPreallocationCOO()`,
742           `DMSetMatrixPreallocateSkip()`
743 @*/
744 PetscErrorCode MatSetPreallocationCOOLocal(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
745 {
746   PetscErrorCode (*f)(Mat, PetscCount, PetscInt[], PetscInt[]) = NULL;
747 
748   PetscFunctionBegin;
749   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
750   PetscValidType(A, 1);
751   if (ncoo) PetscAssertPointer(coo_i, 3);
752   if (ncoo) PetscAssertPointer(coo_j, 4);
753   PetscCheck(ncoo <= PETSC_MAX_INT, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "ncoo %" PetscCount_FMT " overflowed PetscInt; configure --with-64-bit-indices or request support", ncoo);
754   PetscCall(PetscLayoutSetUp(A->rmap));
755   PetscCall(PetscLayoutSetUp(A->cmap));
756 
757   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", &f));
758   if (f) {
759     PetscCall((*f)(A, ncoo, coo_i, coo_j));
760     A->nonzerostate++;
761   } else {
762     ISLocalToGlobalMapping ltog_row, ltog_col;
763     PetscCall(MatGetLocalToGlobalMapping(A, &ltog_row, &ltog_col));
764     if (ltog_row) PetscCall(ISLocalToGlobalMappingApply(ltog_row, ncoo, coo_i, coo_i));
765     if (ltog_col) PetscCall(ISLocalToGlobalMappingApply(ltog_col, ncoo, coo_j, coo_j));
766     PetscCall(MatSetPreallocationCOO(A, ncoo, coo_i, coo_j));
767   }
768   A->preallocated = PETSC_TRUE;
769   PetscFunctionReturn(PETSC_SUCCESS);
770 }
771 
772 /*@
773   MatSetValuesCOO - set values at once in a matrix preallocated using `MatSetPreallocationCOO()`
774 
775   Collective
776 
777   Input Parameters:
778 + A     - matrix being preallocated
779 . coo_v - the matrix values (can be `NULL`)
780 - imode - the insert mode
781 
782   Level: beginner
783 
784   Notes:
785   The values must follow the order of the indices prescribed with `MatSetPreallocationCOO()` or `MatSetPreallocationCOOLocal()`.
786 
787   When repeated entries are specified in the COO indices the `coo_v` values are first properly summed, regardless of the value of imode.
788   The imode flag indicates if coo_v must be added to the current values of the matrix (`ADD_VALUES`) or overwritten (`INSERT_VALUES`).
789 
790   `MatAssemblyBegin()` and `MatAssemblyEnd()` do not need to be called after this routine. It automatically handles the assembly process.
791 
792 .seealso: [](ch_matrices), `Mat`, `MatSetPreallocationCOO()`, `MatSetPreallocationCOOLocal()`, `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
793 @*/
794 PetscErrorCode MatSetValuesCOO(Mat A, const PetscScalar coo_v[], InsertMode imode)
795 {
796   PetscErrorCode (*f)(Mat, const PetscScalar[], InsertMode) = NULL;
797   PetscBool oldFlg;
798 
799   PetscFunctionBegin;
800   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
801   PetscValidType(A, 1);
802   MatCheckPreallocated(A, 1);
803   PetscValidLogicalCollectiveEnum(A, imode, 3);
804   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetValuesCOO_C", &f));
805   PetscCall(PetscLogEventBegin(MAT_SetVCOO, A, 0, 0, 0));
806   if (f) {
807     PetscCall((*f)(A, coo_v, imode)); // all known COO implementations do not use MatStash. They do their own off-proc communication
808     PetscCall(MatGetOption(A, MAT_NO_OFF_PROC_ENTRIES, &oldFlg));
809     PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); // set A->nooffprocentries to avoid costly MatStash scatter in MatAssembly
810   } else {
811     PetscCall(MatSetValuesCOO_Basic(A, coo_v, imode)); // fall back to MatSetValues, which might use MatStash
812   }
813   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
814   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
815   if (f) PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, oldFlg));
816   PetscCall(PetscLogEventEnd(MAT_SetVCOO, A, 0, 0, 0));
817   PetscFunctionReturn(PETSC_SUCCESS);
818 }
819 
820 /*@
821   MatSetBindingPropagates - Sets whether the state of being bound to the CPU for a GPU matrix type propagates to child and some other associated objects
822 
823   Input Parameters:
824 + A   - the matrix
825 - flg - flag indicating whether the boundtocpu flag should be propagated
826 
827   Level: developer
828 
829   Notes:
830   If the value of flg is set to true, the following will occur
831 +   `MatCreateSubMatrices()` and `MatCreateRedundantMatrix()` - bind created matrices to CPU if the input matrix is bound to the CPU.
832 -   `MatCreateVecs()` - bind created vectors to CPU if the input matrix is bound to the CPU.
833 
834   The bindingpropagates flag itself is also propagated by the above routines.
835 
836   Developer Notes:
837   If the fine-scale `DMDA` has the `-dm_bind_below` option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()`
838   on the restriction/interpolation operator to set the bindingpropagates flag to true.
839 
840 .seealso: [](ch_matrices), `Mat`, `VecSetBindingPropagates()`, `MatGetBindingPropagates()`
841 @*/
842 PetscErrorCode MatSetBindingPropagates(Mat A, PetscBool flg)
843 {
844   PetscFunctionBegin;
845   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
846 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
847   A->bindingpropagates = flg;
848 #endif
849   PetscFunctionReturn(PETSC_SUCCESS);
850 }
851 
852 /*@
853   MatGetBindingPropagates - Gets whether the state of being bound to the CPU for a GPU matrix type propagates to child and some other associated objects
854 
855   Input Parameter:
856 . A - the matrix
857 
858   Output Parameter:
859 . flg - flag indicating whether the boundtocpu flag will be propagated
860 
861   Level: developer
862 
863 .seealso: [](ch_matrices), `Mat`, `MatSetBindingPropagates()`
864 @*/
865 PetscErrorCode MatGetBindingPropagates(Mat A, PetscBool *flg)
866 {
867   PetscFunctionBegin;
868   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
869   PetscAssertPointer(flg, 2);
870 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
871   *flg = A->bindingpropagates;
872 #else
873   *flg = PETSC_FALSE;
874 #endif
875   PetscFunctionReturn(PETSC_SUCCESS);
876 }
877