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