xref: /petsc/src/mat/interface/matrix.c (revision 8aa39e1bf17a5ea28fa0458095c26b0a3b4f2478)
1 /*
2    This is where the abstract matrix operations are defined
3    Portions of this code are under:
4    Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
5 */
6 
7 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
8 #include <petsc/private/isimpl.h>
9 #include <petsc/private/vecimpl.h>
10 
11 /* Logging support */
12 PetscClassId MAT_CLASSID;
13 PetscClassId MAT_COLORING_CLASSID;
14 PetscClassId MAT_FDCOLORING_CLASSID;
15 PetscClassId MAT_TRANSPOSECOLORING_CLASSID;
16 
17 PetscLogEvent MAT_Mult, MAT_MultAdd, MAT_MultTranspose;
18 PetscLogEvent MAT_MultTransposeAdd, MAT_Solve, MAT_Solves, MAT_SolveAdd, MAT_SolveTranspose, MAT_MatSolve, MAT_MatTrSolve;
19 PetscLogEvent MAT_SolveTransposeAdd, MAT_SOR, MAT_ForwardSolve, MAT_BackwardSolve, MAT_LUFactor, MAT_LUFactorSymbolic;
20 PetscLogEvent MAT_LUFactorNumeric, MAT_CholeskyFactor, MAT_CholeskyFactorSymbolic, MAT_CholeskyFactorNumeric, MAT_ILUFactor;
21 PetscLogEvent MAT_ILUFactorSymbolic, MAT_ICCFactorSymbolic, MAT_Copy, MAT_Convert, MAT_Scale, MAT_AssemblyBegin;
22 PetscLogEvent MAT_QRFactorNumeric, MAT_QRFactorSymbolic, MAT_QRFactor;
23 PetscLogEvent MAT_AssemblyEnd, MAT_SetValues, MAT_GetValues, MAT_GetRow, MAT_GetRowIJ, MAT_CreateSubMats, MAT_GetOrdering, MAT_RedundantMat, MAT_GetSeqNonzeroStructure;
24 PetscLogEvent MAT_IncreaseOverlap, MAT_Partitioning, MAT_PartitioningND, MAT_Coarsen, MAT_ZeroEntries, MAT_Load, MAT_View, MAT_AXPY, MAT_FDColoringCreate;
25 PetscLogEvent MAT_FDColoringSetUp, MAT_FDColoringApply, MAT_Transpose, MAT_FDColoringFunction, MAT_CreateSubMat;
26 PetscLogEvent MAT_TransposeColoringCreate;
27 PetscLogEvent MAT_MatMult, MAT_MatMultSymbolic, MAT_MatMultNumeric;
28 PetscLogEvent MAT_PtAP, MAT_PtAPSymbolic, MAT_PtAPNumeric, MAT_RARt, MAT_RARtSymbolic, MAT_RARtNumeric;
29 PetscLogEvent MAT_MatTransposeMult, MAT_MatTransposeMultSymbolic, MAT_MatTransposeMultNumeric;
30 PetscLogEvent MAT_TransposeMatMult, MAT_TransposeMatMultSymbolic, MAT_TransposeMatMultNumeric;
31 PetscLogEvent MAT_MatMatMult, MAT_MatMatMultSymbolic, MAT_MatMatMultNumeric;
32 PetscLogEvent MAT_MultHermitianTranspose, MAT_MultHermitianTransposeAdd;
33 PetscLogEvent MAT_Getsymtransreduced, MAT_GetBrowsOfAcols;
34 PetscLogEvent MAT_GetBrowsOfAocols, MAT_Getlocalmat, MAT_Getlocalmatcondensed, MAT_Seqstompi, MAT_Seqstompinum, MAT_Seqstompisym;
35 PetscLogEvent MAT_GetMultiProcBlock;
36 PetscLogEvent MAT_CUSPARSECopyToGPU, MAT_CUSPARSECopyFromGPU, MAT_CUSPARSEGenerateTranspose, MAT_CUSPARSESolveAnalysis;
37 PetscLogEvent MAT_HIPSPARSECopyToGPU, MAT_HIPSPARSECopyFromGPU, MAT_HIPSPARSEGenerateTranspose, MAT_HIPSPARSESolveAnalysis;
38 PetscLogEvent MAT_PreallCOO, MAT_SetVCOO;
39 PetscLogEvent MAT_CreateGraph;
40 PetscLogEvent MAT_SetValuesBatch;
41 PetscLogEvent MAT_ViennaCLCopyToGPU;
42 PetscLogEvent MAT_CUDACopyToGPU, MAT_HIPCopyToGPU;
43 PetscLogEvent MAT_DenseCopyToGPU, MAT_DenseCopyFromGPU;
44 PetscLogEvent MAT_Merge, MAT_Residual, MAT_SetRandom;
45 PetscLogEvent MAT_FactorFactS, MAT_FactorInvS;
46 PetscLogEvent MATCOLORING_Apply, MATCOLORING_Comm, MATCOLORING_Local, MATCOLORING_ISCreate, MATCOLORING_SetUp, MATCOLORING_Weights;
47 PetscLogEvent MAT_H2Opus_Build, MAT_H2Opus_Compress, MAT_H2Opus_Orthog, MAT_H2Opus_LR;
48 
49 const char *const MatFactorTypes[] = {"NONE", "LU", "CHOLESKY", "ILU", "ICC", "ILUDT", "QR", "MatFactorType", "MAT_FACTOR_", NULL};
50 
51 /*@
52   MatSetRandom - Sets all components of a matrix to random numbers.
53 
54   Logically Collective
55 
56   Input Parameters:
57 + x    - the matrix
58 - rctx - the `PetscRandom` object, formed by `PetscRandomCreate()`, or `NULL` and
59           it will create one internally.
60 
61   Example:
62 .vb
63      PetscRandomCreate(PETSC_COMM_WORLD,&rctx);
64      MatSetRandom(x,rctx);
65      PetscRandomDestroy(rctx);
66 .ve
67 
68   Level: intermediate
69 
70   Notes:
71   For sparse matrices that have been preallocated but not been assembled, it randomly selects appropriate locations,
72 
73   for sparse matrices that already have nonzero locations, it fills the locations with random numbers.
74 
75   It generates an error if used on unassembled sparse matrices that have not been preallocated.
76 
77 .seealso: [](ch_matrices), `Mat`, `PetscRandom`, `PetscRandomCreate()`, `MatZeroEntries()`, `MatSetValues()`, `PetscRandomDestroy()`
78 @*/
79 PetscErrorCode MatSetRandom(Mat x, PetscRandom rctx)
80 {
81   PetscRandom randObj = NULL;
82 
83   PetscFunctionBegin;
84   PetscValidHeaderSpecific(x, MAT_CLASSID, 1);
85   if (rctx) PetscValidHeaderSpecific(rctx, PETSC_RANDOM_CLASSID, 2);
86   PetscValidType(x, 1);
87   MatCheckPreallocated(x, 1);
88 
89   if (!rctx) {
90     MPI_Comm comm;
91     PetscCall(PetscObjectGetComm((PetscObject)x, &comm));
92     PetscCall(PetscRandomCreate(comm, &randObj));
93     PetscCall(PetscRandomSetType(randObj, x->defaultrandtype));
94     PetscCall(PetscRandomSetFromOptions(randObj));
95     rctx = randObj;
96   }
97   PetscCall(PetscLogEventBegin(MAT_SetRandom, x, rctx, 0, 0));
98   PetscUseTypeMethod(x, setrandom, rctx);
99   PetscCall(PetscLogEventEnd(MAT_SetRandom, x, rctx, 0, 0));
100 
101   PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
102   PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
103   PetscCall(PetscRandomDestroy(&randObj));
104   PetscFunctionReturn(PETSC_SUCCESS);
105 }
106 
107 /*@
108   MatCopyHashToXAIJ - copy hash table entries into an XAIJ matrix type
109 
110   Logically Collective
111 
112   Input Parameter:
113 . A - A matrix in unassembled, hash table form
114 
115   Output Parameter:
116 . B - The XAIJ matrix. This can either be `A` or some matrix of equivalent size, e.g. obtained from `A` via `MatDuplicate()`
117 
118   Example:
119 .vb
120      PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &B));
121      PetscCall(MatCopyHashToXAIJ(A, B));
122 .ve
123 
124   Level: advanced
125 
126   Notes:
127   If `B` is `A`, then the hash table data structure will be destroyed. `B` is assembled
128 
129 .seealso: [](ch_matrices), `Mat`, `MAT_USE_HASH_TABLE`
130 @*/
131 PetscErrorCode MatCopyHashToXAIJ(Mat A, Mat B)
132 {
133   PetscFunctionBegin;
134   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
135   PetscUseTypeMethod(A, copyhashtoxaij, B);
136   PetscFunctionReturn(PETSC_SUCCESS);
137 }
138 
139 /*@
140   MatFactorGetErrorZeroPivot - returns the pivot value that was determined to be zero and the row it occurred in
141 
142   Logically Collective
143 
144   Input Parameter:
145 . mat - the factored matrix
146 
147   Output Parameters:
148 + pivot - the pivot value computed
149 - row   - the row that the zero pivot occurred. This row value must be interpreted carefully due to row reorderings and which processes
150          the share the matrix
151 
152   Level: advanced
153 
154   Notes:
155   This routine does not work for factorizations done with external packages.
156 
157   This routine should only be called if `MatGetFactorError()` returns a value of `MAT_FACTOR_NUMERIC_ZEROPIVOT`
158 
159   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
160 
161 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`,
162 `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`, `MatFactorClearError()`,
163 `MAT_FACTOR_NUMERIC_ZEROPIVOT`
164 @*/
165 PetscErrorCode MatFactorGetErrorZeroPivot(Mat mat, PetscReal *pivot, PetscInt *row)
166 {
167   PetscFunctionBegin;
168   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
169   PetscAssertPointer(pivot, 2);
170   PetscAssertPointer(row, 3);
171   *pivot = mat->factorerror_zeropivot_value;
172   *row   = mat->factorerror_zeropivot_row;
173   PetscFunctionReturn(PETSC_SUCCESS);
174 }
175 
176 /*@
177   MatFactorGetError - gets the error code from a factorization
178 
179   Logically Collective
180 
181   Input Parameter:
182 . mat - the factored matrix
183 
184   Output Parameter:
185 . err - the error code
186 
187   Level: advanced
188 
189   Note:
190   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
191 
192 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`,
193           `MatFactorClearError()`, `MatFactorGetErrorZeroPivot()`, `MatFactorError`
194 @*/
195 PetscErrorCode MatFactorGetError(Mat mat, MatFactorError *err)
196 {
197   PetscFunctionBegin;
198   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
199   PetscAssertPointer(err, 2);
200   *err = mat->factorerrortype;
201   PetscFunctionReturn(PETSC_SUCCESS);
202 }
203 
204 /*@
205   MatFactorClearError - clears the error code in a factorization
206 
207   Logically Collective
208 
209   Input Parameter:
210 . mat - the factored matrix
211 
212   Level: developer
213 
214   Note:
215   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
216 
217 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`, `MatFactorGetError()`, `MatFactorGetErrorZeroPivot()`,
218           `MatGetErrorCode()`, `MatFactorError`
219 @*/
220 PetscErrorCode MatFactorClearError(Mat mat)
221 {
222   PetscFunctionBegin;
223   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
224   mat->factorerrortype             = MAT_FACTOR_NOERROR;
225   mat->factorerror_zeropivot_value = 0.0;
226   mat->factorerror_zeropivot_row   = 0;
227   PetscFunctionReturn(PETSC_SUCCESS);
228 }
229 
230 PetscErrorCode MatFindNonzeroRowsOrCols_Basic(Mat mat, PetscBool cols, PetscReal tol, IS *nonzero)
231 {
232   Vec                r, l;
233   const PetscScalar *al;
234   PetscInt           i, nz, gnz, N, n, st;
235 
236   PetscFunctionBegin;
237   PetscCall(MatCreateVecs(mat, &r, &l));
238   if (!cols) { /* nonzero rows */
239     PetscCall(MatGetOwnershipRange(mat, &st, NULL));
240     PetscCall(MatGetSize(mat, &N, NULL));
241     PetscCall(MatGetLocalSize(mat, &n, NULL));
242     PetscCall(VecSet(l, 0.0));
243     PetscCall(VecSetRandom(r, NULL));
244     PetscCall(MatMult(mat, r, l));
245     PetscCall(VecGetArrayRead(l, &al));
246   } else { /* nonzero columns */
247     PetscCall(MatGetOwnershipRangeColumn(mat, &st, NULL));
248     PetscCall(MatGetSize(mat, NULL, &N));
249     PetscCall(MatGetLocalSize(mat, NULL, &n));
250     PetscCall(VecSet(r, 0.0));
251     PetscCall(VecSetRandom(l, NULL));
252     PetscCall(MatMultTranspose(mat, l, r));
253     PetscCall(VecGetArrayRead(r, &al));
254   }
255   if (tol <= 0.0) {
256     for (i = 0, nz = 0; i < n; i++)
257       if (al[i] != 0.0) nz++;
258   } else {
259     for (i = 0, nz = 0; i < n; i++)
260       if (PetscAbsScalar(al[i]) > tol) nz++;
261   }
262   PetscCallMPI(MPIU_Allreduce(&nz, &gnz, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
263   if (gnz != N) {
264     PetscInt *nzr;
265     PetscCall(PetscMalloc1(nz, &nzr));
266     if (nz) {
267       if (tol < 0) {
268         for (i = 0, nz = 0; i < n; i++)
269           if (al[i] != 0.0) nzr[nz++] = i + st;
270       } else {
271         for (i = 0, nz = 0; i < n; i++)
272           if (PetscAbsScalar(al[i]) > tol) nzr[nz++] = i + st;
273       }
274     }
275     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nz, nzr, PETSC_OWN_POINTER, nonzero));
276   } else *nonzero = NULL;
277   if (!cols) { /* nonzero rows */
278     PetscCall(VecRestoreArrayRead(l, &al));
279   } else {
280     PetscCall(VecRestoreArrayRead(r, &al));
281   }
282   PetscCall(VecDestroy(&l));
283   PetscCall(VecDestroy(&r));
284   PetscFunctionReturn(PETSC_SUCCESS);
285 }
286 
287 /*@
288   MatFindNonzeroRows - Locate all rows that are not completely zero in the matrix
289 
290   Input Parameter:
291 . mat - the matrix
292 
293   Output Parameter:
294 . keptrows - the rows that are not completely zero
295 
296   Level: intermediate
297 
298   Note:
299   `keptrows` is set to `NULL` if all rows are nonzero.
300 
301   Developer Note:
302   If `keptrows` is not `NULL`, it must be sorted.
303 
304 .seealso: [](ch_matrices), `Mat`, `MatFindZeroRows()`
305  @*/
306 PetscErrorCode MatFindNonzeroRows(Mat mat, IS *keptrows)
307 {
308   PetscFunctionBegin;
309   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
310   PetscValidType(mat, 1);
311   PetscAssertPointer(keptrows, 2);
312   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
313   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
314   if (mat->ops->findnonzerorows) PetscUseTypeMethod(mat, findnonzerorows, keptrows);
315   else PetscCall(MatFindNonzeroRowsOrCols_Basic(mat, PETSC_FALSE, 0.0, keptrows));
316   if (keptrows && *keptrows) PetscCall(ISSetInfo(*keptrows, IS_SORTED, IS_GLOBAL, PETSC_FALSE, PETSC_TRUE));
317   PetscFunctionReturn(PETSC_SUCCESS);
318 }
319 
320 /*@
321   MatFindZeroRows - Locate all rows that are completely zero in the matrix
322 
323   Input Parameter:
324 . mat - the matrix
325 
326   Output Parameter:
327 . zerorows - the rows that are completely zero
328 
329   Level: intermediate
330 
331   Note:
332   `zerorows` is set to `NULL` if no rows are zero.
333 
334 .seealso: [](ch_matrices), `Mat`, `MatFindNonzeroRows()`
335  @*/
336 PetscErrorCode MatFindZeroRows(Mat mat, IS *zerorows)
337 {
338   IS       keptrows;
339   PetscInt m, n;
340 
341   PetscFunctionBegin;
342   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
343   PetscValidType(mat, 1);
344   PetscAssertPointer(zerorows, 2);
345   PetscCall(MatFindNonzeroRows(mat, &keptrows));
346   /* MatFindNonzeroRows sets keptrows to NULL if there are no zero rows.
347      In keeping with this convention, we set zerorows to NULL if there are no zero
348      rows. */
349   if (keptrows == NULL) {
350     *zerorows = NULL;
351   } else {
352     PetscCall(MatGetOwnershipRange(mat, &m, &n));
353     PetscCall(ISComplement(keptrows, m, n, zerorows));
354     PetscCall(ISDestroy(&keptrows));
355   }
356   PetscFunctionReturn(PETSC_SUCCESS);
357 }
358 
359 /*@
360   MatGetDiagonalBlock - Returns the part of the matrix associated with the on-process coupling
361 
362   Not Collective
363 
364   Input Parameter:
365 . A - the matrix
366 
367   Output Parameter:
368 . a - the diagonal part (which is a SEQUENTIAL matrix)
369 
370   Level: advanced
371 
372   Notes:
373   See `MatCreateAIJ()` for more information on the "diagonal part" of the matrix.
374 
375   Use caution, as the reference count on the returned matrix is not incremented and it is used as part of `A`'s normal operation.
376 
377 .seealso: [](ch_matrices), `Mat`, `MatCreateAIJ()`, `MATAIJ`, `MATBAIJ`, `MATSBAIJ`
378 @*/
379 PetscErrorCode MatGetDiagonalBlock(Mat A, Mat *a)
380 {
381   PetscFunctionBegin;
382   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
383   PetscValidType(A, 1);
384   PetscAssertPointer(a, 2);
385   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
386   if (A->ops->getdiagonalblock) PetscUseTypeMethod(A, getdiagonalblock, a);
387   else {
388     PetscMPIInt size;
389 
390     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
391     PetscCheck(size == 1, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for parallel matrix type %s", ((PetscObject)A)->type_name);
392     *a = A;
393   }
394   PetscFunctionReturn(PETSC_SUCCESS);
395 }
396 
397 /*@
398   MatGetTrace - Gets the trace of a matrix. The sum of the diagonal entries.
399 
400   Collective
401 
402   Input Parameter:
403 . mat - the matrix
404 
405   Output Parameter:
406 . trace - the sum of the diagonal entries
407 
408   Level: advanced
409 
410 .seealso: [](ch_matrices), `Mat`
411 @*/
412 PetscErrorCode MatGetTrace(Mat mat, PetscScalar *trace)
413 {
414   Vec diag;
415 
416   PetscFunctionBegin;
417   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
418   PetscAssertPointer(trace, 2);
419   PetscCall(MatCreateVecs(mat, &diag, NULL));
420   PetscCall(MatGetDiagonal(mat, diag));
421   PetscCall(VecSum(diag, trace));
422   PetscCall(VecDestroy(&diag));
423   PetscFunctionReturn(PETSC_SUCCESS);
424 }
425 
426 /*@
427   MatRealPart - Zeros out the imaginary part of the matrix
428 
429   Logically Collective
430 
431   Input Parameter:
432 . mat - the matrix
433 
434   Level: advanced
435 
436 .seealso: [](ch_matrices), `Mat`, `MatImaginaryPart()`
437 @*/
438 PetscErrorCode MatRealPart(Mat mat)
439 {
440   PetscFunctionBegin;
441   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
442   PetscValidType(mat, 1);
443   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
444   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
445   MatCheckPreallocated(mat, 1);
446   PetscUseTypeMethod(mat, realpart);
447   PetscFunctionReturn(PETSC_SUCCESS);
448 }
449 
450 /*@C
451   MatGetGhosts - Get the global indices of all ghost nodes defined by the sparse matrix
452 
453   Collective
454 
455   Input Parameter:
456 . mat - the matrix
457 
458   Output Parameters:
459 + nghosts - number of ghosts (for `MATBAIJ` and `MATSBAIJ` matrices there is one ghost for each matrix block)
460 - ghosts  - the global indices of the ghost points
461 
462   Level: advanced
463 
464   Note:
465   `nghosts` and `ghosts` are suitable to pass into `VecCreateGhost()` or `VecCreateGhostBlock()`
466 
467 .seealso: [](ch_matrices), `Mat`, `VecCreateGhost()`, `VecCreateGhostBlock()`
468 @*/
469 PetscErrorCode MatGetGhosts(Mat mat, PetscInt *nghosts, const PetscInt *ghosts[])
470 {
471   PetscFunctionBegin;
472   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
473   PetscValidType(mat, 1);
474   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
475   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
476   if (mat->ops->getghosts) PetscUseTypeMethod(mat, getghosts, nghosts, ghosts);
477   else {
478     if (nghosts) *nghosts = 0;
479     if (ghosts) *ghosts = NULL;
480   }
481   PetscFunctionReturn(PETSC_SUCCESS);
482 }
483 
484 /*@
485   MatImaginaryPart - Moves the imaginary part of the matrix to the real part and zeros the imaginary part
486 
487   Logically Collective
488 
489   Input Parameter:
490 . mat - the matrix
491 
492   Level: advanced
493 
494 .seealso: [](ch_matrices), `Mat`, `MatRealPart()`
495 @*/
496 PetscErrorCode MatImaginaryPart(Mat mat)
497 {
498   PetscFunctionBegin;
499   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
500   PetscValidType(mat, 1);
501   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
502   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
503   MatCheckPreallocated(mat, 1);
504   PetscUseTypeMethod(mat, imaginarypart);
505   PetscFunctionReturn(PETSC_SUCCESS);
506 }
507 
508 /*@
509   MatMissingDiagonal - Determine if sparse matrix is missing a diagonal entry (or block entry for `MATBAIJ` and `MATSBAIJ` matrices) in the nonzero structure
510 
511   Not Collective
512 
513   Input Parameter:
514 . mat - the matrix
515 
516   Output Parameters:
517 + missing - is any diagonal entry missing
518 - dd      - first diagonal entry that is missing (optional) on this process
519 
520   Level: advanced
521 
522   Note:
523   This does not return diagonal entries that are in the nonzero structure but happen to have a zero numerical value
524 
525 .seealso: [](ch_matrices), `Mat`
526 @*/
527 PetscErrorCode MatMissingDiagonal(Mat mat, PetscBool *missing, PetscInt *dd)
528 {
529   PetscFunctionBegin;
530   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
531   PetscValidType(mat, 1);
532   PetscAssertPointer(missing, 2);
533   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix %s", ((PetscObject)mat)->type_name);
534   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
535   PetscUseTypeMethod(mat, missingdiagonal, missing, dd);
536   PetscFunctionReturn(PETSC_SUCCESS);
537 }
538 
539 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
540 /*@C
541   MatGetRow - Gets a row of a matrix.  You MUST call `MatRestoreRow()`
542   for each row that you get to ensure that your application does
543   not bleed memory.
544 
545   Not Collective
546 
547   Input Parameters:
548 + mat - the matrix
549 - row - the row to get
550 
551   Output Parameters:
552 + ncols - if not `NULL`, the number of nonzeros in `row`
553 . cols  - if not `NULL`, the column numbers
554 - vals  - if not `NULL`, the numerical values
555 
556   Level: advanced
557 
558   Notes:
559   This routine is provided for people who need to have direct access
560   to the structure of a matrix.  We hope that we provide enough
561   high-level matrix routines that few users will need it.
562 
563   `MatGetRow()` always returns 0-based column indices, regardless of
564   whether the internal representation is 0-based (default) or 1-based.
565 
566   For better efficiency, set `cols` and/or `vals` to `NULL` if you do
567   not wish to extract these quantities.
568 
569   The user can only examine the values extracted with `MatGetRow()`;
570   the values CANNOT be altered.  To change the matrix entries, one
571   must use `MatSetValues()`.
572 
573   You can only have one call to `MatGetRow()` outstanding for a particular
574   matrix at a time, per processor. `MatGetRow()` can only obtain rows
575   associated with the given processor, it cannot get rows from the
576   other processors; for that we suggest using `MatCreateSubMatrices()`, then
577   `MatGetRow()` on the submatrix. The row index passed to `MatGetRow()`
578   is in the global number of rows.
579 
580   Use `MatGetRowIJ()` and `MatRestoreRowIJ()` to access all the local indices of the sparse matrix.
581 
582   Use `MatSeqAIJGetArray()` and similar functions to access the numerical values for certain matrix types directly.
583 
584   Fortran Note:
585 .vb
586   PetscInt, pointer :: cols(:)
587   PetscScalar, pointer :: vals(:)
588 .ve
589 
590 .seealso: [](ch_matrices), `Mat`, `MatRestoreRow()`, `MatSetValues()`, `MatGetValues()`, `MatCreateSubMatrices()`, `MatGetDiagonal()`, `MatGetRowIJ()`, `MatRestoreRowIJ()`
591 @*/
592 PetscErrorCode MatGetRow(Mat mat, PetscInt row, PetscInt *ncols, const PetscInt *cols[], const PetscScalar *vals[])
593 {
594   PetscInt incols;
595 
596   PetscFunctionBegin;
597   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
598   PetscValidType(mat, 1);
599   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
600   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
601   MatCheckPreallocated(mat, 1);
602   PetscCheck(row >= mat->rmap->rstart && row < mat->rmap->rend, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Only for local rows, %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ")", row, mat->rmap->rstart, mat->rmap->rend);
603   PetscCall(PetscLogEventBegin(MAT_GetRow, mat, 0, 0, 0));
604   PetscUseTypeMethod(mat, getrow, row, &incols, (PetscInt **)cols, (PetscScalar **)vals);
605   if (ncols) *ncols = incols;
606   PetscCall(PetscLogEventEnd(MAT_GetRow, mat, 0, 0, 0));
607   PetscFunctionReturn(PETSC_SUCCESS);
608 }
609 
610 /*@
611   MatConjugate - replaces the matrix values with their complex conjugates
612 
613   Logically Collective
614 
615   Input Parameter:
616 . mat - the matrix
617 
618   Level: advanced
619 
620 .seealso: [](ch_matrices), `Mat`, `MatRealPart()`, `MatImaginaryPart()`, `VecConjugate()`, `MatTranspose()`
621 @*/
622 PetscErrorCode MatConjugate(Mat mat)
623 {
624   PetscFunctionBegin;
625   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
626   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
627   if (PetscDefined(USE_COMPLEX) && mat->hermitian != PETSC_BOOL3_TRUE) {
628     PetscUseTypeMethod(mat, conjugate);
629     PetscCall(PetscObjectStateIncrease((PetscObject)mat));
630   }
631   PetscFunctionReturn(PETSC_SUCCESS);
632 }
633 
634 /*@C
635   MatRestoreRow - Frees any temporary space allocated by `MatGetRow()`.
636 
637   Not Collective
638 
639   Input Parameters:
640 + mat   - the matrix
641 . row   - the row to get
642 . ncols - the number of nonzeros
643 . cols  - the columns of the nonzeros
644 - vals  - if nonzero the column values
645 
646   Level: advanced
647 
648   Notes:
649   This routine should be called after you have finished examining the entries.
650 
651   This routine zeros out `ncols`, `cols`, and `vals`. This is to prevent accidental
652   us of the array after it has been restored. If you pass `NULL`, it will
653   not zero the pointers.  Use of `cols` or `vals` after `MatRestoreRow()` is invalid.
654 
655   Fortran Note:
656 .vb
657   PetscInt, pointer :: cols(:)
658   PetscScalar, pointer :: vals(:)
659 .ve
660 
661 .seealso: [](ch_matrices), `Mat`, `MatGetRow()`
662 @*/
663 PetscErrorCode MatRestoreRow(Mat mat, PetscInt row, PetscInt *ncols, const PetscInt *cols[], const PetscScalar *vals[])
664 {
665   PetscFunctionBegin;
666   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
667   if (ncols) PetscAssertPointer(ncols, 3);
668   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
669   PetscTryTypeMethod(mat, restorerow, row, ncols, (PetscInt **)cols, (PetscScalar **)vals);
670   if (ncols) *ncols = 0;
671   if (cols) *cols = NULL;
672   if (vals) *vals = NULL;
673   PetscFunctionReturn(PETSC_SUCCESS);
674 }
675 
676 /*@
677   MatGetRowUpperTriangular - Sets a flag to enable calls to `MatGetRow()` for matrix in `MATSBAIJ` format.
678   You should call `MatRestoreRowUpperTriangular()` after calling` MatGetRow()` and `MatRestoreRow()` to disable the flag.
679 
680   Not Collective
681 
682   Input Parameter:
683 . mat - the matrix
684 
685   Level: advanced
686 
687   Note:
688   The flag is to ensure that users are aware that `MatGetRow()` only provides the upper triangular part of the row for the matrices in `MATSBAIJ` format.
689 
690 .seealso: [](ch_matrices), `Mat`, `MATSBAIJ`, `MatRestoreRowUpperTriangular()`
691 @*/
692 PetscErrorCode MatGetRowUpperTriangular(Mat mat)
693 {
694   PetscFunctionBegin;
695   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
696   PetscValidType(mat, 1);
697   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
698   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
699   MatCheckPreallocated(mat, 1);
700   PetscTryTypeMethod(mat, getrowuppertriangular);
701   PetscFunctionReturn(PETSC_SUCCESS);
702 }
703 
704 /*@
705   MatRestoreRowUpperTriangular - Disable calls to `MatGetRow()` for matrix in `MATSBAIJ` format.
706 
707   Not Collective
708 
709   Input Parameter:
710 . mat - the matrix
711 
712   Level: advanced
713 
714   Note:
715   This routine should be called after you have finished calls to `MatGetRow()` and `MatRestoreRow()`.
716 
717 .seealso: [](ch_matrices), `Mat`, `MATSBAIJ`, `MatGetRowUpperTriangular()`
718 @*/
719 PetscErrorCode MatRestoreRowUpperTriangular(Mat mat)
720 {
721   PetscFunctionBegin;
722   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
723   PetscValidType(mat, 1);
724   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
725   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
726   MatCheckPreallocated(mat, 1);
727   PetscTryTypeMethod(mat, restorerowuppertriangular);
728   PetscFunctionReturn(PETSC_SUCCESS);
729 }
730 
731 /*@
732   MatSetOptionsPrefix - Sets the prefix used for searching for all
733   `Mat` options in the database.
734 
735   Logically Collective
736 
737   Input Parameters:
738 + A      - the matrix
739 - prefix - the prefix to prepend to all option names
740 
741   Level: advanced
742 
743   Notes:
744   A hyphen (-) must NOT be given at the beginning of the prefix name.
745   The first character of all runtime options is AUTOMATICALLY the hyphen.
746 
747   This is NOT used for options for the factorization of the matrix. Normally the
748   prefix is automatically passed in from the PC calling the factorization. To set
749   it directly use  `MatSetOptionsPrefixFactor()`
750 
751 .seealso: [](ch_matrices), `Mat`, `MatSetFromOptions()`, `MatSetOptionsPrefixFactor()`
752 @*/
753 PetscErrorCode MatSetOptionsPrefix(Mat A, const char prefix[])
754 {
755   PetscFunctionBegin;
756   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
757   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)A, prefix));
758   PetscTryMethod(A, "MatSetOptionsPrefix_C", (Mat, const char[]), (A, prefix));
759   PetscFunctionReturn(PETSC_SUCCESS);
760 }
761 
762 /*@
763   MatSetOptionsPrefixFactor - Sets the prefix used for searching for all matrix factor options in the database for
764   for matrices created with `MatGetFactor()`
765 
766   Logically Collective
767 
768   Input Parameters:
769 + A      - the matrix
770 - prefix - the prefix to prepend to all option names for the factored matrix
771 
772   Level: developer
773 
774   Notes:
775   A hyphen (-) must NOT be given at the beginning of the prefix name.
776   The first character of all runtime options is AUTOMATICALLY the hyphen.
777 
778   Normally the prefix is automatically passed in from the `PC` calling the factorization. To set
779   it directly when not using `KSP`/`PC` use  `MatSetOptionsPrefixFactor()`
780 
781 .seealso: [](ch_matrices), `Mat`,   [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSetFromOptions()`, `MatSetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`
782 @*/
783 PetscErrorCode MatSetOptionsPrefixFactor(Mat A, const char prefix[])
784 {
785   PetscFunctionBegin;
786   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
787   if (prefix) {
788     PetscAssertPointer(prefix, 2);
789     PetscCheck(prefix[0] != '-', PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
790     if (prefix != A->factorprefix) {
791       PetscCall(PetscFree(A->factorprefix));
792       PetscCall(PetscStrallocpy(prefix, &A->factorprefix));
793     }
794   } else PetscCall(PetscFree(A->factorprefix));
795   PetscFunctionReturn(PETSC_SUCCESS);
796 }
797 
798 /*@
799   MatAppendOptionsPrefixFactor - Appends to the prefix used for searching for all matrix factor options in the database for
800   for matrices created with `MatGetFactor()`
801 
802   Logically Collective
803 
804   Input Parameters:
805 + A      - the matrix
806 - prefix - the prefix to prepend to all option names for the factored matrix
807 
808   Level: developer
809 
810   Notes:
811   A hyphen (-) must NOT be given at the beginning of the prefix name.
812   The first character of all runtime options is AUTOMATICALLY the hyphen.
813 
814   Normally the prefix is automatically passed in from the `PC` calling the factorization. To set
815   it directly when not using `KSP`/`PC` use  `MatAppendOptionsPrefixFactor()`
816 
817 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `PetscOptionsCreate()`, `PetscOptionsDestroy()`, `PetscObjectSetOptionsPrefix()`, `PetscObjectPrependOptionsPrefix()`,
818           `PetscObjectGetOptionsPrefix()`, `TSAppendOptionsPrefix()`, `SNESAppendOptionsPrefix()`, `KSPAppendOptionsPrefix()`, `MatSetOptionsPrefixFactor()`,
819           `MatSetOptionsPrefix()`
820 @*/
821 PetscErrorCode MatAppendOptionsPrefixFactor(Mat A, const char prefix[])
822 {
823   size_t len1, len2, new_len;
824 
825   PetscFunctionBegin;
826   PetscValidHeader(A, 1);
827   if (!prefix) PetscFunctionReturn(PETSC_SUCCESS);
828   if (!A->factorprefix) {
829     PetscCall(MatSetOptionsPrefixFactor(A, prefix));
830     PetscFunctionReturn(PETSC_SUCCESS);
831   }
832   PetscCheck(prefix[0] != '-', PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
833 
834   PetscCall(PetscStrlen(A->factorprefix, &len1));
835   PetscCall(PetscStrlen(prefix, &len2));
836   new_len = len1 + len2 + 1;
837   PetscCall(PetscRealloc(new_len * sizeof(*A->factorprefix), &A->factorprefix));
838   PetscCall(PetscStrncpy(A->factorprefix + len1, prefix, len2 + 1));
839   PetscFunctionReturn(PETSC_SUCCESS);
840 }
841 
842 /*@
843   MatAppendOptionsPrefix - Appends to the prefix used for searching for all
844   matrix options in the database.
845 
846   Logically Collective
847 
848   Input Parameters:
849 + A      - the matrix
850 - prefix - the prefix to prepend to all option names
851 
852   Level: advanced
853 
854   Note:
855   A hyphen (-) must NOT be given at the beginning of the prefix name.
856   The first character of all runtime options is AUTOMATICALLY the hyphen.
857 
858 .seealso: [](ch_matrices), `Mat`, `MatGetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`, `MatSetOptionsPrefix()`
859 @*/
860 PetscErrorCode MatAppendOptionsPrefix(Mat A, const char prefix[])
861 {
862   PetscFunctionBegin;
863   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
864   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)A, prefix));
865   PetscTryMethod(A, "MatAppendOptionsPrefix_C", (Mat, const char[]), (A, prefix));
866   PetscFunctionReturn(PETSC_SUCCESS);
867 }
868 
869 /*@
870   MatGetOptionsPrefix - Gets the prefix used for searching for all
871   matrix options in the database.
872 
873   Not Collective
874 
875   Input Parameter:
876 . A - the matrix
877 
878   Output Parameter:
879 . prefix - pointer to the prefix string used
880 
881   Level: advanced
882 
883 .seealso: [](ch_matrices), `Mat`, `MatAppendOptionsPrefix()`, `MatSetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`, `MatSetOptionsPrefixFactor()`
884 @*/
885 PetscErrorCode MatGetOptionsPrefix(Mat A, const char *prefix[])
886 {
887   PetscFunctionBegin;
888   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
889   PetscAssertPointer(prefix, 2);
890   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)A, prefix));
891   PetscFunctionReturn(PETSC_SUCCESS);
892 }
893 
894 /*@
895   MatGetState - Gets the state of a `Mat`. Same value as returned by `PetscObjectStateGet()`
896 
897   Not Collective
898 
899   Input Parameter:
900 . A - the matrix
901 
902   Output Parameter:
903 . state - the object state
904 
905   Level: advanced
906 
907   Note:
908   Object state is an integer which gets increased every time
909   the object is changed. By saving and later querying the object state
910   one can determine whether information about the object is still current.
911 
912   See `MatGetNonzeroState()` to determine if the nonzero structure of the matrix has changed.
913 
914 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PetscObjectStateGet()`, `MatGetNonzeroState()`
915 @*/
916 PetscErrorCode MatGetState(Mat A, PetscObjectState *state)
917 {
918   PetscFunctionBegin;
919   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
920   PetscAssertPointer(state, 2);
921   PetscCall(PetscObjectStateGet((PetscObject)A, state));
922   PetscFunctionReturn(PETSC_SUCCESS);
923 }
924 
925 /*@
926   MatResetPreallocation - Reset matrix to use the original preallocation values provided by the user, for example with `MatXAIJSetPreallocation()`
927 
928   Collective
929 
930   Input Parameter:
931 . A - the matrix
932 
933   Level: beginner
934 
935   Notes:
936   After calling `MatAssemblyBegin()` and `MatAssemblyEnd()` with `MAT_FINAL_ASSEMBLY` the matrix data structures represent the nonzeros assigned to the
937   matrix. If that space is less than the preallocated space that extra preallocated space is no longer available to take on new values. `MatResetPreallocation()`
938   makes all of the preallocation space available
939 
940   Current values in the matrix are lost in this call
941 
942   Currently only supported for  `MATAIJ` matrices.
943 
944 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatXAIJSetPreallocation()`
945 @*/
946 PetscErrorCode MatResetPreallocation(Mat A)
947 {
948   PetscFunctionBegin;
949   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
950   PetscValidType(A, 1);
951   PetscUseMethod(A, "MatResetPreallocation_C", (Mat), (A));
952   PetscFunctionReturn(PETSC_SUCCESS);
953 }
954 
955 /*@
956   MatResetHash - Reset the matrix so that it will use a hash table for the next round of `MatSetValues()` and `MatAssemblyBegin()`/`MatAssemblyEnd()`.
957 
958   Collective
959 
960   Input Parameter:
961 . A - the matrix
962 
963   Level: intermediate
964 
965   Notes:
966   The matrix will again delete the hash table data structures after following calls to `MatAssemblyBegin()`/`MatAssemblyEnd()` with `MAT_FINAL_ASSEMBLY`.
967 
968   Currently only supported for `MATAIJ` matrices.
969 
970 .seealso: [](ch_matrices), `Mat`, `MatResetPreallocation()`
971 @*/
972 PetscErrorCode MatResetHash(Mat A)
973 {
974   PetscFunctionBegin;
975   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
976   PetscValidType(A, 1);
977   PetscCheck(A->insertmode == NOT_SET_VALUES, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot reset to hash state after setting some values but not yet calling MatAssemblyBegin()/MatAssemblyEnd()");
978   if (A->num_ass == 0) PetscFunctionReturn(PETSC_SUCCESS);
979   PetscUseMethod(A, "MatResetHash_C", (Mat), (A));
980   /* These flags are used to determine whether certain setups occur */
981   A->was_assembled = PETSC_FALSE;
982   A->assembled     = PETSC_FALSE;
983   /* Log that the state of this object has changed; this will help guarantee that preconditioners get re-setup */
984   PetscCall(PetscObjectStateIncrease((PetscObject)A));
985   PetscFunctionReturn(PETSC_SUCCESS);
986 }
987 
988 /*@
989   MatSetUp - Sets up the internal matrix data structures for later use by the matrix
990 
991   Collective
992 
993   Input Parameter:
994 . A - the matrix
995 
996   Level: advanced
997 
998   Notes:
999   If the user has not set preallocation for this matrix then an efficient algorithm will be used for the first round of
1000   setting values in the matrix.
1001 
1002   This routine is called internally by other `Mat` functions when needed so rarely needs to be called by users
1003 
1004 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatCreate()`, `MatDestroy()`, `MatXAIJSetPreallocation()`
1005 @*/
1006 PetscErrorCode MatSetUp(Mat A)
1007 {
1008   PetscFunctionBegin;
1009   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1010   if (!((PetscObject)A)->type_name) {
1011     PetscMPIInt size;
1012 
1013     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
1014     PetscCall(MatSetType(A, size == 1 ? MATSEQAIJ : MATMPIAIJ));
1015   }
1016   if (!A->preallocated) PetscTryTypeMethod(A, setup);
1017   PetscCall(PetscLayoutSetUp(A->rmap));
1018   PetscCall(PetscLayoutSetUp(A->cmap));
1019   A->preallocated = PETSC_TRUE;
1020   PetscFunctionReturn(PETSC_SUCCESS);
1021 }
1022 
1023 #if defined(PETSC_HAVE_SAWS)
1024   #include <petscviewersaws.h>
1025 #endif
1026 
1027 /*
1028    If threadsafety is on extraneous matrices may be printed
1029 
1030    This flag cannot be stored in the matrix because the original matrix in MatView() may assemble a new matrix which is passed into MatViewFromOptions()
1031 */
1032 #if !defined(PETSC_HAVE_THREADSAFETY)
1033 static PetscInt insidematview = 0;
1034 #endif
1035 
1036 /*@
1037   MatViewFromOptions - View properties of the matrix based on options set in the options database
1038 
1039   Collective
1040 
1041   Input Parameters:
1042 + A    - the matrix
1043 . obj  - optional additional object that provides the options prefix to use
1044 - name - command line option
1045 
1046   Options Database Key:
1047 . -mat_view [viewertype]:... - the viewer and its options
1048 
1049   Level: intermediate
1050 
1051   Note:
1052 .vb
1053     If no value is provided ascii:stdout is used
1054        ascii[:[filename][:[format][:append]]]    defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab,
1055                                                   for example ascii::ascii_info prints just the information about the object not all details
1056                                                   unless :append is given filename opens in write mode, overwriting what was already there
1057        binary[:[filename][:[format][:append]]]   defaults to the file binaryoutput
1058        draw[:drawtype[:filename]]                for example, draw:tikz, draw:tikz:figure.tex  or draw:x
1059        socket[:port]                             defaults to the standard output port
1060        saws[:communicatorname]                    publishes object to the Scientific Application Webserver (SAWs)
1061 .ve
1062 
1063 .seealso: [](ch_matrices), `Mat`, `MatView()`, `PetscObjectViewFromOptions()`, `MatCreate()`
1064 @*/
1065 PetscErrorCode MatViewFromOptions(Mat A, PetscObject obj, const char name[])
1066 {
1067   PetscFunctionBegin;
1068   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1069 #if !defined(PETSC_HAVE_THREADSAFETY)
1070   if (insidematview) PetscFunctionReturn(PETSC_SUCCESS);
1071 #endif
1072   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
1073   PetscFunctionReturn(PETSC_SUCCESS);
1074 }
1075 
1076 /*@
1077   MatView - display information about a matrix in a variety ways
1078 
1079   Collective on viewer
1080 
1081   Input Parameters:
1082 + mat    - the matrix
1083 - viewer - visualization context
1084 
1085   Options Database Keys:
1086 + -mat_view ::ascii_info           - Prints info on matrix at conclusion of `MatAssemblyEnd()`
1087 . -mat_view ::ascii_info_detail    - Prints more detailed info
1088 . -mat_view                        - Prints matrix in ASCII format
1089 . -mat_view ::ascii_matlab         - Prints matrix in MATLAB format
1090 . -mat_view draw                   - PetscDraws nonzero structure of matrix, using `MatView()` and `PetscDrawOpenX()`.
1091 . -display <name>                  - Sets display name (default is host)
1092 . -draw_pause <sec>                - Sets number of seconds to pause after display
1093 . -mat_view socket                 - Sends matrix to socket, can be accessed from MATLAB (see Users-Manual: ch_matlab for details)
1094 . -viewer_socket_machine <machine> - -
1095 . -viewer_socket_port <port>       - -
1096 . -mat_view binary                 - save matrix to file in binary format
1097 - -viewer_binary_filename <name>   - -
1098 
1099   Level: beginner
1100 
1101   Notes:
1102   The available visualization contexts include
1103 +    `PETSC_VIEWER_STDOUT_SELF`   - for sequential matrices
1104 .    `PETSC_VIEWER_STDOUT_WORLD`  - for parallel matrices created on `PETSC_COMM_WORLD`
1105 .    `PETSC_VIEWER_STDOUT_`(comm) - for matrices created on MPI communicator comm
1106 -     `PETSC_VIEWER_DRAW_WORLD`   - graphical display of nonzero structure
1107 
1108   The user can open alternative visualization contexts with
1109 +    `PetscViewerASCIIOpen()`  - Outputs matrix to a specified file
1110 .    `PetscViewerBinaryOpen()` - Outputs matrix in binary to a  specified file; corresponding input uses `MatLoad()`
1111 .    `PetscViewerDrawOpen()`   - Outputs nonzero matrix nonzero structure to an X window display
1112 -    `PetscViewerSocketOpen()` - Outputs matrix to Socket viewer, `PETSCVIEWERSOCKET`. Only the `MATSEQDENSE` and `MATAIJ` types support this viewer.
1113 
1114   The user can call `PetscViewerPushFormat()` to specify the output
1115   format of ASCII printed objects (when using `PETSC_VIEWER_STDOUT_SELF`,
1116   `PETSC_VIEWER_STDOUT_WORLD` and `PetscViewerASCIIOpen()`).  Available formats include
1117 +    `PETSC_VIEWER_DEFAULT`           - default, prints matrix contents
1118 .    `PETSC_VIEWER_ASCII_MATLAB`      - prints matrix contents in MATLAB format
1119 .    `PETSC_VIEWER_ASCII_DENSE`       - prints entire matrix including zeros
1120 .    `PETSC_VIEWER_ASCII_COMMON`      - prints matrix contents, using a sparse  format common among all matrix types
1121 .    `PETSC_VIEWER_ASCII_IMPL`        - prints matrix contents, using an implementation-specific format (which is in many cases the same as the default)
1122 .    `PETSC_VIEWER_ASCII_INFO`        - prints basic information about the matrix size and structure (not the matrix entries)
1123 -    `PETSC_VIEWER_ASCII_INFO_DETAIL` - prints more detailed information about the matrix nonzero structure (still not vector or matrix entries)
1124 
1125   The ASCII viewers are only recommended for small matrices on at most a moderate number of processes,
1126   the program will seemingly hang and take hours for larger matrices, for larger matrices one should use the binary format.
1127 
1128   In the debugger you can do "call MatView(mat,0)" to display the matrix. (The same holds for any PETSc object viewer).
1129 
1130   See the manual page for `MatLoad()` for the exact format of the binary file when the binary
1131   viewer is used.
1132 
1133   See share/petsc/matlab/PetscBinaryRead.m for a MATLAB code that can read in the binary file when the binary
1134   viewer is used and lib/petsc/bin/PetscBinaryIO.py for loading them into Python.
1135 
1136   One can use '-mat_view draw -draw_pause -1' to pause the graphical display of matrix nonzero structure,
1137   and then use the following mouse functions.
1138 .vb
1139   left mouse: zoom in
1140   middle mouse: zoom out
1141   right mouse: continue with the simulation
1142 .ve
1143 
1144 .seealso: [](ch_matrices), `Mat`, `PetscViewerPushFormat()`, `PetscViewerASCIIOpen()`, `PetscViewerDrawOpen()`, `PetscViewer`,
1145           `PetscViewerSocketOpen()`, `PetscViewerBinaryOpen()`, `MatLoad()`, `MatViewFromOptions()`
1146 @*/
1147 PetscErrorCode MatView(Mat mat, PetscViewer viewer)
1148 {
1149   PetscInt          rows, cols, rbs, cbs;
1150   PetscBool         isascii, isstring, issaws;
1151   PetscViewerFormat format;
1152   PetscMPIInt       size;
1153 
1154   PetscFunctionBegin;
1155   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1156   PetscValidType(mat, 1);
1157   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat), &viewer));
1158   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1159 
1160   PetscCall(PetscViewerGetFormat(viewer, &format));
1161   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
1162   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
1163 
1164 #if !defined(PETSC_HAVE_THREADSAFETY)
1165   insidematview++;
1166 #endif
1167   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
1168   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1169   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
1170   PetscCheck((isascii && (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL)) || !mat->factortype, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "No viewers for factored matrix except ASCII, info, or info_detail");
1171 
1172   PetscCall(PetscLogEventBegin(MAT_View, mat, viewer, 0, 0));
1173   if (isascii) {
1174     if (!mat->preallocated) {
1175       PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix has not been preallocated yet\n"));
1176 #if !defined(PETSC_HAVE_THREADSAFETY)
1177       insidematview--;
1178 #endif
1179       PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1180       PetscFunctionReturn(PETSC_SUCCESS);
1181     }
1182     if (!mat->assembled) {
1183       PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix has not been assembled yet\n"));
1184 #if !defined(PETSC_HAVE_THREADSAFETY)
1185       insidematview--;
1186 #endif
1187       PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1188       PetscFunctionReturn(PETSC_SUCCESS);
1189     }
1190     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)mat, viewer));
1191     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1192       MatNullSpace nullsp, transnullsp;
1193 
1194       PetscCall(PetscViewerASCIIPushTab(viewer));
1195       PetscCall(MatGetSize(mat, &rows, &cols));
1196       PetscCall(MatGetBlockSizes(mat, &rbs, &cbs));
1197       if (rbs != 1 || cbs != 1) {
1198         if (rbs != cbs) PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT ", rbs=%" PetscInt_FMT ", cbs=%" PetscInt_FMT "%s\n", rows, cols, rbs, cbs, mat->bsizes ? " variable blocks set" : ""));
1199         else PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT ", bs=%" PetscInt_FMT "%s\n", rows, cols, rbs, mat->bsizes ? " variable blocks set" : ""));
1200       } else PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", rows, cols));
1201       if (mat->factortype) {
1202         MatSolverType solver;
1203         PetscCall(MatFactorGetSolverType(mat, &solver));
1204         PetscCall(PetscViewerASCIIPrintf(viewer, "package used to perform factorization: %s\n", solver));
1205       }
1206       if (mat->ops->getinfo) {
1207         PetscBool is_constant_or_diagonal;
1208 
1209         // Don't print nonzero information for constant or diagonal matrices, it just adds noise to the output
1210         PetscCall(PetscObjectTypeCompareAny((PetscObject)mat, &is_constant_or_diagonal, MATCONSTANTDIAGONAL, MATDIAGONAL, ""));
1211         if (!is_constant_or_diagonal) {
1212           MatInfo info;
1213 
1214           PetscCall(MatGetInfo(mat, MAT_GLOBAL_SUM, &info));
1215           PetscCall(PetscViewerASCIIPrintf(viewer, "total: nonzeros=%.f, allocated nonzeros=%.f\n", info.nz_used, info.nz_allocated));
1216           if (!mat->factortype) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of mallocs used during MatSetValues calls=%" PetscInt_FMT "\n", (PetscInt)info.mallocs));
1217         }
1218       }
1219       PetscCall(MatGetNullSpace(mat, &nullsp));
1220       PetscCall(MatGetTransposeNullSpace(mat, &transnullsp));
1221       if (nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached null space\n"));
1222       if (transnullsp && transnullsp != nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached transposed null space\n"));
1223       PetscCall(MatGetNearNullSpace(mat, &nullsp));
1224       if (nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached near null space\n"));
1225       PetscCall(PetscViewerASCIIPushTab(viewer));
1226       PetscCall(MatProductView(mat, viewer));
1227       PetscCall(PetscViewerASCIIPopTab(viewer));
1228       if (mat->bsizes && format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1229         IS tmp;
1230 
1231         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), mat->nblocks, mat->bsizes, PETSC_USE_POINTER, &tmp));
1232         PetscCall(PetscObjectSetName((PetscObject)tmp, "Block Sizes"));
1233         PetscCall(PetscViewerASCIIPushTab(viewer));
1234         PetscCall(ISView(tmp, viewer));
1235         PetscCall(PetscViewerASCIIPopTab(viewer));
1236         PetscCall(ISDestroy(&tmp));
1237       }
1238     }
1239   } else if (issaws) {
1240 #if defined(PETSC_HAVE_SAWS)
1241     PetscMPIInt rank;
1242 
1243     PetscCall(PetscObjectName((PetscObject)mat));
1244     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1245     if (!((PetscObject)mat)->amsmem && rank == 0) PetscCall(PetscObjectViewSAWs((PetscObject)mat, viewer));
1246 #endif
1247   } else if (isstring) {
1248     const char *type;
1249     PetscCall(MatGetType(mat, &type));
1250     PetscCall(PetscViewerStringSPrintf(viewer, " MatType: %-7.7s", type));
1251     PetscTryTypeMethod(mat, view, viewer);
1252   }
1253   if ((format == PETSC_VIEWER_NATIVE || format == PETSC_VIEWER_LOAD_BALANCE) && mat->ops->viewnative) {
1254     PetscCall(PetscViewerASCIIPushTab(viewer));
1255     PetscUseTypeMethod(mat, viewnative, viewer);
1256     PetscCall(PetscViewerASCIIPopTab(viewer));
1257   } else if (mat->ops->view) {
1258     PetscCall(PetscViewerASCIIPushTab(viewer));
1259     PetscUseTypeMethod(mat, view, viewer);
1260     PetscCall(PetscViewerASCIIPopTab(viewer));
1261   }
1262   if (isascii) {
1263     PetscCall(PetscViewerGetFormat(viewer, &format));
1264     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscCall(PetscViewerASCIIPopTab(viewer));
1265   }
1266   PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1267 #if !defined(PETSC_HAVE_THREADSAFETY)
1268   insidematview--;
1269 #endif
1270   PetscFunctionReturn(PETSC_SUCCESS);
1271 }
1272 
1273 #if defined(PETSC_USE_DEBUG)
1274   #include <../src/sys/totalview/tv_data_display.h>
1275 PETSC_UNUSED static int TV_display_type(const struct _p_Mat *mat)
1276 {
1277   TV_add_row("Local rows", "int", &mat->rmap->n);
1278   TV_add_row("Local columns", "int", &mat->cmap->n);
1279   TV_add_row("Global rows", "int", &mat->rmap->N);
1280   TV_add_row("Global columns", "int", &mat->cmap->N);
1281   TV_add_row("Typename", TV_ascii_string_type, ((PetscObject)mat)->type_name);
1282   return TV_format_OK;
1283 }
1284 #endif
1285 
1286 /*@
1287   MatLoad - Loads a matrix that has been stored in binary/HDF5 format
1288   with `MatView()`.  The matrix format is determined from the options database.
1289   Generates a parallel MPI matrix if the communicator has more than one
1290   processor.  The default matrix type is `MATAIJ`.
1291 
1292   Collective
1293 
1294   Input Parameters:
1295 + mat    - the newly loaded matrix, this needs to have been created with `MatCreate()`
1296             or some related function before a call to `MatLoad()`
1297 - viewer - `PETSCVIEWERBINARY`/`PETSCVIEWERHDF5` file viewer
1298 
1299   Options Database Key:
1300 . -matload_block_size <bs> - set block size
1301 
1302   Level: beginner
1303 
1304   Notes:
1305   If the `Mat` type has not yet been given then `MATAIJ` is used, call `MatSetFromOptions()` on the
1306   `Mat` before calling this routine if you wish to set it from the options database.
1307 
1308   `MatLoad()` automatically loads into the options database any options
1309   given in the file filename.info where filename is the name of the file
1310   that was passed to the `PetscViewerBinaryOpen()`. The options in the info
1311   file will be ignored if you use the -viewer_binary_skip_info option.
1312 
1313   If the type or size of mat is not set before a call to `MatLoad()`, PETSc
1314   sets the default matrix type AIJ and sets the local and global sizes.
1315   If type and/or size is already set, then the same are used.
1316 
1317   In parallel, each processor can load a subset of rows (or the
1318   entire matrix).  This routine is especially useful when a large
1319   matrix is stored on disk and only part of it is desired on each
1320   processor.  For example, a parallel solver may access only some of
1321   the rows from each processor.  The algorithm used here reads
1322   relatively small blocks of data rather than reading the entire
1323   matrix and then subsetting it.
1324 
1325   Viewer's `PetscViewerType` must be either `PETSCVIEWERBINARY` or `PETSCVIEWERHDF5`.
1326   Such viewer can be created using `PetscViewerBinaryOpen()` or `PetscViewerHDF5Open()`,
1327   or the sequence like
1328 .vb
1329     `PetscViewer` v;
1330     `PetscViewerCreate`(`PETSC_COMM_WORLD`,&v);
1331     `PetscViewerSetType`(v,`PETSCVIEWERBINARY`);
1332     `PetscViewerSetFromOptions`(v);
1333     `PetscViewerFileSetMode`(v,`FILE_MODE_READ`);
1334     `PetscViewerFileSetName`(v,"datafile");
1335 .ve
1336   The optional `PetscViewerSetFromOptions()` call allows overriding `PetscViewerSetType()` using the option
1337 .vb
1338   -viewer_type {binary, hdf5}
1339 .ve
1340 
1341   See the example src/ksp/ksp/tutorials/ex27.c with the first approach,
1342   and src/mat/tutorials/ex10.c with the second approach.
1343 
1344   In case of `PETSCVIEWERBINARY`, a native PETSc binary format is used. Each of the blocks
1345   is read onto MPI rank 0 and then shipped to its destination MPI rank, one after another.
1346   Multiple objects, both matrices and vectors, can be stored within the same file.
1347   Their `PetscObject` name is ignored; they are loaded in the order of their storage.
1348 
1349   Most users should not need to know the details of the binary storage
1350   format, since `MatLoad()` and `MatView()` completely hide these details.
1351   But for anyone who is interested, the standard binary matrix storage
1352   format is
1353 
1354 .vb
1355     PetscInt    MAT_FILE_CLASSID
1356     PetscInt    number of rows
1357     PetscInt    number of columns
1358     PetscInt    total number of nonzeros
1359     PetscInt    *number nonzeros in each row
1360     PetscInt    *column indices of all nonzeros (starting index is zero)
1361     PetscScalar *values of all nonzeros
1362 .ve
1363   If PETSc was not configured with `--with-64-bit-indices` then only `MATMPIAIJ` matrices with more than `PETSC_INT_MAX` non-zeros can be
1364   stored or loaded (each MPI process part of the matrix must have less than `PETSC_INT_MAX` nonzeros). Since the total nonzero count in this
1365   case will not fit in a (32-bit) `PetscInt` the value `PETSC_INT_MAX` is used for the header entry `total number of nonzeros`.
1366 
1367   PETSc automatically does the byte swapping for
1368   machines that store the bytes reversed. Thus if you write your own binary
1369   read/write routines you have to swap the bytes; see `PetscBinaryRead()`
1370   and `PetscBinaryWrite()` to see how this may be done.
1371 
1372   In case of `PETSCVIEWERHDF5`, a parallel HDF5 reader is used.
1373   Each processor's chunk is loaded independently by its owning MPI process.
1374   Multiple objects, both matrices and vectors, can be stored within the same file.
1375   They are looked up by their PetscObject name.
1376 
1377   As the MATLAB MAT-File Version 7.3 format is also a HDF5 flavor, we decided to use
1378   by default the same structure and naming of the AIJ arrays and column count
1379   within the HDF5 file. This means that a MAT file saved with -v7.3 flag, e.g.
1380 .vb
1381   save example.mat A b -v7.3
1382 .ve
1383   can be directly read by this routine (see Reference 1 for details).
1384 
1385   Depending on your MATLAB version, this format might be a default,
1386   otherwise you can set it as default in Preferences.
1387 
1388   Unless -nocompression flag is used to save the file in MATLAB,
1389   PETSc must be configured with ZLIB package.
1390 
1391   See also examples src/mat/tutorials/ex10.c and src/ksp/ksp/tutorials/ex27.c
1392 
1393   This reader currently supports only real `MATSEQAIJ`, `MATMPIAIJ`, `MATSEQDENSE` and `MATMPIDENSE` matrices for `PETSCVIEWERHDF5`
1394 
1395   Corresponding `MatView()` is not yet implemented.
1396 
1397   The loaded matrix is actually a transpose of the original one in MATLAB,
1398   unless you push `PETSC_VIEWER_HDF5_MAT` format (see examples above).
1399   With this format, matrix is automatically transposed by PETSc,
1400   unless the matrix is marked as SPD or symmetric
1401   (see `MatSetOption()`, `MAT_SPD`, `MAT_SYMMETRIC`).
1402 
1403   See MATLAB Documentation on `save()`, <https://www.mathworks.com/help/matlab/ref/save.html#btox10b-1-version>
1404 
1405 .seealso: [](ch_matrices), `Mat`, `PetscViewerBinaryOpen()`, `PetscViewerSetType()`, `MatView()`, `VecLoad()`
1406  @*/
1407 PetscErrorCode MatLoad(Mat mat, PetscViewer viewer)
1408 {
1409   PetscBool flg;
1410 
1411   PetscFunctionBegin;
1412   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1413   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1414 
1415   if (!((PetscObject)mat)->type_name) PetscCall(MatSetType(mat, MATAIJ));
1416 
1417   flg = PETSC_FALSE;
1418   PetscCall(PetscOptionsGetBool(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matload_symmetric", &flg, NULL));
1419   if (flg) {
1420     PetscCall(MatSetOption(mat, MAT_SYMMETRIC, PETSC_TRUE));
1421     PetscCall(MatSetOption(mat, MAT_SYMMETRY_ETERNAL, PETSC_TRUE));
1422   }
1423   flg = PETSC_FALSE;
1424   PetscCall(PetscOptionsGetBool(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matload_spd", &flg, NULL));
1425   if (flg) PetscCall(MatSetOption(mat, MAT_SPD, PETSC_TRUE));
1426 
1427   PetscCall(PetscLogEventBegin(MAT_Load, mat, viewer, 0, 0));
1428   PetscUseTypeMethod(mat, load, viewer);
1429   PetscCall(PetscLogEventEnd(MAT_Load, mat, viewer, 0, 0));
1430   PetscFunctionReturn(PETSC_SUCCESS);
1431 }
1432 
1433 static PetscErrorCode MatDestroy_Redundant(Mat_Redundant **redundant)
1434 {
1435   Mat_Redundant *redund = *redundant;
1436 
1437   PetscFunctionBegin;
1438   if (redund) {
1439     if (redund->matseq) { /* via MatCreateSubMatrices()  */
1440       PetscCall(ISDestroy(&redund->isrow));
1441       PetscCall(ISDestroy(&redund->iscol));
1442       PetscCall(MatDestroySubMatrices(1, &redund->matseq));
1443     } else {
1444       PetscCall(PetscFree2(redund->send_rank, redund->recv_rank));
1445       PetscCall(PetscFree(redund->sbuf_j));
1446       PetscCall(PetscFree(redund->sbuf_a));
1447       for (PetscInt i = 0; i < redund->nrecvs; i++) {
1448         PetscCall(PetscFree(redund->rbuf_j[i]));
1449         PetscCall(PetscFree(redund->rbuf_a[i]));
1450       }
1451       PetscCall(PetscFree4(redund->sbuf_nz, redund->rbuf_nz, redund->rbuf_j, redund->rbuf_a));
1452     }
1453 
1454     if (redund->subcomm) PetscCall(PetscCommDestroy(&redund->subcomm));
1455     PetscCall(PetscFree(redund));
1456   }
1457   PetscFunctionReturn(PETSC_SUCCESS);
1458 }
1459 
1460 /*@
1461   MatDestroy - Frees space taken by a matrix.
1462 
1463   Collective
1464 
1465   Input Parameter:
1466 . A - the matrix
1467 
1468   Level: beginner
1469 
1470   Developer Note:
1471   Some special arrays of matrices are not destroyed in this routine but instead by the routines called by
1472   `MatDestroySubMatrices()`. Thus one must be sure that any changes here must also be made in those routines.
1473   `MatHeaderMerge()` and `MatHeaderReplace()` also manipulate the data in the `Mat` object and likely need changes
1474   if changes are needed here.
1475 
1476 .seealso: [](ch_matrices), `Mat`, `MatCreate()`
1477 @*/
1478 PetscErrorCode MatDestroy(Mat *A)
1479 {
1480   PetscFunctionBegin;
1481   if (!*A) PetscFunctionReturn(PETSC_SUCCESS);
1482   PetscValidHeaderSpecific(*A, MAT_CLASSID, 1);
1483   if (--((PetscObject)*A)->refct > 0) {
1484     *A = NULL;
1485     PetscFunctionReturn(PETSC_SUCCESS);
1486   }
1487 
1488   /* if memory was published with SAWs then destroy it */
1489   PetscCall(PetscObjectSAWsViewOff((PetscObject)*A));
1490   PetscTryTypeMethod(*A, destroy);
1491 
1492   PetscCall(PetscFree((*A)->factorprefix));
1493   PetscCall(PetscFree((*A)->defaultvectype));
1494   PetscCall(PetscFree((*A)->defaultrandtype));
1495   PetscCall(PetscFree((*A)->bsizes));
1496   PetscCall(PetscFree((*A)->solvertype));
1497   for (PetscInt i = 0; i < MAT_FACTOR_NUM_TYPES; i++) PetscCall(PetscFree((*A)->preferredordering[i]));
1498   if ((*A)->redundant && (*A)->redundant->matseq[0] == *A) (*A)->redundant->matseq[0] = NULL;
1499   PetscCall(MatDestroy_Redundant(&(*A)->redundant));
1500   PetscCall(MatProductClear(*A));
1501   PetscCall(MatNullSpaceDestroy(&(*A)->nullsp));
1502   PetscCall(MatNullSpaceDestroy(&(*A)->transnullsp));
1503   PetscCall(MatNullSpaceDestroy(&(*A)->nearnullsp));
1504   PetscCall(MatDestroy(&(*A)->schur));
1505   PetscCall(PetscLayoutDestroy(&(*A)->rmap));
1506   PetscCall(PetscLayoutDestroy(&(*A)->cmap));
1507   PetscCall(PetscHeaderDestroy(A));
1508   PetscFunctionReturn(PETSC_SUCCESS);
1509 }
1510 
1511 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1512 /*@
1513   MatSetValues - Inserts or adds a block of values into a matrix.
1514   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
1515   MUST be called after all calls to `MatSetValues()` have been completed.
1516 
1517   Not Collective
1518 
1519   Input Parameters:
1520 + mat  - the matrix
1521 . m    - the number of rows
1522 . idxm - the global indices of the rows
1523 . n    - the number of columns
1524 . idxn - the global indices of the columns
1525 . v    - a logically two-dimensional array of values
1526 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
1527 
1528   Level: beginner
1529 
1530   Notes:
1531   By default, the values, `v`, are stored in row-major order. See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
1532 
1533   Calls to `MatSetValues()` with the `INSERT_VALUES` and `ADD_VALUES`
1534   options cannot be mixed without intervening calls to the assembly
1535   routines.
1536 
1537   `MatSetValues()` uses 0-based row and column numbers in Fortran
1538   as well as in C.
1539 
1540   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
1541   simply ignored. This allows easily inserting element stiffness matrices
1542   with homogeneous Dirichlet boundary conditions that you don't want represented
1543   in the matrix.
1544 
1545   Efficiency Alert:
1546   The routine `MatSetValuesBlocked()` may offer much better efficiency
1547   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1548 
1549   Fortran Notes:
1550   If any of `idxm`, `idxn`, and `v` are scalars pass them using, for example,
1551 .vb
1552   call MatSetValues(mat, one, [idxm], one, [idxn], [v], INSERT_VALUES, ierr)
1553 .ve
1554 
1555   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
1556 
1557   Developer Note:
1558   This is labeled with C so does not automatically generate Fortran stubs and interfaces
1559   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
1560 
1561 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1562           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1563 @*/
1564 PetscErrorCode MatSetValues(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar v[], InsertMode addv)
1565 {
1566   PetscFunctionBeginHot;
1567   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1568   PetscValidType(mat, 1);
1569   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1570   PetscAssertPointer(idxm, 3);
1571   PetscAssertPointer(idxn, 5);
1572   MatCheckPreallocated(mat, 1);
1573 
1574   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
1575   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
1576 
1577   if (PetscDefined(USE_DEBUG)) {
1578     PetscInt i, j;
1579 
1580     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1581     if (v) {
1582       for (i = 0; i < m; i++) {
1583         for (j = 0; j < n; j++) {
1584           if (mat->erroriffailure && PetscIsInfOrNanScalar(v[i * n + j]))
1585 #if defined(PETSC_USE_COMPLEX)
1586             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Inserting %g+i%g at matrix entry (%" PetscInt_FMT ",%" PetscInt_FMT ")", (double)PetscRealPart(v[i * n + j]), (double)PetscImaginaryPart(v[i * n + j]), idxm[i], idxn[j]);
1587 #else
1588             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Inserting %g at matrix entry (%" PetscInt_FMT ",%" PetscInt_FMT ")", (double)v[i * n + j], idxm[i], idxn[j]);
1589 #endif
1590         }
1591       }
1592     }
1593     for (i = 0; i < m; i++) PetscCheck(idxm[i] < mat->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot insert in row %" PetscInt_FMT ", maximum is %" PetscInt_FMT, idxm[i], mat->rmap->N - 1);
1594     for (i = 0; i < n; i++) PetscCheck(idxn[i] < mat->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot insert in column %" PetscInt_FMT ", maximum is %" PetscInt_FMT, idxn[i], mat->cmap->N - 1);
1595   }
1596 
1597   if (mat->assembled) {
1598     mat->was_assembled = PETSC_TRUE;
1599     mat->assembled     = PETSC_FALSE;
1600   }
1601   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
1602   PetscUseTypeMethod(mat, setvalues, m, idxm, n, idxn, v, addv);
1603   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
1604   PetscFunctionReturn(PETSC_SUCCESS);
1605 }
1606 
1607 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1608 /*@
1609   MatSetValuesIS - Inserts or adds a block of values into a matrix using an `IS` to indicate the rows and columns
1610   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
1611   MUST be called after all calls to `MatSetValues()` have been completed.
1612 
1613   Not Collective
1614 
1615   Input Parameters:
1616 + mat  - the matrix
1617 . ism  - the rows to provide
1618 . isn  - the columns to provide
1619 . v    - a logically two-dimensional array of values
1620 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
1621 
1622   Level: beginner
1623 
1624   Notes:
1625   By default, the values, `v`, are stored in row-major order. See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
1626 
1627   Calls to `MatSetValues()` with the `INSERT_VALUES` and `ADD_VALUES`
1628   options cannot be mixed without intervening calls to the assembly
1629   routines.
1630 
1631   `MatSetValues()` uses 0-based row and column numbers in Fortran
1632   as well as in C.
1633 
1634   Negative indices may be passed in `ism` and `isn`, these rows and columns are
1635   simply ignored. This allows easily inserting element stiffness matrices
1636   with homogeneous Dirichlet boundary conditions that you don't want represented
1637   in the matrix.
1638 
1639   Efficiency Alert:
1640   The routine `MatSetValuesBlocked()` may offer much better efficiency
1641   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1642 
1643   This is currently not optimized for any particular `ISType`
1644 
1645 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatSetValues()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1646           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1647 @*/
1648 PetscErrorCode MatSetValuesIS(Mat mat, IS ism, IS isn, const PetscScalar v[], InsertMode addv)
1649 {
1650   PetscInt        m, n;
1651   const PetscInt *rows, *cols;
1652 
1653   PetscFunctionBeginHot;
1654   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1655   PetscCall(ISGetIndices(ism, &rows));
1656   PetscCall(ISGetIndices(isn, &cols));
1657   PetscCall(ISGetLocalSize(ism, &m));
1658   PetscCall(ISGetLocalSize(isn, &n));
1659   PetscCall(MatSetValues(mat, m, rows, n, cols, v, addv));
1660   PetscCall(ISRestoreIndices(ism, &rows));
1661   PetscCall(ISRestoreIndices(isn, &cols));
1662   PetscFunctionReturn(PETSC_SUCCESS);
1663 }
1664 
1665 /*@
1666   MatSetValuesRowLocal - Inserts a row (block row for `MATBAIJ` matrices) of nonzero
1667   values into a matrix
1668 
1669   Not Collective
1670 
1671   Input Parameters:
1672 + mat - the matrix
1673 . row - the (block) row to set
1674 - v   - a logically two-dimensional array of values
1675 
1676   Level: intermediate
1677 
1678   Notes:
1679   The values, `v`, are column-oriented (for the block version) and sorted
1680 
1681   All the nonzero values in `row` must be provided
1682 
1683   The matrix must have previously had its column indices set, likely by having been assembled.
1684 
1685   `row` must belong to this MPI process
1686 
1687 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1688           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`, `MatSetValues()`, `MatSetValuesRow()`, `MatSetLocalToGlobalMapping()`
1689 @*/
1690 PetscErrorCode MatSetValuesRowLocal(Mat mat, PetscInt row, const PetscScalar v[])
1691 {
1692   PetscInt globalrow;
1693 
1694   PetscFunctionBegin;
1695   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1696   PetscValidType(mat, 1);
1697   PetscAssertPointer(v, 3);
1698   PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, 1, &row, &globalrow));
1699   PetscCall(MatSetValuesRow(mat, globalrow, v));
1700   PetscFunctionReturn(PETSC_SUCCESS);
1701 }
1702 
1703 /*@
1704   MatSetValuesRow - Inserts a row (block row for `MATBAIJ` matrices) of nonzero
1705   values into a matrix
1706 
1707   Not Collective
1708 
1709   Input Parameters:
1710 + mat - the matrix
1711 . row - the (block) row to set
1712 - v   - a logically two-dimensional (column major) array of values for  block matrices with blocksize larger than one, otherwise a one dimensional array of values
1713 
1714   Level: advanced
1715 
1716   Notes:
1717   The values, `v`, are column-oriented for the block version.
1718 
1719   All the nonzeros in `row` must be provided
1720 
1721   THE MATRIX MUST HAVE PREVIOUSLY HAD ITS COLUMN INDICES SET. IT IS RARE THAT THIS ROUTINE IS USED, usually `MatSetValues()` is used.
1722 
1723   `row` must belong to this process
1724 
1725 .seealso: [](ch_matrices), `Mat`, `MatSetValues()`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1726           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1727 @*/
1728 PetscErrorCode MatSetValuesRow(Mat mat, PetscInt row, const PetscScalar v[])
1729 {
1730   PetscFunctionBeginHot;
1731   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1732   PetscValidType(mat, 1);
1733   MatCheckPreallocated(mat, 1);
1734   PetscAssertPointer(v, 3);
1735   PetscCheck(mat->insertmode != ADD_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add and insert values");
1736   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1737   mat->insertmode = INSERT_VALUES;
1738 
1739   if (mat->assembled) {
1740     mat->was_assembled = PETSC_TRUE;
1741     mat->assembled     = PETSC_FALSE;
1742   }
1743   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
1744   PetscUseTypeMethod(mat, setvaluesrow, row, v);
1745   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
1746   PetscFunctionReturn(PETSC_SUCCESS);
1747 }
1748 
1749 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1750 /*@
1751   MatSetValuesStencil - Inserts or adds a block of values into a matrix.
1752   Using structured grid indexing
1753 
1754   Not Collective
1755 
1756   Input Parameters:
1757 + mat  - the matrix
1758 . m    - number of rows being entered
1759 . idxm - grid coordinates (and component number when dof > 1) for matrix rows being entered
1760 . n    - number of columns being entered
1761 . idxn - grid coordinates (and component number when dof > 1) for matrix columns being entered
1762 . v    - a logically two-dimensional array of values
1763 - addv - either `ADD_VALUES` to add to existing entries at that location or `INSERT_VALUES` to replace existing entries with new values
1764 
1765   Level: beginner
1766 
1767   Notes:
1768   By default the values, `v`, are row-oriented.  See `MatSetOption()` for other options.
1769 
1770   Calls to `MatSetValuesStencil()` with the `INSERT_VALUES` and `ADD_VALUES`
1771   options cannot be mixed without intervening calls to the assembly
1772   routines.
1773 
1774   The grid coordinates are across the entire grid, not just the local portion
1775 
1776   `MatSetValuesStencil()` uses 0-based row and column numbers in Fortran
1777   as well as in C.
1778 
1779   For setting/accessing vector values via array coordinates you can use the `DMDAVecGetArray()` routine
1780 
1781   In order to use this routine you must either obtain the matrix with `DMCreateMatrix()`
1782   or call `MatSetLocalToGlobalMapping()` and `MatSetStencil()` first.
1783 
1784   The columns and rows in the stencil passed in MUST be contained within the
1785   ghost region of the given process as set with DMDACreateXXX() or `MatSetStencil()`. For example,
1786   if you create a `DMDA` with an overlap of one grid level and on a particular process its first
1787   local nonghost x logical coordinate is 6 (so its first ghost x logical coordinate is 5) the
1788   first i index you can use in your column and row indices in `MatSetStencil()` is 5.
1789 
1790   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
1791   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
1792   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
1793   `DM_BOUNDARY_PERIODIC` boundary type.
1794 
1795   For indices that don't mean anything for your case (like the k index when working in 2d) or the c index when you have
1796   a single value per point) you can skip filling those indices.
1797 
1798   Inspired by the structured grid interface to the HYPRE package
1799   (https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods)
1800 
1801   Efficiency Alert:
1802   The routine `MatSetValuesBlockedStencil()` may offer much better efficiency
1803   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1804 
1805 .seealso: [](ch_matrices), `Mat`, `DMDA`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1806           `MatSetValues()`, `MatSetValuesBlockedStencil()`, `MatSetStencil()`, `DMCreateMatrix()`, `DMDAVecGetArray()`, `MatStencil`
1807 @*/
1808 PetscErrorCode MatSetValuesStencil(Mat mat, PetscInt m, const MatStencil idxm[], PetscInt n, const MatStencil idxn[], const PetscScalar v[], InsertMode addv)
1809 {
1810   PetscInt  buf[8192], *bufm = NULL, *bufn = NULL, *jdxm, *jdxn;
1811   PetscInt  j, i, dim = mat->stencil.dim, *dims = mat->stencil.dims + 1, tmp;
1812   PetscInt *starts = mat->stencil.starts, *dxm = (PetscInt *)idxm, *dxn = (PetscInt *)idxn, sdim = dim - (1 - (PetscInt)mat->stencil.noc);
1813 
1814   PetscFunctionBegin;
1815   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1816   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1817   PetscValidType(mat, 1);
1818   PetscAssertPointer(idxm, 3);
1819   PetscAssertPointer(idxn, 5);
1820 
1821   if ((m + n) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
1822     jdxm = buf;
1823     jdxn = buf + m;
1824   } else {
1825     PetscCall(PetscMalloc2(m, &bufm, n, &bufn));
1826     jdxm = bufm;
1827     jdxn = bufn;
1828   }
1829   for (i = 0; i < m; i++) {
1830     for (j = 0; j < 3 - sdim; j++) dxm++;
1831     tmp = *dxm++ - starts[0];
1832     for (j = 0; j < dim - 1; j++) {
1833       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1834       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
1835     }
1836     if (mat->stencil.noc) dxm++;
1837     jdxm[i] = tmp;
1838   }
1839   for (i = 0; i < n; i++) {
1840     for (j = 0; j < 3 - sdim; j++) dxn++;
1841     tmp = *dxn++ - starts[0];
1842     for (j = 0; j < dim - 1; j++) {
1843       if ((*dxn++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1844       else tmp = tmp * dims[j] + *(dxn - 1) - starts[j + 1];
1845     }
1846     if (mat->stencil.noc) dxn++;
1847     jdxn[i] = tmp;
1848   }
1849   PetscCall(MatSetValuesLocal(mat, m, jdxm, n, jdxn, v, addv));
1850   PetscCall(PetscFree2(bufm, bufn));
1851   PetscFunctionReturn(PETSC_SUCCESS);
1852 }
1853 
1854 /*@
1855   MatSetValuesBlockedStencil - Inserts or adds a block of values into a matrix.
1856   Using structured grid indexing
1857 
1858   Not Collective
1859 
1860   Input Parameters:
1861 + mat  - the matrix
1862 . m    - number of rows being entered
1863 . idxm - grid coordinates for matrix rows being entered
1864 . n    - number of columns being entered
1865 . idxn - grid coordinates for matrix columns being entered
1866 . v    - a logically two-dimensional array of values
1867 - addv - either `ADD_VALUES` to add to existing entries or `INSERT_VALUES` to replace existing entries with new values
1868 
1869   Level: beginner
1870 
1871   Notes:
1872   By default the values, `v`, are row-oriented and unsorted.
1873   See `MatSetOption()` for other options.
1874 
1875   Calls to `MatSetValuesBlockedStencil()` with the `INSERT_VALUES` and `ADD_VALUES`
1876   options cannot be mixed without intervening calls to the assembly
1877   routines.
1878 
1879   The grid coordinates are across the entire grid, not just the local portion
1880 
1881   `MatSetValuesBlockedStencil()` uses 0-based row and column numbers in Fortran
1882   as well as in C.
1883 
1884   For setting/accessing vector values via array coordinates you can use the `DMDAVecGetArray()` routine
1885 
1886   In order to use this routine you must either obtain the matrix with `DMCreateMatrix()`
1887   or call `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()` and `MatSetStencil()` first.
1888 
1889   The columns and rows in the stencil passed in MUST be contained within the
1890   ghost region of the given process as set with DMDACreateXXX() or `MatSetStencil()`. For example,
1891   if you create a `DMDA` with an overlap of one grid level and on a particular process its first
1892   local nonghost x logical coordinate is 6 (so its first ghost x logical coordinate is 5) the
1893   first i index you can use in your column and row indices in `MatSetStencil()` is 5.
1894 
1895   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
1896   simply ignored. This allows easily inserting element stiffness matrices
1897   with homogeneous Dirichlet boundary conditions that you don't want represented
1898   in the matrix.
1899 
1900   Inspired by the structured grid interface to the HYPRE package
1901   (https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods)
1902 
1903   Fortran Note:
1904   `idxm` and `idxn` should be declared as
1905 .vb
1906     MatStencil idxm(4,m),idxn(4,n)
1907 .ve
1908   and the values inserted using
1909 .vb
1910     idxm(MatStencil_i,1) = i
1911     idxm(MatStencil_j,1) = j
1912     idxm(MatStencil_k,1) = k
1913    etc
1914 .ve
1915 
1916 .seealso: [](ch_matrices), `Mat`, `DMDA`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1917           `MatSetValues()`, `MatSetValuesStencil()`, `MatSetStencil()`, `DMCreateMatrix()`, `DMDAVecGetArray()`, `MatStencil`,
1918           `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()`
1919 @*/
1920 PetscErrorCode MatSetValuesBlockedStencil(Mat mat, PetscInt m, const MatStencil idxm[], PetscInt n, const MatStencil idxn[], const PetscScalar v[], InsertMode addv)
1921 {
1922   PetscInt  buf[8192], *bufm = NULL, *bufn = NULL, *jdxm, *jdxn;
1923   PetscInt  j, i, dim = mat->stencil.dim, *dims = mat->stencil.dims + 1, tmp;
1924   PetscInt *starts = mat->stencil.starts, *dxm = (PetscInt *)idxm, *dxn = (PetscInt *)idxn, sdim = dim - (1 - (PetscInt)mat->stencil.noc);
1925 
1926   PetscFunctionBegin;
1927   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1928   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1929   PetscValidType(mat, 1);
1930   PetscAssertPointer(idxm, 3);
1931   PetscAssertPointer(idxn, 5);
1932   PetscAssertPointer(v, 6);
1933 
1934   if ((m + n) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
1935     jdxm = buf;
1936     jdxn = buf + m;
1937   } else {
1938     PetscCall(PetscMalloc2(m, &bufm, n, &bufn));
1939     jdxm = bufm;
1940     jdxn = bufn;
1941   }
1942   for (i = 0; i < m; i++) {
1943     for (j = 0; j < 3 - sdim; j++) dxm++;
1944     tmp = *dxm++ - starts[0];
1945     for (j = 0; j < sdim - 1; j++) {
1946       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1947       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
1948     }
1949     dxm++;
1950     jdxm[i] = tmp;
1951   }
1952   for (i = 0; i < n; i++) {
1953     for (j = 0; j < 3 - sdim; j++) dxn++;
1954     tmp = *dxn++ - starts[0];
1955     for (j = 0; j < sdim - 1; j++) {
1956       if ((*dxn++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1957       else tmp = tmp * dims[j] + *(dxn - 1) - starts[j + 1];
1958     }
1959     dxn++;
1960     jdxn[i] = tmp;
1961   }
1962   PetscCall(MatSetValuesBlockedLocal(mat, m, jdxm, n, jdxn, v, addv));
1963   PetscCall(PetscFree2(bufm, bufn));
1964   PetscFunctionReturn(PETSC_SUCCESS);
1965 }
1966 
1967 /*@
1968   MatSetStencil - Sets the grid information for setting values into a matrix via
1969   `MatSetValuesStencil()`
1970 
1971   Not Collective
1972 
1973   Input Parameters:
1974 + mat    - the matrix
1975 . dim    - dimension of the grid 1, 2, or 3
1976 . dims   - number of grid points in x, y, and z direction, including ghost points on your processor
1977 . starts - starting point of ghost nodes on your processor in x, y, and z direction
1978 - dof    - number of degrees of freedom per node
1979 
1980   Level: beginner
1981 
1982   Notes:
1983   Inspired by the structured grid interface to the HYPRE package
1984   (www.llnl.gov/CASC/hyper)
1985 
1986   For matrices generated with `DMCreateMatrix()` this routine is automatically called and so not needed by the
1987   user.
1988 
1989 .seealso: [](ch_matrices), `Mat`, `MatStencil`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1990           `MatSetValues()`, `MatSetValuesBlockedStencil()`, `MatSetValuesStencil()`
1991 @*/
1992 PetscErrorCode MatSetStencil(Mat mat, PetscInt dim, const PetscInt dims[], const PetscInt starts[], PetscInt dof)
1993 {
1994   PetscFunctionBegin;
1995   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1996   PetscAssertPointer(dims, 3);
1997   PetscAssertPointer(starts, 4);
1998 
1999   mat->stencil.dim = dim + (dof > 1);
2000   for (PetscInt i = 0; i < dim; i++) {
2001     mat->stencil.dims[i]   = dims[dim - i - 1]; /* copy the values in backwards */
2002     mat->stencil.starts[i] = starts[dim - i - 1];
2003   }
2004   mat->stencil.dims[dim]   = dof;
2005   mat->stencil.starts[dim] = 0;
2006   mat->stencil.noc         = (PetscBool)(dof == 1);
2007   PetscFunctionReturn(PETSC_SUCCESS);
2008 }
2009 
2010 /*@
2011   MatSetValuesBlocked - Inserts or adds a block of values into a matrix.
2012 
2013   Not Collective
2014 
2015   Input Parameters:
2016 + mat  - the matrix
2017 . m    - the number of block rows
2018 . idxm - the global block indices
2019 . n    - the number of block columns
2020 . idxn - the global block indices
2021 . v    - a logically two-dimensional array of values
2022 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` replaces existing entries with new values
2023 
2024   Level: intermediate
2025 
2026   Notes:
2027   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call
2028   MatXXXXSetPreallocation() or `MatSetUp()` before using this routine.
2029 
2030   The `m` and `n` count the NUMBER of blocks in the row direction and column direction,
2031   NOT the total number of rows/columns; for example, if the block size is 2 and
2032   you are passing in values for rows 2,3,4,5  then `m` would be 2 (not 4).
2033   The values in `idxm` would be 1 2; that is the first index for each block divided by
2034   the block size.
2035 
2036   You must call `MatSetBlockSize()` when constructing this matrix (before
2037   preallocating it).
2038 
2039   By default, the values, `v`, are stored in row-major order. See `MAT_ROW_ORIENTED` in `MatSetOption()` for how to use column-major order.
2040 
2041   Calls to `MatSetValuesBlocked()` with the `INSERT_VALUES` and `ADD_VALUES`
2042   options cannot be mixed without intervening calls to the assembly
2043   routines.
2044 
2045   `MatSetValuesBlocked()` uses 0-based row and column numbers in Fortran
2046   as well as in C.
2047 
2048   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
2049   simply ignored. This allows easily inserting element stiffness matrices
2050   with homogeneous Dirichlet boundary conditions that you don't want represented
2051   in the matrix.
2052 
2053   Each time an entry is set within a sparse matrix via `MatSetValues()`,
2054   internal searching must be done to determine where to place the
2055   data in the matrix storage space.  By instead inserting blocks of
2056   entries via `MatSetValuesBlocked()`, the overhead of matrix assembly is
2057   reduced.
2058 
2059   Example:
2060 .vb
2061    Suppose m=n=2 and block size(bs) = 2 The array is
2062 
2063    1  2  | 3  4
2064    5  6  | 7  8
2065    - - - | - - -
2066    9  10 | 11 12
2067    13 14 | 15 16
2068 
2069    v[] should be passed in like
2070    v[] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
2071 
2072   If you are not using row-oriented storage of v (that is you called MatSetOption(mat,MAT_ROW_ORIENTED,PETSC_FALSE)) then
2073    v[] = [1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16]
2074 .ve
2075 
2076   Fortran Notes:
2077   If any of `idmx`, `idxn`, and `v` are scalars pass them using, for example,
2078 .vb
2079   call MatSetValuesBlocked(mat, one, [idxm], one, [idxn], [v], INSERT_VALUES, ierr)
2080 .ve
2081 
2082   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2083 
2084 .seealso: [](ch_matrices), `Mat`, `MatSetBlockSize()`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetValuesBlockedLocal()`
2085 @*/
2086 PetscErrorCode MatSetValuesBlocked(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar v[], InsertMode addv)
2087 {
2088   PetscFunctionBeginHot;
2089   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2090   PetscValidType(mat, 1);
2091   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2092   PetscAssertPointer(idxm, 3);
2093   PetscAssertPointer(idxn, 5);
2094   MatCheckPreallocated(mat, 1);
2095   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2096   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2097   if (PetscDefined(USE_DEBUG)) {
2098     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2099     PetscCheck(mat->ops->setvaluesblocked || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2100   }
2101   if (PetscDefined(USE_DEBUG)) {
2102     PetscInt rbs, cbs, M, N, i;
2103     PetscCall(MatGetBlockSizes(mat, &rbs, &cbs));
2104     PetscCall(MatGetSize(mat, &M, &N));
2105     for (i = 0; i < m; i++) PetscCheck(idxm[i] * rbs < M, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row block %" PetscInt_FMT " contains an index %" PetscInt_FMT "*%" PetscInt_FMT " greater than row length %" PetscInt_FMT, i, idxm[i], rbs, M);
2106     for (i = 0; i < n; i++)
2107       PetscCheck(idxn[i] * cbs < N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column block %" PetscInt_FMT " contains an index %" PetscInt_FMT "*%" PetscInt_FMT " greater than column length %" PetscInt_FMT, i, idxn[i], cbs, N);
2108   }
2109   if (mat->assembled) {
2110     mat->was_assembled = PETSC_TRUE;
2111     mat->assembled     = PETSC_FALSE;
2112   }
2113   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2114   if (mat->ops->setvaluesblocked) {
2115     PetscUseTypeMethod(mat, setvaluesblocked, m, idxm, n, idxn, v, addv);
2116   } else {
2117     PetscInt buf[8192], *bufr = NULL, *bufc = NULL, *iidxm, *iidxn;
2118     PetscInt i, j, bs, cbs;
2119 
2120     PetscCall(MatGetBlockSizes(mat, &bs, &cbs));
2121     if ((m * bs + n * cbs) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2122       iidxm = buf;
2123       iidxn = buf + m * bs;
2124     } else {
2125       PetscCall(PetscMalloc2(m * bs, &bufr, n * cbs, &bufc));
2126       iidxm = bufr;
2127       iidxn = bufc;
2128     }
2129     for (i = 0; i < m; i++) {
2130       for (j = 0; j < bs; j++) iidxm[i * bs + j] = bs * idxm[i] + j;
2131     }
2132     if (m != n || bs != cbs || idxm != idxn) {
2133       for (i = 0; i < n; i++) {
2134         for (j = 0; j < cbs; j++) iidxn[i * cbs + j] = cbs * idxn[i] + j;
2135       }
2136     } else iidxn = iidxm;
2137     PetscCall(MatSetValues(mat, m * bs, iidxm, n * cbs, iidxn, v, addv));
2138     PetscCall(PetscFree2(bufr, bufc));
2139   }
2140   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2141   PetscFunctionReturn(PETSC_SUCCESS);
2142 }
2143 
2144 /*@
2145   MatGetValues - Gets a block of local values from a matrix.
2146 
2147   Not Collective; can only return values that are owned by the give process
2148 
2149   Input Parameters:
2150 + mat  - the matrix
2151 . v    - a logically two-dimensional array for storing the values
2152 . m    - the number of rows
2153 . idxm - the  global indices of the rows
2154 . n    - the number of columns
2155 - idxn - the global indices of the columns
2156 
2157   Level: advanced
2158 
2159   Notes:
2160   The user must allocate space (m*n `PetscScalar`s) for the values, `v`.
2161   The values, `v`, are then returned in a row-oriented format,
2162   analogous to that used by default in `MatSetValues()`.
2163 
2164   `MatGetValues()` uses 0-based row and column numbers in
2165   Fortran as well as in C.
2166 
2167   `MatGetValues()` requires that the matrix has been assembled
2168   with `MatAssemblyBegin()`/`MatAssemblyEnd()`.  Thus, calls to
2169   `MatSetValues()` and `MatGetValues()` CANNOT be made in succession
2170   without intermediate matrix assembly.
2171 
2172   Negative row or column indices will be ignored and those locations in `v` will be
2173   left unchanged.
2174 
2175   For the standard row-based matrix formats, `idxm` can only contain rows owned by the requesting MPI process.
2176   That is, rows with global index greater than or equal to rstart and less than rend where rstart and rend are obtainable
2177   from `MatGetOwnershipRange`(mat,&rstart,&rend).
2178 
2179 .seealso: [](ch_matrices), `Mat`, `MatGetRow()`, `MatCreateSubMatrices()`, `MatSetValues()`, `MatGetOwnershipRange()`, `MatGetValuesLocal()`, `MatGetValue()`
2180 @*/
2181 PetscErrorCode MatGetValues(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], PetscScalar v[])
2182 {
2183   PetscFunctionBegin;
2184   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2185   PetscValidType(mat, 1);
2186   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS);
2187   PetscAssertPointer(idxm, 3);
2188   PetscAssertPointer(idxn, 5);
2189   PetscAssertPointer(v, 6);
2190   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2191   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2192   MatCheckPreallocated(mat, 1);
2193 
2194   PetscCall(PetscLogEventBegin(MAT_GetValues, mat, 0, 0, 0));
2195   PetscUseTypeMethod(mat, getvalues, m, idxm, n, idxn, v);
2196   PetscCall(PetscLogEventEnd(MAT_GetValues, mat, 0, 0, 0));
2197   PetscFunctionReturn(PETSC_SUCCESS);
2198 }
2199 
2200 /*@
2201   MatGetValuesLocal - retrieves values from certain locations in a matrix using the local numbering of the indices
2202   defined previously by `MatSetLocalToGlobalMapping()`
2203 
2204   Not Collective
2205 
2206   Input Parameters:
2207 + mat  - the matrix
2208 . nrow - number of rows
2209 . irow - the row local indices
2210 . ncol - number of columns
2211 - icol - the column local indices
2212 
2213   Output Parameter:
2214 . y - a logically two-dimensional array of values
2215 
2216   Level: advanced
2217 
2218   Notes:
2219   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetLocalToGlobalMapping()` before using this routine.
2220 
2221   This routine can only return values that are owned by the requesting MPI process. That is, for standard matrix formats, rows that, in the global numbering,
2222   are greater than or equal to rstart and less than rend where rstart and rend are obtainable from `MatGetOwnershipRange`(mat,&rstart,&rend). One can
2223   determine if the resulting global row associated with the local row r is owned by the requesting MPI process by applying the `ISLocalToGlobalMapping` set
2224   with `MatSetLocalToGlobalMapping()`.
2225 
2226 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetLocalToGlobalMapping()`,
2227           `MatSetValuesLocal()`, `MatGetValues()`
2228 @*/
2229 PetscErrorCode MatGetValuesLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], PetscScalar y[])
2230 {
2231   PetscFunctionBeginHot;
2232   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2233   PetscValidType(mat, 1);
2234   MatCheckPreallocated(mat, 1);
2235   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to retrieve */
2236   PetscAssertPointer(irow, 3);
2237   PetscAssertPointer(icol, 5);
2238   if (PetscDefined(USE_DEBUG)) {
2239     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2240     PetscCheck(mat->ops->getvalueslocal || mat->ops->getvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2241   }
2242   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2243   PetscCall(PetscLogEventBegin(MAT_GetValues, mat, 0, 0, 0));
2244   if (mat->ops->getvalueslocal) PetscUseTypeMethod(mat, getvalueslocal, nrow, irow, ncol, icol, y);
2245   else {
2246     PetscInt buf[8192], *bufr = NULL, *bufc = NULL, *irowm, *icolm;
2247     if ((nrow + ncol) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2248       irowm = buf;
2249       icolm = buf + nrow;
2250     } else {
2251       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2252       irowm = bufr;
2253       icolm = bufc;
2254     }
2255     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MatGetValuesLocal() cannot proceed without local-to-global row mapping (See MatSetLocalToGlobalMapping()).");
2256     PetscCheck(mat->cmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MatGetValuesLocal() cannot proceed without local-to-global column mapping (See MatSetLocalToGlobalMapping()).");
2257     PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, nrow, irow, irowm));
2258     PetscCall(ISLocalToGlobalMappingApply(mat->cmap->mapping, ncol, icol, icolm));
2259     PetscCall(MatGetValues(mat, nrow, irowm, ncol, icolm, y));
2260     PetscCall(PetscFree2(bufr, bufc));
2261   }
2262   PetscCall(PetscLogEventEnd(MAT_GetValues, mat, 0, 0, 0));
2263   PetscFunctionReturn(PETSC_SUCCESS);
2264 }
2265 
2266 /*@
2267   MatSetValuesBatch - Adds (`ADD_VALUES`) many blocks of values into a matrix at once. The blocks must all be square and
2268   the same size. Currently, this can only be called once and creates the given matrix.
2269 
2270   Not Collective
2271 
2272   Input Parameters:
2273 + mat  - the matrix
2274 . nb   - the number of blocks
2275 . bs   - the number of rows (and columns) in each block
2276 . rows - a concatenation of the rows for each block
2277 - v    - a concatenation of logically two-dimensional arrays of values
2278 
2279   Level: advanced
2280 
2281   Notes:
2282   `MatSetPreallocationCOO()` and `MatSetValuesCOO()` may be a better way to provide the values
2283 
2284   In the future, we will extend this routine to handle rectangular blocks, and to allow multiple calls for a given matrix.
2285 
2286 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
2287           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`, `MatSetValues()`, `MatSetPreallocationCOO()`, `MatSetValuesCOO()`
2288 @*/
2289 PetscErrorCode MatSetValuesBatch(Mat mat, PetscInt nb, PetscInt bs, PetscInt rows[], const PetscScalar v[])
2290 {
2291   PetscFunctionBegin;
2292   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2293   PetscValidType(mat, 1);
2294   PetscAssertPointer(rows, 4);
2295   PetscAssertPointer(v, 5);
2296   PetscAssert(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2297 
2298   PetscCall(PetscLogEventBegin(MAT_SetValuesBatch, mat, 0, 0, 0));
2299   if (mat->ops->setvaluesbatch) PetscUseTypeMethod(mat, setvaluesbatch, nb, bs, rows, v);
2300   else {
2301     for (PetscInt b = 0; b < nb; ++b) PetscCall(MatSetValues(mat, bs, &rows[b * bs], bs, &rows[b * bs], &v[b * bs * bs], ADD_VALUES));
2302   }
2303   PetscCall(PetscLogEventEnd(MAT_SetValuesBatch, mat, 0, 0, 0));
2304   PetscFunctionReturn(PETSC_SUCCESS);
2305 }
2306 
2307 /*@
2308   MatSetLocalToGlobalMapping - Sets a local-to-global numbering for use by
2309   the routine `MatSetValuesLocal()` to allow users to insert matrix entries
2310   using a local (per-processor) numbering.
2311 
2312   Not Collective
2313 
2314   Input Parameters:
2315 + x        - the matrix
2316 . rmapping - row mapping created with `ISLocalToGlobalMappingCreate()` or `ISLocalToGlobalMappingCreateIS()`
2317 - cmapping - column mapping
2318 
2319   Level: intermediate
2320 
2321   Note:
2322   If the matrix is obtained with `DMCreateMatrix()` then this may already have been called on the matrix
2323 
2324 .seealso: [](ch_matrices), `Mat`, `DM`, `DMCreateMatrix()`, `MatGetLocalToGlobalMapping()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetValuesLocal()`, `MatGetValuesLocal()`
2325 @*/
2326 PetscErrorCode MatSetLocalToGlobalMapping(Mat x, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2327 {
2328   PetscFunctionBegin;
2329   PetscValidHeaderSpecific(x, MAT_CLASSID, 1);
2330   PetscValidType(x, 1);
2331   if (rmapping) PetscValidHeaderSpecific(rmapping, IS_LTOGM_CLASSID, 2);
2332   if (cmapping) PetscValidHeaderSpecific(cmapping, IS_LTOGM_CLASSID, 3);
2333   if (x->ops->setlocaltoglobalmapping) PetscUseTypeMethod(x, setlocaltoglobalmapping, rmapping, cmapping);
2334   else {
2335     PetscCall(PetscLayoutSetISLocalToGlobalMapping(x->rmap, rmapping));
2336     PetscCall(PetscLayoutSetISLocalToGlobalMapping(x->cmap, cmapping));
2337   }
2338   PetscFunctionReturn(PETSC_SUCCESS);
2339 }
2340 
2341 /*@
2342   MatGetLocalToGlobalMapping - Gets the local-to-global numbering set by `MatSetLocalToGlobalMapping()`
2343 
2344   Not Collective
2345 
2346   Input Parameter:
2347 . A - the matrix
2348 
2349   Output Parameters:
2350 + rmapping - row mapping
2351 - cmapping - column mapping
2352 
2353   Level: advanced
2354 
2355 .seealso: [](ch_matrices), `Mat`, `MatSetLocalToGlobalMapping()`, `MatSetValuesLocal()`
2356 @*/
2357 PetscErrorCode MatGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
2358 {
2359   PetscFunctionBegin;
2360   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2361   PetscValidType(A, 1);
2362   if (rmapping) {
2363     PetscAssertPointer(rmapping, 2);
2364     *rmapping = A->rmap->mapping;
2365   }
2366   if (cmapping) {
2367     PetscAssertPointer(cmapping, 3);
2368     *cmapping = A->cmap->mapping;
2369   }
2370   PetscFunctionReturn(PETSC_SUCCESS);
2371 }
2372 
2373 /*@
2374   MatSetLayouts - Sets the `PetscLayout` objects for rows and columns of a matrix
2375 
2376   Logically Collective
2377 
2378   Input Parameters:
2379 + A    - the matrix
2380 . rmap - row layout
2381 - cmap - column layout
2382 
2383   Level: advanced
2384 
2385   Note:
2386   The `PetscLayout` objects are usually created automatically for the matrix so this routine rarely needs to be called.
2387 
2388 .seealso: [](ch_matrices), `Mat`, `PetscLayout`, `MatCreateVecs()`, `MatGetLocalToGlobalMapping()`, `MatGetLayouts()`
2389 @*/
2390 PetscErrorCode MatSetLayouts(Mat A, PetscLayout rmap, PetscLayout cmap)
2391 {
2392   PetscFunctionBegin;
2393   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2394   PetscCall(PetscLayoutReference(rmap, &A->rmap));
2395   PetscCall(PetscLayoutReference(cmap, &A->cmap));
2396   PetscFunctionReturn(PETSC_SUCCESS);
2397 }
2398 
2399 /*@
2400   MatGetLayouts - Gets the `PetscLayout` objects for rows and columns
2401 
2402   Not Collective
2403 
2404   Input Parameter:
2405 . A - the matrix
2406 
2407   Output Parameters:
2408 + rmap - row layout
2409 - cmap - column layout
2410 
2411   Level: advanced
2412 
2413 .seealso: [](ch_matrices), `Mat`, [Matrix Layouts](sec_matlayout), `PetscLayout`, `MatCreateVecs()`, `MatGetLocalToGlobalMapping()`, `MatSetLayouts()`
2414 @*/
2415 PetscErrorCode MatGetLayouts(Mat A, PetscLayout *rmap, PetscLayout *cmap)
2416 {
2417   PetscFunctionBegin;
2418   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2419   PetscValidType(A, 1);
2420   if (rmap) {
2421     PetscAssertPointer(rmap, 2);
2422     *rmap = A->rmap;
2423   }
2424   if (cmap) {
2425     PetscAssertPointer(cmap, 3);
2426     *cmap = A->cmap;
2427   }
2428   PetscFunctionReturn(PETSC_SUCCESS);
2429 }
2430 
2431 /*@
2432   MatSetValuesLocal - Inserts or adds values into certain locations of a matrix,
2433   using a local numbering of the rows and columns.
2434 
2435   Not Collective
2436 
2437   Input Parameters:
2438 + mat  - the matrix
2439 . nrow - number of rows
2440 . irow - the row local indices
2441 . ncol - number of columns
2442 . icol - the column local indices
2443 . y    - a logically two-dimensional array of values
2444 - addv - either `INSERT_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
2445 
2446   Level: intermediate
2447 
2448   Notes:
2449   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetLocalToGlobalMapping()` before using this routine
2450 
2451   Calls to `MatSetValuesLocal()` with the `INSERT_VALUES` and `ADD_VALUES`
2452   options cannot be mixed without intervening calls to the assembly
2453   routines.
2454 
2455   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
2456   MUST be called after all calls to `MatSetValuesLocal()` have been completed.
2457 
2458   Fortran Notes:
2459   If any of `irow`, `icol`, and `y` are scalars pass them using, for example,
2460 .vb
2461   call MatSetValuesLocal(mat, one, [irow], one, [icol], [y], INSERT_VALUES, ierr)
2462 .ve
2463 
2464   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2465 
2466 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetLocalToGlobalMapping()`,
2467           `MatGetValuesLocal()`
2468 @*/
2469 PetscErrorCode MatSetValuesLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv)
2470 {
2471   PetscFunctionBeginHot;
2472   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2473   PetscValidType(mat, 1);
2474   MatCheckPreallocated(mat, 1);
2475   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2476   PetscAssertPointer(irow, 3);
2477   PetscAssertPointer(icol, 5);
2478   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2479   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2480   if (PetscDefined(USE_DEBUG)) {
2481     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2482     PetscCheck(mat->ops->setvalueslocal || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2483   }
2484 
2485   if (mat->assembled) {
2486     mat->was_assembled = PETSC_TRUE;
2487     mat->assembled     = PETSC_FALSE;
2488   }
2489   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2490   if (mat->ops->setvalueslocal) PetscUseTypeMethod(mat, setvalueslocal, nrow, irow, ncol, icol, y, addv);
2491   else {
2492     PetscInt        buf[8192], *bufr = NULL, *bufc = NULL;
2493     const PetscInt *irowm, *icolm;
2494 
2495     if ((!mat->rmap->mapping && !mat->cmap->mapping) || (nrow + ncol) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2496       bufr  = buf;
2497       bufc  = buf + nrow;
2498       irowm = bufr;
2499       icolm = bufc;
2500     } else {
2501       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2502       irowm = bufr;
2503       icolm = bufc;
2504     }
2505     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, nrow, irow, bufr));
2506     else irowm = irow;
2507     if (mat->cmap->mapping) {
2508       if (mat->cmap->mapping != mat->rmap->mapping || ncol != nrow || icol != irow) {
2509         PetscCall(ISLocalToGlobalMappingApply(mat->cmap->mapping, ncol, icol, bufc));
2510       } else icolm = irowm;
2511     } else icolm = icol;
2512     PetscCall(MatSetValues(mat, nrow, irowm, ncol, icolm, y, addv));
2513     if (bufr != buf) PetscCall(PetscFree2(bufr, bufc));
2514   }
2515   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2516   PetscFunctionReturn(PETSC_SUCCESS);
2517 }
2518 
2519 /*@
2520   MatSetValuesBlockedLocal - Inserts or adds values into certain locations of a matrix,
2521   using a local ordering of the nodes a block at a time.
2522 
2523   Not Collective
2524 
2525   Input Parameters:
2526 + mat  - the matrix
2527 . nrow - number of rows
2528 . irow - the row local indices
2529 . ncol - number of columns
2530 . icol - the column local indices
2531 . y    - a logically two-dimensional array of values
2532 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
2533 
2534   Level: intermediate
2535 
2536   Notes:
2537   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetBlockSize()` and `MatSetLocalToGlobalMapping()`
2538   before using this routineBefore calling `MatSetValuesLocal()`, the user must first set the
2539 
2540   Calls to `MatSetValuesBlockedLocal()` with the `INSERT_VALUES` and `ADD_VALUES`
2541   options cannot be mixed without intervening calls to the assembly
2542   routines.
2543 
2544   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
2545   MUST be called after all calls to `MatSetValuesBlockedLocal()` have been completed.
2546 
2547   Fortran Notes:
2548   If any of `irow`, `icol`, and `y` are scalars pass them using, for example,
2549 .vb
2550   call MatSetValuesBlockedLocal(mat, one, [irow], one, [icol], [y], INSERT_VALUES, ierr)
2551 .ve
2552 
2553   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2554 
2555 .seealso: [](ch_matrices), `Mat`, `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`,
2556           `MatSetValuesLocal()`, `MatSetValuesBlocked()`
2557 @*/
2558 PetscErrorCode MatSetValuesBlockedLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv)
2559 {
2560   PetscFunctionBeginHot;
2561   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2562   PetscValidType(mat, 1);
2563   MatCheckPreallocated(mat, 1);
2564   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2565   PetscAssertPointer(irow, 3);
2566   PetscAssertPointer(icol, 5);
2567   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2568   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2569   if (PetscDefined(USE_DEBUG)) {
2570     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2571     PetscCheck(mat->ops->setvaluesblockedlocal || mat->ops->setvaluesblocked || mat->ops->setvalueslocal || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2572   }
2573 
2574   if (mat->assembled) {
2575     mat->was_assembled = PETSC_TRUE;
2576     mat->assembled     = PETSC_FALSE;
2577   }
2578   if (PetscUnlikelyDebug(mat->rmap->mapping)) { /* Condition on the mapping existing, because MatSetValuesBlockedLocal_IS does not require it to be set. */
2579     PetscInt irbs, rbs;
2580     PetscCall(MatGetBlockSizes(mat, &rbs, NULL));
2581     PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &irbs));
2582     PetscCheck(rbs == irbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Different row block sizes! mat %" PetscInt_FMT ", row l2g map %" PetscInt_FMT, rbs, irbs);
2583   }
2584   if (PetscUnlikelyDebug(mat->cmap->mapping)) {
2585     PetscInt icbs, cbs;
2586     PetscCall(MatGetBlockSizes(mat, NULL, &cbs));
2587     PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &icbs));
2588     PetscCheck(cbs == icbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Different col block sizes! mat %" PetscInt_FMT ", col l2g map %" PetscInt_FMT, cbs, icbs);
2589   }
2590   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2591   if (mat->ops->setvaluesblockedlocal) PetscUseTypeMethod(mat, setvaluesblockedlocal, nrow, irow, ncol, icol, y, addv);
2592   else {
2593     PetscInt        buf[8192], *bufr = NULL, *bufc = NULL;
2594     const PetscInt *irowm, *icolm;
2595 
2596     if ((!mat->rmap->mapping && !mat->cmap->mapping) || (nrow + ncol) <= ((PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf))) {
2597       bufr  = buf;
2598       bufc  = buf + nrow;
2599       irowm = bufr;
2600       icolm = bufc;
2601     } else {
2602       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2603       irowm = bufr;
2604       icolm = bufc;
2605     }
2606     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingApplyBlock(mat->rmap->mapping, nrow, irow, bufr));
2607     else irowm = irow;
2608     if (mat->cmap->mapping) {
2609       if (mat->cmap->mapping != mat->rmap->mapping || ncol != nrow || icol != irow) {
2610         PetscCall(ISLocalToGlobalMappingApplyBlock(mat->cmap->mapping, ncol, icol, bufc));
2611       } else icolm = irowm;
2612     } else icolm = icol;
2613     PetscCall(MatSetValuesBlocked(mat, nrow, irowm, ncol, icolm, y, addv));
2614     if (bufr != buf) PetscCall(PetscFree2(bufr, bufc));
2615   }
2616   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2617   PetscFunctionReturn(PETSC_SUCCESS);
2618 }
2619 
2620 /*@
2621   MatMultDiagonalBlock - Computes the matrix-vector product, $y = Dx$. Where `D` is defined by the inode or block structure of the diagonal
2622 
2623   Collective
2624 
2625   Input Parameters:
2626 + mat - the matrix
2627 - x   - the vector to be multiplied
2628 
2629   Output Parameter:
2630 . y - the result
2631 
2632   Level: developer
2633 
2634   Note:
2635   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2636   call `MatMultDiagonalBlock`(A,y,y).
2637 
2638 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
2639 @*/
2640 PetscErrorCode MatMultDiagonalBlock(Mat mat, Vec x, Vec y)
2641 {
2642   PetscFunctionBegin;
2643   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2644   PetscValidType(mat, 1);
2645   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2646   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2647 
2648   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2649   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2650   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2651   MatCheckPreallocated(mat, 1);
2652 
2653   PetscUseTypeMethod(mat, multdiagonalblock, x, y);
2654   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2655   PetscFunctionReturn(PETSC_SUCCESS);
2656 }
2657 
2658 /*@
2659   MatMult - Computes the matrix-vector product, $y = Ax$.
2660 
2661   Neighbor-wise Collective
2662 
2663   Input Parameters:
2664 + mat - the matrix
2665 - x   - the vector to be multiplied
2666 
2667   Output Parameter:
2668 . y - the result
2669 
2670   Level: beginner
2671 
2672   Note:
2673   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2674   call `MatMult`(A,y,y).
2675 
2676 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
2677 @*/
2678 PetscErrorCode MatMult(Mat mat, Vec x, Vec y)
2679 {
2680   PetscFunctionBegin;
2681   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2682   PetscValidType(mat, 1);
2683   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2684   VecCheckAssembled(x);
2685   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2686   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2687   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2688   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2689   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
2690   PetscCheck(mat->rmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, y->map->N);
2691   PetscCheck(mat->cmap->n == x->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->n, x->map->n);
2692   PetscCheck(mat->rmap->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, y->map->n);
2693   PetscCall(VecSetErrorIfLocked(y, 3));
2694   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2695   MatCheckPreallocated(mat, 1);
2696 
2697   PetscCall(VecLockReadPush(x));
2698   PetscCall(PetscLogEventBegin(MAT_Mult, mat, x, y, 0));
2699   PetscUseTypeMethod(mat, mult, x, y);
2700   PetscCall(PetscLogEventEnd(MAT_Mult, mat, x, y, 0));
2701   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(y, 3, PETSC_FALSE));
2702   PetscCall(VecLockReadPop(x));
2703   PetscFunctionReturn(PETSC_SUCCESS);
2704 }
2705 
2706 /*@
2707   MatMultTranspose - Computes matrix transpose times a vector $y = A^T * x$.
2708 
2709   Neighbor-wise Collective
2710 
2711   Input Parameters:
2712 + mat - the matrix
2713 - x   - the vector to be multiplied
2714 
2715   Output Parameter:
2716 . y - the result
2717 
2718   Level: beginner
2719 
2720   Notes:
2721   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2722   call `MatMultTranspose`(A,y,y).
2723 
2724   For complex numbers this does NOT compute the Hermitian (complex conjugate) transpose multiple,
2725   use `MatMultHermitianTranspose()`
2726 
2727 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatMultHermitianTranspose()`, `MatTranspose()`
2728 @*/
2729 PetscErrorCode MatMultTranspose(Mat mat, Vec x, Vec y)
2730 {
2731   PetscErrorCode (*op)(Mat, Vec, Vec) = NULL;
2732 
2733   PetscFunctionBegin;
2734   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2735   PetscValidType(mat, 1);
2736   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2737   VecCheckAssembled(x);
2738   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2739 
2740   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2741   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2742   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2743   PetscCheck(mat->cmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, y->map->N);
2744   PetscCheck(mat->rmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, x->map->N);
2745   PetscCheck(mat->cmap->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->n, y->map->n);
2746   PetscCheck(mat->rmap->n == x->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, x->map->n);
2747   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2748   MatCheckPreallocated(mat, 1);
2749 
2750   if (!mat->ops->multtranspose) {
2751     if (mat->symmetric == PETSC_BOOL3_TRUE && mat->ops->mult) op = mat->ops->mult;
2752     PetscCheck(op, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Matrix type %s does not have a multiply transpose defined or is symmetric and does not have a multiply defined", ((PetscObject)mat)->type_name);
2753   } else op = mat->ops->multtranspose;
2754   PetscCall(PetscLogEventBegin(MAT_MultTranspose, mat, x, y, 0));
2755   PetscCall(VecLockReadPush(x));
2756   PetscCall((*op)(mat, x, y));
2757   PetscCall(VecLockReadPop(x));
2758   PetscCall(PetscLogEventEnd(MAT_MultTranspose, mat, x, y, 0));
2759   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2760   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(y, 3, PETSC_FALSE));
2761   PetscFunctionReturn(PETSC_SUCCESS);
2762 }
2763 
2764 /*@
2765   MatMultHermitianTranspose - Computes matrix Hermitian-transpose times a vector $y = A^H * x$.
2766 
2767   Neighbor-wise Collective
2768 
2769   Input Parameters:
2770 + mat - the matrix
2771 - x   - the vector to be multiplied
2772 
2773   Output Parameter:
2774 . y - the result
2775 
2776   Level: beginner
2777 
2778   Notes:
2779   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2780   call `MatMultHermitianTranspose`(A,y,y).
2781 
2782   Also called the conjugate transpose, complex conjugate transpose, or adjoint.
2783 
2784   For real numbers `MatMultTranspose()` and `MatMultHermitianTranspose()` are identical.
2785 
2786 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `MatMultHermitianTransposeAdd()`, `MatMultTranspose()`
2787 @*/
2788 PetscErrorCode MatMultHermitianTranspose(Mat mat, Vec x, Vec y)
2789 {
2790   PetscFunctionBegin;
2791   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2792   PetscValidType(mat, 1);
2793   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2794   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2795 
2796   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2797   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2798   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2799   PetscCheck(mat->cmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, y->map->N);
2800   PetscCheck(mat->rmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, x->map->N);
2801   PetscCheck(mat->cmap->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->n, y->map->n);
2802   PetscCheck(mat->rmap->n == x->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, x->map->n);
2803   MatCheckPreallocated(mat, 1);
2804 
2805   PetscCall(PetscLogEventBegin(MAT_MultHermitianTranspose, mat, x, y, 0));
2806 #if defined(PETSC_USE_COMPLEX)
2807   if (mat->ops->multhermitiantranspose || (mat->hermitian == PETSC_BOOL3_TRUE && mat->ops->mult)) {
2808     PetscCall(VecLockReadPush(x));
2809     if (mat->ops->multhermitiantranspose) PetscUseTypeMethod(mat, multhermitiantranspose, x, y);
2810     else PetscUseTypeMethod(mat, mult, x, y);
2811     PetscCall(VecLockReadPop(x));
2812   } else {
2813     Vec w;
2814     PetscCall(VecDuplicate(x, &w));
2815     PetscCall(VecCopy(x, w));
2816     PetscCall(VecConjugate(w));
2817     PetscCall(MatMultTranspose(mat, w, y));
2818     PetscCall(VecDestroy(&w));
2819     PetscCall(VecConjugate(y));
2820   }
2821   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2822 #else
2823   PetscCall(MatMultTranspose(mat, x, y));
2824 #endif
2825   PetscCall(PetscLogEventEnd(MAT_MultHermitianTranspose, mat, x, y, 0));
2826   PetscFunctionReturn(PETSC_SUCCESS);
2827 }
2828 
2829 /*@
2830   MatMultAdd -  Computes $v3 = v2 + A * v1$.
2831 
2832   Neighbor-wise Collective
2833 
2834   Input Parameters:
2835 + mat - the matrix
2836 . v1  - the vector to be multiplied by `mat`
2837 - v2  - the vector to be added to the result
2838 
2839   Output Parameter:
2840 . v3 - the result
2841 
2842   Level: beginner
2843 
2844   Note:
2845   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2846   call `MatMultAdd`(A,v1,v2,v1).
2847 
2848 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMult()`, `MatMultTransposeAdd()`
2849 @*/
2850 PetscErrorCode MatMultAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2851 {
2852   PetscFunctionBegin;
2853   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2854   PetscValidType(mat, 1);
2855   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2856   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2857   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2858 
2859   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2860   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2861   PetscCheck(mat->cmap->N == v1->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v1: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v1->map->N);
2862   /* PetscCheck(mat->rmap->N == v2->map->N,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Mat mat,Vec v2: global dim %" PetscInt_FMT " %" PetscInt_FMT,mat->rmap->N,v2->map->N);
2863      PetscCheck(mat->rmap->N == v3->map->N,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Mat mat,Vec v3: global dim %" PetscInt_FMT " %" PetscInt_FMT,mat->rmap->N,v3->map->N); */
2864   PetscCheck(mat->rmap->n == v3->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec v3: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, v3->map->n);
2865   PetscCheck(mat->rmap->n == v2->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec v2: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, v2->map->n);
2866   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2867   MatCheckPreallocated(mat, 1);
2868 
2869   PetscCall(PetscLogEventBegin(MAT_MultAdd, mat, v1, v2, v3));
2870   PetscCall(VecLockReadPush(v1));
2871   PetscUseTypeMethod(mat, multadd, v1, v2, v3);
2872   PetscCall(VecLockReadPop(v1));
2873   PetscCall(PetscLogEventEnd(MAT_MultAdd, mat, v1, v2, v3));
2874   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2875   PetscFunctionReturn(PETSC_SUCCESS);
2876 }
2877 
2878 /*@
2879   MatMultTransposeAdd - Computes $v3 = v2 + A^T * v1$.
2880 
2881   Neighbor-wise Collective
2882 
2883   Input Parameters:
2884 + mat - the matrix
2885 . v1  - the vector to be multiplied by the transpose of the matrix
2886 - v2  - the vector to be added to the result
2887 
2888   Output Parameter:
2889 . v3 - the result
2890 
2891   Level: beginner
2892 
2893   Note:
2894   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2895   call `MatMultTransposeAdd`(A,v1,v2,v1).
2896 
2897 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMult()`
2898 @*/
2899 PetscErrorCode MatMultTransposeAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2900 {
2901   PetscErrorCode (*op)(Mat, Vec, Vec, Vec) = (!mat->ops->multtransposeadd && mat->symmetric) ? mat->ops->multadd : mat->ops->multtransposeadd;
2902 
2903   PetscFunctionBegin;
2904   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2905   PetscValidType(mat, 1);
2906   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2907   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2908   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2909 
2910   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2911   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2912   PetscCheck(mat->rmap->N == v1->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v1: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, v1->map->N);
2913   PetscCheck(mat->cmap->N == v2->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v2: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v2->map->N);
2914   PetscCheck(mat->cmap->N == v3->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v3: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v3->map->N);
2915   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2916   PetscCheck(op, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2917   MatCheckPreallocated(mat, 1);
2918 
2919   PetscCall(PetscLogEventBegin(MAT_MultTransposeAdd, mat, v1, v2, v3));
2920   PetscCall(VecLockReadPush(v1));
2921   PetscCall((*op)(mat, v1, v2, v3));
2922   PetscCall(VecLockReadPop(v1));
2923   PetscCall(PetscLogEventEnd(MAT_MultTransposeAdd, mat, v1, v2, v3));
2924   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2925   PetscFunctionReturn(PETSC_SUCCESS);
2926 }
2927 
2928 /*@
2929   MatMultHermitianTransposeAdd - Computes $v3 = v2 + A^H * v1$.
2930 
2931   Neighbor-wise Collective
2932 
2933   Input Parameters:
2934 + mat - the matrix
2935 . v1  - the vector to be multiplied by the Hermitian transpose
2936 - v2  - the vector to be added to the result
2937 
2938   Output Parameter:
2939 . v3 - the result
2940 
2941   Level: beginner
2942 
2943   Note:
2944   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2945   call `MatMultHermitianTransposeAdd`(A,v1,v2,v1).
2946 
2947 .seealso: [](ch_matrices), `Mat`, `MatMultHermitianTranspose()`, `MatMultTranspose()`, `MatMultAdd()`, `MatMult()`
2948 @*/
2949 PetscErrorCode MatMultHermitianTransposeAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2950 {
2951   PetscFunctionBegin;
2952   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2953   PetscValidType(mat, 1);
2954   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2955   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2956   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2957 
2958   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2959   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2960   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2961   PetscCheck(mat->rmap->N == v1->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v1: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, v1->map->N);
2962   PetscCheck(mat->cmap->N == v2->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v2: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v2->map->N);
2963   PetscCheck(mat->cmap->N == v3->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v3: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v3->map->N);
2964   MatCheckPreallocated(mat, 1);
2965 
2966   PetscCall(PetscLogEventBegin(MAT_MultHermitianTransposeAdd, mat, v1, v2, v3));
2967   PetscCall(VecLockReadPush(v1));
2968   if (mat->ops->multhermitiantransposeadd) PetscUseTypeMethod(mat, multhermitiantransposeadd, v1, v2, v3);
2969   else {
2970     Vec w, z;
2971     PetscCall(VecDuplicate(v1, &w));
2972     PetscCall(VecCopy(v1, w));
2973     PetscCall(VecConjugate(w));
2974     PetscCall(VecDuplicate(v3, &z));
2975     PetscCall(MatMultTranspose(mat, w, z));
2976     PetscCall(VecDestroy(&w));
2977     PetscCall(VecConjugate(z));
2978     if (v2 != v3) {
2979       PetscCall(VecWAXPY(v3, 1.0, v2, z));
2980     } else {
2981       PetscCall(VecAXPY(v3, 1.0, z));
2982     }
2983     PetscCall(VecDestroy(&z));
2984   }
2985   PetscCall(VecLockReadPop(v1));
2986   PetscCall(PetscLogEventEnd(MAT_MultHermitianTransposeAdd, mat, v1, v2, v3));
2987   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2988   PetscFunctionReturn(PETSC_SUCCESS);
2989 }
2990 
2991 /*@
2992   MatGetFactorType - gets the type of factorization a matrix is
2993 
2994   Not Collective
2995 
2996   Input Parameter:
2997 . mat - the matrix
2998 
2999   Output Parameter:
3000 . t - the type, one of `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`, `MAT_FACTOR_ICC,MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3001 
3002   Level: intermediate
3003 
3004 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatGetFactor()`, `MatSetFactorType()`, `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`,
3005           `MAT_FACTOR_ICC`,`MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3006 @*/
3007 PetscErrorCode MatGetFactorType(Mat mat, MatFactorType *t)
3008 {
3009   PetscFunctionBegin;
3010   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3011   PetscValidType(mat, 1);
3012   PetscAssertPointer(t, 2);
3013   *t = mat->factortype;
3014   PetscFunctionReturn(PETSC_SUCCESS);
3015 }
3016 
3017 /*@
3018   MatSetFactorType - sets the type of factorization a matrix is
3019 
3020   Logically Collective
3021 
3022   Input Parameters:
3023 + mat - the matrix
3024 - t   - the type, one of `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`, `MAT_FACTOR_ICC,MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3025 
3026   Level: intermediate
3027 
3028 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatGetFactor()`, `MatGetFactorType()`, `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`,
3029           `MAT_FACTOR_ICC`,`MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3030 @*/
3031 PetscErrorCode MatSetFactorType(Mat mat, MatFactorType t)
3032 {
3033   PetscFunctionBegin;
3034   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3035   PetscValidType(mat, 1);
3036   mat->factortype = t;
3037   PetscFunctionReturn(PETSC_SUCCESS);
3038 }
3039 
3040 /*@
3041   MatGetInfo - Returns information about matrix storage (number of
3042   nonzeros, memory, etc.).
3043 
3044   Collective if `MAT_GLOBAL_MAX` or `MAT_GLOBAL_SUM` is used as the flag
3045 
3046   Input Parameters:
3047 + mat  - the matrix
3048 - flag - flag indicating the type of parameters to be returned (`MAT_LOCAL` - local matrix, `MAT_GLOBAL_MAX` - maximum over all processors, `MAT_GLOBAL_SUM` - sum over all processors)
3049 
3050   Output Parameter:
3051 . info - matrix information context
3052 
3053   Options Database Key:
3054 . -mat_view ::ascii_info - print matrix info to `PETSC_STDOUT`
3055 
3056   Level: intermediate
3057 
3058   Notes:
3059   The `MatInfo` context contains a variety of matrix data, including
3060   number of nonzeros allocated and used, number of mallocs during
3061   matrix assembly, etc.  Additional information for factored matrices
3062   is provided (such as the fill ratio, number of mallocs during
3063   factorization, etc.).
3064 
3065   Example:
3066   See the file ${PETSC_DIR}/include/petscmat.h for a complete list of
3067   data within the `MatInfo` context.  For example,
3068 .vb
3069       MatInfo info;
3070       Mat     A;
3071       double  mal, nz_a, nz_u;
3072 
3073       MatGetInfo(A, MAT_LOCAL, &info);
3074       mal  = info.mallocs;
3075       nz_a = info.nz_allocated;
3076 .ve
3077 
3078 .seealso: [](ch_matrices), `Mat`, `MatInfo`, `MatStashGetInfo()`
3079 @*/
3080 PetscErrorCode MatGetInfo(Mat mat, MatInfoType flag, MatInfo *info)
3081 {
3082   PetscFunctionBegin;
3083   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3084   PetscValidType(mat, 1);
3085   PetscAssertPointer(info, 3);
3086   MatCheckPreallocated(mat, 1);
3087   PetscUseTypeMethod(mat, getinfo, flag, info);
3088   PetscFunctionReturn(PETSC_SUCCESS);
3089 }
3090 
3091 /*
3092    This is used by external packages where it is not easy to get the info from the actual
3093    matrix factorization.
3094 */
3095 PetscErrorCode MatGetInfo_External(Mat A, MatInfoType flag, MatInfo *info)
3096 {
3097   PetscFunctionBegin;
3098   PetscCall(PetscMemzero(info, sizeof(MatInfo)));
3099   PetscFunctionReturn(PETSC_SUCCESS);
3100 }
3101 
3102 /*@
3103   MatLUFactor - Performs in-place LU factorization of matrix.
3104 
3105   Collective
3106 
3107   Input Parameters:
3108 + mat  - the matrix
3109 . row  - row permutation
3110 . col  - column permutation
3111 - info - options for factorization, includes
3112 .vb
3113           fill - expected fill as ratio of original fill.
3114           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3115                    Run with the option -info to determine an optimal value to use
3116 .ve
3117 
3118   Level: developer
3119 
3120   Notes:
3121   Most users should employ the `KSP` interface for linear solvers
3122   instead of working directly with matrix algebra routines such as this.
3123   See, e.g., `KSPCreate()`.
3124 
3125   This changes the state of the matrix to a factored matrix; it cannot be used
3126   for example with `MatSetValues()` unless one first calls `MatSetUnfactored()`.
3127 
3128   This is really in-place only for dense matrices, the preferred approach is to use `MatGetFactor()`, `MatLUFactorSymbolic()`, and `MatLUFactorNumeric()`
3129   when not using `KSP`.
3130 
3131   Fortran Note:
3132   A valid (non-null) `info` argument must be provided
3133 
3134 .seealso: [](ch_matrices), [Matrix Factorization](sec_matfactor), `Mat`, `MatFactorType`, `MatLUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`,
3135           `MatGetOrdering()`, `MatSetUnfactored()`, `MatFactorInfo`, `MatGetFactor()`
3136 @*/
3137 PetscErrorCode MatLUFactor(Mat mat, IS row, IS col, const MatFactorInfo *info)
3138 {
3139   MatFactorInfo tinfo;
3140 
3141   PetscFunctionBegin;
3142   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3143   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
3144   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3145   if (info) PetscAssertPointer(info, 4);
3146   PetscValidType(mat, 1);
3147   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3148   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3149   MatCheckPreallocated(mat, 1);
3150   if (!info) {
3151     PetscCall(MatFactorInfoInitialize(&tinfo));
3152     info = &tinfo;
3153   }
3154 
3155   PetscCall(PetscLogEventBegin(MAT_LUFactor, mat, row, col, 0));
3156   PetscUseTypeMethod(mat, lufactor, row, col, info);
3157   PetscCall(PetscLogEventEnd(MAT_LUFactor, mat, row, col, 0));
3158   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3159   PetscFunctionReturn(PETSC_SUCCESS);
3160 }
3161 
3162 /*@
3163   MatILUFactor - Performs in-place ILU factorization of matrix.
3164 
3165   Collective
3166 
3167   Input Parameters:
3168 + mat  - the matrix
3169 . row  - row permutation
3170 . col  - column permutation
3171 - info - structure containing
3172 .vb
3173       levels - number of levels of fill.
3174       expected fill - as ratio of original fill.
3175       1 or 0 - indicating force fill on diagonal (improves robustness for matrices
3176                 missing diagonal entries)
3177 .ve
3178 
3179   Level: developer
3180 
3181   Notes:
3182   Most users should employ the `KSP` interface for linear solvers
3183   instead of working directly with matrix algebra routines such as this.
3184   See, e.g., `KSPCreate()`.
3185 
3186   Probably really in-place only when level of fill is zero, otherwise allocates
3187   new space to store factored matrix and deletes previous memory. The preferred approach is to use `MatGetFactor()`, `MatILUFactorSymbolic()`, and `MatILUFactorNumeric()`
3188   when not using `KSP`.
3189 
3190   Fortran Note:
3191   A valid (non-null) `info` argument must be provided
3192 
3193 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatILUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`
3194 @*/
3195 PetscErrorCode MatILUFactor(Mat mat, IS row, IS col, const MatFactorInfo *info)
3196 {
3197   PetscFunctionBegin;
3198   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3199   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
3200   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3201   PetscAssertPointer(info, 4);
3202   PetscValidType(mat, 1);
3203   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
3204   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3205   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3206   MatCheckPreallocated(mat, 1);
3207 
3208   PetscCall(PetscLogEventBegin(MAT_ILUFactor, mat, row, col, 0));
3209   PetscUseTypeMethod(mat, ilufactor, row, col, info);
3210   PetscCall(PetscLogEventEnd(MAT_ILUFactor, mat, row, col, 0));
3211   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3212   PetscFunctionReturn(PETSC_SUCCESS);
3213 }
3214 
3215 /*@
3216   MatLUFactorSymbolic - Performs symbolic LU factorization of matrix.
3217   Call this routine before calling `MatLUFactorNumeric()` and after `MatGetFactor()`.
3218 
3219   Collective
3220 
3221   Input Parameters:
3222 + fact - the factor matrix obtained with `MatGetFactor()`
3223 . mat  - the matrix
3224 . row  - the row permutation
3225 . col  - the column permutation
3226 - info - options for factorization, includes
3227 .vb
3228           fill - expected fill as ratio of original fill. Run with the option -info to determine an optimal value to use
3229           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3230 .ve
3231 
3232   Level: developer
3233 
3234   Notes:
3235   See [Matrix Factorization](sec_matfactor) for additional information about factorizations
3236 
3237   Most users should employ the simplified `KSP` interface for linear solvers
3238   instead of working directly with matrix algebra routines such as this.
3239   See, e.g., `KSPCreate()`.
3240 
3241   Fortran Note:
3242   A valid (non-null) `info` argument must be provided
3243 
3244 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactor()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`, `MatFactorInfoInitialize()`
3245 @*/
3246 PetscErrorCode MatLUFactorSymbolic(Mat fact, Mat mat, IS row, IS col, const MatFactorInfo *info)
3247 {
3248   MatFactorInfo tinfo;
3249 
3250   PetscFunctionBegin;
3251   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3252   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3253   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 3);
3254   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 4);
3255   if (info) PetscAssertPointer(info, 5);
3256   PetscValidType(fact, 1);
3257   PetscValidType(mat, 2);
3258   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3259   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3260   MatCheckPreallocated(mat, 2);
3261   if (!info) {
3262     PetscCall(MatFactorInfoInitialize(&tinfo));
3263     info = &tinfo;
3264   }
3265 
3266   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_LUFactorSymbolic, mat, row, col, 0));
3267   PetscUseTypeMethod(fact, lufactorsymbolic, mat, row, col, info);
3268   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_LUFactorSymbolic, mat, row, col, 0));
3269   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3270   PetscFunctionReturn(PETSC_SUCCESS);
3271 }
3272 
3273 /*@
3274   MatLUFactorNumeric - Performs numeric LU factorization of a matrix.
3275   Call this routine after first calling `MatLUFactorSymbolic()` and `MatGetFactor()`.
3276 
3277   Collective
3278 
3279   Input Parameters:
3280 + fact - the factor matrix obtained with `MatGetFactor()`
3281 . mat  - the matrix
3282 - info - options for factorization
3283 
3284   Level: developer
3285 
3286   Notes:
3287   See `MatLUFactor()` for in-place factorization.  See
3288   `MatCholeskyFactorNumeric()` for the symmetric, positive definite case.
3289 
3290   Most users should employ the `KSP` interface for linear solvers
3291   instead of working directly with matrix algebra routines such as this.
3292   See, e.g., `KSPCreate()`.
3293 
3294   Fortran Note:
3295   A valid (non-null) `info` argument must be provided
3296 
3297 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatLUFactorSymbolic()`, `MatLUFactor()`, `MatCholeskyFactor()`
3298 @*/
3299 PetscErrorCode MatLUFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3300 {
3301   MatFactorInfo tinfo;
3302 
3303   PetscFunctionBegin;
3304   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3305   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3306   PetscValidType(fact, 1);
3307   PetscValidType(mat, 2);
3308   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3309   PetscCheck(mat->rmap->N == (fact)->rmap->N && mat->cmap->N == (fact)->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Mat fact: global dimensions are different %" PetscInt_FMT " should = %" PetscInt_FMT " %" PetscInt_FMT " should = %" PetscInt_FMT,
3310              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3311 
3312   MatCheckPreallocated(mat, 2);
3313   if (!info) {
3314     PetscCall(MatFactorInfoInitialize(&tinfo));
3315     info = &tinfo;
3316   }
3317 
3318   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_LUFactorNumeric, mat, fact, 0, 0));
3319   else PetscCall(PetscLogEventBegin(MAT_LUFactor, mat, fact, 0, 0));
3320   PetscUseTypeMethod(fact, lufactornumeric, mat, info);
3321   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_LUFactorNumeric, mat, fact, 0, 0));
3322   else PetscCall(PetscLogEventEnd(MAT_LUFactor, mat, fact, 0, 0));
3323   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3324   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3325   PetscFunctionReturn(PETSC_SUCCESS);
3326 }
3327 
3328 /*@
3329   MatCholeskyFactor - Performs in-place Cholesky factorization of a
3330   symmetric matrix.
3331 
3332   Collective
3333 
3334   Input Parameters:
3335 + mat  - the matrix
3336 . perm - row and column permutations
3337 - info - expected fill as ratio of original fill
3338 
3339   Level: developer
3340 
3341   Notes:
3342   See `MatLUFactor()` for the nonsymmetric case.  See also `MatGetFactor()`,
3343   `MatCholeskyFactorSymbolic()`, and `MatCholeskyFactorNumeric()`.
3344 
3345   Most users should employ the `KSP` interface for linear solvers
3346   instead of working directly with matrix algebra routines such as this.
3347   See, e.g., `KSPCreate()`.
3348 
3349   Fortran Note:
3350   A valid (non-null) `info` argument must be provided
3351 
3352 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatLUFactor()`, `MatCholeskyFactorSymbolic()`, `MatCholeskyFactorNumeric()`
3353           `MatGetOrdering()`
3354 @*/
3355 PetscErrorCode MatCholeskyFactor(Mat mat, IS perm, const MatFactorInfo *info)
3356 {
3357   MatFactorInfo tinfo;
3358 
3359   PetscFunctionBegin;
3360   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3361   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 2);
3362   if (info) PetscAssertPointer(info, 3);
3363   PetscValidType(mat, 1);
3364   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Matrix must be square");
3365   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3366   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3367   MatCheckPreallocated(mat, 1);
3368   if (!info) {
3369     PetscCall(MatFactorInfoInitialize(&tinfo));
3370     info = &tinfo;
3371   }
3372 
3373   PetscCall(PetscLogEventBegin(MAT_CholeskyFactor, mat, perm, 0, 0));
3374   PetscUseTypeMethod(mat, choleskyfactor, perm, info);
3375   PetscCall(PetscLogEventEnd(MAT_CholeskyFactor, mat, perm, 0, 0));
3376   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3377   PetscFunctionReturn(PETSC_SUCCESS);
3378 }
3379 
3380 /*@
3381   MatCholeskyFactorSymbolic - Performs symbolic Cholesky factorization
3382   of a symmetric matrix.
3383 
3384   Collective
3385 
3386   Input Parameters:
3387 + fact - the factor matrix obtained with `MatGetFactor()`
3388 . mat  - the matrix
3389 . perm - row and column permutations
3390 - info - options for factorization, includes
3391 .vb
3392           fill - expected fill as ratio of original fill.
3393           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3394                    Run with the option -info to determine an optimal value to use
3395 .ve
3396 
3397   Level: developer
3398 
3399   Notes:
3400   See `MatLUFactorSymbolic()` for the nonsymmetric case.  See also
3401   `MatCholeskyFactor()` and `MatCholeskyFactorNumeric()`.
3402 
3403   Most users should employ the `KSP` interface for linear solvers
3404   instead of working directly with matrix algebra routines such as this.
3405   See, e.g., `KSPCreate()`.
3406 
3407   Fortran Note:
3408   A valid (non-null) `info` argument must be provided
3409 
3410 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactor()`, `MatCholeskyFactorNumeric()`
3411           `MatGetOrdering()`
3412 @*/
3413 PetscErrorCode MatCholeskyFactorSymbolic(Mat fact, Mat mat, IS perm, const MatFactorInfo *info)
3414 {
3415   MatFactorInfo tinfo;
3416 
3417   PetscFunctionBegin;
3418   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3419   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3420   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 3);
3421   if (info) PetscAssertPointer(info, 4);
3422   PetscValidType(fact, 1);
3423   PetscValidType(mat, 2);
3424   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Matrix must be square");
3425   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3426   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3427   MatCheckPreallocated(mat, 2);
3428   if (!info) {
3429     PetscCall(MatFactorInfoInitialize(&tinfo));
3430     info = &tinfo;
3431   }
3432 
3433   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_CholeskyFactorSymbolic, mat, perm, 0, 0));
3434   PetscUseTypeMethod(fact, choleskyfactorsymbolic, mat, perm, info);
3435   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_CholeskyFactorSymbolic, mat, perm, 0, 0));
3436   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3437   PetscFunctionReturn(PETSC_SUCCESS);
3438 }
3439 
3440 /*@
3441   MatCholeskyFactorNumeric - Performs numeric Cholesky factorization
3442   of a symmetric matrix. Call this routine after first calling `MatGetFactor()` and
3443   `MatCholeskyFactorSymbolic()`.
3444 
3445   Collective
3446 
3447   Input Parameters:
3448 + fact - the factor matrix obtained with `MatGetFactor()`, where the factored values are stored
3449 . mat  - the initial matrix that is to be factored
3450 - info - options for factorization
3451 
3452   Level: developer
3453 
3454   Note:
3455   Most users should employ the `KSP` interface for linear solvers
3456   instead of working directly with matrix algebra routines such as this.
3457   See, e.g., `KSPCreate()`.
3458 
3459   Fortran Note:
3460   A valid (non-null) `info` argument must be provided
3461 
3462 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatCholeskyFactorSymbolic()`, `MatCholeskyFactor()`, `MatLUFactorNumeric()`
3463 @*/
3464 PetscErrorCode MatCholeskyFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3465 {
3466   MatFactorInfo tinfo;
3467 
3468   PetscFunctionBegin;
3469   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3470   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3471   PetscValidType(fact, 1);
3472   PetscValidType(mat, 2);
3473   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3474   PetscCheck(mat->rmap->N == (fact)->rmap->N && mat->cmap->N == (fact)->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Mat fact: global dim %" PetscInt_FMT " should = %" PetscInt_FMT " %" PetscInt_FMT " should = %" PetscInt_FMT,
3475              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3476   MatCheckPreallocated(mat, 2);
3477   if (!info) {
3478     PetscCall(MatFactorInfoInitialize(&tinfo));
3479     info = &tinfo;
3480   }
3481 
3482   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_CholeskyFactorNumeric, mat, fact, 0, 0));
3483   else PetscCall(PetscLogEventBegin(MAT_CholeskyFactor, mat, fact, 0, 0));
3484   PetscUseTypeMethod(fact, choleskyfactornumeric, mat, info);
3485   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_CholeskyFactorNumeric, mat, fact, 0, 0));
3486   else PetscCall(PetscLogEventEnd(MAT_CholeskyFactor, mat, fact, 0, 0));
3487   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3488   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3489   PetscFunctionReturn(PETSC_SUCCESS);
3490 }
3491 
3492 /*@
3493   MatQRFactor - Performs in-place QR factorization of matrix.
3494 
3495   Collective
3496 
3497   Input Parameters:
3498 + mat  - the matrix
3499 . col  - column permutation
3500 - info - options for factorization, includes
3501 .vb
3502           fill - expected fill as ratio of original fill.
3503           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3504                    Run with the option -info to determine an optimal value to use
3505 .ve
3506 
3507   Level: developer
3508 
3509   Notes:
3510   Most users should employ the `KSP` interface for linear solvers
3511   instead of working directly with matrix algebra routines such as this.
3512   See, e.g., `KSPCreate()`.
3513 
3514   This changes the state of the matrix to a factored matrix; it cannot be used
3515   for example with `MatSetValues()` unless one first calls `MatSetUnfactored()`.
3516 
3517   Fortran Note:
3518   A valid (non-null) `info` argument must be provided
3519 
3520 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatQRFactorSymbolic()`, `MatQRFactorNumeric()`, `MatLUFactor()`,
3521           `MatSetUnfactored()`
3522 @*/
3523 PetscErrorCode MatQRFactor(Mat mat, IS col, const MatFactorInfo *info)
3524 {
3525   PetscFunctionBegin;
3526   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3527   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 2);
3528   if (info) PetscAssertPointer(info, 3);
3529   PetscValidType(mat, 1);
3530   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3531   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3532   MatCheckPreallocated(mat, 1);
3533   PetscCall(PetscLogEventBegin(MAT_QRFactor, mat, col, 0, 0));
3534   PetscUseMethod(mat, "MatQRFactor_C", (Mat, IS, const MatFactorInfo *), (mat, col, info));
3535   PetscCall(PetscLogEventEnd(MAT_QRFactor, mat, col, 0, 0));
3536   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3537   PetscFunctionReturn(PETSC_SUCCESS);
3538 }
3539 
3540 /*@
3541   MatQRFactorSymbolic - Performs symbolic QR factorization of matrix.
3542   Call this routine after `MatGetFactor()` but before calling `MatQRFactorNumeric()`.
3543 
3544   Collective
3545 
3546   Input Parameters:
3547 + fact - the factor matrix obtained with `MatGetFactor()`
3548 . mat  - the matrix
3549 . col  - column permutation
3550 - info - options for factorization, includes
3551 .vb
3552           fill - expected fill as ratio of original fill.
3553           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3554                    Run with the option -info to determine an optimal value to use
3555 .ve
3556 
3557   Level: developer
3558 
3559   Note:
3560   Most users should employ the `KSP` interface for linear solvers
3561   instead of working directly with matrix algebra routines such as this.
3562   See, e.g., `KSPCreate()`.
3563 
3564   Fortran Note:
3565   A valid (non-null) `info` argument must be provided
3566 
3567 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatQRFactor()`, `MatQRFactorNumeric()`, `MatLUFactor()`, `MatFactorInfoInitialize()`
3568 @*/
3569 PetscErrorCode MatQRFactorSymbolic(Mat fact, Mat mat, IS col, const MatFactorInfo *info)
3570 {
3571   MatFactorInfo tinfo;
3572 
3573   PetscFunctionBegin;
3574   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3575   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3576   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3577   if (info) PetscAssertPointer(info, 4);
3578   PetscValidType(fact, 1);
3579   PetscValidType(mat, 2);
3580   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3581   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3582   MatCheckPreallocated(mat, 2);
3583   if (!info) {
3584     PetscCall(MatFactorInfoInitialize(&tinfo));
3585     info = &tinfo;
3586   }
3587 
3588   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_QRFactorSymbolic, fact, mat, col, 0));
3589   PetscUseMethod(fact, "MatQRFactorSymbolic_C", (Mat, Mat, IS, const MatFactorInfo *), (fact, mat, col, info));
3590   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_QRFactorSymbolic, fact, mat, col, 0));
3591   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3592   PetscFunctionReturn(PETSC_SUCCESS);
3593 }
3594 
3595 /*@
3596   MatQRFactorNumeric - Performs numeric QR factorization of a matrix.
3597   Call this routine after first calling `MatGetFactor()`, and `MatQRFactorSymbolic()`.
3598 
3599   Collective
3600 
3601   Input Parameters:
3602 + fact - the factor matrix obtained with `MatGetFactor()`
3603 . mat  - the matrix
3604 - info - options for factorization
3605 
3606   Level: developer
3607 
3608   Notes:
3609   See `MatQRFactor()` for in-place factorization.
3610 
3611   Most users should employ the `KSP` interface for linear solvers
3612   instead of working directly with matrix algebra routines such as this.
3613   See, e.g., `KSPCreate()`.
3614 
3615   Fortran Note:
3616   A valid (non-null) `info` argument must be provided
3617 
3618 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatQRFactor()`, `MatQRFactorSymbolic()`, `MatLUFactor()`
3619 @*/
3620 PetscErrorCode MatQRFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3621 {
3622   MatFactorInfo tinfo;
3623 
3624   PetscFunctionBegin;
3625   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3626   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3627   PetscValidType(fact, 1);
3628   PetscValidType(mat, 2);
3629   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3630   PetscCheck(mat->rmap->N == fact->rmap->N && mat->cmap->N == fact->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Mat fact: global dimensions are different %" PetscInt_FMT " should = %" PetscInt_FMT " %" PetscInt_FMT " should = %" PetscInt_FMT,
3631              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3632 
3633   MatCheckPreallocated(mat, 2);
3634   if (!info) {
3635     PetscCall(MatFactorInfoInitialize(&tinfo));
3636     info = &tinfo;
3637   }
3638 
3639   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_QRFactorNumeric, mat, fact, 0, 0));
3640   else PetscCall(PetscLogEventBegin(MAT_QRFactor, mat, fact, 0, 0));
3641   PetscUseMethod(fact, "MatQRFactorNumeric_C", (Mat, Mat, const MatFactorInfo *), (fact, mat, info));
3642   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_QRFactorNumeric, mat, fact, 0, 0));
3643   else PetscCall(PetscLogEventEnd(MAT_QRFactor, mat, fact, 0, 0));
3644   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3645   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3646   PetscFunctionReturn(PETSC_SUCCESS);
3647 }
3648 
3649 /*@
3650   MatSolve - Solves $A x = b$, given a factored matrix.
3651 
3652   Neighbor-wise Collective
3653 
3654   Input Parameters:
3655 + mat - the factored matrix
3656 - b   - the right-hand-side vector
3657 
3658   Output Parameter:
3659 . x - the result vector
3660 
3661   Level: developer
3662 
3663   Notes:
3664   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3665   call `MatSolve`(A,x,x).
3666 
3667   Most users should employ the `KSP` interface for linear solvers
3668   instead of working directly with matrix algebra routines such as this.
3669   See, e.g., `KSPCreate()`.
3670 
3671 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactor()`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`
3672 @*/
3673 PetscErrorCode MatSolve(Mat mat, Vec b, Vec x)
3674 {
3675   PetscFunctionBegin;
3676   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3677   PetscValidType(mat, 1);
3678   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3679   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3680   PetscCheckSameComm(mat, 1, b, 2);
3681   PetscCheckSameComm(mat, 1, x, 3);
3682   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3683   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
3684   PetscCheck(mat->rmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, b->map->N);
3685   PetscCheck(mat->rmap->n == b->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, b->map->n);
3686   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3687   MatCheckPreallocated(mat, 1);
3688 
3689   PetscCall(PetscLogEventBegin(MAT_Solve, mat, b, x, 0));
3690   PetscCall(VecFlag(x, mat->factorerrortype));
3691   if (mat->factorerrortype) {
3692     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
3693   } else PetscUseTypeMethod(mat, solve, b, x);
3694   PetscCall(PetscLogEventEnd(MAT_Solve, mat, b, x, 0));
3695   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3696   PetscFunctionReturn(PETSC_SUCCESS);
3697 }
3698 
3699 static PetscErrorCode MatMatSolve_Basic(Mat A, Mat B, Mat X, PetscBool trans)
3700 {
3701   Vec      b, x;
3702   PetscInt N, i;
3703   PetscErrorCode (*f)(Mat, Vec, Vec);
3704   PetscBool Abound, Bneedconv = PETSC_FALSE, Xneedconv = PETSC_FALSE;
3705 
3706   PetscFunctionBegin;
3707   if (A->factorerrortype) {
3708     PetscCall(PetscInfo(A, "MatFactorError %d\n", A->factorerrortype));
3709     PetscCall(MatSetInf(X));
3710     PetscFunctionReturn(PETSC_SUCCESS);
3711   }
3712   f = (!trans || (!A->ops->solvetranspose && A->symmetric)) ? A->ops->solve : A->ops->solvetranspose;
3713   PetscCheck(f, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Mat type %s", ((PetscObject)A)->type_name);
3714   PetscCall(MatBoundToCPU(A, &Abound));
3715   if (!Abound) {
3716     PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &Bneedconv, MATSEQDENSE, MATMPIDENSE, ""));
3717     PetscCall(PetscObjectTypeCompareAny((PetscObject)X, &Xneedconv, MATSEQDENSE, MATMPIDENSE, ""));
3718   }
3719 #if PetscDefined(HAVE_CUDA)
3720   if (Bneedconv) PetscCall(MatConvert(B, MATDENSECUDA, MAT_INPLACE_MATRIX, &B));
3721   if (Xneedconv) PetscCall(MatConvert(X, MATDENSECUDA, MAT_INPLACE_MATRIX, &X));
3722 #elif PetscDefined(HAVE_HIP)
3723   if (Bneedconv) PetscCall(MatConvert(B, MATDENSEHIP, MAT_INPLACE_MATRIX, &B));
3724   if (Xneedconv) PetscCall(MatConvert(X, MATDENSEHIP, MAT_INPLACE_MATRIX, &X));
3725 #endif
3726   PetscCall(MatGetSize(B, NULL, &N));
3727   for (i = 0; i < N; i++) {
3728     PetscCall(MatDenseGetColumnVecRead(B, i, &b));
3729     PetscCall(MatDenseGetColumnVecWrite(X, i, &x));
3730     PetscCall((*f)(A, b, x));
3731     PetscCall(MatDenseRestoreColumnVecWrite(X, i, &x));
3732     PetscCall(MatDenseRestoreColumnVecRead(B, i, &b));
3733   }
3734   if (Bneedconv) PetscCall(MatConvert(B, MATDENSE, MAT_INPLACE_MATRIX, &B));
3735   if (Xneedconv) PetscCall(MatConvert(X, MATDENSE, MAT_INPLACE_MATRIX, &X));
3736   PetscFunctionReturn(PETSC_SUCCESS);
3737 }
3738 
3739 /*@
3740   MatMatSolve - Solves $A X = B$, given a factored matrix.
3741 
3742   Neighbor-wise Collective
3743 
3744   Input Parameters:
3745 + A - the factored matrix
3746 - B - the right-hand-side matrix `MATDENSE` (or sparse `MATAIJ`-- when using MUMPS)
3747 
3748   Output Parameter:
3749 . X - the result matrix (dense matrix)
3750 
3751   Level: developer
3752 
3753   Note:
3754   If `B` is a `MATDENSE` matrix then one can call `MatMatSolve`(A,B,B) except with `MATSOLVERMKL_CPARDISO`;
3755   otherwise, `B` and `X` cannot be the same.
3756 
3757 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolve()`, `MatMatSolveTranspose()`, `MatLUFactor()`, `MatCholeskyFactor()`
3758 @*/
3759 PetscErrorCode MatMatSolve(Mat A, Mat B, Mat X)
3760 {
3761   PetscFunctionBegin;
3762   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3763   PetscValidType(A, 1);
3764   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
3765   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3766   PetscCheckSameComm(A, 1, B, 2);
3767   PetscCheckSameComm(A, 1, X, 3);
3768   PetscCheck(A->cmap->N == X->rmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat X: global dim %" PetscInt_FMT " %" PetscInt_FMT, A->cmap->N, X->rmap->N);
3769   PetscCheck(A->rmap->N == B->rmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat B: global dim %" PetscInt_FMT " %" PetscInt_FMT, A->rmap->N, B->rmap->N);
3770   PetscCheck(X->cmap->N == B->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Solution matrix must have same number of columns as rhs matrix");
3771   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3772   MatCheckPreallocated(A, 1);
3773 
3774   PetscCall(PetscLogEventBegin(MAT_MatSolve, A, B, X, 0));
3775   if (!A->ops->matsolve) {
3776     PetscCall(PetscInfo(A, "Mat type %s using basic MatMatSolve\n", ((PetscObject)A)->type_name));
3777     PetscCall(MatMatSolve_Basic(A, B, X, PETSC_FALSE));
3778   } else PetscUseTypeMethod(A, matsolve, B, X);
3779   PetscCall(PetscLogEventEnd(MAT_MatSolve, A, B, X, 0));
3780   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3781   PetscFunctionReturn(PETSC_SUCCESS);
3782 }
3783 
3784 /*@
3785   MatMatSolveTranspose - Solves $A^T X = B $, given a factored matrix.
3786 
3787   Neighbor-wise Collective
3788 
3789   Input Parameters:
3790 + A - the factored matrix
3791 - B - the right-hand-side matrix  (`MATDENSE` matrix)
3792 
3793   Output Parameter:
3794 . X - the result matrix (dense matrix)
3795 
3796   Level: developer
3797 
3798   Note:
3799   The matrices `B` and `X` cannot be the same.  I.e., one cannot
3800   call `MatMatSolveTranspose`(A,X,X).
3801 
3802 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolveTranspose()`, `MatMatSolve()`, `MatLUFactor()`, `MatCholeskyFactor()`
3803 @*/
3804 PetscErrorCode MatMatSolveTranspose(Mat A, Mat B, Mat X)
3805 {
3806   PetscFunctionBegin;
3807   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3808   PetscValidType(A, 1);
3809   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
3810   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3811   PetscCheckSameComm(A, 1, B, 2);
3812   PetscCheckSameComm(A, 1, X, 3);
3813   PetscCheck(X != B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_IDN, "X and B must be different matrices");
3814   PetscCheck(A->cmap->N == X->rmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat X: global dim %" PetscInt_FMT " %" PetscInt_FMT, A->cmap->N, X->rmap->N);
3815   PetscCheck(A->rmap->N == B->rmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat B: global dim %" PetscInt_FMT " %" PetscInt_FMT, A->rmap->N, B->rmap->N);
3816   PetscCheck(A->rmap->n == B->rmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat A,Mat B: local dim %" PetscInt_FMT " %" PetscInt_FMT, A->rmap->n, B->rmap->n);
3817   PetscCheck(X->cmap->N >= B->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Solution matrix must have same number of columns as rhs matrix");
3818   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3819   MatCheckPreallocated(A, 1);
3820 
3821   PetscCall(PetscLogEventBegin(MAT_MatSolve, A, B, X, 0));
3822   if (!A->ops->matsolvetranspose) {
3823     PetscCall(PetscInfo(A, "Mat type %s using basic MatMatSolveTranspose\n", ((PetscObject)A)->type_name));
3824     PetscCall(MatMatSolve_Basic(A, B, X, PETSC_TRUE));
3825   } else PetscUseTypeMethod(A, matsolvetranspose, B, X);
3826   PetscCall(PetscLogEventEnd(MAT_MatSolve, A, B, X, 0));
3827   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3828   PetscFunctionReturn(PETSC_SUCCESS);
3829 }
3830 
3831 /*@
3832   MatMatTransposeSolve - Solves $A X = B^T$, given a factored matrix.
3833 
3834   Neighbor-wise Collective
3835 
3836   Input Parameters:
3837 + A  - the factored matrix
3838 - Bt - the transpose of right-hand-side matrix as a `MATDENSE`
3839 
3840   Output Parameter:
3841 . X - the result matrix (dense matrix)
3842 
3843   Level: developer
3844 
3845   Note:
3846   For MUMPS, it only supports centralized sparse compressed column format on the host processor for right-hand side matrix. User must create `Bt` in sparse compressed row
3847   format on the host processor and call `MatMatTransposeSolve()` to implement MUMPS' `MatMatSolve()`.
3848 
3849 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatMatSolve()`, `MatMatSolveTranspose()`, `MatLUFactor()`, `MatCholeskyFactor()`
3850 @*/
3851 PetscErrorCode MatMatTransposeSolve(Mat A, Mat Bt, Mat X)
3852 {
3853   PetscFunctionBegin;
3854   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3855   PetscValidType(A, 1);
3856   PetscValidHeaderSpecific(Bt, MAT_CLASSID, 2);
3857   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3858   PetscCheckSameComm(A, 1, Bt, 2);
3859   PetscCheckSameComm(A, 1, X, 3);
3860 
3861   PetscCheck(X != Bt, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_IDN, "X and B must be different matrices");
3862   PetscCheck(A->cmap->N == X->rmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat X: global dim %" PetscInt_FMT " %" PetscInt_FMT, A->cmap->N, X->rmap->N);
3863   PetscCheck(A->rmap->N == Bt->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat Bt: global dim %" PetscInt_FMT " %" PetscInt_FMT, A->rmap->N, Bt->cmap->N);
3864   PetscCheck(X->cmap->N >= Bt->rmap->N, PetscObjectComm((PetscObject)X), PETSC_ERR_ARG_SIZ, "Solution matrix must have same number of columns as row number of the rhs matrix");
3865   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3866   PetscCheck(A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
3867   MatCheckPreallocated(A, 1);
3868 
3869   PetscCall(PetscLogEventBegin(MAT_MatTrSolve, A, Bt, X, 0));
3870   PetscUseTypeMethod(A, mattransposesolve, Bt, X);
3871   PetscCall(PetscLogEventEnd(MAT_MatTrSolve, A, Bt, X, 0));
3872   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3873   PetscFunctionReturn(PETSC_SUCCESS);
3874 }
3875 
3876 /*@
3877   MatForwardSolve - Solves $ L x = b $, given a factored matrix, $A = LU $, or
3878   $U^T*D^(1/2) x = b$, given a factored symmetric matrix, $A = U^T*D*U$,
3879 
3880   Neighbor-wise Collective
3881 
3882   Input Parameters:
3883 + mat - the factored matrix
3884 - b   - the right-hand-side vector
3885 
3886   Output Parameter:
3887 . x - the result vector
3888 
3889   Level: developer
3890 
3891   Notes:
3892   `MatSolve()` should be used for most applications, as it performs
3893   a forward solve followed by a backward solve.
3894 
3895   The vectors `b` and `x` cannot be the same,  i.e., one cannot
3896   call `MatForwardSolve`(A,x,x).
3897 
3898   For matrix in `MATSEQBAIJ` format with block size larger than 1,
3899   the diagonal blocks are not implemented as $D = D^(1/2) * D^(1/2)$ yet.
3900   `MatForwardSolve()` solves $U^T*D y = b$, and
3901   `MatBackwardSolve()` solves $U x = y$.
3902   Thus they do not provide a symmetric preconditioner.
3903 
3904 .seealso: [](ch_matrices), `Mat`, `MatBackwardSolve()`, `MatGetFactor()`, `MatSolve()`
3905 @*/
3906 PetscErrorCode MatForwardSolve(Mat mat, Vec b, Vec x)
3907 {
3908   PetscFunctionBegin;
3909   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3910   PetscValidType(mat, 1);
3911   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3912   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3913   PetscCheckSameComm(mat, 1, b, 2);
3914   PetscCheckSameComm(mat, 1, x, 3);
3915   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3916   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
3917   PetscCheck(mat->rmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, b->map->N);
3918   PetscCheck(mat->rmap->n == b->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, b->map->n);
3919   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3920   MatCheckPreallocated(mat, 1);
3921 
3922   PetscCall(PetscLogEventBegin(MAT_ForwardSolve, mat, b, x, 0));
3923   PetscUseTypeMethod(mat, forwardsolve, b, x);
3924   PetscCall(PetscLogEventEnd(MAT_ForwardSolve, mat, b, x, 0));
3925   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3926   PetscFunctionReturn(PETSC_SUCCESS);
3927 }
3928 
3929 /*@
3930   MatBackwardSolve - Solves $U x = b$, given a factored matrix, $A = LU$.
3931   $D^(1/2) U x = b$, given a factored symmetric matrix, $A = U^T*D*U$,
3932 
3933   Neighbor-wise Collective
3934 
3935   Input Parameters:
3936 + mat - the factored matrix
3937 - b   - the right-hand-side vector
3938 
3939   Output Parameter:
3940 . x - the result vector
3941 
3942   Level: developer
3943 
3944   Notes:
3945   `MatSolve()` should be used for most applications, as it performs
3946   a forward solve followed by a backward solve.
3947 
3948   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3949   call `MatBackwardSolve`(A,x,x).
3950 
3951   For matrix in `MATSEQBAIJ` format with block size larger than 1,
3952   the diagonal blocks are not implemented as $D = D^(1/2) * D^(1/2)$ yet.
3953   `MatForwardSolve()` solves $U^T*D y = b$, and
3954   `MatBackwardSolve()` solves $U x = y$.
3955   Thus they do not provide a symmetric preconditioner.
3956 
3957 .seealso: [](ch_matrices), `Mat`, `MatForwardSolve()`, `MatGetFactor()`, `MatSolve()`
3958 @*/
3959 PetscErrorCode MatBackwardSolve(Mat mat, Vec b, Vec x)
3960 {
3961   PetscFunctionBegin;
3962   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3963   PetscValidType(mat, 1);
3964   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3965   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3966   PetscCheckSameComm(mat, 1, b, 2);
3967   PetscCheckSameComm(mat, 1, x, 3);
3968   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3969   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
3970   PetscCheck(mat->rmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, b->map->N);
3971   PetscCheck(mat->rmap->n == b->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, b->map->n);
3972   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3973   MatCheckPreallocated(mat, 1);
3974 
3975   PetscCall(PetscLogEventBegin(MAT_BackwardSolve, mat, b, x, 0));
3976   PetscUseTypeMethod(mat, backwardsolve, b, x);
3977   PetscCall(PetscLogEventEnd(MAT_BackwardSolve, mat, b, x, 0));
3978   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3979   PetscFunctionReturn(PETSC_SUCCESS);
3980 }
3981 
3982 /*@
3983   MatSolveAdd - Computes $x = y + A^{-1}*b$, given a factored matrix.
3984 
3985   Neighbor-wise Collective
3986 
3987   Input Parameters:
3988 + mat - the factored matrix
3989 . b   - the right-hand-side vector
3990 - y   - the vector to be added to
3991 
3992   Output Parameter:
3993 . x - the result vector
3994 
3995   Level: developer
3996 
3997   Note:
3998   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3999   call `MatSolveAdd`(A,x,y,x).
4000 
4001 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatSolve()`, `MatGetFactor()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`
4002 @*/
4003 PetscErrorCode MatSolveAdd(Mat mat, Vec b, Vec y, Vec x)
4004 {
4005   PetscScalar one = 1.0;
4006   Vec         tmp;
4007 
4008   PetscFunctionBegin;
4009   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4010   PetscValidType(mat, 1);
4011   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
4012   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4013   PetscValidHeaderSpecific(x, VEC_CLASSID, 4);
4014   PetscCheckSameComm(mat, 1, b, 2);
4015   PetscCheckSameComm(mat, 1, y, 3);
4016   PetscCheckSameComm(mat, 1, x, 4);
4017   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4018   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
4019   PetscCheck(mat->rmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, b->map->N);
4020   PetscCheck(mat->rmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, y->map->N);
4021   PetscCheck(mat->rmap->n == b->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, b->map->n);
4022   PetscCheck(x->map->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Vec x,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, x->map->n, y->map->n);
4023   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4024   MatCheckPreallocated(mat, 1);
4025 
4026   PetscCall(PetscLogEventBegin(MAT_SolveAdd, mat, b, x, y));
4027   PetscCall(VecFlag(x, mat->factorerrortype));
4028   if (mat->factorerrortype) {
4029     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4030   } else if (mat->ops->solveadd) {
4031     PetscUseTypeMethod(mat, solveadd, b, y, x);
4032   } else {
4033     /* do the solve then the add manually */
4034     if (x != y) {
4035       PetscCall(MatSolve(mat, b, x));
4036       PetscCall(VecAXPY(x, one, y));
4037     } else {
4038       PetscCall(VecDuplicate(x, &tmp));
4039       PetscCall(VecCopy(x, tmp));
4040       PetscCall(MatSolve(mat, b, x));
4041       PetscCall(VecAXPY(x, one, tmp));
4042       PetscCall(VecDestroy(&tmp));
4043     }
4044   }
4045   PetscCall(PetscLogEventEnd(MAT_SolveAdd, mat, b, x, y));
4046   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4047   PetscFunctionReturn(PETSC_SUCCESS);
4048 }
4049 
4050 /*@
4051   MatSolveTranspose - Solves $A^T x = b$, given a factored matrix.
4052 
4053   Neighbor-wise Collective
4054 
4055   Input Parameters:
4056 + mat - the factored matrix
4057 - b   - the right-hand-side vector
4058 
4059   Output Parameter:
4060 . x - the result vector
4061 
4062   Level: developer
4063 
4064   Notes:
4065   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4066   call `MatSolveTranspose`(A,x,x).
4067 
4068   Most users should employ the `KSP` interface for linear solvers
4069   instead of working directly with matrix algebra routines such as this.
4070   See, e.g., `KSPCreate()`.
4071 
4072 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `KSP`, `MatSolve()`, `MatSolveAdd()`, `MatSolveTransposeAdd()`
4073 @*/
4074 PetscErrorCode MatSolveTranspose(Mat mat, Vec b, Vec x)
4075 {
4076   PetscErrorCode (*f)(Mat, Vec, Vec) = (!mat->ops->solvetranspose && mat->symmetric) ? mat->ops->solve : mat->ops->solvetranspose;
4077 
4078   PetscFunctionBegin;
4079   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4080   PetscValidType(mat, 1);
4081   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4082   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
4083   PetscCheckSameComm(mat, 1, b, 2);
4084   PetscCheckSameComm(mat, 1, x, 3);
4085   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4086   PetscCheck(mat->rmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, x->map->N);
4087   PetscCheck(mat->cmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, b->map->N);
4088   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4089   MatCheckPreallocated(mat, 1);
4090   PetscCall(PetscLogEventBegin(MAT_SolveTranspose, mat, b, x, 0));
4091   PetscCall(VecFlag(x, mat->factorerrortype));
4092   if (mat->factorerrortype) {
4093     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4094   } else {
4095     PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Matrix type %s", ((PetscObject)mat)->type_name);
4096     PetscCall((*f)(mat, b, x));
4097   }
4098   PetscCall(PetscLogEventEnd(MAT_SolveTranspose, mat, b, x, 0));
4099   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4100   PetscFunctionReturn(PETSC_SUCCESS);
4101 }
4102 
4103 /*@
4104   MatSolveTransposeAdd - Computes $x = y + A^{-T} b$
4105   factored matrix.
4106 
4107   Neighbor-wise Collective
4108 
4109   Input Parameters:
4110 + mat - the factored matrix
4111 . b   - the right-hand-side vector
4112 - y   - the vector to be added to
4113 
4114   Output Parameter:
4115 . x - the result vector
4116 
4117   Level: developer
4118 
4119   Note:
4120   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4121   call `MatSolveTransposeAdd`(A,x,y,x).
4122 
4123 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatSolve()`, `MatSolveAdd()`, `MatSolveTranspose()`
4124 @*/
4125 PetscErrorCode MatSolveTransposeAdd(Mat mat, Vec b, Vec y, Vec x)
4126 {
4127   PetscScalar one = 1.0;
4128   Vec         tmp;
4129   PetscErrorCode (*f)(Mat, Vec, Vec, Vec) = (!mat->ops->solvetransposeadd && mat->symmetric) ? mat->ops->solveadd : mat->ops->solvetransposeadd;
4130 
4131   PetscFunctionBegin;
4132   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4133   PetscValidType(mat, 1);
4134   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
4135   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4136   PetscValidHeaderSpecific(x, VEC_CLASSID, 4);
4137   PetscCheckSameComm(mat, 1, b, 2);
4138   PetscCheckSameComm(mat, 1, y, 3);
4139   PetscCheckSameComm(mat, 1, x, 4);
4140   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4141   PetscCheck(mat->rmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, x->map->N);
4142   PetscCheck(mat->cmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, b->map->N);
4143   PetscCheck(mat->cmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, y->map->N);
4144   PetscCheck(x->map->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Vec x,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, x->map->n, y->map->n);
4145   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4146   MatCheckPreallocated(mat, 1);
4147 
4148   PetscCall(PetscLogEventBegin(MAT_SolveTransposeAdd, mat, b, x, y));
4149   PetscCall(VecFlag(x, mat->factorerrortype));
4150   if (mat->factorerrortype) {
4151     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4152   } else if (f) {
4153     PetscCall((*f)(mat, b, y, x));
4154   } else {
4155     /* do the solve then the add manually */
4156     if (x != y) {
4157       PetscCall(MatSolveTranspose(mat, b, x));
4158       PetscCall(VecAXPY(x, one, y));
4159     } else {
4160       PetscCall(VecDuplicate(x, &tmp));
4161       PetscCall(VecCopy(x, tmp));
4162       PetscCall(MatSolveTranspose(mat, b, x));
4163       PetscCall(VecAXPY(x, one, tmp));
4164       PetscCall(VecDestroy(&tmp));
4165     }
4166   }
4167   PetscCall(PetscLogEventEnd(MAT_SolveTransposeAdd, mat, b, x, y));
4168   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4169   PetscFunctionReturn(PETSC_SUCCESS);
4170 }
4171 
4172 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
4173 /*@
4174   MatSOR - Computes relaxation (SOR, Gauss-Seidel) sweeps.
4175 
4176   Neighbor-wise Collective
4177 
4178   Input Parameters:
4179 + mat   - the matrix
4180 . b     - the right-hand side
4181 . omega - the relaxation factor
4182 . flag  - flag indicating the type of SOR (see below)
4183 . shift - diagonal shift
4184 . its   - the number of iterations
4185 - lits  - the number of local iterations
4186 
4187   Output Parameter:
4188 . x - the solution (can contain an initial guess, use option `SOR_ZERO_INITIAL_GUESS` to indicate no guess)
4189 
4190   SOR Flags:
4191 +     `SOR_FORWARD_SWEEP` - forward SOR
4192 .     `SOR_BACKWARD_SWEEP` - backward SOR
4193 .     `SOR_SYMMETRIC_SWEEP` - SSOR (symmetric SOR)
4194 .     `SOR_LOCAL_FORWARD_SWEEP` - local forward SOR
4195 .     `SOR_LOCAL_BACKWARD_SWEEP` - local forward SOR
4196 .     `SOR_LOCAL_SYMMETRIC_SWEEP` - local SSOR
4197 .     `SOR_EISENSTAT` - SOR with Eisenstat trick
4198 .     `SOR_APPLY_UPPER`, `SOR_APPLY_LOWER` - applies
4199   upper/lower triangular part of matrix to
4200   vector (with omega)
4201 -     `SOR_ZERO_INITIAL_GUESS` - zero initial guess
4202 
4203   Level: developer
4204 
4205   Notes:
4206   `SOR_LOCAL_FORWARD_SWEEP`, `SOR_LOCAL_BACKWARD_SWEEP`, and
4207   `SOR_LOCAL_SYMMETRIC_SWEEP` perform separate independent smoothings
4208   on each processor.
4209 
4210   Application programmers will not generally use `MatSOR()` directly,
4211   but instead will employ the `KSP`/`PC` interface.
4212 
4213   For `MATBAIJ`, `MATSBAIJ`, and `MATAIJ` matrices with Inodes this does a block SOR smoothing, otherwise it does a pointwise smoothing
4214 
4215   Most users should employ the `KSP` interface for linear solvers
4216   instead of working directly with matrix algebra routines such as this.
4217   See, e.g., `KSPCreate()`.
4218 
4219   Vectors `x` and `b` CANNOT be the same
4220 
4221   The flags are implemented as bitwise inclusive or operations.
4222   For example, use (`SOR_ZERO_INITIAL_GUESS` | `SOR_SYMMETRIC_SWEEP`)
4223   to specify a zero initial guess for SSOR.
4224 
4225   Developer Note:
4226   We should add block SOR support for `MATAIJ` matrices with block size set to great than one and no inodes
4227 
4228 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `KSP`, `PC`, `MatGetFactor()`
4229 @*/
4230 PetscErrorCode MatSOR(Mat mat, Vec b, PetscReal omega, MatSORType flag, PetscReal shift, PetscInt its, PetscInt lits, Vec x)
4231 {
4232   PetscFunctionBegin;
4233   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4234   PetscValidType(mat, 1);
4235   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4236   PetscValidHeaderSpecific(x, VEC_CLASSID, 8);
4237   PetscCheckSameComm(mat, 1, b, 2);
4238   PetscCheckSameComm(mat, 1, x, 8);
4239   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4240   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4241   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
4242   PetscCheck(mat->rmap->N == b->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, b->map->N);
4243   PetscCheck(mat->rmap->n == b->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec b: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, b->map->n);
4244   PetscCheck(its > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires global its %" PetscInt_FMT " positive", its);
4245   PetscCheck(lits > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires local its %" PetscInt_FMT " positive", lits);
4246   PetscCheck(b != x, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "b and x vector cannot be the same");
4247 
4248   MatCheckPreallocated(mat, 1);
4249   PetscCall(PetscLogEventBegin(MAT_SOR, mat, b, x, 0));
4250   PetscUseTypeMethod(mat, sor, b, omega, flag, shift, its, lits, x);
4251   PetscCall(PetscLogEventEnd(MAT_SOR, mat, b, x, 0));
4252   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4253   PetscFunctionReturn(PETSC_SUCCESS);
4254 }
4255 
4256 /*
4257       Default matrix copy routine.
4258 */
4259 PetscErrorCode MatCopy_Basic(Mat A, Mat B, MatStructure str)
4260 {
4261   PetscInt           i, rstart = 0, rend = 0, nz;
4262   const PetscInt    *cwork;
4263   const PetscScalar *vwork;
4264 
4265   PetscFunctionBegin;
4266   if (B->assembled) PetscCall(MatZeroEntries(B));
4267   if (str == SAME_NONZERO_PATTERN) {
4268     PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
4269     for (i = rstart; i < rend; i++) {
4270       PetscCall(MatGetRow(A, i, &nz, &cwork, &vwork));
4271       PetscCall(MatSetValues(B, 1, &i, nz, cwork, vwork, INSERT_VALUES));
4272       PetscCall(MatRestoreRow(A, i, &nz, &cwork, &vwork));
4273     }
4274   } else {
4275     PetscCall(MatAYPX(B, 0.0, A, str));
4276   }
4277   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
4278   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
4279   PetscFunctionReturn(PETSC_SUCCESS);
4280 }
4281 
4282 /*@
4283   MatCopy - Copies a matrix to another matrix.
4284 
4285   Collective
4286 
4287   Input Parameters:
4288 + A   - the matrix
4289 - str - `SAME_NONZERO_PATTERN` or `DIFFERENT_NONZERO_PATTERN`
4290 
4291   Output Parameter:
4292 . B - where the copy is put
4293 
4294   Level: intermediate
4295 
4296   Notes:
4297   If you use `SAME_NONZERO_PATTERN`, then the two matrices must have the same nonzero pattern or the routine will crash.
4298 
4299   `MatCopy()` copies the matrix entries of a matrix to another existing
4300   matrix (after first zeroing the second matrix).  A related routine is
4301   `MatConvert()`, which first creates a new matrix and then copies the data.
4302 
4303 .seealso: [](ch_matrices), `Mat`, `MatConvert()`, `MatDuplicate()`
4304 @*/
4305 PetscErrorCode MatCopy(Mat A, Mat B, MatStructure str)
4306 {
4307   PetscInt i;
4308 
4309   PetscFunctionBegin;
4310   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
4311   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
4312   PetscValidType(A, 1);
4313   PetscValidType(B, 2);
4314   PetscCheckSameComm(A, 1, B, 2);
4315   MatCheckPreallocated(B, 2);
4316   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4317   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4318   PetscCheck(A->rmap->N == B->rmap->N && A->cmap->N == B->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat B: global dim (%" PetscInt_FMT ",%" PetscInt_FMT ") (%" PetscInt_FMT ",%" PetscInt_FMT ")", A->rmap->N, B->rmap->N,
4319              A->cmap->N, B->cmap->N);
4320   MatCheckPreallocated(A, 1);
4321   if (A == B) PetscFunctionReturn(PETSC_SUCCESS);
4322 
4323   PetscCall(PetscLogEventBegin(MAT_Copy, A, B, 0, 0));
4324   if (A->ops->copy) PetscUseTypeMethod(A, copy, B, str);
4325   else PetscCall(MatCopy_Basic(A, B, str));
4326 
4327   B->stencil.dim = A->stencil.dim;
4328   B->stencil.noc = A->stencil.noc;
4329   for (i = 0; i <= A->stencil.dim + (A->stencil.noc ? 0 : -1); i++) {
4330     B->stencil.dims[i]   = A->stencil.dims[i];
4331     B->stencil.starts[i] = A->stencil.starts[i];
4332   }
4333 
4334   PetscCall(PetscLogEventEnd(MAT_Copy, A, B, 0, 0));
4335   PetscCall(PetscObjectStateIncrease((PetscObject)B));
4336   PetscFunctionReturn(PETSC_SUCCESS);
4337 }
4338 
4339 /*@
4340   MatConvert - Converts a matrix to another matrix, either of the same
4341   or different type.
4342 
4343   Collective
4344 
4345   Input Parameters:
4346 + mat     - the matrix
4347 . newtype - new matrix type.  Use `MATSAME` to create a new matrix of the
4348             same type as the original matrix.
4349 - reuse   - denotes if the destination matrix is to be created or reused.
4350             Use `MAT_INPLACE_MATRIX` for inplace conversion (that is when you want the input `Mat` to be changed to contain the matrix in the new format), otherwise use
4351             `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX` (can only be used after the first call was made with `MAT_INITIAL_MATRIX`, causes the matrix space in M to be reused).
4352 
4353   Output Parameter:
4354 . M - pointer to place new matrix
4355 
4356   Level: intermediate
4357 
4358   Notes:
4359   `MatConvert()` first creates a new matrix and then copies the data from
4360   the first matrix.  A related routine is `MatCopy()`, which copies the matrix
4361   entries of one matrix to another already existing matrix context.
4362 
4363   Cannot be used to convert a sequential matrix to parallel or parallel to sequential,
4364   the MPI communicator of the generated matrix is always the same as the communicator
4365   of the input matrix.
4366 
4367 .seealso: [](ch_matrices), `Mat`, `MatCopy()`, `MatDuplicate()`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
4368 @*/
4369 PetscErrorCode MatConvert(Mat mat, MatType newtype, MatReuse reuse, Mat *M)
4370 {
4371   PetscBool  sametype, issame, flg;
4372   PetscBool3 issymmetric, ishermitian;
4373   char       convname[256], mtype[256];
4374   Mat        B;
4375 
4376   PetscFunctionBegin;
4377   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4378   PetscValidType(mat, 1);
4379   PetscAssertPointer(M, 4);
4380   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4381   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4382   MatCheckPreallocated(mat, 1);
4383 
4384   PetscCall(PetscOptionsGetString(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matconvert_type", mtype, sizeof(mtype), &flg));
4385   if (flg) newtype = mtype;
4386 
4387   PetscCall(PetscObjectTypeCompare((PetscObject)mat, newtype, &sametype));
4388   PetscCall(PetscStrcmp(newtype, "same", &issame));
4389   PetscCheck(!(reuse == MAT_INPLACE_MATRIX) || !(mat != *M), PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX requires same input and output matrix");
4390   if (reuse == MAT_REUSE_MATRIX) {
4391     PetscValidHeaderSpecific(*M, MAT_CLASSID, 4);
4392     PetscCheck(mat != *M, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_REUSE_MATRIX means reuse matrix in final argument, perhaps you mean MAT_INPLACE_MATRIX");
4393   }
4394 
4395   if ((reuse == MAT_INPLACE_MATRIX) && (issame || sametype)) {
4396     PetscCall(PetscInfo(mat, "Early return for inplace %s %d %d\n", ((PetscObject)mat)->type_name, sametype, issame));
4397     PetscFunctionReturn(PETSC_SUCCESS);
4398   }
4399 
4400   /* Cache Mat options because some converters use MatHeaderReplace  */
4401   issymmetric = mat->symmetric;
4402   ishermitian = mat->hermitian;
4403 
4404   if ((sametype || issame) && (reuse == MAT_INITIAL_MATRIX) && mat->ops->duplicate) {
4405     PetscCall(PetscInfo(mat, "Calling duplicate for initial matrix %s %d %d\n", ((PetscObject)mat)->type_name, sametype, issame));
4406     PetscUseTypeMethod(mat, duplicate, MAT_COPY_VALUES, M);
4407   } else {
4408     PetscErrorCode (*conv)(Mat, MatType, MatReuse, Mat *) = NULL;
4409     const char *prefix[3]                                 = {"seq", "mpi", ""};
4410     PetscInt    i;
4411     /*
4412        Order of precedence:
4413        0) See if newtype is a superclass of the current matrix.
4414        1) See if a specialized converter is known to the current matrix.
4415        2) See if a specialized converter is known to the desired matrix class.
4416        3) See if a good general converter is registered for the desired class
4417           (as of 6/27/03 only MATMPIADJ falls into this category).
4418        4) See if a good general converter is known for the current matrix.
4419        5) Use a really basic converter.
4420     */
4421 
4422     /* 0) See if newtype is a superclass of the current matrix.
4423           i.e mat is mpiaij and newtype is aij */
4424     for (i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(prefix); i++) {
4425       PetscCall(PetscStrncpy(convname, prefix[i], sizeof(convname)));
4426       PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4427       PetscCall(PetscStrcmp(convname, ((PetscObject)mat)->type_name, &flg));
4428       PetscCall(PetscInfo(mat, "Check superclass %s %s -> %d\n", convname, ((PetscObject)mat)->type_name, flg));
4429       if (flg) {
4430         if (reuse == MAT_INPLACE_MATRIX) {
4431           PetscCall(PetscInfo(mat, "Early return\n"));
4432           PetscFunctionReturn(PETSC_SUCCESS);
4433         } else if (reuse == MAT_INITIAL_MATRIX && mat->ops->duplicate) {
4434           PetscCall(PetscInfo(mat, "Calling MatDuplicate\n"));
4435           PetscUseTypeMethod(mat, duplicate, MAT_COPY_VALUES, M);
4436           PetscFunctionReturn(PETSC_SUCCESS);
4437         } else if (reuse == MAT_REUSE_MATRIX && mat->ops->copy) {
4438           PetscCall(PetscInfo(mat, "Calling MatCopy\n"));
4439           PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
4440           PetscFunctionReturn(PETSC_SUCCESS);
4441         }
4442       }
4443     }
4444     /* 1) See if a specialized converter is known to the current matrix and the desired class */
4445     for (i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(prefix); i++) {
4446       PetscCall(PetscStrncpy(convname, "MatConvert_", sizeof(convname)));
4447       PetscCall(PetscStrlcat(convname, ((PetscObject)mat)->type_name, sizeof(convname)));
4448       PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4449       PetscCall(PetscStrlcat(convname, prefix[i], sizeof(convname)));
4450       PetscCall(PetscStrlcat(convname, issame ? ((PetscObject)mat)->type_name : newtype, sizeof(convname)));
4451       PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4452       PetscCall(PetscObjectQueryFunction((PetscObject)mat, convname, &conv));
4453       PetscCall(PetscInfo(mat, "Check specialized (1) %s (%s) -> %d\n", convname, ((PetscObject)mat)->type_name, !!conv));
4454       if (conv) goto foundconv;
4455     }
4456 
4457     /* 2)  See if a specialized converter is known to the desired matrix class. */
4458     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
4459     PetscCall(MatSetSizes(B, mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N));
4460     PetscCall(MatSetType(B, newtype));
4461     for (i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(prefix); i++) {
4462       PetscCall(PetscStrncpy(convname, "MatConvert_", sizeof(convname)));
4463       PetscCall(PetscStrlcat(convname, ((PetscObject)mat)->type_name, sizeof(convname)));
4464       PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4465       PetscCall(PetscStrlcat(convname, prefix[i], sizeof(convname)));
4466       PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4467       PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4468       PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4469       PetscCall(PetscInfo(mat, "Check specialized (2) %s (%s) -> %d\n", convname, ((PetscObject)B)->type_name, !!conv));
4470       if (conv) {
4471         PetscCall(MatDestroy(&B));
4472         goto foundconv;
4473       }
4474     }
4475 
4476     /* 3) See if a good general converter is registered for the desired class */
4477     conv = B->ops->convertfrom;
4478     PetscCall(PetscInfo(mat, "Check convertfrom (%s) -> %d\n", ((PetscObject)B)->type_name, !!conv));
4479     PetscCall(MatDestroy(&B));
4480     if (conv) goto foundconv;
4481 
4482     /* 4) See if a good general converter is known for the current matrix */
4483     if (mat->ops->convert) conv = mat->ops->convert;
4484     PetscCall(PetscInfo(mat, "Check general convert (%s) -> %d\n", ((PetscObject)mat)->type_name, !!conv));
4485     if (conv) goto foundconv;
4486 
4487     /* 5) Use a really basic converter. */
4488     PetscCall(PetscInfo(mat, "Using MatConvert_Basic\n"));
4489     conv = MatConvert_Basic;
4490 
4491   foundconv:
4492     PetscCall(PetscLogEventBegin(MAT_Convert, mat, 0, 0, 0));
4493     PetscCall((*conv)(mat, newtype, reuse, M));
4494     if (mat->rmap->mapping && mat->cmap->mapping && !(*M)->rmap->mapping && !(*M)->cmap->mapping) {
4495       /* the block sizes must be same if the mappings are copied over */
4496       (*M)->rmap->bs = mat->rmap->bs;
4497       (*M)->cmap->bs = mat->cmap->bs;
4498       PetscCall(PetscObjectReference((PetscObject)mat->rmap->mapping));
4499       PetscCall(PetscObjectReference((PetscObject)mat->cmap->mapping));
4500       (*M)->rmap->mapping = mat->rmap->mapping;
4501       (*M)->cmap->mapping = mat->cmap->mapping;
4502     }
4503     (*M)->stencil.dim = mat->stencil.dim;
4504     (*M)->stencil.noc = mat->stencil.noc;
4505     for (i = 0; i <= mat->stencil.dim + (mat->stencil.noc ? 0 : -1); i++) {
4506       (*M)->stencil.dims[i]   = mat->stencil.dims[i];
4507       (*M)->stencil.starts[i] = mat->stencil.starts[i];
4508     }
4509     PetscCall(PetscLogEventEnd(MAT_Convert, mat, 0, 0, 0));
4510   }
4511   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4512 
4513   /* Copy Mat options */
4514   if (issymmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*M, MAT_SYMMETRIC, PETSC_TRUE));
4515   else if (issymmetric == PETSC_BOOL3_FALSE) PetscCall(MatSetOption(*M, MAT_SYMMETRIC, PETSC_FALSE));
4516   if (ishermitian == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*M, MAT_HERMITIAN, PETSC_TRUE));
4517   else if (ishermitian == PETSC_BOOL3_FALSE) PetscCall(MatSetOption(*M, MAT_HERMITIAN, PETSC_FALSE));
4518   PetscFunctionReturn(PETSC_SUCCESS);
4519 }
4520 
4521 /*@
4522   MatFactorGetSolverType - Returns name of the package providing the factorization routines
4523 
4524   Not Collective
4525 
4526   Input Parameter:
4527 . mat - the matrix, must be a factored matrix
4528 
4529   Output Parameter:
4530 . type - the string name of the package (do not free this string)
4531 
4532   Level: intermediate
4533 
4534 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolverType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`
4535 @*/
4536 PetscErrorCode MatFactorGetSolverType(Mat mat, MatSolverType *type)
4537 {
4538   PetscErrorCode (*conv)(Mat, MatSolverType *);
4539 
4540   PetscFunctionBegin;
4541   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4542   PetscValidType(mat, 1);
4543   PetscAssertPointer(type, 2);
4544   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
4545   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorGetSolverType_C", &conv));
4546   if (conv) PetscCall((*conv)(mat, type));
4547   else *type = MATSOLVERPETSC;
4548   PetscFunctionReturn(PETSC_SUCCESS);
4549 }
4550 
4551 typedef struct _MatSolverTypeForSpecifcType *MatSolverTypeForSpecifcType;
4552 struct _MatSolverTypeForSpecifcType {
4553   MatType mtype;
4554   /* no entry for MAT_FACTOR_NONE */
4555   PetscErrorCode (*createfactor[MAT_FACTOR_NUM_TYPES - 1])(Mat, MatFactorType, Mat *);
4556   MatSolverTypeForSpecifcType next;
4557 };
4558 
4559 typedef struct _MatSolverTypeHolder *MatSolverTypeHolder;
4560 struct _MatSolverTypeHolder {
4561   char                       *name;
4562   MatSolverTypeForSpecifcType handlers;
4563   MatSolverTypeHolder         next;
4564 };
4565 
4566 static MatSolverTypeHolder MatSolverTypeHolders = NULL;
4567 
4568 /*@C
4569   MatSolverTypeRegister - Registers a `MatSolverType` that works for a particular matrix type
4570 
4571   Logically Collective, No Fortran Support
4572 
4573   Input Parameters:
4574 + package      - name of the package, for example `petsc` or `superlu`
4575 . mtype        - the matrix type that works with this package
4576 . ftype        - the type of factorization supported by the package
4577 - createfactor - routine that will create the factored matrix ready to be used
4578 
4579   Level: developer
4580 
4581 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorGetSolverType()`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`,
4582   `MatGetFactor()`
4583 @*/
4584 PetscErrorCode MatSolverTypeRegister(MatSolverType package, MatType mtype, MatFactorType ftype, PetscErrorCode (*createfactor)(Mat, MatFactorType, Mat *))
4585 {
4586   MatSolverTypeHolder         next = MatSolverTypeHolders, prev = NULL;
4587   PetscBool                   flg;
4588   MatSolverTypeForSpecifcType inext, iprev = NULL;
4589 
4590   PetscFunctionBegin;
4591   PetscCall(MatInitializePackage());
4592   if (!next) {
4593     PetscCall(PetscNew(&MatSolverTypeHolders));
4594     PetscCall(PetscStrallocpy(package, &MatSolverTypeHolders->name));
4595     PetscCall(PetscNew(&MatSolverTypeHolders->handlers));
4596     PetscCall(PetscStrallocpy(mtype, (char **)&MatSolverTypeHolders->handlers->mtype));
4597     MatSolverTypeHolders->handlers->createfactor[(int)ftype - 1] = createfactor;
4598     PetscFunctionReturn(PETSC_SUCCESS);
4599   }
4600   while (next) {
4601     PetscCall(PetscStrcasecmp(package, next->name, &flg));
4602     if (flg) {
4603       PetscCheck(next->handlers, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatSolverTypeHolder is missing handlers");
4604       inext = next->handlers;
4605       while (inext) {
4606         PetscCall(PetscStrcasecmp(mtype, inext->mtype, &flg));
4607         if (flg) {
4608           inext->createfactor[(int)ftype - 1] = createfactor;
4609           PetscFunctionReturn(PETSC_SUCCESS);
4610         }
4611         iprev = inext;
4612         inext = inext->next;
4613       }
4614       PetscCall(PetscNew(&iprev->next));
4615       PetscCall(PetscStrallocpy(mtype, (char **)&iprev->next->mtype));
4616       iprev->next->createfactor[(int)ftype - 1] = createfactor;
4617       PetscFunctionReturn(PETSC_SUCCESS);
4618     }
4619     prev = next;
4620     next = next->next;
4621   }
4622   PetscCall(PetscNew(&prev->next));
4623   PetscCall(PetscStrallocpy(package, &prev->next->name));
4624   PetscCall(PetscNew(&prev->next->handlers));
4625   PetscCall(PetscStrallocpy(mtype, (char **)&prev->next->handlers->mtype));
4626   prev->next->handlers->createfactor[(int)ftype - 1] = createfactor;
4627   PetscFunctionReturn(PETSC_SUCCESS);
4628 }
4629 
4630 /*@C
4631   MatSolverTypeGet - Gets the function that creates the factor matrix if it exist
4632 
4633   Input Parameters:
4634 + type  - name of the package, for example `petsc` or `superlu`, if this is 'NULL', then the first result that satisfies the other criteria is returned
4635 . ftype - the type of factorization supported by the type
4636 - mtype - the matrix type that works with this type
4637 
4638   Output Parameters:
4639 + foundtype    - `PETSC_TRUE` if the type was registered
4640 . foundmtype   - `PETSC_TRUE` if the type supports the requested mtype
4641 - createfactor - routine that will create the factored matrix ready to be used or `NULL` if not found
4642 
4643   Calling sequence of `createfactor`:
4644 + A     - the matrix providing the factor matrix
4645 . ftype - the `MatFactorType` of the factor requested
4646 - B     - the new factor matrix that responds to MatXXFactorSymbolic,Numeric() functions, such as `MatLUFactorSymbolic()`
4647 
4648   Level: developer
4649 
4650   Note:
4651   When `type` is `NULL` the available functions are searched for based on the order of the calls to `MatSolverTypeRegister()` in `MatInitializePackage()`.
4652   Since different PETSc configurations may have different external solvers, seemingly identical runs with different PETSc configurations may use a different solver.
4653   For example if one configuration had `--download-mumps` while a different one had `--download-superlu_dist`.
4654 
4655 .seealso: [](ch_matrices), `Mat`, `MatFactorType`, `MatType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatSolverTypeRegister()`, `MatGetFactor()`,
4656           `MatInitializePackage()`
4657 @*/
4658 PetscErrorCode MatSolverTypeGet(MatSolverType type, MatType mtype, MatFactorType ftype, PetscBool *foundtype, PetscBool *foundmtype, PetscErrorCode (**createfactor)(Mat A, MatFactorType ftype, Mat *B))
4659 {
4660   MatSolverTypeHolder         next = MatSolverTypeHolders;
4661   PetscBool                   flg;
4662   MatSolverTypeForSpecifcType inext;
4663 
4664   PetscFunctionBegin;
4665   if (foundtype) *foundtype = PETSC_FALSE;
4666   if (foundmtype) *foundmtype = PETSC_FALSE;
4667   if (createfactor) *createfactor = NULL;
4668 
4669   if (type) {
4670     while (next) {
4671       PetscCall(PetscStrcasecmp(type, next->name, &flg));
4672       if (flg) {
4673         if (foundtype) *foundtype = PETSC_TRUE;
4674         inext = next->handlers;
4675         while (inext) {
4676           PetscCall(PetscStrbeginswith(mtype, inext->mtype, &flg));
4677           if (flg) {
4678             if (foundmtype) *foundmtype = PETSC_TRUE;
4679             if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4680             PetscFunctionReturn(PETSC_SUCCESS);
4681           }
4682           inext = inext->next;
4683         }
4684       }
4685       next = next->next;
4686     }
4687   } else {
4688     while (next) {
4689       inext = next->handlers;
4690       while (inext) {
4691         PetscCall(PetscStrcmp(mtype, inext->mtype, &flg));
4692         if (flg && inext->createfactor[(int)ftype - 1]) {
4693           if (foundtype) *foundtype = PETSC_TRUE;
4694           if (foundmtype) *foundmtype = PETSC_TRUE;
4695           if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4696           PetscFunctionReturn(PETSC_SUCCESS);
4697         }
4698         inext = inext->next;
4699       }
4700       next = next->next;
4701     }
4702     /* try with base classes inext->mtype */
4703     next = MatSolverTypeHolders;
4704     while (next) {
4705       inext = next->handlers;
4706       while (inext) {
4707         PetscCall(PetscStrbeginswith(mtype, inext->mtype, &flg));
4708         if (flg && inext->createfactor[(int)ftype - 1]) {
4709           if (foundtype) *foundtype = PETSC_TRUE;
4710           if (foundmtype) *foundmtype = PETSC_TRUE;
4711           if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4712           PetscFunctionReturn(PETSC_SUCCESS);
4713         }
4714         inext = inext->next;
4715       }
4716       next = next->next;
4717     }
4718   }
4719   PetscFunctionReturn(PETSC_SUCCESS);
4720 }
4721 
4722 PetscErrorCode MatSolverTypeDestroy(void)
4723 {
4724   MatSolverTypeHolder         next = MatSolverTypeHolders, prev;
4725   MatSolverTypeForSpecifcType inext, iprev;
4726 
4727   PetscFunctionBegin;
4728   while (next) {
4729     PetscCall(PetscFree(next->name));
4730     inext = next->handlers;
4731     while (inext) {
4732       PetscCall(PetscFree(inext->mtype));
4733       iprev = inext;
4734       inext = inext->next;
4735       PetscCall(PetscFree(iprev));
4736     }
4737     prev = next;
4738     next = next->next;
4739     PetscCall(PetscFree(prev));
4740   }
4741   MatSolverTypeHolders = NULL;
4742   PetscFunctionReturn(PETSC_SUCCESS);
4743 }
4744 
4745 /*@
4746   MatFactorGetCanUseOrdering - Indicates if the factorization can use the ordering provided in `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4747 
4748   Logically Collective
4749 
4750   Input Parameter:
4751 . mat - the matrix
4752 
4753   Output Parameter:
4754 . flg - `PETSC_TRUE` if uses the ordering
4755 
4756   Level: developer
4757 
4758   Note:
4759   Most internal PETSc factorizations use the ordering passed to the factorization routine but external
4760   packages do not, thus we want to skip generating the ordering when it is not needed or used.
4761 
4762 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4763 @*/
4764 PetscErrorCode MatFactorGetCanUseOrdering(Mat mat, PetscBool *flg)
4765 {
4766   PetscFunctionBegin;
4767   *flg = mat->canuseordering;
4768   PetscFunctionReturn(PETSC_SUCCESS);
4769 }
4770 
4771 /*@
4772   MatFactorGetPreferredOrdering - The preferred ordering for a particular matrix factor object
4773 
4774   Logically Collective
4775 
4776   Input Parameters:
4777 + mat   - the matrix obtained with `MatGetFactor()`
4778 - ftype - the factorization type to be used
4779 
4780   Output Parameter:
4781 . otype - the preferred ordering type
4782 
4783   Level: developer
4784 
4785 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatOrderingType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4786 @*/
4787 PetscErrorCode MatFactorGetPreferredOrdering(Mat mat, MatFactorType ftype, MatOrderingType *otype)
4788 {
4789   PetscFunctionBegin;
4790   *otype = mat->preferredordering[ftype];
4791   PetscCheck(*otype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatFactor did not have a preferred ordering");
4792   PetscFunctionReturn(PETSC_SUCCESS);
4793 }
4794 
4795 /*@
4796   MatGetFactor - Returns a matrix suitable to calls to MatXXFactorSymbolic,Numeric()
4797 
4798   Collective
4799 
4800   Input Parameters:
4801 + mat   - the matrix
4802 . type  - name of solver type, for example, `superlu`, `petsc` (to use PETSc's solver if it is available), if this is 'NULL', then the first result that satisfies
4803           the other criteria is returned
4804 - ftype - factor type, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`
4805 
4806   Output Parameter:
4807 . f - the factor matrix used with MatXXFactorSymbolic,Numeric() calls. Can be `NULL` in some cases, see notes below.
4808 
4809   Options Database Keys:
4810 + -pc_factor_mat_solver_type <type>    - choose the type at run time. When using `KSP` solvers
4811 . -pc_factor_mat_factor_on_host <bool> - do mat factorization on host (with device matrices). Default is doing it on device
4812 - -pc_factor_mat_solve_on_host <bool>  - do mat solve on host (with device matrices). Default is doing it on device
4813 
4814   Level: intermediate
4815 
4816   Notes:
4817   The return matrix can be `NULL` if the requested factorization is not available, since some combinations of matrix types and factorization
4818   types registered with `MatSolverTypeRegister()` cannot be fully tested if not at runtime.
4819 
4820   Users usually access the factorization solvers via `KSP`
4821 
4822   Some PETSc matrix formats have alternative solvers available that are contained in alternative packages
4823   such as pastix, superlu, mumps etc. PETSc must have been ./configure to use the external solver, using the option --download-package or --with-package-dir
4824 
4825   When `type` is `NULL` the available results are searched for based on the order of the calls to `MatSolverTypeRegister()` in `MatInitializePackage()`.
4826   Since different PETSc configurations may have different external solvers, seemingly identical runs with different PETSc configurations may use a different solver.
4827   For example if one configuration had --download-mumps while a different one had --download-superlu_dist.
4828 
4829   Some of the packages have options for controlling the factorization, these are in the form -prefix_mat_packagename_packageoption
4830   where prefix is normally obtained from the calling `KSP`/`PC`. If `MatGetFactor()` is called directly one can set
4831   call `MatSetOptionsPrefixFactor()` on the originating matrix or  `MatSetOptionsPrefix()` on the resulting factor matrix.
4832 
4833   Developer Note:
4834   This should actually be called `MatCreateFactor()` since it creates a new factor object
4835 
4836 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `KSP`, `MatSolverType`, `MatFactorType`, `MatCopy()`, `MatDuplicate()`,
4837           `MatGetFactorAvailable()`, `MatFactorGetCanUseOrdering()`, `MatSolverTypeRegister()`, `MatSolverTypeGet()`
4838           `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`, `MatInitializePackage()`
4839 @*/
4840 PetscErrorCode MatGetFactor(Mat mat, MatSolverType type, MatFactorType ftype, Mat *f)
4841 {
4842   PetscBool foundtype, foundmtype, shell, hasop = PETSC_FALSE;
4843   PetscErrorCode (*conv)(Mat, MatFactorType, Mat *);
4844 
4845   PetscFunctionBegin;
4846   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4847   PetscValidType(mat, 1);
4848 
4849   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4850   MatCheckPreallocated(mat, 1);
4851 
4852   PetscCall(MatIsShell(mat, &shell));
4853   if (shell) PetscCall(MatHasOperation(mat, MATOP_GET_FACTOR, &hasop));
4854   if (hasop) {
4855     PetscUseTypeMethod(mat, getfactor, type, ftype, f);
4856     PetscFunctionReturn(PETSC_SUCCESS);
4857   }
4858 
4859   PetscCall(MatSolverTypeGet(type, ((PetscObject)mat)->type_name, ftype, &foundtype, &foundmtype, &conv));
4860   if (!foundtype) {
4861     if (type) {
4862       SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_MISSING_FACTOR, "Could not locate solver type %s for factorization type %s and matrix type %s. Perhaps you must ./configure with --download-%s", type, MatFactorTypes[ftype],
4863               ((PetscObject)mat)->type_name, type);
4864     } else {
4865       SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_MISSING_FACTOR, "Could not locate a solver type for factorization type %s and matrix type %s.", MatFactorTypes[ftype], ((PetscObject)mat)->type_name);
4866     }
4867   }
4868   PetscCheck(foundmtype, PetscObjectComm((PetscObject)mat), PETSC_ERR_MISSING_FACTOR, "MatSolverType %s does not support matrix type %s", type, ((PetscObject)mat)->type_name);
4869   PetscCheck(conv, PetscObjectComm((PetscObject)mat), PETSC_ERR_MISSING_FACTOR, "MatSolverType %s does not support factorization type %s for matrix type %s", type, MatFactorTypes[ftype], ((PetscObject)mat)->type_name);
4870 
4871   PetscCall((*conv)(mat, ftype, f));
4872   if (mat->factorprefix) PetscCall(MatSetOptionsPrefix(*f, mat->factorprefix));
4873   PetscFunctionReturn(PETSC_SUCCESS);
4874 }
4875 
4876 /*@
4877   MatGetFactorAvailable - Returns a flag if matrix supports particular type and factor type
4878 
4879   Not Collective
4880 
4881   Input Parameters:
4882 + mat   - the matrix
4883 . type  - name of solver type, for example, `superlu`, `petsc` (to use PETSc's default)
4884 - ftype - factor type, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`
4885 
4886   Output Parameter:
4887 . flg - PETSC_TRUE if the factorization is available
4888 
4889   Level: intermediate
4890 
4891   Notes:
4892   Some PETSc matrix formats have alternative solvers available that are contained in alternative packages
4893   such as pastix, superlu, mumps etc.
4894 
4895   PETSc must have been ./configure to use the external solver, using the option --download-package
4896 
4897   Developer Note:
4898   This should actually be called `MatCreateFactorAvailable()` since `MatGetFactor()` creates a new factor object
4899 
4900 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatSolverType`, `MatFactorType`, `MatGetFactor()`, `MatCopy()`, `MatDuplicate()`, `MatSolverTypeRegister()`,
4901           `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`, `MatSolverTypeGet()`
4902 @*/
4903 PetscErrorCode MatGetFactorAvailable(Mat mat, MatSolverType type, MatFactorType ftype, PetscBool *flg)
4904 {
4905   PetscErrorCode (*gconv)(Mat, MatFactorType, Mat *);
4906 
4907   PetscFunctionBegin;
4908   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4909   PetscAssertPointer(flg, 4);
4910 
4911   *flg = PETSC_FALSE;
4912   if (!((PetscObject)mat)->type_name) PetscFunctionReturn(PETSC_SUCCESS);
4913 
4914   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4915   MatCheckPreallocated(mat, 1);
4916 
4917   PetscCall(MatSolverTypeGet(type, ((PetscObject)mat)->type_name, ftype, NULL, NULL, &gconv));
4918   *flg = gconv ? PETSC_TRUE : PETSC_FALSE;
4919   PetscFunctionReturn(PETSC_SUCCESS);
4920 }
4921 
4922 /*@
4923   MatDuplicate - Duplicates a matrix including the non-zero structure.
4924 
4925   Collective
4926 
4927   Input Parameters:
4928 + mat - the matrix
4929 - op  - One of `MAT_DO_NOT_COPY_VALUES`, `MAT_COPY_VALUES`, or `MAT_SHARE_NONZERO_PATTERN`.
4930         See the manual page for `MatDuplicateOption()` for an explanation of these options.
4931 
4932   Output Parameter:
4933 . M - pointer to place new matrix
4934 
4935   Level: intermediate
4936 
4937   Notes:
4938   You cannot change the nonzero pattern for the parent or child matrix later if you use `MAT_SHARE_NONZERO_PATTERN`.
4939 
4940   If `op` is not `MAT_COPY_VALUES` the numerical values in the new matrix are zeroed.
4941 
4942   May be called with an unassembled input `Mat` if `MAT_DO_NOT_COPY_VALUES` is used, in which case the output `Mat` is unassembled as well.
4943 
4944   When original mat is a product of matrix operation, e.g., an output of `MatMatMult()` or `MatCreateSubMatrix()`, only the matrix data structure of `mat`
4945   is duplicated and the internal data structures created for the reuse of previous matrix operations are not duplicated.
4946   User should not use `MatDuplicate()` to create new matrix `M` if `M` is intended to be reused as the product of matrix operation.
4947 
4948 .seealso: [](ch_matrices), `Mat`, `MatCopy()`, `MatConvert()`, `MatDuplicateOption`
4949 @*/
4950 PetscErrorCode MatDuplicate(Mat mat, MatDuplicateOption op, Mat *M)
4951 {
4952   Mat         B;
4953   VecType     vtype;
4954   PetscInt    i;
4955   PetscObject dm, container_h, container_d;
4956   void (*viewf)(void);
4957 
4958   PetscFunctionBegin;
4959   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4960   PetscValidType(mat, 1);
4961   PetscAssertPointer(M, 3);
4962   PetscCheck(op != MAT_COPY_VALUES || mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MAT_COPY_VALUES not allowed for unassembled matrix");
4963   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4964   MatCheckPreallocated(mat, 1);
4965 
4966   PetscCall(PetscLogEventBegin(MAT_Convert, mat, 0, 0, 0));
4967   PetscUseTypeMethod(mat, duplicate, op, M);
4968   PetscCall(PetscLogEventEnd(MAT_Convert, mat, 0, 0, 0));
4969   B = *M;
4970 
4971   PetscCall(MatGetOperation(mat, MATOP_VIEW, &viewf));
4972   if (viewf) PetscCall(MatSetOperation(B, MATOP_VIEW, viewf));
4973   PetscCall(MatGetVecType(mat, &vtype));
4974   PetscCall(MatSetVecType(B, vtype));
4975 
4976   B->stencil.dim = mat->stencil.dim;
4977   B->stencil.noc = mat->stencil.noc;
4978   for (i = 0; i <= mat->stencil.dim + (mat->stencil.noc ? 0 : -1); i++) {
4979     B->stencil.dims[i]   = mat->stencil.dims[i];
4980     B->stencil.starts[i] = mat->stencil.starts[i];
4981   }
4982 
4983   B->nooffproczerorows = mat->nooffproczerorows;
4984   B->nooffprocentries  = mat->nooffprocentries;
4985 
4986   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_dm", &dm));
4987   if (dm) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_dm", dm));
4988   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_MatCOOStruct_Host", &container_h));
4989   if (container_h) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_MatCOOStruct_Host", container_h));
4990   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_MatCOOStruct_Device", &container_d));
4991   if (container_d) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_MatCOOStruct_Device", container_d));
4992   if (op == MAT_COPY_VALUES) PetscCall(MatPropagateSymmetryOptions(mat, B));
4993   PetscCall(PetscObjectStateIncrease((PetscObject)B));
4994   PetscFunctionReturn(PETSC_SUCCESS);
4995 }
4996 
4997 /*@
4998   MatGetDiagonal - Gets the diagonal of a matrix as a `Vec`
4999 
5000   Logically Collective
5001 
5002   Input Parameter:
5003 . mat - the matrix
5004 
5005   Output Parameter:
5006 . v - the diagonal of the matrix
5007 
5008   Level: intermediate
5009 
5010   Note:
5011   If `mat` has local sizes `n` x `m`, this routine fills the first `ndiag = min(n, m)` entries
5012   of `v` with the diagonal values. Thus `v` must have local size of at least `ndiag`. If `v`
5013   is larger than `ndiag`, the values of the remaining entries are unspecified.
5014 
5015   Currently only correct in parallel for square matrices.
5016 
5017 .seealso: [](ch_matrices), `Mat`, `Vec`, `MatGetRow()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`
5018 @*/
5019 PetscErrorCode MatGetDiagonal(Mat mat, Vec v)
5020 {
5021   PetscFunctionBegin;
5022   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5023   PetscValidType(mat, 1);
5024   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5025   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5026   MatCheckPreallocated(mat, 1);
5027   if (PetscDefined(USE_DEBUG)) {
5028     PetscInt nv, row, col, ndiag;
5029 
5030     PetscCall(VecGetLocalSize(v, &nv));
5031     PetscCall(MatGetLocalSize(mat, &row, &col));
5032     ndiag = PetscMin(row, col);
5033     PetscCheck(nv >= ndiag, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming Mat and Vec. Vec local size %" PetscInt_FMT " < Mat local diagonal length %" PetscInt_FMT, nv, ndiag);
5034   }
5035 
5036   PetscUseTypeMethod(mat, getdiagonal, v);
5037   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5038   PetscFunctionReturn(PETSC_SUCCESS);
5039 }
5040 
5041 /*@
5042   MatGetRowMin - Gets the minimum value (of the real part) of each
5043   row of the matrix
5044 
5045   Logically Collective
5046 
5047   Input Parameter:
5048 . mat - the matrix
5049 
5050   Output Parameters:
5051 + v   - the vector for storing the maximums
5052 - idx - the indices of the column found for each row (optional, pass `NULL` if not needed)
5053 
5054   Level: intermediate
5055 
5056   Note:
5057   The result of this call are the same as if one converted the matrix to dense format
5058   and found the minimum value in each row (i.e. the implicit zeros are counted as zeros).
5059 
5060   This code is only implemented for a couple of matrix formats.
5061 
5062 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`, `MatGetRowMinAbs()`,
5063           `MatGetRowMax()`
5064 @*/
5065 PetscErrorCode MatGetRowMin(Mat mat, Vec v, PetscInt idx[])
5066 {
5067   PetscFunctionBegin;
5068   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5069   PetscValidType(mat, 1);
5070   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5071   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5072 
5073   if (!mat->cmap->N) {
5074     PetscCall(VecSet(v, PETSC_MAX_REAL));
5075     if (idx) {
5076       PetscInt i, m = mat->rmap->n;
5077       for (i = 0; i < m; i++) idx[i] = -1;
5078     }
5079   } else {
5080     MatCheckPreallocated(mat, 1);
5081   }
5082   PetscUseTypeMethod(mat, getrowmin, v, idx);
5083   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5084   PetscFunctionReturn(PETSC_SUCCESS);
5085 }
5086 
5087 /*@
5088   MatGetRowMinAbs - Gets the minimum value (in absolute value) of each
5089   row of the matrix
5090 
5091   Logically Collective
5092 
5093   Input Parameter:
5094 . mat - the matrix
5095 
5096   Output Parameters:
5097 + v   - the vector for storing the minimums
5098 - idx - the indices of the column found for each row (or `NULL` if not needed)
5099 
5100   Level: intermediate
5101 
5102   Notes:
5103   if a row is completely empty or has only 0.0 values, then the `idx` value for that
5104   row is 0 (the first column).
5105 
5106   This code is only implemented for a couple of matrix formats.
5107 
5108 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMaxAbs()`, `MatGetRowMin()`
5109 @*/
5110 PetscErrorCode MatGetRowMinAbs(Mat mat, Vec v, PetscInt idx[])
5111 {
5112   PetscFunctionBegin;
5113   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5114   PetscValidType(mat, 1);
5115   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5116   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5117   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5118 
5119   if (!mat->cmap->N) {
5120     PetscCall(VecSet(v, 0.0));
5121     if (idx) {
5122       PetscInt i, m = mat->rmap->n;
5123       for (i = 0; i < m; i++) idx[i] = -1;
5124     }
5125   } else {
5126     MatCheckPreallocated(mat, 1);
5127     if (idx) PetscCall(PetscArrayzero(idx, mat->rmap->n));
5128     PetscUseTypeMethod(mat, getrowminabs, v, idx);
5129   }
5130   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5131   PetscFunctionReturn(PETSC_SUCCESS);
5132 }
5133 
5134 /*@
5135   MatGetRowMax - Gets the maximum value (of the real part) of each
5136   row of the matrix
5137 
5138   Logically Collective
5139 
5140   Input Parameter:
5141 . mat - the matrix
5142 
5143   Output Parameters:
5144 + v   - the vector for storing the maximums
5145 - idx - the indices of the column found for each row (optional, otherwise pass `NULL`)
5146 
5147   Level: intermediate
5148 
5149   Notes:
5150   The result of this call are the same as if one converted the matrix to dense format
5151   and found the minimum value in each row (i.e. the implicit zeros are counted as zeros).
5152 
5153   This code is only implemented for a couple of matrix formats.
5154 
5155 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5156 @*/
5157 PetscErrorCode MatGetRowMax(Mat mat, Vec v, PetscInt idx[])
5158 {
5159   PetscFunctionBegin;
5160   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5161   PetscValidType(mat, 1);
5162   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5163   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5164 
5165   if (!mat->cmap->N) {
5166     PetscCall(VecSet(v, PETSC_MIN_REAL));
5167     if (idx) {
5168       PetscInt i, m = mat->rmap->n;
5169       for (i = 0; i < m; i++) idx[i] = -1;
5170     }
5171   } else {
5172     MatCheckPreallocated(mat, 1);
5173     PetscUseTypeMethod(mat, getrowmax, v, idx);
5174   }
5175   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5176   PetscFunctionReturn(PETSC_SUCCESS);
5177 }
5178 
5179 /*@
5180   MatGetRowMaxAbs - Gets the maximum value (in absolute value) of each
5181   row of the matrix
5182 
5183   Logically Collective
5184 
5185   Input Parameter:
5186 . mat - the matrix
5187 
5188   Output Parameters:
5189 + v   - the vector for storing the maximums
5190 - idx - the indices of the column found for each row (or `NULL` if not needed)
5191 
5192   Level: intermediate
5193 
5194   Notes:
5195   if a row is completely empty or has only 0.0 values, then the `idx` value for that
5196   row is 0 (the first column).
5197 
5198   This code is only implemented for a couple of matrix formats.
5199 
5200 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowSum()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5201 @*/
5202 PetscErrorCode MatGetRowMaxAbs(Mat mat, Vec v, PetscInt idx[])
5203 {
5204   PetscFunctionBegin;
5205   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5206   PetscValidType(mat, 1);
5207   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5208   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5209 
5210   if (!mat->cmap->N) {
5211     PetscCall(VecSet(v, 0.0));
5212     if (idx) {
5213       PetscInt i, m = mat->rmap->n;
5214       for (i = 0; i < m; i++) idx[i] = -1;
5215     }
5216   } else {
5217     MatCheckPreallocated(mat, 1);
5218     if (idx) PetscCall(PetscArrayzero(idx, mat->rmap->n));
5219     PetscUseTypeMethod(mat, getrowmaxabs, v, idx);
5220   }
5221   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5222   PetscFunctionReturn(PETSC_SUCCESS);
5223 }
5224 
5225 /*@
5226   MatGetRowSumAbs - Gets the sum value (in absolute value) of each row of the matrix
5227 
5228   Logically Collective
5229 
5230   Input Parameter:
5231 . mat - the matrix
5232 
5233   Output Parameter:
5234 . v - the vector for storing the sum
5235 
5236   Level: intermediate
5237 
5238   This code is only implemented for a couple of matrix formats.
5239 
5240 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5241 @*/
5242 PetscErrorCode MatGetRowSumAbs(Mat mat, Vec v)
5243 {
5244   PetscFunctionBegin;
5245   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5246   PetscValidType(mat, 1);
5247   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5248   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5249 
5250   if (!mat->cmap->N) {
5251     PetscCall(VecSet(v, 0.0));
5252   } else {
5253     MatCheckPreallocated(mat, 1);
5254     PetscUseTypeMethod(mat, getrowsumabs, v);
5255   }
5256   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5257   PetscFunctionReturn(PETSC_SUCCESS);
5258 }
5259 
5260 /*@
5261   MatGetRowSum - Gets the sum of each row of the matrix
5262 
5263   Logically or Neighborhood Collective
5264 
5265   Input Parameter:
5266 . mat - the matrix
5267 
5268   Output Parameter:
5269 . v - the vector for storing the sum of rows
5270 
5271   Level: intermediate
5272 
5273   Note:
5274   This code is slow since it is not currently specialized for different formats
5275 
5276 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMin()`, `MatGetRowMaxAbs()`, `MatGetRowMinAbs()`, `MatGetRowSumAbs()`
5277 @*/
5278 PetscErrorCode MatGetRowSum(Mat mat, Vec v)
5279 {
5280   Vec ones;
5281 
5282   PetscFunctionBegin;
5283   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5284   PetscValidType(mat, 1);
5285   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5286   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5287   MatCheckPreallocated(mat, 1);
5288   PetscCall(MatCreateVecs(mat, &ones, NULL));
5289   PetscCall(VecSet(ones, 1.));
5290   PetscCall(MatMult(mat, ones, v));
5291   PetscCall(VecDestroy(&ones));
5292   PetscFunctionReturn(PETSC_SUCCESS);
5293 }
5294 
5295 /*@
5296   MatTransposeSetPrecursor - Set the matrix from which the second matrix will receive numerical transpose data with a call to `MatTranspose`(A,`MAT_REUSE_MATRIX`,&B)
5297   when B was not obtained with `MatTranspose`(A,`MAT_INITIAL_MATRIX`,&B)
5298 
5299   Collective
5300 
5301   Input Parameter:
5302 . mat - the matrix to provide the transpose
5303 
5304   Output Parameter:
5305 . B - the matrix to contain the transpose; it MUST have the nonzero structure of the transpose of A or the code will crash or generate incorrect results
5306 
5307   Level: advanced
5308 
5309   Note:
5310   Normally the use of `MatTranspose`(A, `MAT_REUSE_MATRIX`, &B) requires that `B` was obtained with a call to `MatTranspose`(A, `MAT_INITIAL_MATRIX`, &B). This
5311   routine allows bypassing that call.
5312 
5313 .seealso: [](ch_matrices), `Mat`, `MatTransposeSymbolic()`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
5314 @*/
5315 PetscErrorCode MatTransposeSetPrecursor(Mat mat, Mat B)
5316 {
5317   MatParentState *rb = NULL;
5318 
5319   PetscFunctionBegin;
5320   PetscCall(PetscNew(&rb));
5321   rb->id    = ((PetscObject)mat)->id;
5322   rb->state = 0;
5323   PetscCall(MatGetNonzeroState(mat, &rb->nonzerostate));
5324   PetscCall(PetscObjectContainerCompose((PetscObject)B, "MatTransposeParent", rb, PetscCtxDestroyDefault));
5325   PetscFunctionReturn(PETSC_SUCCESS);
5326 }
5327 
5328 /*@
5329   MatTranspose - Computes the transpose of a matrix, either in-place or out-of-place.
5330 
5331   Collective
5332 
5333   Input Parameters:
5334 + mat   - the matrix to transpose
5335 - reuse - either `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, or `MAT_INPLACE_MATRIX`
5336 
5337   Output Parameter:
5338 . B - the transpose of the matrix
5339 
5340   Level: intermediate
5341 
5342   Notes:
5343   If you use `MAT_INPLACE_MATRIX` then you must pass in `&mat` for `B`
5344 
5345   `MAT_REUSE_MATRIX` uses the `B` matrix obtained from a previous call to this function with `MAT_INITIAL_MATRIX` to store the transpose. If you already have a matrix to contain the
5346   transpose, call `MatTransposeSetPrecursor(mat, B)` before calling this routine.
5347 
5348   If the nonzero structure of `mat` changed from the previous call to this function with the same matrices an error will be generated for some matrix types.
5349 
5350   Consider using `MatCreateTranspose()` instead if you only need a matrix that behaves like the transpose but don't need the storage to be changed.
5351   For example, the result of `MatCreateTranspose()` will compute the transpose of the given matrix times a vector for matrix-vector products computed with `MatMult()`.
5352 
5353   If `mat` is unchanged from the last call this function returns immediately without recomputing the result
5354 
5355   If you only need the symbolic transpose of a matrix, and not the numerical values, use `MatTransposeSymbolic()`
5356 
5357 .seealso: [](ch_matrices), `Mat`, `MatTransposeSetPrecursor()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`,
5358           `MatTransposeSymbolic()`, `MatCreateTranspose()`
5359 @*/
5360 PetscErrorCode MatTranspose(Mat mat, MatReuse reuse, Mat *B)
5361 {
5362   PetscContainer  rB = NULL;
5363   MatParentState *rb = NULL;
5364 
5365   PetscFunctionBegin;
5366   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5367   PetscValidType(mat, 1);
5368   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5369   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5370   PetscCheck(reuse != MAT_INPLACE_MATRIX || mat == *B, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX requires last matrix to match first");
5371   PetscCheck(reuse != MAT_REUSE_MATRIX || mat != *B, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Perhaps you mean MAT_INPLACE_MATRIX");
5372   MatCheckPreallocated(mat, 1);
5373   if (reuse == MAT_REUSE_MATRIX) {
5374     PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
5375     PetscCheck(rB, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose(). Suggest MatTransposeSetPrecursor().");
5376     PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5377     PetscCheck(rb->id == ((PetscObject)mat)->id, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from input matrix");
5378     if (rb->state == ((PetscObject)mat)->state) PetscFunctionReturn(PETSC_SUCCESS);
5379   }
5380 
5381   PetscCall(PetscLogEventBegin(MAT_Transpose, mat, 0, 0, 0));
5382   if (reuse != MAT_INPLACE_MATRIX || mat->symmetric != PETSC_BOOL3_TRUE) {
5383     PetscUseTypeMethod(mat, transpose, reuse, B);
5384     PetscCall(PetscObjectStateIncrease((PetscObject)*B));
5385   }
5386   PetscCall(PetscLogEventEnd(MAT_Transpose, mat, 0, 0, 0));
5387 
5388   if (reuse == MAT_INITIAL_MATRIX) PetscCall(MatTransposeSetPrecursor(mat, *B));
5389   if (reuse != MAT_INPLACE_MATRIX) {
5390     PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
5391     PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5392     rb->state        = ((PetscObject)mat)->state;
5393     rb->nonzerostate = mat->nonzerostate;
5394   }
5395   PetscFunctionReturn(PETSC_SUCCESS);
5396 }
5397 
5398 /*@
5399   MatTransposeSymbolic - Computes the symbolic part of the transpose of a matrix.
5400 
5401   Collective
5402 
5403   Input Parameter:
5404 . A - the matrix to transpose
5405 
5406   Output Parameter:
5407 . B - the transpose. This is a complete matrix but the numerical portion is invalid. One can call `MatTranspose`(A,`MAT_REUSE_MATRIX`,&B) to compute the
5408       numerical portion.
5409 
5410   Level: intermediate
5411 
5412   Note:
5413   This is not supported for many matrix types, use `MatTranspose()` in those cases
5414 
5415 .seealso: [](ch_matrices), `Mat`, `MatTransposeSetPrecursor()`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
5416 @*/
5417 PetscErrorCode MatTransposeSymbolic(Mat A, Mat *B)
5418 {
5419   PetscFunctionBegin;
5420   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5421   PetscValidType(A, 1);
5422   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5423   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5424   PetscCall(PetscLogEventBegin(MAT_Transpose, A, 0, 0, 0));
5425   PetscUseTypeMethod(A, transposesymbolic, B);
5426   PetscCall(PetscLogEventEnd(MAT_Transpose, A, 0, 0, 0));
5427 
5428   PetscCall(MatTransposeSetPrecursor(A, *B));
5429   PetscFunctionReturn(PETSC_SUCCESS);
5430 }
5431 
5432 PetscErrorCode MatTransposeCheckNonzeroState_Private(Mat A, Mat B)
5433 {
5434   PetscContainer  rB;
5435   MatParentState *rb;
5436 
5437   PetscFunctionBegin;
5438   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5439   PetscValidType(A, 1);
5440   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5441   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5442   PetscCall(PetscObjectQuery((PetscObject)B, "MatTransposeParent", (PetscObject *)&rB));
5443   PetscCheck(rB, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose()");
5444   PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5445   PetscCheck(rb->id == ((PetscObject)A)->id, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from input matrix");
5446   PetscCheck(rb->nonzerostate == A->nonzerostate, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Reuse matrix has changed nonzero structure");
5447   PetscFunctionReturn(PETSC_SUCCESS);
5448 }
5449 
5450 /*@
5451   MatIsTranspose - Test whether a matrix is another one's transpose,
5452   or its own, in which case it tests symmetry.
5453 
5454   Collective
5455 
5456   Input Parameters:
5457 + A   - the matrix to test
5458 . B   - the matrix to test against, this can equal the first parameter
5459 - tol - tolerance, differences between entries smaller than this are counted as zero
5460 
5461   Output Parameter:
5462 . flg - the result
5463 
5464   Level: intermediate
5465 
5466   Notes:
5467   The sequential algorithm has a running time of the order of the number of nonzeros; the parallel
5468   test involves parallel copies of the block off-diagonal parts of the matrix.
5469 
5470 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsSymmetric()`, `MatIsHermitian()`
5471 @*/
5472 PetscErrorCode MatIsTranspose(Mat A, Mat B, PetscReal tol, PetscBool *flg)
5473 {
5474   PetscErrorCode (*f)(Mat, Mat, PetscReal, PetscBool *), (*g)(Mat, Mat, PetscReal, PetscBool *);
5475 
5476   PetscFunctionBegin;
5477   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5478   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5479   PetscAssertPointer(flg, 4);
5480   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatIsTranspose_C", &f));
5481   PetscCall(PetscObjectQueryFunction((PetscObject)B, "MatIsTranspose_C", &g));
5482   *flg = PETSC_FALSE;
5483   if (f && g) {
5484     PetscCheck(f == g, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_NOTSAMETYPE, "Matrices do not have the same comparator for symmetry test");
5485     PetscCall((*f)(A, B, tol, flg));
5486   } else {
5487     MatType mattype;
5488 
5489     PetscCall(MatGetType(f ? B : A, &mattype));
5490     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Matrix of type %s does not support checking for transpose", mattype);
5491   }
5492   PetscFunctionReturn(PETSC_SUCCESS);
5493 }
5494 
5495 /*@
5496   MatHermitianTranspose - Computes an in-place or out-of-place Hermitian transpose of a matrix in complex conjugate.
5497 
5498   Collective
5499 
5500   Input Parameters:
5501 + mat   - the matrix to transpose and complex conjugate
5502 - reuse - either `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, or `MAT_INPLACE_MATRIX`
5503 
5504   Output Parameter:
5505 . B - the Hermitian transpose
5506 
5507   Level: intermediate
5508 
5509 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`
5510 @*/
5511 PetscErrorCode MatHermitianTranspose(Mat mat, MatReuse reuse, Mat *B)
5512 {
5513   PetscFunctionBegin;
5514   PetscCall(MatTranspose(mat, reuse, B));
5515 #if defined(PETSC_USE_COMPLEX)
5516   PetscCall(MatConjugate(*B));
5517 #endif
5518   PetscFunctionReturn(PETSC_SUCCESS);
5519 }
5520 
5521 /*@
5522   MatIsHermitianTranspose - Test whether a matrix is another one's Hermitian transpose,
5523 
5524   Collective
5525 
5526   Input Parameters:
5527 + A   - the matrix to test
5528 . B   - the matrix to test against, this can equal the first parameter
5529 - tol - tolerance, differences between entries smaller than this are counted as zero
5530 
5531   Output Parameter:
5532 . flg - the result
5533 
5534   Level: intermediate
5535 
5536   Notes:
5537   Only available for `MATAIJ` matrices.
5538 
5539   The sequential algorithm
5540   has a running time of the order of the number of nonzeros; the parallel
5541   test involves parallel copies of the block off-diagonal parts of the matrix.
5542 
5543 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsTranspose()`
5544 @*/
5545 PetscErrorCode MatIsHermitianTranspose(Mat A, Mat B, PetscReal tol, PetscBool *flg)
5546 {
5547   PetscErrorCode (*f)(Mat, Mat, PetscReal, PetscBool *), (*g)(Mat, Mat, PetscReal, PetscBool *);
5548 
5549   PetscFunctionBegin;
5550   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5551   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5552   PetscAssertPointer(flg, 4);
5553   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatIsHermitianTranspose_C", &f));
5554   PetscCall(PetscObjectQueryFunction((PetscObject)B, "MatIsHermitianTranspose_C", &g));
5555   if (f && g) {
5556     PetscCheck(f != g, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_NOTSAMETYPE, "Matrices do not have the same comparator for Hermitian test");
5557     PetscCall((*f)(A, B, tol, flg));
5558   }
5559   PetscFunctionReturn(PETSC_SUCCESS);
5560 }
5561 
5562 /*@
5563   MatPermute - Creates a new matrix with rows and columns permuted from the
5564   original.
5565 
5566   Collective
5567 
5568   Input Parameters:
5569 + mat - the matrix to permute
5570 . row - row permutation, each processor supplies only the permutation for its rows
5571 - col - column permutation, each processor supplies only the permutation for its columns
5572 
5573   Output Parameter:
5574 . B - the permuted matrix
5575 
5576   Level: advanced
5577 
5578   Note:
5579   The index sets map from row/col of permuted matrix to row/col of original matrix.
5580   The index sets should be on the same communicator as mat and have the same local sizes.
5581 
5582   Developer Note:
5583   If you want to implement `MatPermute()` for a matrix type, and your approach doesn't
5584   exploit the fact that row and col are permutations, consider implementing the
5585   more general `MatCreateSubMatrix()` instead.
5586 
5587 .seealso: [](ch_matrices), `Mat`, `MatGetOrdering()`, `ISAllGather()`, `MatCreateSubMatrix()`
5588 @*/
5589 PetscErrorCode MatPermute(Mat mat, IS row, IS col, Mat *B)
5590 {
5591   PetscFunctionBegin;
5592   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5593   PetscValidType(mat, 1);
5594   PetscValidHeaderSpecific(row, IS_CLASSID, 2);
5595   PetscValidHeaderSpecific(col, IS_CLASSID, 3);
5596   PetscAssertPointer(B, 4);
5597   PetscCheckSameComm(mat, 1, row, 2);
5598   if (row != col) PetscCheckSameComm(row, 2, col, 3);
5599   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5600   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5601   PetscCheck(mat->ops->permute || mat->ops->createsubmatrix, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatPermute not available for Mat type %s", ((PetscObject)mat)->type_name);
5602   MatCheckPreallocated(mat, 1);
5603 
5604   if (mat->ops->permute) {
5605     PetscUseTypeMethod(mat, permute, row, col, B);
5606     PetscCall(PetscObjectStateIncrease((PetscObject)*B));
5607   } else {
5608     PetscCall(MatCreateSubMatrix(mat, row, col, MAT_INITIAL_MATRIX, B));
5609   }
5610   PetscFunctionReturn(PETSC_SUCCESS);
5611 }
5612 
5613 /*@
5614   MatEqual - Compares two matrices.
5615 
5616   Collective
5617 
5618   Input Parameters:
5619 + A - the first matrix
5620 - B - the second matrix
5621 
5622   Output Parameter:
5623 . flg - `PETSC_TRUE` if the matrices are equal; `PETSC_FALSE` otherwise.
5624 
5625   Level: intermediate
5626 
5627   Note:
5628   If either of the matrix is "matrix-free", meaning the matrix entries are not stored explicitly then equality is determined by comparing the results of several matrix-vector product
5629   using several randomly created vectors, see `MatMultEqual()`.
5630 
5631 .seealso: [](ch_matrices), `Mat`, `MatMultEqual()`
5632 @*/
5633 PetscErrorCode MatEqual(Mat A, Mat B, PetscBool *flg)
5634 {
5635   PetscFunctionBegin;
5636   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5637   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5638   PetscValidType(A, 1);
5639   PetscValidType(B, 2);
5640   PetscAssertPointer(flg, 3);
5641   PetscCheckSameComm(A, 1, B, 2);
5642   MatCheckPreallocated(A, 1);
5643   MatCheckPreallocated(B, 2);
5644   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5645   PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5646   PetscCheck(A->rmap->N == B->rmap->N && A->cmap->N == B->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Mat A,Mat B: global dim %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT, A->rmap->N, B->rmap->N, A->cmap->N,
5647              B->cmap->N);
5648   if (A->ops->equal && A->ops->equal == B->ops->equal) {
5649     PetscUseTypeMethod(A, equal, B, flg);
5650   } else {
5651     PetscCall(MatMultEqual(A, B, 10, flg));
5652   }
5653   PetscFunctionReturn(PETSC_SUCCESS);
5654 }
5655 
5656 /*@
5657   MatDiagonalScale - Scales a matrix on the left and right by diagonal
5658   matrices that are stored as vectors.  Either of the two scaling
5659   matrices can be `NULL`.
5660 
5661   Collective
5662 
5663   Input Parameters:
5664 + mat - the matrix to be scaled
5665 . l   - the left scaling vector (or `NULL`)
5666 - r   - the right scaling vector (or `NULL`)
5667 
5668   Level: intermediate
5669 
5670   Note:
5671   `MatDiagonalScale()` computes $A = LAR$, where
5672   L = a diagonal matrix (stored as a vector), R = a diagonal matrix (stored as a vector)
5673   The L scales the rows of the matrix, the R scales the columns of the matrix.
5674 
5675 .seealso: [](ch_matrices), `Mat`, `MatScale()`, `MatShift()`, `MatDiagonalSet()`
5676 @*/
5677 PetscErrorCode MatDiagonalScale(Mat mat, Vec l, Vec r)
5678 {
5679   PetscFunctionBegin;
5680   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5681   PetscValidType(mat, 1);
5682   if (l) {
5683     PetscValidHeaderSpecific(l, VEC_CLASSID, 2);
5684     PetscCheckSameComm(mat, 1, l, 2);
5685   }
5686   if (r) {
5687     PetscValidHeaderSpecific(r, VEC_CLASSID, 3);
5688     PetscCheckSameComm(mat, 1, r, 3);
5689   }
5690   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5691   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5692   MatCheckPreallocated(mat, 1);
5693   if (!l && !r) PetscFunctionReturn(PETSC_SUCCESS);
5694 
5695   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
5696   PetscUseTypeMethod(mat, diagonalscale, l, r);
5697   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
5698   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5699   if (l != r) mat->symmetric = PETSC_BOOL3_FALSE;
5700   PetscFunctionReturn(PETSC_SUCCESS);
5701 }
5702 
5703 /*@
5704   MatScale - Scales all elements of a matrix by a given number.
5705 
5706   Logically Collective
5707 
5708   Input Parameters:
5709 + mat - the matrix to be scaled
5710 - a   - the scaling value
5711 
5712   Level: intermediate
5713 
5714 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
5715 @*/
5716 PetscErrorCode MatScale(Mat mat, PetscScalar a)
5717 {
5718   PetscFunctionBegin;
5719   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5720   PetscValidType(mat, 1);
5721   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5722   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5723   PetscValidLogicalCollectiveScalar(mat, a, 2);
5724   MatCheckPreallocated(mat, 1);
5725 
5726   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
5727   if (a != (PetscScalar)1.0) {
5728     PetscUseTypeMethod(mat, scale, a);
5729     PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5730   }
5731   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
5732   PetscFunctionReturn(PETSC_SUCCESS);
5733 }
5734 
5735 /*@
5736   MatNorm - Calculates various norms of a matrix.
5737 
5738   Collective
5739 
5740   Input Parameters:
5741 + mat  - the matrix
5742 - type - the type of norm, `NORM_1`, `NORM_FROBENIUS`, `NORM_INFINITY`
5743 
5744   Output Parameter:
5745 . nrm - the resulting norm
5746 
5747   Level: intermediate
5748 
5749 .seealso: [](ch_matrices), `Mat`
5750 @*/
5751 PetscErrorCode MatNorm(Mat mat, NormType type, PetscReal *nrm)
5752 {
5753   PetscFunctionBegin;
5754   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5755   PetscValidType(mat, 1);
5756   PetscAssertPointer(nrm, 3);
5757 
5758   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5759   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5760   MatCheckPreallocated(mat, 1);
5761 
5762   PetscUseTypeMethod(mat, norm, type, nrm);
5763   PetscFunctionReturn(PETSC_SUCCESS);
5764 }
5765 
5766 /*
5767      This variable is used to prevent counting of MatAssemblyBegin() that
5768    are called from within a MatAssemblyEnd().
5769 */
5770 static PetscInt MatAssemblyEnd_InUse = 0;
5771 /*@
5772   MatAssemblyBegin - Begins assembling the matrix.  This routine should
5773   be called after completing all calls to `MatSetValues()`.
5774 
5775   Collective
5776 
5777   Input Parameters:
5778 + mat  - the matrix
5779 - type - type of assembly, either `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY`
5780 
5781   Level: beginner
5782 
5783   Notes:
5784   `MatSetValues()` generally caches the values that belong to other MPI processes.  The matrix is ready to
5785   use only after `MatAssemblyBegin()` and `MatAssemblyEnd()` have been called.
5786 
5787   Use `MAT_FLUSH_ASSEMBLY` when switching between `ADD_VALUES` and `INSERT_VALUES`
5788   in `MatSetValues()`; use `MAT_FINAL_ASSEMBLY` for the final assembly before
5789   using the matrix.
5790 
5791   ALL processes that share a matrix MUST call `MatAssemblyBegin()` and `MatAssemblyEnd()` the SAME NUMBER of times, and each time with the
5792   same flag of `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY` for all processes. Thus you CANNOT locally change from `ADD_VALUES` to `INSERT_VALUES`, that is
5793   a global collective operation requiring all processes that share the matrix.
5794 
5795   Space for preallocated nonzeros that is not filled by a call to `MatSetValues()` or a related routine are compressed
5796   out by assembly. If you intend to use that extra space on a subsequent assembly, be sure to insert explicit zeros
5797   before `MAT_FINAL_ASSEMBLY` so the space is not compressed out.
5798 
5799 .seealso: [](ch_matrices), `Mat`, `MatAssemblyEnd()`, `MatSetValues()`, `MatAssembled()`
5800 @*/
5801 PetscErrorCode MatAssemblyBegin(Mat mat, MatAssemblyType type)
5802 {
5803   PetscFunctionBegin;
5804   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5805   PetscValidType(mat, 1);
5806   MatCheckPreallocated(mat, 1);
5807   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix. Did you forget to call MatSetUnfactored()?");
5808   if (mat->assembled) {
5809     mat->was_assembled = PETSC_TRUE;
5810     mat->assembled     = PETSC_FALSE;
5811   }
5812 
5813   if (!MatAssemblyEnd_InUse) {
5814     PetscCall(PetscLogEventBegin(MAT_AssemblyBegin, mat, 0, 0, 0));
5815     PetscTryTypeMethod(mat, assemblybegin, type);
5816     PetscCall(PetscLogEventEnd(MAT_AssemblyBegin, mat, 0, 0, 0));
5817   } else PetscTryTypeMethod(mat, assemblybegin, type);
5818   PetscFunctionReturn(PETSC_SUCCESS);
5819 }
5820 
5821 /*@
5822   MatAssembled - Indicates if a matrix has been assembled and is ready for
5823   use; for example, in matrix-vector product.
5824 
5825   Not Collective
5826 
5827   Input Parameter:
5828 . mat - the matrix
5829 
5830   Output Parameter:
5831 . assembled - `PETSC_TRUE` or `PETSC_FALSE`
5832 
5833   Level: advanced
5834 
5835 .seealso: [](ch_matrices), `Mat`, `MatAssemblyEnd()`, `MatSetValues()`, `MatAssemblyBegin()`
5836 @*/
5837 PetscErrorCode MatAssembled(Mat mat, PetscBool *assembled)
5838 {
5839   PetscFunctionBegin;
5840   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5841   PetscAssertPointer(assembled, 2);
5842   *assembled = mat->assembled;
5843   PetscFunctionReturn(PETSC_SUCCESS);
5844 }
5845 
5846 /*@
5847   MatAssemblyEnd - Completes assembling the matrix.  This routine should
5848   be called after `MatAssemblyBegin()`.
5849 
5850   Collective
5851 
5852   Input Parameters:
5853 + mat  - the matrix
5854 - type - type of assembly, either `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY`
5855 
5856   Options Database Keys:
5857 + -mat_view ::ascii_info             - Prints info on matrix at conclusion of `MatAssemblyEnd()`
5858 . -mat_view ::ascii_info_detail      - Prints more detailed info
5859 . -mat_view                          - Prints matrix in ASCII format
5860 . -mat_view ::ascii_matlab           - Prints matrix in MATLAB format
5861 . -mat_view draw                     - draws nonzero structure of matrix, using `MatView()` and `PetscDrawOpenX()`.
5862 . -display <name>                    - Sets display name (default is host)
5863 . -draw_pause <sec>                  - Sets number of seconds to pause after display
5864 . -mat_view socket                   - Sends matrix to socket, can be accessed from MATLAB (See [Using MATLAB with PETSc](ch_matlab))
5865 . -viewer_socket_machine <machine>   - Machine to use for socket
5866 . -viewer_socket_port <port>         - Port number to use for socket
5867 - -mat_view binary:filename[:append] - Save matrix to file in binary format
5868 
5869   Level: beginner
5870 
5871 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatSetValues()`, `PetscDrawOpenX()`, `PetscDrawCreate()`, `MatView()`, `MatAssembled()`, `PetscViewerSocketOpen()`
5872 @*/
5873 PetscErrorCode MatAssemblyEnd(Mat mat, MatAssemblyType type)
5874 {
5875   static PetscInt inassm = 0;
5876   PetscBool       flg    = PETSC_FALSE;
5877 
5878   PetscFunctionBegin;
5879   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5880   PetscValidType(mat, 1);
5881 
5882   inassm++;
5883   MatAssemblyEnd_InUse++;
5884   if (MatAssemblyEnd_InUse == 1) { /* Do the logging only the first time through */
5885     PetscCall(PetscLogEventBegin(MAT_AssemblyEnd, mat, 0, 0, 0));
5886     PetscTryTypeMethod(mat, assemblyend, type);
5887     PetscCall(PetscLogEventEnd(MAT_AssemblyEnd, mat, 0, 0, 0));
5888   } else PetscTryTypeMethod(mat, assemblyend, type);
5889 
5890   /* Flush assembly is not a true assembly */
5891   if (type != MAT_FLUSH_ASSEMBLY) {
5892     if (mat->num_ass) {
5893       if (!mat->symmetry_eternal) {
5894         mat->symmetric = PETSC_BOOL3_UNKNOWN;
5895         mat->hermitian = PETSC_BOOL3_UNKNOWN;
5896       }
5897       if (!mat->structural_symmetry_eternal && mat->ass_nonzerostate != mat->nonzerostate) mat->structurally_symmetric = PETSC_BOOL3_UNKNOWN;
5898       if (!mat->spd_eternal) mat->spd = PETSC_BOOL3_UNKNOWN;
5899     }
5900     mat->num_ass++;
5901     mat->assembled        = PETSC_TRUE;
5902     mat->ass_nonzerostate = mat->nonzerostate;
5903   }
5904 
5905   mat->insertmode = NOT_SET_VALUES;
5906   MatAssemblyEnd_InUse--;
5907   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5908   if (inassm == 1 && type != MAT_FLUSH_ASSEMBLY) {
5909     PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
5910 
5911     if (mat->checksymmetryonassembly) {
5912       PetscCall(MatIsSymmetric(mat, mat->checksymmetrytol, &flg));
5913       if (flg) {
5914         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "Matrix is symmetric (tolerance %g)\n", (double)mat->checksymmetrytol));
5915       } else {
5916         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "Matrix is not symmetric (tolerance %g)\n", (double)mat->checksymmetrytol));
5917       }
5918     }
5919     if (mat->nullsp && mat->checknullspaceonassembly) PetscCall(MatNullSpaceTest(mat->nullsp, mat, NULL));
5920   }
5921   inassm--;
5922   PetscFunctionReturn(PETSC_SUCCESS);
5923 }
5924 
5925 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
5926 /*@
5927   MatSetOption - Sets a parameter option for a matrix. Some options
5928   may be specific to certain storage formats.  Some options
5929   determine how values will be inserted (or added). Sorted,
5930   row-oriented input will generally assemble the fastest. The default
5931   is row-oriented.
5932 
5933   Logically Collective for certain operations, such as `MAT_SPD`, not collective for `MAT_ROW_ORIENTED`, see `MatOption`
5934 
5935   Input Parameters:
5936 + mat - the matrix
5937 . op  - the option, one of those listed below (and possibly others),
5938 - flg - turn the option on (`PETSC_TRUE`) or off (`PETSC_FALSE`)
5939 
5940   Options Describing Matrix Structure:
5941 + `MAT_SPD`                         - symmetric positive definite
5942 . `MAT_SYMMETRIC`                   - symmetric in terms of both structure and value
5943 . `MAT_HERMITIAN`                   - transpose is the complex conjugation
5944 . `MAT_STRUCTURALLY_SYMMETRIC`      - symmetric nonzero structure
5945 . `MAT_SYMMETRY_ETERNAL`            - indicates the symmetry (or Hermitian structure) or its absence will persist through any changes to the matrix
5946 . `MAT_STRUCTURAL_SYMMETRY_ETERNAL` - indicates the structural symmetry or its absence will persist through any changes to the matrix
5947 . `MAT_SPD_ETERNAL`                 - indicates the value of `MAT_SPD` (true or false) will persist through any changes to the matrix
5948 
5949    These are not really options of the matrix, they are knowledge about the structure of the matrix that users may provide so that they
5950    do not need to be computed (usually at a high cost)
5951 
5952    Options For Use with `MatSetValues()`:
5953    Insert a logically dense subblock, which can be
5954 . `MAT_ROW_ORIENTED`                - row-oriented (default)
5955 
5956    These options reflect the data you pass in with `MatSetValues()`; it has
5957    nothing to do with how the data is stored internally in the matrix
5958    data structure.
5959 
5960    When (re)assembling a matrix, we can restrict the input for
5961    efficiency/debugging purposes.  These options include
5962 . `MAT_NEW_NONZERO_LOCATIONS`       - additional insertions will be allowed if they generate a new nonzero (slow)
5963 . `MAT_FORCE_DIAGONAL_ENTRIES`      - forces diagonal entries to be allocated
5964 . `MAT_IGNORE_OFF_PROC_ENTRIES`     - drops off-processor entries
5965 . `MAT_NEW_NONZERO_LOCATION_ERR`    - generates an error for new matrix entry
5966 . `MAT_USE_HASH_TABLE`              - uses a hash table to speed up matrix assembly
5967 . `MAT_NO_OFF_PROC_ENTRIES`         - you know each process will only set values for its own rows, will generate an error if
5968         any process sets values for another process. This avoids all reductions in the MatAssembly routines and thus improves
5969         performance for very large process counts.
5970 - `MAT_SUBSET_OFF_PROC_ENTRIES`     - you know that the first assembly after setting this flag will set a superset
5971         of the off-process entries required for all subsequent assemblies. This avoids a rendezvous step in the MatAssembly
5972         functions, instead sending only neighbor messages.
5973 
5974   Level: intermediate
5975 
5976   Notes:
5977   Except for `MAT_UNUSED_NONZERO_LOCATION_ERR` and  `MAT_ROW_ORIENTED` all processes that share the matrix must pass the same value in flg!
5978 
5979   Some options are relevant only for particular matrix types and
5980   are thus ignored by others.  Other options are not supported by
5981   certain matrix types and will generate an error message if set.
5982 
5983   If using Fortran to compute a matrix, one may need to
5984   use the column-oriented option (or convert to the row-oriented
5985   format).
5986 
5987   `MAT_NEW_NONZERO_LOCATIONS` set to `PETSC_FALSE` indicates that any add or insertion
5988   that would generate a new entry in the nonzero structure is instead
5989   ignored.  Thus, if memory has not already been allocated for this particular
5990   data, then the insertion is ignored. For dense matrices, in which
5991   the entire array is allocated, no entries are ever ignored.
5992   Set after the first `MatAssemblyEnd()`. If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
5993 
5994   `MAT_NEW_NONZERO_LOCATION_ERR` set to PETSC_TRUE indicates that any add or insertion
5995   that would generate a new entry in the nonzero structure instead produces
5996   an error. (Currently supported for `MATAIJ` and `MATBAIJ` formats only.) If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
5997 
5998   `MAT_NEW_NONZERO_ALLOCATION_ERR` set to `PETSC_TRUE` indicates that any add or insertion
5999   that would generate a new entry that has not been preallocated will
6000   instead produce an error. (Currently supported for `MATAIJ` and `MATBAIJ` formats
6001   only.) This is a useful flag when debugging matrix memory preallocation.
6002   If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
6003 
6004   `MAT_IGNORE_OFF_PROC_ENTRIES` set to `PETSC_TRUE` indicates entries destined for
6005   other processors should be dropped, rather than stashed.
6006   This is useful if you know that the "owning" processor is also
6007   always generating the correct matrix entries, so that PETSc need
6008   not transfer duplicate entries generated on another processor.
6009 
6010   `MAT_USE_HASH_TABLE` indicates that a hash table be used to improve the
6011   searches during matrix assembly. When this flag is set, the hash table
6012   is created during the first matrix assembly. This hash table is
6013   used the next time through, during `MatSetValues()`/`MatSetValuesBlocked()`
6014   to improve the searching of indices. `MAT_NEW_NONZERO_LOCATIONS` flag
6015   should be used with `MAT_USE_HASH_TABLE` flag. This option is currently
6016   supported by `MATMPIBAIJ` format only.
6017 
6018   `MAT_KEEP_NONZERO_PATTERN` indicates when `MatZeroRows()` is called the zeroed entries
6019   are kept in the nonzero structure. This flag is not used for `MatZeroRowsColumns()`
6020 
6021   `MAT_IGNORE_ZERO_ENTRIES` - for `MATAIJ` and `MATIS` matrices this will stop zero values from creating
6022   a zero location in the matrix
6023 
6024   `MAT_USE_INODES` - indicates using inode version of the code - works with `MATAIJ` matrix types
6025 
6026   `MAT_NO_OFF_PROC_ZERO_ROWS` - you know each process will only zero its own rows. This avoids all reductions in the
6027   zero row routines and thus improves performance for very large process counts.
6028 
6029   `MAT_IGNORE_LOWER_TRIANGULAR` - For `MATSBAIJ` matrices will ignore any insertions you make in the lower triangular
6030   part of the matrix (since they should match the upper triangular part).
6031 
6032   `MAT_SORTED_FULL` - each process provides exactly its local rows; all column indices for a given row are passed in a
6033   single call to `MatSetValues()`, preallocation is perfect, row-oriented, `INSERT_VALUES` is used. Common
6034   with finite difference schemes with non-periodic boundary conditions.
6035 
6036   Developer Note:
6037   `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, and `MAT_SPD_ETERNAL` are used by `MatAssemblyEnd()` and in other
6038   places where otherwise the value of `MAT_SYMMETRIC`, `MAT_STRUCTURALLY_SYMMETRIC` or `MAT_SPD` would need to be changed back
6039   to `PETSC_BOOL3_UNKNOWN` because the matrix values had changed so the code cannot be certain that the related property had
6040   not changed.
6041 
6042 .seealso: [](ch_matrices), `MatOption`, `Mat`, `MatGetOption()`
6043 @*/
6044 PetscErrorCode MatSetOption(Mat mat, MatOption op, PetscBool flg)
6045 {
6046   PetscFunctionBegin;
6047   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6048   if (op > 0) {
6049     PetscValidLogicalCollectiveEnum(mat, op, 2);
6050     PetscValidLogicalCollectiveBool(mat, flg, 3);
6051   }
6052 
6053   PetscCheck(((int)op) > MAT_OPTION_MIN && ((int)op) < MAT_OPTION_MAX, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Options %d is out of range", (int)op);
6054 
6055   switch (op) {
6056   case MAT_FORCE_DIAGONAL_ENTRIES:
6057     mat->force_diagonals = flg;
6058     PetscFunctionReturn(PETSC_SUCCESS);
6059   case MAT_NO_OFF_PROC_ENTRIES:
6060     mat->nooffprocentries = flg;
6061     PetscFunctionReturn(PETSC_SUCCESS);
6062   case MAT_SUBSET_OFF_PROC_ENTRIES:
6063     mat->assembly_subset = flg;
6064     if (!mat->assembly_subset) { /* See the same logic in VecAssembly wrt VEC_SUBSET_OFF_PROC_ENTRIES */
6065 #if !defined(PETSC_HAVE_MPIUNI)
6066       PetscCall(MatStashScatterDestroy_BTS(&mat->stash));
6067 #endif
6068       mat->stash.first_assembly_done = PETSC_FALSE;
6069     }
6070     PetscFunctionReturn(PETSC_SUCCESS);
6071   case MAT_NO_OFF_PROC_ZERO_ROWS:
6072     mat->nooffproczerorows = flg;
6073     PetscFunctionReturn(PETSC_SUCCESS);
6074   case MAT_SPD:
6075     if (flg) {
6076       mat->spd                    = PETSC_BOOL3_TRUE;
6077       mat->symmetric              = PETSC_BOOL3_TRUE;
6078       mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6079     } else {
6080       mat->spd = PETSC_BOOL3_FALSE;
6081     }
6082     break;
6083   case MAT_SYMMETRIC:
6084     mat->symmetric = PetscBoolToBool3(flg);
6085     if (flg) mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6086 #if !defined(PETSC_USE_COMPLEX)
6087     mat->hermitian = PetscBoolToBool3(flg);
6088 #endif
6089     break;
6090   case MAT_HERMITIAN:
6091     mat->hermitian = PetscBoolToBool3(flg);
6092     if (flg) mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6093 #if !defined(PETSC_USE_COMPLEX)
6094     mat->symmetric = PetscBoolToBool3(flg);
6095 #endif
6096     break;
6097   case MAT_STRUCTURALLY_SYMMETRIC:
6098     mat->structurally_symmetric = PetscBoolToBool3(flg);
6099     break;
6100   case MAT_SYMMETRY_ETERNAL:
6101     PetscCheck(mat->symmetric != PETSC_BOOL3_UNKNOWN, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot set MAT_SYMMETRY_ETERNAL without first setting MAT_SYMMETRIC to true or false");
6102     mat->symmetry_eternal = flg;
6103     if (flg) mat->structural_symmetry_eternal = PETSC_TRUE;
6104     break;
6105   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
6106     PetscCheck(mat->structurally_symmetric != PETSC_BOOL3_UNKNOWN, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot set MAT_STRUCTURAL_SYMMETRY_ETERNAL without first setting MAT_STRUCTURALLY_SYMMETRIC to true or false");
6107     mat->structural_symmetry_eternal = flg;
6108     break;
6109   case MAT_SPD_ETERNAL:
6110     PetscCheck(mat->spd != PETSC_BOOL3_UNKNOWN, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot set MAT_SPD_ETERNAL without first setting MAT_SPD to true or false");
6111     mat->spd_eternal = flg;
6112     if (flg) {
6113       mat->structural_symmetry_eternal = PETSC_TRUE;
6114       mat->symmetry_eternal            = PETSC_TRUE;
6115     }
6116     break;
6117   case MAT_STRUCTURE_ONLY:
6118     mat->structure_only = flg;
6119     break;
6120   case MAT_SORTED_FULL:
6121     mat->sortedfull = flg;
6122     break;
6123   default:
6124     break;
6125   }
6126   PetscTryTypeMethod(mat, setoption, op, flg);
6127   PetscFunctionReturn(PETSC_SUCCESS);
6128 }
6129 
6130 /*@
6131   MatGetOption - Gets a parameter option that has been set for a matrix.
6132 
6133   Logically Collective
6134 
6135   Input Parameters:
6136 + mat - the matrix
6137 - op  - the option, this only responds to certain options, check the code for which ones
6138 
6139   Output Parameter:
6140 . flg - turn the option on (`PETSC_TRUE`) or off (`PETSC_FALSE`)
6141 
6142   Level: intermediate
6143 
6144   Notes:
6145   Can only be called after `MatSetSizes()` and `MatSetType()` have been set.
6146 
6147   Certain option values may be unknown, for those use the routines `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, or
6148   `MatIsSymmetricKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
6149 
6150 .seealso: [](ch_matrices), `Mat`, `MatOption`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`,
6151     `MatIsSymmetricKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
6152 @*/
6153 PetscErrorCode MatGetOption(Mat mat, MatOption op, PetscBool *flg)
6154 {
6155   PetscFunctionBegin;
6156   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6157   PetscValidType(mat, 1);
6158 
6159   PetscCheck(((int)op) > MAT_OPTION_MIN && ((int)op) < MAT_OPTION_MAX, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Options %d is out of range", (int)op);
6160   PetscCheck(((PetscObject)mat)->type_name, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_TYPENOTSET, "Cannot get options until type and size have been set, see MatSetType() and MatSetSizes()");
6161 
6162   switch (op) {
6163   case MAT_NO_OFF_PROC_ENTRIES:
6164     *flg = mat->nooffprocentries;
6165     break;
6166   case MAT_NO_OFF_PROC_ZERO_ROWS:
6167     *flg = mat->nooffproczerorows;
6168     break;
6169   case MAT_SYMMETRIC:
6170     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsSymmetric() or MatIsSymmetricKnown()");
6171     break;
6172   case MAT_HERMITIAN:
6173     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsHermitian() or MatIsHermitianKnown()");
6174     break;
6175   case MAT_STRUCTURALLY_SYMMETRIC:
6176     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsStructurallySymmetric() or MatIsStructurallySymmetricKnown()");
6177     break;
6178   case MAT_SPD:
6179     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsSPDKnown()");
6180     break;
6181   case MAT_SYMMETRY_ETERNAL:
6182     *flg = mat->symmetry_eternal;
6183     break;
6184   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
6185     *flg = mat->symmetry_eternal;
6186     break;
6187   default:
6188     break;
6189   }
6190   PetscFunctionReturn(PETSC_SUCCESS);
6191 }
6192 
6193 /*@
6194   MatZeroEntries - Zeros all entries of a matrix.  For sparse matrices
6195   this routine retains the old nonzero structure.
6196 
6197   Logically Collective
6198 
6199   Input Parameter:
6200 . mat - the matrix
6201 
6202   Level: intermediate
6203 
6204   Note:
6205   If the matrix was not preallocated then a default, likely poor preallocation will be set in the matrix, so this should be called after the preallocation phase.
6206   See the Performance chapter of the users manual for information on preallocating matrices.
6207 
6208 .seealso: [](ch_matrices), `Mat`, `MatZeroRows()`, `MatZeroRowsColumns()`
6209 @*/
6210 PetscErrorCode MatZeroEntries(Mat mat)
6211 {
6212   PetscFunctionBegin;
6213   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6214   PetscValidType(mat, 1);
6215   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6216   PetscCheck(mat->insertmode == NOT_SET_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for matrices where you have set values but not yet assembled");
6217   MatCheckPreallocated(mat, 1);
6218 
6219   PetscCall(PetscLogEventBegin(MAT_ZeroEntries, mat, 0, 0, 0));
6220   PetscUseTypeMethod(mat, zeroentries);
6221   PetscCall(PetscLogEventEnd(MAT_ZeroEntries, mat, 0, 0, 0));
6222   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6223   PetscFunctionReturn(PETSC_SUCCESS);
6224 }
6225 
6226 /*@
6227   MatZeroRowsColumns - Zeros all entries (except possibly the main diagonal)
6228   of a set of rows and columns of a matrix.
6229 
6230   Collective
6231 
6232   Input Parameters:
6233 + mat     - the matrix
6234 . numRows - the number of rows/columns to zero
6235 . rows    - the global row indices
6236 . diag    - value put in the diagonal of the eliminated rows
6237 . x       - optional vector of the solution for zeroed rows (other entries in vector are not used), these must be set before this call
6238 - b       - optional vector of the right-hand side, that will be adjusted by provided solution entries
6239 
6240   Level: intermediate
6241 
6242   Notes:
6243   This routine, along with `MatZeroRows()`, is typically used to eliminate known Dirichlet boundary conditions from a linear system.
6244 
6245   For each zeroed row, the value of the corresponding `b` is set to diag times the value of the corresponding `x`.
6246   The other entries of `b` will be adjusted by the known values of `x` times the corresponding matrix entries in the columns that are being eliminated
6247 
6248   If the resulting linear system is to be solved with `KSP` then one can (but does not have to) call `KSPSetInitialGuessNonzero()` to allow the
6249   Krylov method to take advantage of the known solution on the zeroed rows.
6250 
6251   For the parallel case, all processes that share the matrix (i.e.,
6252   those in the communicator used for matrix creation) MUST call this
6253   routine, regardless of whether any rows being zeroed are owned by
6254   them.
6255 
6256   Unlike `MatZeroRows()`, this ignores the `MAT_KEEP_NONZERO_PATTERN` option value set with `MatSetOption()`, it merely zeros those entries in the matrix, but never
6257   removes them from the nonzero pattern. The nonzero pattern of the matrix can still change if a nonzero needs to be inserted on a diagonal entry that was previously
6258   missing.
6259 
6260   Each processor can indicate any rows in the entire matrix to be zeroed (i.e. each process does NOT have to
6261   list only rows local to itself).
6262 
6263   The option `MAT_NO_OFF_PROC_ZERO_ROWS` does not apply to this routine.
6264 
6265 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRows()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6266           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6267 @*/
6268 PetscErrorCode MatZeroRowsColumns(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6269 {
6270   PetscFunctionBegin;
6271   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6272   PetscValidType(mat, 1);
6273   if (numRows) PetscAssertPointer(rows, 3);
6274   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6275   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6276   MatCheckPreallocated(mat, 1);
6277 
6278   PetscUseTypeMethod(mat, zerorowscolumns, numRows, rows, diag, x, b);
6279   PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
6280   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6281   PetscFunctionReturn(PETSC_SUCCESS);
6282 }
6283 
6284 /*@
6285   MatZeroRowsColumnsIS - Zeros all entries (except possibly the main diagonal)
6286   of a set of rows and columns of a matrix.
6287 
6288   Collective
6289 
6290   Input Parameters:
6291 + mat  - the matrix
6292 . is   - the rows to zero
6293 . diag - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6294 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6295 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6296 
6297   Level: intermediate
6298 
6299   Note:
6300   See `MatZeroRowsColumns()` for details on how this routine operates.
6301 
6302 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6303           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRows()`, `MatZeroRowsColumnsStencil()`
6304 @*/
6305 PetscErrorCode MatZeroRowsColumnsIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6306 {
6307   PetscInt        numRows;
6308   const PetscInt *rows;
6309 
6310   PetscFunctionBegin;
6311   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6312   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6313   PetscValidType(mat, 1);
6314   PetscValidType(is, 2);
6315   PetscCall(ISGetLocalSize(is, &numRows));
6316   PetscCall(ISGetIndices(is, &rows));
6317   PetscCall(MatZeroRowsColumns(mat, numRows, rows, diag, x, b));
6318   PetscCall(ISRestoreIndices(is, &rows));
6319   PetscFunctionReturn(PETSC_SUCCESS);
6320 }
6321 
6322 /*@
6323   MatZeroRows - Zeros all entries (except possibly the main diagonal)
6324   of a set of rows of a matrix.
6325 
6326   Collective
6327 
6328   Input Parameters:
6329 + mat     - the matrix
6330 . numRows - the number of rows to zero
6331 . rows    - the global row indices
6332 . diag    - value put in the diagonal of the zeroed rows
6333 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used), these must be set before this call
6334 - b       - optional vector of right-hand side, that will be adjusted by provided solution entries
6335 
6336   Level: intermediate
6337 
6338   Notes:
6339   This routine, along with `MatZeroRowsColumns()`, is typically used to eliminate known Dirichlet boundary conditions from a linear system.
6340 
6341   For each zeroed row, the value of the corresponding `b` is set to `diag` times the value of the corresponding `x`.
6342 
6343   If the resulting linear system is to be solved with `KSP` then one can (but does not have to) call `KSPSetInitialGuessNonzero()` to allow the
6344   Krylov method to take advantage of the known solution on the zeroed rows.
6345 
6346   May be followed by using a `PC` of type `PCREDISTRIBUTE` to solve the reduced problem (`PCDISTRIBUTE` completely eliminates the zeroed rows and their corresponding columns)
6347   from the matrix.
6348 
6349   Unlike `MatZeroRowsColumns()` for the `MATAIJ` and `MATBAIJ` matrix formats this removes the old nonzero structure, from the eliminated rows of the matrix
6350   but does not release memory.  Because of this removal matrix-vector products with the adjusted matrix will be a bit faster. For the dense
6351   formats this does not alter the nonzero structure.
6352 
6353   If the option `MatSetOption`(mat,`MAT_KEEP_NONZERO_PATTERN`,`PETSC_TRUE`) the nonzero structure
6354   of the matrix is not changed the values are
6355   merely zeroed.
6356 
6357   The user can set a value in the diagonal entry (or for the `MATAIJ` format
6358   formats can optionally remove the main diagonal entry from the
6359   nonzero structure as well, by passing 0.0 as the final argument).
6360 
6361   For the parallel case, all processes that share the matrix (i.e.,
6362   those in the communicator used for matrix creation) MUST call this
6363   routine, regardless of whether any rows being zeroed are owned by
6364   them.
6365 
6366   Each processor can indicate any rows in the entire matrix to be zeroed (i.e. each process does NOT have to
6367   list only rows local to itself).
6368 
6369   You can call `MatSetOption`(mat,`MAT_NO_OFF_PROC_ZERO_ROWS`,`PETSC_TRUE`) if each process indicates only rows it
6370   owns that are to be zeroed. This saves a global synchronization in the implementation.
6371 
6372 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6373           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`, `PCREDISTRIBUTE`, `MAT_KEEP_NONZERO_PATTERN`
6374 @*/
6375 PetscErrorCode MatZeroRows(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6376 {
6377   PetscFunctionBegin;
6378   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6379   PetscValidType(mat, 1);
6380   if (numRows) PetscAssertPointer(rows, 3);
6381   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6382   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6383   MatCheckPreallocated(mat, 1);
6384 
6385   PetscUseTypeMethod(mat, zerorows, numRows, rows, diag, x, b);
6386   PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
6387   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6388   PetscFunctionReturn(PETSC_SUCCESS);
6389 }
6390 
6391 /*@
6392   MatZeroRowsIS - Zeros all entries (except possibly the main diagonal)
6393   of a set of rows of a matrix indicated by an `IS`
6394 
6395   Collective
6396 
6397   Input Parameters:
6398 + mat  - the matrix
6399 . is   - index set, `IS`, of rows to remove (if `NULL` then no row is removed)
6400 . diag - value put in all diagonals of eliminated rows
6401 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6402 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6403 
6404   Level: intermediate
6405 
6406   Note:
6407   See `MatZeroRows()` for details on how this routine operates.
6408 
6409 .seealso: [](ch_matrices), `Mat`, `MatZeroRows()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6410           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`, `IS`
6411 @*/
6412 PetscErrorCode MatZeroRowsIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6413 {
6414   PetscInt        numRows = 0;
6415   const PetscInt *rows    = NULL;
6416 
6417   PetscFunctionBegin;
6418   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6419   PetscValidType(mat, 1);
6420   if (is) {
6421     PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6422     PetscCall(ISGetLocalSize(is, &numRows));
6423     PetscCall(ISGetIndices(is, &rows));
6424   }
6425   PetscCall(MatZeroRows(mat, numRows, rows, diag, x, b));
6426   if (is) PetscCall(ISRestoreIndices(is, &rows));
6427   PetscFunctionReturn(PETSC_SUCCESS);
6428 }
6429 
6430 /*@
6431   MatZeroRowsStencil - Zeros all entries (except possibly the main diagonal)
6432   of a set of rows of a matrix indicated by a `MatStencil`. These rows must be local to the process.
6433 
6434   Collective
6435 
6436   Input Parameters:
6437 + mat     - the matrix
6438 . numRows - the number of rows to remove
6439 . rows    - the grid coordinates (and component number when dof > 1) for matrix rows indicated by an array of `MatStencil`
6440 . diag    - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6441 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6442 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6443 
6444   Level: intermediate
6445 
6446   Notes:
6447   See `MatZeroRows()` for details on how this routine operates.
6448 
6449   The grid coordinates are across the entire grid, not just the local portion
6450 
6451   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
6452   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
6453   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
6454   `DM_BOUNDARY_PERIODIC` boundary type.
6455 
6456   For indices that don't mean anything for your case (like the `k` index when working in 2d) or the `c` index when you have
6457   a single value per point) you can skip filling those indices.
6458 
6459   Fortran Note:
6460   `idxm` and `idxn` should be declared as
6461 .vb
6462     MatStencil idxm(4, m)
6463 .ve
6464   and the values inserted using
6465 .vb
6466     idxm(MatStencil_i, 1) = i
6467     idxm(MatStencil_j, 1) = j
6468     idxm(MatStencil_k, 1) = k
6469     idxm(MatStencil_c, 1) = c
6470    etc
6471 .ve
6472 
6473 .seealso: [](ch_matrices), `Mat`, `MatStencil`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRows()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6474           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6475 @*/
6476 PetscErrorCode MatZeroRowsStencil(Mat mat, PetscInt numRows, const MatStencil rows[], PetscScalar diag, Vec x, Vec b)
6477 {
6478   PetscInt  dim    = mat->stencil.dim;
6479   PetscInt  sdim   = dim - (1 - (PetscInt)mat->stencil.noc);
6480   PetscInt *dims   = mat->stencil.dims + 1;
6481   PetscInt *starts = mat->stencil.starts;
6482   PetscInt *dxm    = (PetscInt *)rows;
6483   PetscInt *jdxm, i, j, tmp, numNewRows = 0;
6484 
6485   PetscFunctionBegin;
6486   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6487   PetscValidType(mat, 1);
6488   if (numRows) PetscAssertPointer(rows, 3);
6489 
6490   PetscCall(PetscMalloc1(numRows, &jdxm));
6491   for (i = 0; i < numRows; ++i) {
6492     /* Skip unused dimensions (they are ordered k, j, i, c) */
6493     for (j = 0; j < 3 - sdim; ++j) dxm++;
6494     /* Local index in X dir */
6495     tmp = *dxm++ - starts[0];
6496     /* Loop over remaining dimensions */
6497     for (j = 0; j < dim - 1; ++j) {
6498       /* If nonlocal, set index to be negative */
6499       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = PETSC_INT_MIN;
6500       /* Update local index */
6501       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
6502     }
6503     /* Skip component slot if necessary */
6504     if (mat->stencil.noc) dxm++;
6505     /* Local row number */
6506     if (tmp >= 0) jdxm[numNewRows++] = tmp;
6507   }
6508   PetscCall(MatZeroRowsLocal(mat, numNewRows, jdxm, diag, x, b));
6509   PetscCall(PetscFree(jdxm));
6510   PetscFunctionReturn(PETSC_SUCCESS);
6511 }
6512 
6513 /*@
6514   MatZeroRowsColumnsStencil - Zeros all row and column entries (except possibly the main diagonal)
6515   of a set of rows and columns of a matrix.
6516 
6517   Collective
6518 
6519   Input Parameters:
6520 + mat     - the matrix
6521 . numRows - the number of rows/columns to remove
6522 . rows    - the grid coordinates (and component number when dof > 1) for matrix rows
6523 . diag    - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6524 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6525 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6526 
6527   Level: intermediate
6528 
6529   Notes:
6530   See `MatZeroRowsColumns()` for details on how this routine operates.
6531 
6532   The grid coordinates are across the entire grid, not just the local portion
6533 
6534   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
6535   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
6536   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
6537   `DM_BOUNDARY_PERIODIC` boundary type.
6538 
6539   For indices that don't mean anything for your case (like the `k` index when working in 2d) or the `c` index when you have
6540   a single value per point) you can skip filling those indices.
6541 
6542   Fortran Note:
6543   `idxm` and `idxn` should be declared as
6544 .vb
6545     MatStencil idxm(4, m)
6546 .ve
6547   and the values inserted using
6548 .vb
6549     idxm(MatStencil_i, 1) = i
6550     idxm(MatStencil_j, 1) = j
6551     idxm(MatStencil_k, 1) = k
6552     idxm(MatStencil_c, 1) = c
6553     etc
6554 .ve
6555 
6556 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6557           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRows()`
6558 @*/
6559 PetscErrorCode MatZeroRowsColumnsStencil(Mat mat, PetscInt numRows, const MatStencil rows[], PetscScalar diag, Vec x, Vec b)
6560 {
6561   PetscInt  dim    = mat->stencil.dim;
6562   PetscInt  sdim   = dim - (1 - (PetscInt)mat->stencil.noc);
6563   PetscInt *dims   = mat->stencil.dims + 1;
6564   PetscInt *starts = mat->stencil.starts;
6565   PetscInt *dxm    = (PetscInt *)rows;
6566   PetscInt *jdxm, i, j, tmp, numNewRows = 0;
6567 
6568   PetscFunctionBegin;
6569   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6570   PetscValidType(mat, 1);
6571   if (numRows) PetscAssertPointer(rows, 3);
6572 
6573   PetscCall(PetscMalloc1(numRows, &jdxm));
6574   for (i = 0; i < numRows; ++i) {
6575     /* Skip unused dimensions (they are ordered k, j, i, c) */
6576     for (j = 0; j < 3 - sdim; ++j) dxm++;
6577     /* Local index in X dir */
6578     tmp = *dxm++ - starts[0];
6579     /* Loop over remaining dimensions */
6580     for (j = 0; j < dim - 1; ++j) {
6581       /* If nonlocal, set index to be negative */
6582       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = PETSC_INT_MIN;
6583       /* Update local index */
6584       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
6585     }
6586     /* Skip component slot if necessary */
6587     if (mat->stencil.noc) dxm++;
6588     /* Local row number */
6589     if (tmp >= 0) jdxm[numNewRows++] = tmp;
6590   }
6591   PetscCall(MatZeroRowsColumnsLocal(mat, numNewRows, jdxm, diag, x, b));
6592   PetscCall(PetscFree(jdxm));
6593   PetscFunctionReturn(PETSC_SUCCESS);
6594 }
6595 
6596 /*@
6597   MatZeroRowsLocal - Zeros all entries (except possibly the main diagonal)
6598   of a set of rows of a matrix; using local numbering of rows.
6599 
6600   Collective
6601 
6602   Input Parameters:
6603 + mat     - the matrix
6604 . numRows - the number of rows to remove
6605 . rows    - the local row indices
6606 . diag    - value put in all diagonals of eliminated rows
6607 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6608 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6609 
6610   Level: intermediate
6611 
6612   Notes:
6613   Before calling `MatZeroRowsLocal()`, the user must first set the
6614   local-to-global mapping by calling MatSetLocalToGlobalMapping(), this is often already set for matrices obtained with `DMCreateMatrix()`.
6615 
6616   See `MatZeroRows()` for details on how this routine operates.
6617 
6618 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRows()`, `MatSetOption()`,
6619           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6620 @*/
6621 PetscErrorCode MatZeroRowsLocal(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6622 {
6623   PetscFunctionBegin;
6624   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6625   PetscValidType(mat, 1);
6626   if (numRows) PetscAssertPointer(rows, 3);
6627   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6628   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6629   MatCheckPreallocated(mat, 1);
6630 
6631   if (mat->ops->zerorowslocal) {
6632     PetscUseTypeMethod(mat, zerorowslocal, numRows, rows, diag, x, b);
6633   } else {
6634     IS              is, newis;
6635     const PetscInt *newRows;
6636 
6637     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Need to provide local to global mapping to matrix first");
6638     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numRows, rows, PETSC_COPY_VALUES, &is));
6639     PetscCall(ISLocalToGlobalMappingApplyIS(mat->rmap->mapping, is, &newis));
6640     PetscCall(ISGetIndices(newis, &newRows));
6641     PetscUseTypeMethod(mat, zerorows, numRows, newRows, diag, x, b);
6642     PetscCall(ISRestoreIndices(newis, &newRows));
6643     PetscCall(ISDestroy(&newis));
6644     PetscCall(ISDestroy(&is));
6645   }
6646   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6647   PetscFunctionReturn(PETSC_SUCCESS);
6648 }
6649 
6650 /*@
6651   MatZeroRowsLocalIS - Zeros all entries (except possibly the main diagonal)
6652   of a set of rows of a matrix; using local numbering of rows.
6653 
6654   Collective
6655 
6656   Input Parameters:
6657 + mat  - the matrix
6658 . is   - index set of rows to remove
6659 . diag - value put in all diagonals of eliminated rows
6660 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6661 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6662 
6663   Level: intermediate
6664 
6665   Notes:
6666   Before calling `MatZeroRowsLocalIS()`, the user must first set the
6667   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6668 
6669   See `MatZeroRows()` for details on how this routine operates.
6670 
6671 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRows()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6672           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6673 @*/
6674 PetscErrorCode MatZeroRowsLocalIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6675 {
6676   PetscInt        numRows;
6677   const PetscInt *rows;
6678 
6679   PetscFunctionBegin;
6680   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6681   PetscValidType(mat, 1);
6682   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6683   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6684   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6685   MatCheckPreallocated(mat, 1);
6686 
6687   PetscCall(ISGetLocalSize(is, &numRows));
6688   PetscCall(ISGetIndices(is, &rows));
6689   PetscCall(MatZeroRowsLocal(mat, numRows, rows, diag, x, b));
6690   PetscCall(ISRestoreIndices(is, &rows));
6691   PetscFunctionReturn(PETSC_SUCCESS);
6692 }
6693 
6694 /*@
6695   MatZeroRowsColumnsLocal - Zeros all entries (except possibly the main diagonal)
6696   of a set of rows and columns of a matrix; using local numbering of rows.
6697 
6698   Collective
6699 
6700   Input Parameters:
6701 + mat     - the matrix
6702 . numRows - the number of rows to remove
6703 . rows    - the global row indices
6704 . diag    - value put in all diagonals of eliminated rows
6705 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6706 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6707 
6708   Level: intermediate
6709 
6710   Notes:
6711   Before calling `MatZeroRowsColumnsLocal()`, the user must first set the
6712   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6713 
6714   See `MatZeroRowsColumns()` for details on how this routine operates.
6715 
6716 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6717           `MatZeroRows()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6718 @*/
6719 PetscErrorCode MatZeroRowsColumnsLocal(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6720 {
6721   IS              is, newis;
6722   const PetscInt *newRows;
6723 
6724   PetscFunctionBegin;
6725   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6726   PetscValidType(mat, 1);
6727   if (numRows) PetscAssertPointer(rows, 3);
6728   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6729   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6730   MatCheckPreallocated(mat, 1);
6731 
6732   PetscCheck(mat->cmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Need to provide local to global mapping to matrix first");
6733   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numRows, rows, PETSC_COPY_VALUES, &is));
6734   PetscCall(ISLocalToGlobalMappingApplyIS(mat->cmap->mapping, is, &newis));
6735   PetscCall(ISGetIndices(newis, &newRows));
6736   PetscUseTypeMethod(mat, zerorowscolumns, numRows, newRows, diag, x, b);
6737   PetscCall(ISRestoreIndices(newis, &newRows));
6738   PetscCall(ISDestroy(&newis));
6739   PetscCall(ISDestroy(&is));
6740   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6741   PetscFunctionReturn(PETSC_SUCCESS);
6742 }
6743 
6744 /*@
6745   MatZeroRowsColumnsLocalIS - Zeros all entries (except possibly the main diagonal)
6746   of a set of rows and columns of a matrix; using local numbering of rows.
6747 
6748   Collective
6749 
6750   Input Parameters:
6751 + mat  - the matrix
6752 . is   - index set of rows to remove
6753 . diag - value put in all diagonals of eliminated rows
6754 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6755 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6756 
6757   Level: intermediate
6758 
6759   Notes:
6760   Before calling `MatZeroRowsColumnsLocalIS()`, the user must first set the
6761   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6762 
6763   See `MatZeroRowsColumns()` for details on how this routine operates.
6764 
6765 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6766           `MatZeroRowsColumnsLocal()`, `MatZeroRows()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6767 @*/
6768 PetscErrorCode MatZeroRowsColumnsLocalIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6769 {
6770   PetscInt        numRows;
6771   const PetscInt *rows;
6772 
6773   PetscFunctionBegin;
6774   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6775   PetscValidType(mat, 1);
6776   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6777   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6778   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6779   MatCheckPreallocated(mat, 1);
6780 
6781   PetscCall(ISGetLocalSize(is, &numRows));
6782   PetscCall(ISGetIndices(is, &rows));
6783   PetscCall(MatZeroRowsColumnsLocal(mat, numRows, rows, diag, x, b));
6784   PetscCall(ISRestoreIndices(is, &rows));
6785   PetscFunctionReturn(PETSC_SUCCESS);
6786 }
6787 
6788 /*@
6789   MatGetSize - Returns the numbers of rows and columns in a matrix.
6790 
6791   Not Collective
6792 
6793   Input Parameter:
6794 . mat - the matrix
6795 
6796   Output Parameters:
6797 + m - the number of global rows
6798 - n - the number of global columns
6799 
6800   Level: beginner
6801 
6802   Note:
6803   Both output parameters can be `NULL` on input.
6804 
6805 .seealso: [](ch_matrices), `Mat`, `MatSetSizes()`, `MatGetLocalSize()`
6806 @*/
6807 PetscErrorCode MatGetSize(Mat mat, PetscInt *m, PetscInt *n)
6808 {
6809   PetscFunctionBegin;
6810   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6811   if (m) *m = mat->rmap->N;
6812   if (n) *n = mat->cmap->N;
6813   PetscFunctionReturn(PETSC_SUCCESS);
6814 }
6815 
6816 /*@
6817   MatGetLocalSize - For most matrix formats, excluding `MATELEMENTAL` and `MATSCALAPACK`, Returns the number of local rows and local columns
6818   of a matrix. For all matrices this is the local size of the left and right vectors as returned by `MatCreateVecs()`.
6819 
6820   Not Collective
6821 
6822   Input Parameter:
6823 . mat - the matrix
6824 
6825   Output Parameters:
6826 + m - the number of local rows, use `NULL` to not obtain this value
6827 - n - the number of local columns, use `NULL` to not obtain this value
6828 
6829   Level: beginner
6830 
6831 .seealso: [](ch_matrices), `Mat`, `MatSetSizes()`, `MatGetSize()`
6832 @*/
6833 PetscErrorCode MatGetLocalSize(Mat mat, PetscInt *m, PetscInt *n)
6834 {
6835   PetscFunctionBegin;
6836   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6837   if (m) PetscAssertPointer(m, 2);
6838   if (n) PetscAssertPointer(n, 3);
6839   if (m) *m = mat->rmap->n;
6840   if (n) *n = mat->cmap->n;
6841   PetscFunctionReturn(PETSC_SUCCESS);
6842 }
6843 
6844 /*@
6845   MatGetOwnershipRangeColumn - Returns the range of matrix columns associated with rows of a
6846   vector one multiplies this matrix by that are owned by this processor.
6847 
6848   Not Collective, unless matrix has not been allocated, then collective
6849 
6850   Input Parameter:
6851 . mat - the matrix
6852 
6853   Output Parameters:
6854 + m - the global index of the first local column, use `NULL` to not obtain this value
6855 - n - one more than the global index of the last local column, use `NULL` to not obtain this value
6856 
6857   Level: developer
6858 
6859   Notes:
6860   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6861 
6862   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6863   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6864 
6865   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6866   the local values in the matrix.
6867 
6868   Returns the columns of the "diagonal block" for most sparse matrix formats. See [Matrix
6869   Layouts](sec_matlayout) for details on matrix layouts.
6870 
6871 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`,
6872           `MatSetSizes()`, `MatCreateAIJ()`, `DMDAGetGhostCorners()`, `DM`
6873 @*/
6874 PetscErrorCode MatGetOwnershipRangeColumn(Mat mat, PetscInt *m, PetscInt *n)
6875 {
6876   PetscFunctionBegin;
6877   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6878   PetscValidType(mat, 1);
6879   if (m) PetscAssertPointer(m, 2);
6880   if (n) PetscAssertPointer(n, 3);
6881   MatCheckPreallocated(mat, 1);
6882   if (m) *m = mat->cmap->rstart;
6883   if (n) *n = mat->cmap->rend;
6884   PetscFunctionReturn(PETSC_SUCCESS);
6885 }
6886 
6887 /*@
6888   MatGetOwnershipRange - For matrices that own values by row, excludes `MATELEMENTAL` and `MATSCALAPACK`, returns the range of matrix rows owned by
6889   this MPI process.
6890 
6891   Not Collective
6892 
6893   Input Parameter:
6894 . mat - the matrix
6895 
6896   Output Parameters:
6897 + m - the global index of the first local row, use `NULL` to not obtain this value
6898 - n - one more than the global index of the last local row, use `NULL` to not obtain this value
6899 
6900   Level: beginner
6901 
6902   Notes:
6903   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6904 
6905   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6906   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6907 
6908   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6909   the local values in the matrix.
6910 
6911   The high argument is one more than the last element stored locally.
6912 
6913   For all matrices  it returns the range of matrix rows associated with rows of a vector that
6914   would contain the result of a matrix vector product with this matrix. See [Matrix
6915   Layouts](sec_matlayout) for details on matrix layouts.
6916 
6917 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscSplitOwnership()`,
6918           `PetscSplitOwnershipBlock()`, `PetscLayout`, `MatSetSizes()`, `MatCreateAIJ()`, `DMDAGetGhostCorners()`, `DM`
6919 @*/
6920 PetscErrorCode MatGetOwnershipRange(Mat mat, PetscInt *m, PetscInt *n)
6921 {
6922   PetscFunctionBegin;
6923   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6924   PetscValidType(mat, 1);
6925   if (m) PetscAssertPointer(m, 2);
6926   if (n) PetscAssertPointer(n, 3);
6927   MatCheckPreallocated(mat, 1);
6928   if (m) *m = mat->rmap->rstart;
6929   if (n) *n = mat->rmap->rend;
6930   PetscFunctionReturn(PETSC_SUCCESS);
6931 }
6932 
6933 /*@C
6934   MatGetOwnershipRanges - For matrices that own values by row, excludes `MATELEMENTAL` and
6935   `MATSCALAPACK`, returns the range of matrix rows owned by each process.
6936 
6937   Not Collective, unless matrix has not been allocated
6938 
6939   Input Parameter:
6940 . mat - the matrix
6941 
6942   Output Parameter:
6943 . ranges - start of each processors portion plus one more than the total length at the end, of length `size` + 1
6944            where `size` is the number of MPI processes used by `mat`
6945 
6946   Level: beginner
6947 
6948   Notes:
6949   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6950 
6951   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6952   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6953 
6954   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6955   the local values in the matrix.
6956 
6957   For all matrices  it returns the ranges of matrix rows associated with rows of a vector that
6958   would contain the result of a matrix vector product with this matrix. See [Matrix
6959   Layouts](sec_matlayout) for details on matrix layouts.
6960 
6961 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`,
6962           `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`, `MatSetSizes()`, `MatCreateAIJ()`,
6963           `DMDAGetGhostCorners()`, `DM`
6964 @*/
6965 PetscErrorCode MatGetOwnershipRanges(Mat mat, const PetscInt *ranges[])
6966 {
6967   PetscFunctionBegin;
6968   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6969   PetscValidType(mat, 1);
6970   MatCheckPreallocated(mat, 1);
6971   PetscCall(PetscLayoutGetRanges(mat->rmap, ranges));
6972   PetscFunctionReturn(PETSC_SUCCESS);
6973 }
6974 
6975 /*@C
6976   MatGetOwnershipRangesColumn - Returns the ranges of matrix columns associated with rows of a
6977   vector one multiplies this vector by that are owned by each processor.
6978 
6979   Not Collective, unless matrix has not been allocated
6980 
6981   Input Parameter:
6982 . mat - the matrix
6983 
6984   Output Parameter:
6985 . ranges - start of each processors portion plus one more than the total length at the end
6986 
6987   Level: beginner
6988 
6989   Notes:
6990   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6991 
6992   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6993   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6994 
6995   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6996   the local values in the matrix.
6997 
6998   Returns the columns of the "diagonal blocks", for most sparse matrix formats. See [Matrix
6999   Layouts](sec_matlayout) for details on matrix layouts.
7000 
7001 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRanges()`,
7002           `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`, `PetscLayout`, `MatSetSizes()`, `MatCreateAIJ()`,
7003           `DMDAGetGhostCorners()`, `DM`
7004 @*/
7005 PetscErrorCode MatGetOwnershipRangesColumn(Mat mat, const PetscInt *ranges[])
7006 {
7007   PetscFunctionBegin;
7008   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7009   PetscValidType(mat, 1);
7010   MatCheckPreallocated(mat, 1);
7011   PetscCall(PetscLayoutGetRanges(mat->cmap, ranges));
7012   PetscFunctionReturn(PETSC_SUCCESS);
7013 }
7014 
7015 /*@
7016   MatGetOwnershipIS - Get row and column ownership of a matrices' values as index sets.
7017 
7018   Not Collective
7019 
7020   Input Parameter:
7021 . A - matrix
7022 
7023   Output Parameters:
7024 + rows - rows in which this process owns elements, , use `NULL` to not obtain this value
7025 - cols - columns in which this process owns elements, use `NULL` to not obtain this value
7026 
7027   Level: intermediate
7028 
7029   Note:
7030   You should call `ISDestroy()` on the returned `IS`
7031 
7032   For most matrices, excluding `MATELEMENTAL` and `MATSCALAPACK`, this corresponds to values
7033   returned by `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`. For `MATELEMENTAL` and
7034   `MATSCALAPACK` the ownership is more complicated. See [Matrix Layouts](sec_matlayout) for
7035   details on matrix layouts.
7036 
7037 .seealso: [](ch_matrices), `IS`, `Mat`, `MatGetOwnershipRanges()`, `MatSetValues()`, `MATELEMENTAL`, `MATSCALAPACK`
7038 @*/
7039 PetscErrorCode MatGetOwnershipIS(Mat A, IS *rows, IS *cols)
7040 {
7041   PetscErrorCode (*f)(Mat, IS *, IS *);
7042 
7043   PetscFunctionBegin;
7044   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
7045   PetscValidType(A, 1);
7046   MatCheckPreallocated(A, 1);
7047   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatGetOwnershipIS_C", &f));
7048   if (f) {
7049     PetscCall((*f)(A, rows, cols));
7050   } else { /* Create a standard row-based partition, each process is responsible for ALL columns in their row block */
7051     if (rows) PetscCall(ISCreateStride(PETSC_COMM_SELF, A->rmap->n, A->rmap->rstart, 1, rows));
7052     if (cols) PetscCall(ISCreateStride(PETSC_COMM_SELF, A->cmap->N, 0, 1, cols));
7053   }
7054   PetscFunctionReturn(PETSC_SUCCESS);
7055 }
7056 
7057 /*@
7058   MatILUFactorSymbolic - Performs symbolic ILU factorization of a matrix obtained with `MatGetFactor()`
7059   Uses levels of fill only, not drop tolerance. Use `MatLUFactorNumeric()`
7060   to complete the factorization.
7061 
7062   Collective
7063 
7064   Input Parameters:
7065 + fact - the factorized matrix obtained with `MatGetFactor()`
7066 . mat  - the matrix
7067 . row  - row permutation
7068 . col  - column permutation
7069 - info - structure containing
7070 .vb
7071       levels - number of levels of fill.
7072       expected fill - as ratio of original fill.
7073       1 or 0 - indicating force fill on diagonal (improves robustness for matrices
7074                 missing diagonal entries)
7075 .ve
7076 
7077   Level: developer
7078 
7079   Notes:
7080   See [Matrix Factorization](sec_matfactor) for additional information.
7081 
7082   Most users should employ the `KSP` interface for linear solvers
7083   instead of working directly with matrix algebra routines such as this.
7084   See, e.g., `KSPCreate()`.
7085 
7086   Uses the definition of level of fill as in Y. Saad, {cite}`saad2003`
7087 
7088   Fortran Note:
7089   A valid (non-null) `info` argument must be provided
7090 
7091 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
7092           `MatGetOrdering()`, `MatFactorInfo`
7093 @*/
7094 PetscErrorCode MatILUFactorSymbolic(Mat fact, Mat mat, IS row, IS col, const MatFactorInfo *info)
7095 {
7096   PetscFunctionBegin;
7097   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
7098   PetscValidType(mat, 2);
7099   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 3);
7100   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 4);
7101   PetscAssertPointer(info, 5);
7102   PetscAssertPointer(fact, 1);
7103   PetscCheck(info->levels >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Levels of fill negative %" PetscInt_FMT, (PetscInt)info->levels);
7104   PetscCheck(info->fill >= 1.0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Expected fill less than 1.0 %g", (double)info->fill);
7105   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7106   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7107   MatCheckPreallocated(mat, 2);
7108 
7109   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_ILUFactorSymbolic, mat, row, col, 0));
7110   PetscUseTypeMethod(fact, ilufactorsymbolic, mat, row, col, info);
7111   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_ILUFactorSymbolic, mat, row, col, 0));
7112   PetscFunctionReturn(PETSC_SUCCESS);
7113 }
7114 
7115 /*@
7116   MatICCFactorSymbolic - Performs symbolic incomplete
7117   Cholesky factorization for a symmetric matrix.  Use
7118   `MatCholeskyFactorNumeric()` to complete the factorization.
7119 
7120   Collective
7121 
7122   Input Parameters:
7123 + fact - the factorized matrix obtained with `MatGetFactor()`
7124 . mat  - the matrix to be factored
7125 . perm - row and column permutation
7126 - info - structure containing
7127 .vb
7128       levels - number of levels of fill.
7129       expected fill - as ratio of original fill.
7130 .ve
7131 
7132   Level: developer
7133 
7134   Notes:
7135   Most users should employ the `KSP` interface for linear solvers
7136   instead of working directly with matrix algebra routines such as this.
7137   See, e.g., `KSPCreate()`.
7138 
7139   This uses the definition of level of fill as in Y. Saad {cite}`saad2003`
7140 
7141   Fortran Note:
7142   A valid (non-null) `info` argument must be provided
7143 
7144 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`
7145 @*/
7146 PetscErrorCode MatICCFactorSymbolic(Mat fact, Mat mat, IS perm, const MatFactorInfo *info)
7147 {
7148   PetscFunctionBegin;
7149   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
7150   PetscValidType(mat, 2);
7151   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 3);
7152   PetscAssertPointer(info, 4);
7153   PetscAssertPointer(fact, 1);
7154   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7155   PetscCheck(info->levels >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Levels negative %" PetscInt_FMT, (PetscInt)info->levels);
7156   PetscCheck(info->fill >= 1.0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Expected fill less than 1.0 %g", (double)info->fill);
7157   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7158   MatCheckPreallocated(mat, 2);
7159 
7160   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_ICCFactorSymbolic, mat, perm, 0, 0));
7161   PetscUseTypeMethod(fact, iccfactorsymbolic, mat, perm, info);
7162   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_ICCFactorSymbolic, mat, perm, 0, 0));
7163   PetscFunctionReturn(PETSC_SUCCESS);
7164 }
7165 
7166 /*@C
7167   MatCreateSubMatrices - Extracts several submatrices from a matrix. If submat
7168   points to an array of valid matrices, they may be reused to store the new
7169   submatrices.
7170 
7171   Collective
7172 
7173   Input Parameters:
7174 + mat   - the matrix
7175 . n     - the number of submatrixes to be extracted (on this processor, may be zero)
7176 . irow  - index set of rows to extract
7177 . icol  - index set of columns to extract
7178 - scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
7179 
7180   Output Parameter:
7181 . submat - the array of submatrices
7182 
7183   Level: advanced
7184 
7185   Notes:
7186   `MatCreateSubMatrices()` can extract ONLY sequential submatrices
7187   (from both sequential and parallel matrices). Use `MatCreateSubMatrix()`
7188   to extract a parallel submatrix.
7189 
7190   Some matrix types place restrictions on the row and column
7191   indices, such as that they be sorted or that they be equal to each other.
7192 
7193   The index sets may not have duplicate entries.
7194 
7195   When extracting submatrices from a parallel matrix, each processor can
7196   form a different submatrix by setting the rows and columns of its
7197   individual index sets according to the local submatrix desired.
7198 
7199   When finished using the submatrices, the user should destroy
7200   them with `MatDestroySubMatrices()`.
7201 
7202   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
7203   original matrix has not changed from that last call to `MatCreateSubMatrices()`.
7204 
7205   This routine creates the matrices in submat; you should NOT create them before
7206   calling it. It also allocates the array of matrix pointers submat.
7207 
7208   For `MATBAIJ` matrices the index sets must respect the block structure, that is if they
7209   request one row/column in a block, they must request all rows/columns that are in
7210   that block. For example, if the block size is 2 you cannot request just row 0 and
7211   column 0.
7212 
7213   Fortran Note:
7214 .vb
7215   Mat, pointer :: submat(:)
7216 .ve
7217 
7218 .seealso: [](ch_matrices), `Mat`, `MatDestroySubMatrices()`, `MatCreateSubMatrix()`, `MatGetRow()`, `MatGetDiagonal()`, `MatReuse`
7219 @*/
7220 PetscErrorCode MatCreateSubMatrices(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
7221 {
7222   PetscInt  i;
7223   PetscBool eq;
7224 
7225   PetscFunctionBegin;
7226   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7227   PetscValidType(mat, 1);
7228   if (n) {
7229     PetscAssertPointer(irow, 3);
7230     for (i = 0; i < n; i++) PetscValidHeaderSpecific(irow[i], IS_CLASSID, 3);
7231     PetscAssertPointer(icol, 4);
7232     for (i = 0; i < n; i++) PetscValidHeaderSpecific(icol[i], IS_CLASSID, 4);
7233   }
7234   PetscAssertPointer(submat, 6);
7235   if (n && scall == MAT_REUSE_MATRIX) {
7236     PetscAssertPointer(*submat, 6);
7237     for (i = 0; i < n; i++) PetscValidHeaderSpecific((*submat)[i], MAT_CLASSID, 6);
7238   }
7239   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7240   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7241   MatCheckPreallocated(mat, 1);
7242   PetscCall(PetscLogEventBegin(MAT_CreateSubMats, mat, 0, 0, 0));
7243   PetscUseTypeMethod(mat, createsubmatrices, n, irow, icol, scall, submat);
7244   PetscCall(PetscLogEventEnd(MAT_CreateSubMats, mat, 0, 0, 0));
7245   for (i = 0; i < n; i++) {
7246     (*submat)[i]->factortype = MAT_FACTOR_NONE; /* in case in place factorization was previously done on submatrix */
7247     PetscCall(ISEqualUnsorted(irow[i], icol[i], &eq));
7248     if (eq) PetscCall(MatPropagateSymmetryOptions(mat, (*submat)[i]));
7249 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
7250     if (mat->boundtocpu && mat->bindingpropagates) {
7251       PetscCall(MatBindToCPU((*submat)[i], PETSC_TRUE));
7252       PetscCall(MatSetBindingPropagates((*submat)[i], PETSC_TRUE));
7253     }
7254 #endif
7255   }
7256   PetscFunctionReturn(PETSC_SUCCESS);
7257 }
7258 
7259 /*@C
7260   MatCreateSubMatricesMPI - Extracts MPI submatrices across a sub communicator of `mat` (by pairs of `IS` that may live on subcomms).
7261 
7262   Collective
7263 
7264   Input Parameters:
7265 + mat   - the matrix
7266 . n     - the number of submatrixes to be extracted
7267 . irow  - index set of rows to extract
7268 . icol  - index set of columns to extract
7269 - scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
7270 
7271   Output Parameter:
7272 . submat - the array of submatrices
7273 
7274   Level: advanced
7275 
7276   Note:
7277   This is used by `PCGASM`
7278 
7279 .seealso: [](ch_matrices), `Mat`, `PCGASM`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRow()`, `MatGetDiagonal()`, `MatReuse`
7280 @*/
7281 PetscErrorCode MatCreateSubMatricesMPI(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
7282 {
7283   PetscInt  i;
7284   PetscBool eq;
7285 
7286   PetscFunctionBegin;
7287   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7288   PetscValidType(mat, 1);
7289   if (n) {
7290     PetscAssertPointer(irow, 3);
7291     PetscValidHeaderSpecific(*irow, IS_CLASSID, 3);
7292     PetscAssertPointer(icol, 4);
7293     PetscValidHeaderSpecific(*icol, IS_CLASSID, 4);
7294   }
7295   PetscAssertPointer(submat, 6);
7296   if (n && scall == MAT_REUSE_MATRIX) {
7297     PetscAssertPointer(*submat, 6);
7298     PetscValidHeaderSpecific(**submat, MAT_CLASSID, 6);
7299   }
7300   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7301   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7302   MatCheckPreallocated(mat, 1);
7303 
7304   PetscCall(PetscLogEventBegin(MAT_CreateSubMats, mat, 0, 0, 0));
7305   PetscUseTypeMethod(mat, createsubmatricesmpi, n, irow, icol, scall, submat);
7306   PetscCall(PetscLogEventEnd(MAT_CreateSubMats, mat, 0, 0, 0));
7307   for (i = 0; i < n; i++) {
7308     PetscCall(ISEqualUnsorted(irow[i], icol[i], &eq));
7309     if (eq) PetscCall(MatPropagateSymmetryOptions(mat, (*submat)[i]));
7310   }
7311   PetscFunctionReturn(PETSC_SUCCESS);
7312 }
7313 
7314 /*@C
7315   MatDestroyMatrices - Destroys an array of matrices
7316 
7317   Collective
7318 
7319   Input Parameters:
7320 + n   - the number of local matrices
7321 - mat - the matrices (this is a pointer to the array of matrices)
7322 
7323   Level: advanced
7324 
7325   Notes:
7326   Frees not only the matrices, but also the array that contains the matrices
7327 
7328   For matrices obtained with  `MatCreateSubMatrices()` use `MatDestroySubMatrices()`
7329 
7330 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatDestroySubMatrices()`
7331 @*/
7332 PetscErrorCode MatDestroyMatrices(PetscInt n, Mat *mat[])
7333 {
7334   PetscInt i;
7335 
7336   PetscFunctionBegin;
7337   if (!*mat) PetscFunctionReturn(PETSC_SUCCESS);
7338   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy negative number of matrices %" PetscInt_FMT, n);
7339   PetscAssertPointer(mat, 2);
7340 
7341   for (i = 0; i < n; i++) PetscCall(MatDestroy(&(*mat)[i]));
7342 
7343   /* memory is allocated even if n = 0 */
7344   PetscCall(PetscFree(*mat));
7345   PetscFunctionReturn(PETSC_SUCCESS);
7346 }
7347 
7348 /*@C
7349   MatDestroySubMatrices - Destroys a set of matrices obtained with `MatCreateSubMatrices()`.
7350 
7351   Collective
7352 
7353   Input Parameters:
7354 + n   - the number of local matrices
7355 - mat - the matrices (this is a pointer to the array of matrices, to match the calling sequence of `MatCreateSubMatrices()`)
7356 
7357   Level: advanced
7358 
7359   Note:
7360   Frees not only the matrices, but also the array that contains the matrices
7361 
7362 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatDestroyMatrices()`
7363 @*/
7364 PetscErrorCode MatDestroySubMatrices(PetscInt n, Mat *mat[])
7365 {
7366   Mat mat0;
7367 
7368   PetscFunctionBegin;
7369   if (!*mat) PetscFunctionReturn(PETSC_SUCCESS);
7370   /* mat[] is an array of length n+1, see MatCreateSubMatrices_xxx() */
7371   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy negative number of matrices %" PetscInt_FMT, n);
7372   PetscAssertPointer(mat, 2);
7373 
7374   mat0 = (*mat)[0];
7375   if (mat0 && mat0->ops->destroysubmatrices) {
7376     PetscCall((*mat0->ops->destroysubmatrices)(n, mat));
7377   } else {
7378     PetscCall(MatDestroyMatrices(n, mat));
7379   }
7380   PetscFunctionReturn(PETSC_SUCCESS);
7381 }
7382 
7383 /*@
7384   MatGetSeqNonzeroStructure - Extracts the nonzero structure from a matrix and stores it, in its entirety, on each process
7385 
7386   Collective
7387 
7388   Input Parameter:
7389 . mat - the matrix
7390 
7391   Output Parameter:
7392 . matstruct - the sequential matrix with the nonzero structure of `mat`
7393 
7394   Level: developer
7395 
7396 .seealso: [](ch_matrices), `Mat`, `MatDestroySeqNonzeroStructure()`, `MatCreateSubMatrices()`, `MatDestroyMatrices()`
7397 @*/
7398 PetscErrorCode MatGetSeqNonzeroStructure(Mat mat, Mat *matstruct)
7399 {
7400   PetscFunctionBegin;
7401   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7402   PetscAssertPointer(matstruct, 2);
7403 
7404   PetscValidType(mat, 1);
7405   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7406   MatCheckPreallocated(mat, 1);
7407 
7408   PetscCall(PetscLogEventBegin(MAT_GetSeqNonzeroStructure, mat, 0, 0, 0));
7409   PetscUseTypeMethod(mat, getseqnonzerostructure, matstruct);
7410   PetscCall(PetscLogEventEnd(MAT_GetSeqNonzeroStructure, mat, 0, 0, 0));
7411   PetscFunctionReturn(PETSC_SUCCESS);
7412 }
7413 
7414 /*@C
7415   MatDestroySeqNonzeroStructure - Destroys matrix obtained with `MatGetSeqNonzeroStructure()`.
7416 
7417   Collective
7418 
7419   Input Parameter:
7420 . mat - the matrix
7421 
7422   Level: advanced
7423 
7424   Note:
7425   This is not needed, one can just call `MatDestroy()`
7426 
7427 .seealso: [](ch_matrices), `Mat`, `MatGetSeqNonzeroStructure()`
7428 @*/
7429 PetscErrorCode MatDestroySeqNonzeroStructure(Mat *mat)
7430 {
7431   PetscFunctionBegin;
7432   PetscAssertPointer(mat, 1);
7433   PetscCall(MatDestroy(mat));
7434   PetscFunctionReturn(PETSC_SUCCESS);
7435 }
7436 
7437 /*@
7438   MatIncreaseOverlap - Given a set of submatrices indicated by index sets,
7439   replaces the index sets by larger ones that represent submatrices with
7440   additional overlap.
7441 
7442   Collective
7443 
7444   Input Parameters:
7445 + mat - the matrix
7446 . n   - the number of index sets
7447 . is  - the array of index sets (these index sets will changed during the call)
7448 - ov  - the additional overlap requested
7449 
7450   Options Database Key:
7451 . -mat_increase_overlap_scalable - use a scalable algorithm to compute the overlap (supported by MPIAIJ matrix)
7452 
7453   Level: developer
7454 
7455   Note:
7456   The computed overlap preserves the matrix block sizes when the blocks are square.
7457   That is: if a matrix nonzero for a given block would increase the overlap all columns associated with
7458   that block are included in the overlap regardless of whether each specific column would increase the overlap.
7459 
7460 .seealso: [](ch_matrices), `Mat`, `PCASM`, `MatSetBlockSize()`, `MatIncreaseOverlapSplit()`, `MatCreateSubMatrices()`
7461 @*/
7462 PetscErrorCode MatIncreaseOverlap(Mat mat, PetscInt n, IS is[], PetscInt ov)
7463 {
7464   PetscInt i, bs, cbs;
7465 
7466   PetscFunctionBegin;
7467   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7468   PetscValidType(mat, 1);
7469   PetscValidLogicalCollectiveInt(mat, n, 2);
7470   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have one or more domains, you have %" PetscInt_FMT, n);
7471   if (n) {
7472     PetscAssertPointer(is, 3);
7473     for (i = 0; i < n; i++) PetscValidHeaderSpecific(is[i], IS_CLASSID, 3);
7474   }
7475   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7476   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7477   MatCheckPreallocated(mat, 1);
7478 
7479   if (!ov || !n) PetscFunctionReturn(PETSC_SUCCESS);
7480   PetscCall(PetscLogEventBegin(MAT_IncreaseOverlap, mat, 0, 0, 0));
7481   PetscUseTypeMethod(mat, increaseoverlap, n, is, ov);
7482   PetscCall(PetscLogEventEnd(MAT_IncreaseOverlap, mat, 0, 0, 0));
7483   PetscCall(MatGetBlockSizes(mat, &bs, &cbs));
7484   if (bs == cbs) {
7485     for (i = 0; i < n; i++) PetscCall(ISSetBlockSize(is[i], bs));
7486   }
7487   PetscFunctionReturn(PETSC_SUCCESS);
7488 }
7489 
7490 PetscErrorCode MatIncreaseOverlapSplit_Single(Mat, IS *, PetscInt);
7491 
7492 /*@
7493   MatIncreaseOverlapSplit - Given a set of submatrices indicated by index sets across
7494   a sub communicator, replaces the index sets by larger ones that represent submatrices with
7495   additional overlap.
7496 
7497   Collective
7498 
7499   Input Parameters:
7500 + mat - the matrix
7501 . n   - the number of index sets
7502 . is  - the array of index sets (these index sets will changed during the call)
7503 - ov  - the additional overlap requested
7504 
7505   `   Options Database Key:
7506 . -mat_increase_overlap_scalable - use a scalable algorithm to compute the overlap (supported by MPIAIJ matrix)
7507 
7508   Level: developer
7509 
7510 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatIncreaseOverlap()`
7511 @*/
7512 PetscErrorCode MatIncreaseOverlapSplit(Mat mat, PetscInt n, IS is[], PetscInt ov)
7513 {
7514   PetscInt i;
7515 
7516   PetscFunctionBegin;
7517   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7518   PetscValidType(mat, 1);
7519   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have one or more domains, you have %" PetscInt_FMT, n);
7520   if (n) {
7521     PetscAssertPointer(is, 3);
7522     PetscValidHeaderSpecific(*is, IS_CLASSID, 3);
7523   }
7524   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7525   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7526   MatCheckPreallocated(mat, 1);
7527   if (!ov) PetscFunctionReturn(PETSC_SUCCESS);
7528   PetscCall(PetscLogEventBegin(MAT_IncreaseOverlap, mat, 0, 0, 0));
7529   for (i = 0; i < n; i++) PetscCall(MatIncreaseOverlapSplit_Single(mat, &is[i], ov));
7530   PetscCall(PetscLogEventEnd(MAT_IncreaseOverlap, mat, 0, 0, 0));
7531   PetscFunctionReturn(PETSC_SUCCESS);
7532 }
7533 
7534 /*@
7535   MatGetBlockSize - Returns the matrix block size.
7536 
7537   Not Collective
7538 
7539   Input Parameter:
7540 . mat - the matrix
7541 
7542   Output Parameter:
7543 . bs - block size
7544 
7545   Level: intermediate
7546 
7547   Notes:
7548   Block row formats are `MATBAIJ` and `MATSBAIJ` ALWAYS have square block storage in the matrix.
7549 
7550   If the block size has not been set yet this routine returns 1.
7551 
7552 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSizes()`
7553 @*/
7554 PetscErrorCode MatGetBlockSize(Mat mat, PetscInt *bs)
7555 {
7556   PetscFunctionBegin;
7557   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7558   PetscAssertPointer(bs, 2);
7559   *bs = mat->rmap->bs;
7560   PetscFunctionReturn(PETSC_SUCCESS);
7561 }
7562 
7563 /*@
7564   MatGetBlockSizes - Returns the matrix block row and column sizes.
7565 
7566   Not Collective
7567 
7568   Input Parameter:
7569 . mat - the matrix
7570 
7571   Output Parameters:
7572 + rbs - row block size
7573 - cbs - column block size
7574 
7575   Level: intermediate
7576 
7577   Notes:
7578   Block row formats are `MATBAIJ` and `MATSBAIJ` ALWAYS have square block storage in the matrix.
7579   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
7580 
7581   If a block size has not been set yet this routine returns 1.
7582 
7583 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatSetBlockSizes()`
7584 @*/
7585 PetscErrorCode MatGetBlockSizes(Mat mat, PetscInt *rbs, PetscInt *cbs)
7586 {
7587   PetscFunctionBegin;
7588   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7589   if (rbs) PetscAssertPointer(rbs, 2);
7590   if (cbs) PetscAssertPointer(cbs, 3);
7591   if (rbs) *rbs = mat->rmap->bs;
7592   if (cbs) *cbs = mat->cmap->bs;
7593   PetscFunctionReturn(PETSC_SUCCESS);
7594 }
7595 
7596 /*@
7597   MatSetBlockSize - Sets the matrix block size.
7598 
7599   Logically Collective
7600 
7601   Input Parameters:
7602 + mat - the matrix
7603 - bs  - block size
7604 
7605   Level: intermediate
7606 
7607   Notes:
7608   Block row formats are `MATBAIJ` and `MATSBAIJ` formats ALWAYS have square block storage in the matrix.
7609   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
7610 
7611   For `MATAIJ` matrix format, this function can be called at a later stage, provided that the specified block size
7612   is compatible with the matrix local sizes.
7613 
7614 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MATAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`
7615 @*/
7616 PetscErrorCode MatSetBlockSize(Mat mat, PetscInt bs)
7617 {
7618   PetscFunctionBegin;
7619   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7620   PetscValidLogicalCollectiveInt(mat, bs, 2);
7621   PetscCall(MatSetBlockSizes(mat, bs, bs));
7622   PetscFunctionReturn(PETSC_SUCCESS);
7623 }
7624 
7625 typedef struct {
7626   PetscInt         n;
7627   IS              *is;
7628   Mat             *mat;
7629   PetscObjectState nonzerostate;
7630   Mat              C;
7631 } EnvelopeData;
7632 
7633 static PetscErrorCode EnvelopeDataDestroy(void **ptr)
7634 {
7635   EnvelopeData *edata = (EnvelopeData *)*ptr;
7636 
7637   PetscFunctionBegin;
7638   for (PetscInt i = 0; i < edata->n; i++) PetscCall(ISDestroy(&edata->is[i]));
7639   PetscCall(PetscFree(edata->is));
7640   PetscCall(PetscFree(edata));
7641   PetscFunctionReturn(PETSC_SUCCESS);
7642 }
7643 
7644 /*@
7645   MatComputeVariableBlockEnvelope - Given a matrix whose nonzeros are in blocks along the diagonal this computes and stores
7646   the sizes of these blocks in the matrix. An individual block may lie over several processes.
7647 
7648   Collective
7649 
7650   Input Parameter:
7651 . mat - the matrix
7652 
7653   Level: intermediate
7654 
7655   Notes:
7656   There can be zeros within the blocks
7657 
7658   The blocks can overlap between processes, including laying on more than two processes
7659 
7660 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatSetVariableBlockSizes()`
7661 @*/
7662 PetscErrorCode MatComputeVariableBlockEnvelope(Mat mat)
7663 {
7664   PetscInt           n, *sizes, *starts, i = 0, env = 0, tbs = 0, lblocks = 0, rstart, II, ln = 0, cnt = 0, cstart, cend;
7665   PetscInt          *diag, *odiag, sc;
7666   VecScatter         scatter;
7667   PetscScalar       *seqv;
7668   const PetscScalar *parv;
7669   const PetscInt    *ia, *ja;
7670   PetscBool          set, flag, done;
7671   Mat                AA = mat, A;
7672   MPI_Comm           comm;
7673   PetscMPIInt        rank, size, tag;
7674   MPI_Status         status;
7675   PetscContainer     container;
7676   EnvelopeData      *edata;
7677   Vec                seq, par;
7678   IS                 isglobal;
7679 
7680   PetscFunctionBegin;
7681   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7682   PetscCall(MatIsSymmetricKnown(mat, &set, &flag));
7683   if (!set || !flag) {
7684     /* TODO: only needs nonzero structure of transpose */
7685     PetscCall(MatTranspose(mat, MAT_INITIAL_MATRIX, &AA));
7686     PetscCall(MatAXPY(AA, 1.0, mat, DIFFERENT_NONZERO_PATTERN));
7687   }
7688   PetscCall(MatAIJGetLocalMat(AA, &A));
7689   PetscCall(MatGetRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ia, &ja, &done));
7690   PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Unable to get IJ structure from matrix");
7691 
7692   PetscCall(MatGetLocalSize(mat, &n, NULL));
7693   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag));
7694   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
7695   PetscCallMPI(MPI_Comm_size(comm, &size));
7696   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7697 
7698   PetscCall(PetscMalloc2(n, &sizes, n, &starts));
7699 
7700   if (rank > 0) {
7701     PetscCallMPI(MPI_Recv(&env, 1, MPIU_INT, rank - 1, tag, comm, &status));
7702     PetscCallMPI(MPI_Recv(&tbs, 1, MPIU_INT, rank - 1, tag, comm, &status));
7703   }
7704   PetscCall(MatGetOwnershipRange(mat, &rstart, NULL));
7705   for (i = 0; i < n; i++) {
7706     env = PetscMax(env, ja[ia[i + 1] - 1]);
7707     II  = rstart + i;
7708     if (env == II) {
7709       starts[lblocks]  = tbs;
7710       sizes[lblocks++] = 1 + II - tbs;
7711       tbs              = 1 + II;
7712     }
7713   }
7714   if (rank < size - 1) {
7715     PetscCallMPI(MPI_Send(&env, 1, MPIU_INT, rank + 1, tag, comm));
7716     PetscCallMPI(MPI_Send(&tbs, 1, MPIU_INT, rank + 1, tag, comm));
7717   }
7718 
7719   PetscCall(MatRestoreRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ia, &ja, &done));
7720   if (!set || !flag) PetscCall(MatDestroy(&AA));
7721   PetscCall(MatDestroy(&A));
7722 
7723   PetscCall(PetscNew(&edata));
7724   PetscCall(MatGetNonzeroState(mat, &edata->nonzerostate));
7725   edata->n = lblocks;
7726   /* create IS needed for extracting blocks from the original matrix */
7727   PetscCall(PetscMalloc1(lblocks, &edata->is));
7728   for (PetscInt i = 0; i < lblocks; i++) PetscCall(ISCreateStride(PETSC_COMM_SELF, sizes[i], starts[i], 1, &edata->is[i]));
7729 
7730   /* Create the resulting inverse matrix nonzero structure with preallocation information */
7731   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &edata->C));
7732   PetscCall(MatSetSizes(edata->C, mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N));
7733   PetscCall(MatSetBlockSizesFromMats(edata->C, mat, mat));
7734   PetscCall(MatSetType(edata->C, MATAIJ));
7735 
7736   /* Communicate the start and end of each row, from each block to the correct rank */
7737   /* TODO: Use PetscSF instead of VecScatter */
7738   for (PetscInt i = 0; i < lblocks; i++) ln += sizes[i];
7739   PetscCall(VecCreateSeq(PETSC_COMM_SELF, 2 * ln, &seq));
7740   PetscCall(VecGetArrayWrite(seq, &seqv));
7741   for (PetscInt i = 0; i < lblocks; i++) {
7742     for (PetscInt j = 0; j < sizes[i]; j++) {
7743       seqv[cnt]     = starts[i];
7744       seqv[cnt + 1] = starts[i] + sizes[i];
7745       cnt += 2;
7746     }
7747   }
7748   PetscCall(VecRestoreArrayWrite(seq, &seqv));
7749   PetscCallMPI(MPI_Scan(&cnt, &sc, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
7750   sc -= cnt;
7751   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)mat), 2 * mat->rmap->n, 2 * mat->rmap->N, &par));
7752   PetscCall(ISCreateStride(PETSC_COMM_SELF, cnt, sc, 1, &isglobal));
7753   PetscCall(VecScatterCreate(seq, NULL, par, isglobal, &scatter));
7754   PetscCall(ISDestroy(&isglobal));
7755   PetscCall(VecScatterBegin(scatter, seq, par, INSERT_VALUES, SCATTER_FORWARD));
7756   PetscCall(VecScatterEnd(scatter, seq, par, INSERT_VALUES, SCATTER_FORWARD));
7757   PetscCall(VecScatterDestroy(&scatter));
7758   PetscCall(VecDestroy(&seq));
7759   PetscCall(MatGetOwnershipRangeColumn(mat, &cstart, &cend));
7760   PetscCall(PetscMalloc2(mat->rmap->n, &diag, mat->rmap->n, &odiag));
7761   PetscCall(VecGetArrayRead(par, &parv));
7762   cnt = 0;
7763   PetscCall(MatGetSize(mat, NULL, &n));
7764   for (PetscInt i = 0; i < mat->rmap->n; i++) {
7765     PetscInt start, end, d = 0, od = 0;
7766 
7767     start = (PetscInt)PetscRealPart(parv[cnt]);
7768     end   = (PetscInt)PetscRealPart(parv[cnt + 1]);
7769     cnt += 2;
7770 
7771     if (start < cstart) {
7772       od += cstart - start + n - cend;
7773       d += cend - cstart;
7774     } else if (start < cend) {
7775       od += n - cend;
7776       d += cend - start;
7777     } else od += n - start;
7778     if (end <= cstart) {
7779       od -= cstart - end + n - cend;
7780       d -= cend - cstart;
7781     } else if (end < cend) {
7782       od -= n - cend;
7783       d -= cend - end;
7784     } else od -= n - end;
7785 
7786     odiag[i] = od;
7787     diag[i]  = d;
7788   }
7789   PetscCall(VecRestoreArrayRead(par, &parv));
7790   PetscCall(VecDestroy(&par));
7791   PetscCall(MatXAIJSetPreallocation(edata->C, mat->rmap->bs, diag, odiag, NULL, NULL));
7792   PetscCall(PetscFree2(diag, odiag));
7793   PetscCall(PetscFree2(sizes, starts));
7794 
7795   PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container));
7796   PetscCall(PetscContainerSetPointer(container, edata));
7797   PetscCall(PetscContainerSetCtxDestroy(container, EnvelopeDataDestroy));
7798   PetscCall(PetscObjectCompose((PetscObject)mat, "EnvelopeData", (PetscObject)container));
7799   PetscCall(PetscObjectDereference((PetscObject)container));
7800   PetscFunctionReturn(PETSC_SUCCESS);
7801 }
7802 
7803 /*@
7804   MatInvertVariableBlockEnvelope - set matrix C to be the inverted block diagonal of matrix A
7805 
7806   Collective
7807 
7808   Input Parameters:
7809 + A     - the matrix
7810 - reuse - indicates if the `C` matrix was obtained from a previous call to this routine
7811 
7812   Output Parameter:
7813 . C - matrix with inverted block diagonal of `A`
7814 
7815   Level: advanced
7816 
7817   Note:
7818   For efficiency the matrix `A` should have all the nonzero entries clustered in smallish blocks along the diagonal.
7819 
7820 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatComputeBlockDiagonal()`
7821 @*/
7822 PetscErrorCode MatInvertVariableBlockEnvelope(Mat A, MatReuse reuse, Mat *C)
7823 {
7824   PetscContainer   container;
7825   EnvelopeData    *edata;
7826   PetscObjectState nonzerostate;
7827 
7828   PetscFunctionBegin;
7829   PetscCall(PetscObjectQuery((PetscObject)A, "EnvelopeData", (PetscObject *)&container));
7830   if (!container) {
7831     PetscCall(MatComputeVariableBlockEnvelope(A));
7832     PetscCall(PetscObjectQuery((PetscObject)A, "EnvelopeData", (PetscObject *)&container));
7833   }
7834   PetscCall(PetscContainerGetPointer(container, (void **)&edata));
7835   PetscCall(MatGetNonzeroState(A, &nonzerostate));
7836   PetscCheck(nonzerostate <= edata->nonzerostate, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot handle changes to matrix nonzero structure");
7837   PetscCheck(reuse != MAT_REUSE_MATRIX || *C == edata->C, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "C matrix must be the same as previously output");
7838 
7839   PetscCall(MatCreateSubMatrices(A, edata->n, edata->is, edata->is, MAT_INITIAL_MATRIX, &edata->mat));
7840   *C = edata->C;
7841 
7842   for (PetscInt i = 0; i < edata->n; i++) {
7843     Mat          D;
7844     PetscScalar *dvalues;
7845 
7846     PetscCall(MatConvert(edata->mat[i], MATSEQDENSE, MAT_INITIAL_MATRIX, &D));
7847     PetscCall(MatSetOption(*C, MAT_ROW_ORIENTED, PETSC_FALSE));
7848     PetscCall(MatSeqDenseInvert(D));
7849     PetscCall(MatDenseGetArray(D, &dvalues));
7850     PetscCall(MatSetValuesIS(*C, edata->is[i], edata->is[i], dvalues, INSERT_VALUES));
7851     PetscCall(MatDestroy(&D));
7852   }
7853   PetscCall(MatDestroySubMatrices(edata->n, &edata->mat));
7854   PetscCall(MatAssemblyBegin(*C, MAT_FINAL_ASSEMBLY));
7855   PetscCall(MatAssemblyEnd(*C, MAT_FINAL_ASSEMBLY));
7856   PetscFunctionReturn(PETSC_SUCCESS);
7857 }
7858 
7859 /*@
7860   MatSetVariableBlockSizes - Sets diagonal point-blocks of the matrix that need not be of the same size
7861 
7862   Not Collective
7863 
7864   Input Parameters:
7865 + mat     - the matrix
7866 . nblocks - the number of blocks on this process, each block can only exist on a single process
7867 - bsizes  - the block sizes
7868 
7869   Level: intermediate
7870 
7871   Notes:
7872   Currently used by `PCVPBJACOBI` for `MATAIJ` matrices
7873 
7874   Each variable point-block set of degrees of freedom must live on a single MPI process. That is a point block cannot straddle two MPI processes.
7875 
7876 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`, `MatGetVariableBlockSizes()`,
7877           `MatComputeVariableBlockEnvelope()`, `PCVPBJACOBI`
7878 @*/
7879 PetscErrorCode MatSetVariableBlockSizes(Mat mat, PetscInt nblocks, const PetscInt bsizes[])
7880 {
7881   PetscInt ncnt = 0, nlocal;
7882 
7883   PetscFunctionBegin;
7884   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7885   PetscCall(MatGetLocalSize(mat, &nlocal, NULL));
7886   PetscCheck(nblocks >= 0 && nblocks <= nlocal, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of local blocks %" PetscInt_FMT " is not in [0, %" PetscInt_FMT "]", nblocks, nlocal);
7887   for (PetscInt i = 0; i < nblocks; i++) ncnt += bsizes[i];
7888   PetscCheck(ncnt == nlocal, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Sum of local block sizes %" PetscInt_FMT " does not equal local size of matrix %" PetscInt_FMT, ncnt, nlocal);
7889   PetscCall(PetscFree(mat->bsizes));
7890   mat->nblocks = nblocks;
7891   PetscCall(PetscMalloc1(nblocks, &mat->bsizes));
7892   PetscCall(PetscArraycpy(mat->bsizes, bsizes, nblocks));
7893   PetscFunctionReturn(PETSC_SUCCESS);
7894 }
7895 
7896 /*@C
7897   MatGetVariableBlockSizes - Gets a diagonal blocks of the matrix that need not be of the same size
7898 
7899   Not Collective; No Fortran Support
7900 
7901   Input Parameter:
7902 . mat - the matrix
7903 
7904   Output Parameters:
7905 + nblocks - the number of blocks on this process
7906 - bsizes  - the block sizes
7907 
7908   Level: intermediate
7909 
7910 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`, `MatSetVariableBlockSizes()`, `MatComputeVariableBlockEnvelope()`
7911 @*/
7912 PetscErrorCode MatGetVariableBlockSizes(Mat mat, PetscInt *nblocks, const PetscInt *bsizes[])
7913 {
7914   PetscFunctionBegin;
7915   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7916   if (nblocks) *nblocks = mat->nblocks;
7917   if (bsizes) *bsizes = mat->bsizes;
7918   PetscFunctionReturn(PETSC_SUCCESS);
7919 }
7920 
7921 /*
7922   MatSelectVariableBlockSizes - When creating a submatrix, pass on the variable block sizes
7923 
7924   Not Collective
7925 
7926   Input Parameter:
7927 + subA  - the submatrix
7928 . A     - the original matrix
7929 - isrow - The `IS` of selected rows for the submatrix
7930 
7931   Level: developer
7932 
7933 .seealso: [](ch_matrices), `Mat`, `MatSetVariableBlockSizes()`, `MatComputeVariableBlockEnvelope()`
7934 */
7935 static PetscErrorCode MatSelectVariableBlockSizes(Mat subA, Mat A, IS isrow)
7936 {
7937   const PetscInt *rows;
7938   PetscInt        n, rStart, rEnd, Nb = 0;
7939 
7940   PetscFunctionBegin;
7941   if (!A->bsizes) PetscFunctionReturn(PETSC_SUCCESS);
7942   // The IS contains global row numbers, we cannot preserve blocks if it contains off-process entries
7943   PetscCall(MatGetOwnershipRange(A, &rStart, &rEnd));
7944   PetscCall(ISGetIndices(isrow, &rows));
7945   PetscCall(ISGetLocalSize(isrow, &n));
7946   for (PetscInt i = 0; i < n; ++i) {
7947     if (rows[i] < rStart || rows[i] >= rEnd) {
7948       PetscCall(ISRestoreIndices(isrow, &rows));
7949       PetscFunctionReturn(PETSC_SUCCESS);
7950     }
7951   }
7952   for (PetscInt b = 0, gr = rStart, i = 0; b < A->nblocks; ++b) {
7953     PetscBool occupied = PETSC_FALSE;
7954 
7955     for (PetscInt br = 0; br < A->bsizes[b]; ++br) {
7956       const PetscInt row = gr + br;
7957 
7958       if (i == n) break;
7959       if (rows[i] == row) {
7960         occupied = PETSC_TRUE;
7961         ++i;
7962       }
7963       while (i < n && rows[i] < row) ++i;
7964     }
7965     gr += A->bsizes[b];
7966     if (occupied) ++Nb;
7967   }
7968   subA->nblocks = Nb;
7969   PetscCall(PetscFree(subA->bsizes));
7970   PetscCall(PetscMalloc1(subA->nblocks, &subA->bsizes));
7971   PetscInt sb = 0;
7972   for (PetscInt b = 0, gr = rStart, i = 0; b < A->nblocks; ++b) {
7973     if (sb < subA->nblocks) subA->bsizes[sb] = 0;
7974     for (PetscInt br = 0; br < A->bsizes[b]; ++br) {
7975       const PetscInt row = gr + br;
7976 
7977       if (i == n) break;
7978       if (rows[i] == row) {
7979         ++subA->bsizes[sb];
7980         ++i;
7981       }
7982       while (i < n && rows[i] < row) ++i;
7983     }
7984     gr += A->bsizes[b];
7985     if (sb < subA->nblocks && subA->bsizes[sb]) ++sb;
7986   }
7987   PetscCheck(sb == subA->nblocks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of blocks %" PetscInt_FMT " != %" PetscInt_FMT, sb, subA->nblocks);
7988   PetscInt nlocal, ncnt = 0;
7989   PetscCall(MatGetLocalSize(subA, &nlocal, NULL));
7990   PetscCheck(subA->nblocks >= 0 && subA->nblocks <= nlocal, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of local blocks %" PetscInt_FMT " is not in [0, %" PetscInt_FMT "]", subA->nblocks, nlocal);
7991   for (PetscInt i = 0; i < subA->nblocks; i++) ncnt += subA->bsizes[i];
7992   PetscCheck(ncnt == nlocal, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Sum of local block sizes %" PetscInt_FMT " does not equal local size of matrix %" PetscInt_FMT, ncnt, nlocal);
7993   PetscCall(ISRestoreIndices(isrow, &rows));
7994   PetscFunctionReturn(PETSC_SUCCESS);
7995 }
7996 
7997 /*@
7998   MatSetBlockSizes - Sets the matrix block row and column sizes.
7999 
8000   Logically Collective
8001 
8002   Input Parameters:
8003 + mat - the matrix
8004 . rbs - row block size
8005 - cbs - column block size
8006 
8007   Level: intermediate
8008 
8009   Notes:
8010   Block row formats are `MATBAIJ` and  `MATSBAIJ`. These formats ALWAYS have square block storage in the matrix.
8011   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
8012   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
8013 
8014   For `MATAIJ` matrix this function can be called at a later stage, provided that the specified block sizes
8015   are compatible with the matrix local sizes.
8016 
8017   The row and column block size determine the blocksize of the "row" and "column" vectors returned by `MatCreateVecs()`.
8018 
8019 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatGetBlockSizes()`
8020 @*/
8021 PetscErrorCode MatSetBlockSizes(Mat mat, PetscInt rbs, PetscInt cbs)
8022 {
8023   PetscFunctionBegin;
8024   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8025   PetscValidLogicalCollectiveInt(mat, rbs, 2);
8026   PetscValidLogicalCollectiveInt(mat, cbs, 3);
8027   PetscTryTypeMethod(mat, setblocksizes, rbs, cbs);
8028   if (mat->rmap->refcnt) {
8029     ISLocalToGlobalMapping l2g  = NULL;
8030     PetscLayout            nmap = NULL;
8031 
8032     PetscCall(PetscLayoutDuplicate(mat->rmap, &nmap));
8033     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->rmap->mapping, &l2g));
8034     PetscCall(PetscLayoutDestroy(&mat->rmap));
8035     mat->rmap          = nmap;
8036     mat->rmap->mapping = l2g;
8037   }
8038   if (mat->cmap->refcnt) {
8039     ISLocalToGlobalMapping l2g  = NULL;
8040     PetscLayout            nmap = NULL;
8041 
8042     PetscCall(PetscLayoutDuplicate(mat->cmap, &nmap));
8043     if (mat->cmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->cmap->mapping, &l2g));
8044     PetscCall(PetscLayoutDestroy(&mat->cmap));
8045     mat->cmap          = nmap;
8046     mat->cmap->mapping = l2g;
8047   }
8048   PetscCall(PetscLayoutSetBlockSize(mat->rmap, rbs));
8049   PetscCall(PetscLayoutSetBlockSize(mat->cmap, cbs));
8050   PetscFunctionReturn(PETSC_SUCCESS);
8051 }
8052 
8053 /*@
8054   MatSetBlockSizesFromMats - Sets the matrix block row and column sizes to match a pair of matrices
8055 
8056   Logically Collective
8057 
8058   Input Parameters:
8059 + mat     - the matrix
8060 . fromRow - matrix from which to copy row block size
8061 - fromCol - matrix from which to copy column block size (can be same as fromRow)
8062 
8063   Level: developer
8064 
8065 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`
8066 @*/
8067 PetscErrorCode MatSetBlockSizesFromMats(Mat mat, Mat fromRow, Mat fromCol)
8068 {
8069   PetscFunctionBegin;
8070   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8071   PetscValidHeaderSpecific(fromRow, MAT_CLASSID, 2);
8072   PetscValidHeaderSpecific(fromCol, MAT_CLASSID, 3);
8073   PetscCall(PetscLayoutSetBlockSize(mat->rmap, fromRow->rmap->bs));
8074   PetscCall(PetscLayoutSetBlockSize(mat->cmap, fromCol->cmap->bs));
8075   PetscFunctionReturn(PETSC_SUCCESS);
8076 }
8077 
8078 /*@
8079   MatResidual - Default routine to calculate the residual r = b - Ax
8080 
8081   Collective
8082 
8083   Input Parameters:
8084 + mat - the matrix
8085 . b   - the right-hand-side
8086 - x   - the approximate solution
8087 
8088   Output Parameter:
8089 . r - location to store the residual
8090 
8091   Level: developer
8092 
8093 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `PCMGSetResidual()`
8094 @*/
8095 PetscErrorCode MatResidual(Mat mat, Vec b, Vec x, Vec r)
8096 {
8097   PetscFunctionBegin;
8098   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8099   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
8100   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
8101   PetscValidHeaderSpecific(r, VEC_CLASSID, 4);
8102   PetscValidType(mat, 1);
8103   MatCheckPreallocated(mat, 1);
8104   PetscCall(PetscLogEventBegin(MAT_Residual, mat, 0, 0, 0));
8105   if (!mat->ops->residual) {
8106     PetscCall(MatMult(mat, x, r));
8107     PetscCall(VecAYPX(r, -1.0, b));
8108   } else {
8109     PetscUseTypeMethod(mat, residual, b, x, r);
8110   }
8111   PetscCall(PetscLogEventEnd(MAT_Residual, mat, 0, 0, 0));
8112   PetscFunctionReturn(PETSC_SUCCESS);
8113 }
8114 
8115 /*@C
8116   MatGetRowIJ - Returns the compressed row storage i and j indices for the local rows of a sparse matrix
8117 
8118   Collective
8119 
8120   Input Parameters:
8121 + mat             - the matrix
8122 . shift           - 0 or 1 indicating we want the indices starting at 0 or 1
8123 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8124 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE`  indicating if the nonzero structure of the
8125                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8126                  always used.
8127 
8128   Output Parameters:
8129 + n    - number of local rows in the (possibly compressed) matrix, use `NULL` if not needed
8130 . ia   - the row pointers; that is ia[0] = 0, ia[row] = ia[row-1] + number of elements in that row of the matrix, use `NULL` if not needed
8131 . ja   - the column indices, use `NULL` if not needed
8132 - done - indicates if the routine actually worked and returned appropriate ia[] and ja[] arrays; callers
8133            are responsible for handling the case when done == `PETSC_FALSE` and ia and ja are not set
8134 
8135   Level: developer
8136 
8137   Notes:
8138   You CANNOT change any of the ia[] or ja[] values.
8139 
8140   Use `MatRestoreRowIJ()` when you are finished accessing the ia[] and ja[] values.
8141 
8142   Fortran Notes:
8143   Use
8144 .vb
8145     PetscInt, pointer :: ia(:),ja(:)
8146     call MatGetRowIJ(mat,shift,symmetric,inodecompressed,n,ia,ja,done,ierr)
8147     ! Access the ith and jth entries via ia(i) and ja(j)
8148 .ve
8149 
8150 .seealso: [](ch_matrices), `Mat`, `MATAIJ`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`, `MatSeqAIJGetArray()`
8151 @*/
8152 PetscErrorCode MatGetRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8153 {
8154   PetscFunctionBegin;
8155   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8156   PetscValidType(mat, 1);
8157   if (n) PetscAssertPointer(n, 5);
8158   if (ia) PetscAssertPointer(ia, 6);
8159   if (ja) PetscAssertPointer(ja, 7);
8160   if (done) PetscAssertPointer(done, 8);
8161   MatCheckPreallocated(mat, 1);
8162   if (!mat->ops->getrowij && done) *done = PETSC_FALSE;
8163   else {
8164     if (done) *done = PETSC_TRUE;
8165     PetscCall(PetscLogEventBegin(MAT_GetRowIJ, mat, 0, 0, 0));
8166     PetscUseTypeMethod(mat, getrowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8167     PetscCall(PetscLogEventEnd(MAT_GetRowIJ, mat, 0, 0, 0));
8168   }
8169   PetscFunctionReturn(PETSC_SUCCESS);
8170 }
8171 
8172 /*@C
8173   MatGetColumnIJ - Returns the compressed column storage i and j indices for sequential matrices.
8174 
8175   Collective
8176 
8177   Input Parameters:
8178 + mat             - the matrix
8179 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8180 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be
8181                 symmetrized
8182 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8183                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8184                  always used.
8185 . n               - number of columns in the (possibly compressed) matrix
8186 . ia              - the column pointers; that is ia[0] = 0, ia[col] = i[col-1] + number of elements in that col of the matrix
8187 - ja              - the row indices
8188 
8189   Output Parameter:
8190 . done - `PETSC_TRUE` or `PETSC_FALSE`, indicating whether the values have been returned
8191 
8192   Level: developer
8193 
8194 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8195 @*/
8196 PetscErrorCode MatGetColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8197 {
8198   PetscFunctionBegin;
8199   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8200   PetscValidType(mat, 1);
8201   PetscAssertPointer(n, 5);
8202   if (ia) PetscAssertPointer(ia, 6);
8203   if (ja) PetscAssertPointer(ja, 7);
8204   PetscAssertPointer(done, 8);
8205   MatCheckPreallocated(mat, 1);
8206   if (!mat->ops->getcolumnij) *done = PETSC_FALSE;
8207   else {
8208     *done = PETSC_TRUE;
8209     PetscUseTypeMethod(mat, getcolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8210   }
8211   PetscFunctionReturn(PETSC_SUCCESS);
8212 }
8213 
8214 /*@C
8215   MatRestoreRowIJ - Call after you are completed with the ia,ja indices obtained with `MatGetRowIJ()`.
8216 
8217   Collective
8218 
8219   Input Parameters:
8220 + mat             - the matrix
8221 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8222 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8223 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8224                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8225                     always used.
8226 . n               - size of (possibly compressed) matrix
8227 . ia              - the row pointers
8228 - ja              - the column indices
8229 
8230   Output Parameter:
8231 . done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8232 
8233   Level: developer
8234 
8235   Note:
8236   This routine zeros out `n`, `ia`, and `ja`. This is to prevent accidental
8237   us of the array after it has been restored. If you pass `NULL`, it will
8238   not zero the pointers.  Use of ia or ja after `MatRestoreRowIJ()` is invalid.
8239 
8240 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8241 @*/
8242 PetscErrorCode MatRestoreRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8243 {
8244   PetscFunctionBegin;
8245   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8246   PetscValidType(mat, 1);
8247   if (ia) PetscAssertPointer(ia, 6);
8248   if (ja) PetscAssertPointer(ja, 7);
8249   if (done) PetscAssertPointer(done, 8);
8250   MatCheckPreallocated(mat, 1);
8251 
8252   if (!mat->ops->restorerowij && done) *done = PETSC_FALSE;
8253   else {
8254     if (done) *done = PETSC_TRUE;
8255     PetscUseTypeMethod(mat, restorerowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8256     if (n) *n = 0;
8257     if (ia) *ia = NULL;
8258     if (ja) *ja = NULL;
8259   }
8260   PetscFunctionReturn(PETSC_SUCCESS);
8261 }
8262 
8263 /*@C
8264   MatRestoreColumnIJ - Call after you are completed with the ia,ja indices obtained with `MatGetColumnIJ()`.
8265 
8266   Collective
8267 
8268   Input Parameters:
8269 + mat             - the matrix
8270 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8271 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8272 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8273                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8274                     always used.
8275 
8276   Output Parameters:
8277 + n    - size of (possibly compressed) matrix
8278 . ia   - the column pointers
8279 . ja   - the row indices
8280 - done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8281 
8282   Level: developer
8283 
8284 .seealso: [](ch_matrices), `Mat`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`
8285 @*/
8286 PetscErrorCode MatRestoreColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8287 {
8288   PetscFunctionBegin;
8289   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8290   PetscValidType(mat, 1);
8291   if (ia) PetscAssertPointer(ia, 6);
8292   if (ja) PetscAssertPointer(ja, 7);
8293   PetscAssertPointer(done, 8);
8294   MatCheckPreallocated(mat, 1);
8295 
8296   if (!mat->ops->restorecolumnij) *done = PETSC_FALSE;
8297   else {
8298     *done = PETSC_TRUE;
8299     PetscUseTypeMethod(mat, restorecolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8300     if (n) *n = 0;
8301     if (ia) *ia = NULL;
8302     if (ja) *ja = NULL;
8303   }
8304   PetscFunctionReturn(PETSC_SUCCESS);
8305 }
8306 
8307 /*@
8308   MatColoringPatch - Used inside matrix coloring routines that use `MatGetRowIJ()` and/or
8309   `MatGetColumnIJ()`.
8310 
8311   Collective
8312 
8313   Input Parameters:
8314 + mat        - the matrix
8315 . ncolors    - maximum color value
8316 . n          - number of entries in colorarray
8317 - colorarray - array indicating color for each column
8318 
8319   Output Parameter:
8320 . iscoloring - coloring generated using colorarray information
8321 
8322   Level: developer
8323 
8324 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatGetColumnIJ()`
8325 @*/
8326 PetscErrorCode MatColoringPatch(Mat mat, PetscInt ncolors, PetscInt n, ISColoringValue colorarray[], ISColoring *iscoloring)
8327 {
8328   PetscFunctionBegin;
8329   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8330   PetscValidType(mat, 1);
8331   PetscAssertPointer(colorarray, 4);
8332   PetscAssertPointer(iscoloring, 5);
8333   MatCheckPreallocated(mat, 1);
8334 
8335   if (!mat->ops->coloringpatch) {
8336     PetscCall(ISColoringCreate(PetscObjectComm((PetscObject)mat), ncolors, n, colorarray, PETSC_OWN_POINTER, iscoloring));
8337   } else {
8338     PetscUseTypeMethod(mat, coloringpatch, ncolors, n, colorarray, iscoloring);
8339   }
8340   PetscFunctionReturn(PETSC_SUCCESS);
8341 }
8342 
8343 /*@
8344   MatSetUnfactored - Resets a factored matrix to be treated as unfactored.
8345 
8346   Logically Collective
8347 
8348   Input Parameter:
8349 . mat - the factored matrix to be reset
8350 
8351   Level: developer
8352 
8353   Notes:
8354   This routine should be used only with factored matrices formed by in-place
8355   factorization via ILU(0) (or by in-place LU factorization for the `MATSEQDENSE`
8356   format).  This option can save memory, for example, when solving nonlinear
8357   systems with a matrix-free Newton-Krylov method and a matrix-based, in-place
8358   ILU(0) preconditioner.
8359 
8360   One can specify in-place ILU(0) factorization by calling
8361 .vb
8362      PCType(pc,PCILU);
8363      PCFactorSeUseInPlace(pc);
8364 .ve
8365   or by using the options -pc_type ilu -pc_factor_in_place
8366 
8367   In-place factorization ILU(0) can also be used as a local
8368   solver for the blocks within the block Jacobi or additive Schwarz
8369   methods (runtime option: -sub_pc_factor_in_place).  See Users-Manual: ch_pc
8370   for details on setting local solver options.
8371 
8372   Most users should employ the `KSP` interface for linear solvers
8373   instead of working directly with matrix algebra routines such as this.
8374   See, e.g., `KSPCreate()`.
8375 
8376 .seealso: [](ch_matrices), `Mat`, `PCFactorSetUseInPlace()`, `PCFactorGetUseInPlace()`
8377 @*/
8378 PetscErrorCode MatSetUnfactored(Mat mat)
8379 {
8380   PetscFunctionBegin;
8381   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8382   PetscValidType(mat, 1);
8383   MatCheckPreallocated(mat, 1);
8384   mat->factortype = MAT_FACTOR_NONE;
8385   if (!mat->ops->setunfactored) PetscFunctionReturn(PETSC_SUCCESS);
8386   PetscUseTypeMethod(mat, setunfactored);
8387   PetscFunctionReturn(PETSC_SUCCESS);
8388 }
8389 
8390 /*@
8391   MatCreateSubMatrix - Gets a single submatrix on the same number of processors
8392   as the original matrix.
8393 
8394   Collective
8395 
8396   Input Parameters:
8397 + mat   - the original matrix
8398 . isrow - parallel `IS` containing the rows this processor should obtain
8399 . iscol - parallel `IS` containing all columns you wish to keep. Each process should list the columns that will be in IT's "diagonal part" in the new matrix.
8400 - cll   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
8401 
8402   Output Parameter:
8403 . newmat - the new submatrix, of the same type as the original matrix
8404 
8405   Level: advanced
8406 
8407   Notes:
8408   The submatrix will be able to be multiplied with vectors using the same layout as `iscol`.
8409 
8410   Some matrix types place restrictions on the row and column indices, such
8411   as that they be sorted or that they be equal to each other. For `MATBAIJ` and `MATSBAIJ` matrices the indices must include all rows/columns of a block;
8412   for example, if the block size is 3 one cannot select the 0 and 2 rows without selecting the 1 row.
8413 
8414   The index sets may not have duplicate entries.
8415 
8416   The first time this is called you should use a cll of `MAT_INITIAL_MATRIX`,
8417   the `MatCreateSubMatrix()` routine will create the newmat for you. Any additional calls
8418   to this routine with a mat of the same nonzero structure and with a call of `MAT_REUSE_MATRIX`
8419   will reuse the matrix generated the first time.  You should call `MatDestroy()` on `newmat` when
8420   you are finished using it.
8421 
8422   The communicator of the newly obtained matrix is ALWAYS the same as the communicator of
8423   the input matrix.
8424 
8425   If `iscol` is `NULL` then all columns are obtained (not supported in Fortran).
8426 
8427   If `isrow` and `iscol` have a nontrivial block-size, then the resulting matrix has this block-size as well. This feature
8428   is used by `PCFIELDSPLIT` to allow easy nesting of its use.
8429 
8430   Example usage:
8431   Consider the following 8x8 matrix with 34 non-zero values, that is
8432   assembled across 3 processors. Let's assume that proc0 owns 3 rows,
8433   proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
8434   as follows
8435 .vb
8436             1  2  0  |  0  3  0  |  0  4
8437     Proc0   0  5  6  |  7  0  0  |  8  0
8438             9  0 10  | 11  0  0  | 12  0
8439     -------------------------------------
8440            13  0 14  | 15 16 17  |  0  0
8441     Proc1   0 18  0  | 19 20 21  |  0  0
8442             0  0  0  | 22 23  0  | 24  0
8443     -------------------------------------
8444     Proc2  25 26 27  |  0  0 28  | 29  0
8445            30  0  0  | 31 32 33  |  0 34
8446 .ve
8447 
8448   Suppose `isrow` = [0 1 | 4 | 6 7] and `iscol` = [1 2 | 3 4 5 | 6].  The resulting submatrix is
8449 
8450 .vb
8451             2  0  |  0  3  0  |  0
8452     Proc0   5  6  |  7  0  0  |  8
8453     -------------------------------
8454     Proc1  18  0  | 19 20 21  |  0
8455     -------------------------------
8456     Proc2  26 27  |  0  0 28  | 29
8457             0  0  | 31 32 33  |  0
8458 .ve
8459 
8460 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatCreateSubMatricesMPI()`, `MatCreateSubMatrixVirtual()`, `MatSubMatrixVirtualUpdate()`
8461 @*/
8462 PetscErrorCode MatCreateSubMatrix(Mat mat, IS isrow, IS iscol, MatReuse cll, Mat *newmat)
8463 {
8464   PetscMPIInt size;
8465   Mat        *local;
8466   IS          iscoltmp;
8467   PetscBool   flg;
8468 
8469   PetscFunctionBegin;
8470   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8471   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
8472   if (iscol) PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
8473   PetscAssertPointer(newmat, 5);
8474   if (cll == MAT_REUSE_MATRIX) PetscValidHeaderSpecific(*newmat, MAT_CLASSID, 5);
8475   PetscValidType(mat, 1);
8476   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
8477   PetscCheck(cll != MAT_IGNORE_MATRIX, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot use MAT_IGNORE_MATRIX");
8478 
8479   MatCheckPreallocated(mat, 1);
8480   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
8481 
8482   if (!iscol || isrow == iscol) {
8483     PetscBool   stride;
8484     PetscMPIInt grabentirematrix = 0, grab;
8485     PetscCall(PetscObjectTypeCompare((PetscObject)isrow, ISSTRIDE, &stride));
8486     if (stride) {
8487       PetscInt first, step, n, rstart, rend;
8488       PetscCall(ISStrideGetInfo(isrow, &first, &step));
8489       if (step == 1) {
8490         PetscCall(MatGetOwnershipRange(mat, &rstart, &rend));
8491         if (rstart == first) {
8492           PetscCall(ISGetLocalSize(isrow, &n));
8493           if (n == rend - rstart) grabentirematrix = 1;
8494         }
8495       }
8496     }
8497     PetscCallMPI(MPIU_Allreduce(&grabentirematrix, &grab, 1, MPI_INT, MPI_MIN, PetscObjectComm((PetscObject)mat)));
8498     if (grab) {
8499       PetscCall(PetscInfo(mat, "Getting entire matrix as submatrix\n"));
8500       if (cll == MAT_INITIAL_MATRIX) {
8501         *newmat = mat;
8502         PetscCall(PetscObjectReference((PetscObject)mat));
8503       }
8504       PetscFunctionReturn(PETSC_SUCCESS);
8505     }
8506   }
8507 
8508   if (!iscol) {
8509     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)mat), mat->cmap->n, mat->cmap->rstart, 1, &iscoltmp));
8510   } else {
8511     iscoltmp = iscol;
8512   }
8513 
8514   /* if original matrix is on just one processor then use submatrix generated */
8515   if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1 && cll == MAT_REUSE_MATRIX) {
8516     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_REUSE_MATRIX, &newmat));
8517     goto setproperties;
8518   } else if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1) {
8519     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_INITIAL_MATRIX, &local));
8520     *newmat = *local;
8521     PetscCall(PetscFree(local));
8522     goto setproperties;
8523   } else if (!mat->ops->createsubmatrix) {
8524     /* Create a new matrix type that implements the operation using the full matrix */
8525     PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8526     switch (cll) {
8527     case MAT_INITIAL_MATRIX:
8528       PetscCall(MatCreateSubMatrixVirtual(mat, isrow, iscoltmp, newmat));
8529       break;
8530     case MAT_REUSE_MATRIX:
8531       PetscCall(MatSubMatrixVirtualUpdate(*newmat, mat, isrow, iscoltmp));
8532       break;
8533     default:
8534       SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Invalid MatReuse, must be either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX");
8535     }
8536     PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8537     goto setproperties;
8538   }
8539 
8540   PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8541   PetscUseTypeMethod(mat, createsubmatrix, isrow, iscoltmp, cll, newmat);
8542   PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8543 
8544 setproperties:
8545   if ((*newmat)->symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->structurally_symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->spd == PETSC_BOOL3_UNKNOWN && (*newmat)->hermitian == PETSC_BOOL3_UNKNOWN) {
8546     PetscCall(ISEqualUnsorted(isrow, iscoltmp, &flg));
8547     if (flg) PetscCall(MatPropagateSymmetryOptions(mat, *newmat));
8548   }
8549   if (!iscol) PetscCall(ISDestroy(&iscoltmp));
8550   if (*newmat && cll == MAT_INITIAL_MATRIX) PetscCall(PetscObjectStateIncrease((PetscObject)*newmat));
8551   if (!iscol || isrow == iscol) PetscCall(MatSelectVariableBlockSizes(*newmat, mat, isrow));
8552   PetscFunctionReturn(PETSC_SUCCESS);
8553 }
8554 
8555 /*@
8556   MatPropagateSymmetryOptions - Propagates symmetry options set on a matrix to another matrix
8557 
8558   Not Collective
8559 
8560   Input Parameters:
8561 + A - the matrix we wish to propagate options from
8562 - B - the matrix we wish to propagate options to
8563 
8564   Level: beginner
8565 
8566   Note:
8567   Propagates the options associated to `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_HERMITIAN`, `MAT_SPD`, `MAT_SYMMETRIC`, and `MAT_STRUCTURAL_SYMMETRY_ETERNAL`
8568 
8569 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatIsSymmetricKnown()`, `MatIsSPDKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
8570 @*/
8571 PetscErrorCode MatPropagateSymmetryOptions(Mat A, Mat B)
8572 {
8573   PetscFunctionBegin;
8574   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8575   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
8576   B->symmetry_eternal            = A->symmetry_eternal;
8577   B->structural_symmetry_eternal = A->structural_symmetry_eternal;
8578   B->symmetric                   = A->symmetric;
8579   B->structurally_symmetric      = A->structurally_symmetric;
8580   B->spd                         = A->spd;
8581   B->hermitian                   = A->hermitian;
8582   PetscFunctionReturn(PETSC_SUCCESS);
8583 }
8584 
8585 /*@
8586   MatStashSetInitialSize - sets the sizes of the matrix stash, that is
8587   used during the assembly process to store values that belong to
8588   other processors.
8589 
8590   Not Collective
8591 
8592   Input Parameters:
8593 + mat   - the matrix
8594 . size  - the initial size of the stash.
8595 - bsize - the initial size of the block-stash(if used).
8596 
8597   Options Database Keys:
8598 + -matstash_initial_size <size> or <size0,size1,...sizep-1>            - set initial size
8599 - -matstash_block_initial_size <bsize>  or <bsize0,bsize1,...bsizep-1> - set initial block size
8600 
8601   Level: intermediate
8602 
8603   Notes:
8604   The block-stash is used for values set with `MatSetValuesBlocked()` while
8605   the stash is used for values set with `MatSetValues()`
8606 
8607   Run with the option -info and look for output of the form
8608   MatAssemblyBegin_MPIXXX:Stash has MM entries, uses nn mallocs.
8609   to determine the appropriate value, MM, to use for size and
8610   MatAssemblyBegin_MPIXXX:Block-Stash has BMM entries, uses nn mallocs.
8611   to determine the value, BMM to use for bsize
8612 
8613 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashGetInfo()`
8614 @*/
8615 PetscErrorCode MatStashSetInitialSize(Mat mat, PetscInt size, PetscInt bsize)
8616 {
8617   PetscFunctionBegin;
8618   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8619   PetscValidType(mat, 1);
8620   PetscCall(MatStashSetInitialSize_Private(&mat->stash, size));
8621   PetscCall(MatStashSetInitialSize_Private(&mat->bstash, bsize));
8622   PetscFunctionReturn(PETSC_SUCCESS);
8623 }
8624 
8625 /*@
8626   MatInterpolateAdd - $w = y + A*x$ or $A^T*x$ depending on the shape of
8627   the matrix
8628 
8629   Neighbor-wise Collective
8630 
8631   Input Parameters:
8632 + A - the matrix
8633 . x - the vector to be multiplied by the interpolation operator
8634 - y - the vector to be added to the result
8635 
8636   Output Parameter:
8637 . w - the resulting vector
8638 
8639   Level: intermediate
8640 
8641   Notes:
8642   `w` may be the same vector as `y`.
8643 
8644   This allows one to use either the restriction or interpolation (its transpose)
8645   matrix to do the interpolation
8646 
8647 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8648 @*/
8649 PetscErrorCode MatInterpolateAdd(Mat A, Vec x, Vec y, Vec w)
8650 {
8651   PetscInt M, N, Ny;
8652 
8653   PetscFunctionBegin;
8654   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8655   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8656   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8657   PetscValidHeaderSpecific(w, VEC_CLASSID, 4);
8658   PetscCall(MatGetSize(A, &M, &N));
8659   PetscCall(VecGetSize(y, &Ny));
8660   if (M == Ny) {
8661     PetscCall(MatMultAdd(A, x, y, w));
8662   } else {
8663     PetscCall(MatMultTransposeAdd(A, x, y, w));
8664   }
8665   PetscFunctionReturn(PETSC_SUCCESS);
8666 }
8667 
8668 /*@
8669   MatInterpolate - $y = A*x$ or $A^T*x$ depending on the shape of
8670   the matrix
8671 
8672   Neighbor-wise Collective
8673 
8674   Input Parameters:
8675 + A - the matrix
8676 - x - the vector to be interpolated
8677 
8678   Output Parameter:
8679 . y - the resulting vector
8680 
8681   Level: intermediate
8682 
8683   Note:
8684   This allows one to use either the restriction or interpolation (its transpose)
8685   matrix to do the interpolation
8686 
8687 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8688 @*/
8689 PetscErrorCode MatInterpolate(Mat A, Vec x, Vec y)
8690 {
8691   PetscInt M, N, Ny;
8692 
8693   PetscFunctionBegin;
8694   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8695   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8696   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8697   PetscCall(MatGetSize(A, &M, &N));
8698   PetscCall(VecGetSize(y, &Ny));
8699   if (M == Ny) {
8700     PetscCall(MatMult(A, x, y));
8701   } else {
8702     PetscCall(MatMultTranspose(A, x, y));
8703   }
8704   PetscFunctionReturn(PETSC_SUCCESS);
8705 }
8706 
8707 /*@
8708   MatRestrict - $y = A*x$ or $A^T*x$
8709 
8710   Neighbor-wise Collective
8711 
8712   Input Parameters:
8713 + A - the matrix
8714 - x - the vector to be restricted
8715 
8716   Output Parameter:
8717 . y - the resulting vector
8718 
8719   Level: intermediate
8720 
8721   Note:
8722   This allows one to use either the restriction or interpolation (its transpose)
8723   matrix to do the restriction
8724 
8725 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatInterpolate()`, `PCMG`
8726 @*/
8727 PetscErrorCode MatRestrict(Mat A, Vec x, Vec y)
8728 {
8729   PetscInt M, N, Nx;
8730 
8731   PetscFunctionBegin;
8732   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8733   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8734   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8735   PetscCall(MatGetSize(A, &M, &N));
8736   PetscCall(VecGetSize(x, &Nx));
8737   if (M == Nx) {
8738     PetscCall(MatMultTranspose(A, x, y));
8739   } else {
8740     PetscCall(MatMult(A, x, y));
8741   }
8742   PetscFunctionReturn(PETSC_SUCCESS);
8743 }
8744 
8745 /*@
8746   MatMatInterpolateAdd - $Y = W + A*X$ or $W + A^T*X$ depending on the shape of `A`
8747 
8748   Neighbor-wise Collective
8749 
8750   Input Parameters:
8751 + A - the matrix
8752 . x - the input dense matrix to be multiplied
8753 - w - the input dense matrix to be added to the result
8754 
8755   Output Parameter:
8756 . y - the output dense matrix
8757 
8758   Level: intermediate
8759 
8760   Note:
8761   This allows one to use either the restriction or interpolation (its transpose)
8762   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8763   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8764 
8765 .seealso: [](ch_matrices), `Mat`, `MatInterpolateAdd()`, `MatMatInterpolate()`, `MatMatRestrict()`, `PCMG`
8766 @*/
8767 PetscErrorCode MatMatInterpolateAdd(Mat A, Mat x, Mat w, Mat *y)
8768 {
8769   PetscInt  M, N, Mx, Nx, Mo, My = 0, Ny = 0;
8770   PetscBool trans = PETSC_TRUE;
8771   MatReuse  reuse = MAT_INITIAL_MATRIX;
8772 
8773   PetscFunctionBegin;
8774   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8775   PetscValidHeaderSpecific(x, MAT_CLASSID, 2);
8776   PetscValidType(x, 2);
8777   if (w) PetscValidHeaderSpecific(w, MAT_CLASSID, 3);
8778   if (*y) PetscValidHeaderSpecific(*y, MAT_CLASSID, 4);
8779   PetscCall(MatGetSize(A, &M, &N));
8780   PetscCall(MatGetSize(x, &Mx, &Nx));
8781   if (N == Mx) trans = PETSC_FALSE;
8782   else PetscCheck(M == Mx, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Size mismatch: A %" PetscInt_FMT "x%" PetscInt_FMT ", X %" PetscInt_FMT "x%" PetscInt_FMT, M, N, Mx, Nx);
8783   Mo = trans ? N : M;
8784   if (*y) {
8785     PetscCall(MatGetSize(*y, &My, &Ny));
8786     if (Mo == My && Nx == Ny) {
8787       reuse = MAT_REUSE_MATRIX;
8788     } else {
8789       PetscCheck(w || *y != w, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot reuse y and w, size mismatch: A %" PetscInt_FMT "x%" PetscInt_FMT ", X %" PetscInt_FMT "x%" PetscInt_FMT ", Y %" PetscInt_FMT "x%" PetscInt_FMT, M, N, Mx, Nx, My, Ny);
8790       PetscCall(MatDestroy(y));
8791     }
8792   }
8793 
8794   if (w && *y == w) { /* this is to minimize changes in PCMG */
8795     PetscBool flg;
8796 
8797     PetscCall(PetscObjectQuery((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject *)&w));
8798     if (w) {
8799       PetscInt My, Ny, Mw, Nw;
8800 
8801       PetscCall(PetscObjectTypeCompare((PetscObject)*y, ((PetscObject)w)->type_name, &flg));
8802       PetscCall(MatGetSize(*y, &My, &Ny));
8803       PetscCall(MatGetSize(w, &Mw, &Nw));
8804       if (!flg || My != Mw || Ny != Nw) w = NULL;
8805     }
8806     if (!w) {
8807       PetscCall(MatDuplicate(*y, MAT_COPY_VALUES, &w));
8808       PetscCall(PetscObjectCompose((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject)w));
8809       PetscCall(PetscObjectDereference((PetscObject)w));
8810     } else {
8811       PetscCall(MatCopy(*y, w, UNKNOWN_NONZERO_PATTERN));
8812     }
8813   }
8814   if (!trans) {
8815     PetscCall(MatMatMult(A, x, reuse, PETSC_DETERMINE, y));
8816   } else {
8817     PetscCall(MatTransposeMatMult(A, x, reuse, PETSC_DETERMINE, y));
8818   }
8819   if (w) PetscCall(MatAXPY(*y, 1.0, w, UNKNOWN_NONZERO_PATTERN));
8820   PetscFunctionReturn(PETSC_SUCCESS);
8821 }
8822 
8823 /*@
8824   MatMatInterpolate - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8825 
8826   Neighbor-wise Collective
8827 
8828   Input Parameters:
8829 + A - the matrix
8830 - x - the input dense matrix
8831 
8832   Output Parameter:
8833 . y - the output dense matrix
8834 
8835   Level: intermediate
8836 
8837   Note:
8838   This allows one to use either the restriction or interpolation (its transpose)
8839   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8840   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8841 
8842 .seealso: [](ch_matrices), `Mat`, `MatInterpolate()`, `MatRestrict()`, `MatMatRestrict()`, `PCMG`
8843 @*/
8844 PetscErrorCode MatMatInterpolate(Mat A, Mat x, Mat *y)
8845 {
8846   PetscFunctionBegin;
8847   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8848   PetscFunctionReturn(PETSC_SUCCESS);
8849 }
8850 
8851 /*@
8852   MatMatRestrict - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8853 
8854   Neighbor-wise Collective
8855 
8856   Input Parameters:
8857 + A - the matrix
8858 - x - the input dense matrix
8859 
8860   Output Parameter:
8861 . y - the output dense matrix
8862 
8863   Level: intermediate
8864 
8865   Note:
8866   This allows one to use either the restriction or interpolation (its transpose)
8867   matrix to do the restriction. `y` matrix can be reused if already created with the proper sizes,
8868   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8869 
8870 .seealso: [](ch_matrices), `Mat`, `MatRestrict()`, `MatInterpolate()`, `MatMatInterpolate()`, `PCMG`
8871 @*/
8872 PetscErrorCode MatMatRestrict(Mat A, Mat x, Mat *y)
8873 {
8874   PetscFunctionBegin;
8875   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8876   PetscFunctionReturn(PETSC_SUCCESS);
8877 }
8878 
8879 /*@
8880   MatGetNullSpace - retrieves the null space of a matrix.
8881 
8882   Logically Collective
8883 
8884   Input Parameters:
8885 + mat    - the matrix
8886 - nullsp - the null space object
8887 
8888   Level: developer
8889 
8890 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetNullSpace()`, `MatNullSpace`
8891 @*/
8892 PetscErrorCode MatGetNullSpace(Mat mat, MatNullSpace *nullsp)
8893 {
8894   PetscFunctionBegin;
8895   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8896   PetscAssertPointer(nullsp, 2);
8897   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->nullsp) ? mat->transnullsp : mat->nullsp;
8898   PetscFunctionReturn(PETSC_SUCCESS);
8899 }
8900 
8901 /*@C
8902   MatGetNullSpaces - gets the null spaces, transpose null spaces, and near null spaces from an array of matrices
8903 
8904   Logically Collective
8905 
8906   Input Parameters:
8907 + n   - the number of matrices
8908 - mat - the array of matrices
8909 
8910   Output Parameters:
8911 . nullsp - an array of null spaces, `NULL` for each matrix that does not have a null space, length 3 * `n`
8912 
8913   Level: developer
8914 
8915   Note:
8916   Call `MatRestoreNullspaces()` to provide these to another array of matrices
8917 
8918 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
8919           `MatNullSpaceRemove()`, `MatRestoreNullSpaces()`
8920 @*/
8921 PetscErrorCode MatGetNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
8922 {
8923   PetscFunctionBegin;
8924   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
8925   PetscAssertPointer(mat, 2);
8926   PetscAssertPointer(nullsp, 3);
8927 
8928   PetscCall(PetscCalloc1(3 * n, nullsp));
8929   for (PetscInt i = 0; i < n; i++) {
8930     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
8931     (*nullsp)[i] = mat[i]->nullsp;
8932     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[i]));
8933     (*nullsp)[n + i] = mat[i]->nearnullsp;
8934     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[n + i]));
8935     (*nullsp)[2 * n + i] = mat[i]->transnullsp;
8936     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[2 * n + i]));
8937   }
8938   PetscFunctionReturn(PETSC_SUCCESS);
8939 }
8940 
8941 /*@C
8942   MatRestoreNullSpaces - sets the null spaces, transpose null spaces, and near null spaces obtained with `MatGetNullSpaces()` for an array of matrices
8943 
8944   Logically Collective
8945 
8946   Input Parameters:
8947 + n      - the number of matrices
8948 . mat    - the array of matrices
8949 - nullsp - an array of null spaces
8950 
8951   Level: developer
8952 
8953   Note:
8954   Call `MatGetNullSpaces()` to create `nullsp`
8955 
8956 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
8957           `MatNullSpaceRemove()`, `MatGetNullSpaces()`
8958 @*/
8959 PetscErrorCode MatRestoreNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
8960 {
8961   PetscFunctionBegin;
8962   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
8963   PetscAssertPointer(mat, 2);
8964   PetscAssertPointer(nullsp, 3);
8965   PetscAssertPointer(*nullsp, 3);
8966 
8967   for (PetscInt i = 0; i < n; i++) {
8968     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
8969     PetscCall(MatSetNullSpace(mat[i], (*nullsp)[i]));
8970     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[i]));
8971     PetscCall(MatSetNearNullSpace(mat[i], (*nullsp)[n + i]));
8972     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[n + i]));
8973     PetscCall(MatSetTransposeNullSpace(mat[i], (*nullsp)[2 * n + i]));
8974     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[2 * n + i]));
8975   }
8976   PetscCall(PetscFree(*nullsp));
8977   PetscFunctionReturn(PETSC_SUCCESS);
8978 }
8979 
8980 /*@
8981   MatSetNullSpace - attaches a null space to a matrix.
8982 
8983   Logically Collective
8984 
8985   Input Parameters:
8986 + mat    - the matrix
8987 - nullsp - the null space object
8988 
8989   Level: advanced
8990 
8991   Notes:
8992   This null space is used by the `KSP` linear solvers to solve singular systems.
8993 
8994   Overwrites any previous null space that may have been attached. You can remove the null space from the matrix object by calling this routine with an nullsp of `NULL`
8995 
8996   For inconsistent singular systems (linear systems where the right-hand side is not in the range of the operator) the `KSP` residuals will not converge
8997   to zero but the linear system will still be solved in a least squares sense.
8998 
8999   The fundamental theorem of linear algebra (Gilbert Strang, Introduction to Applied Mathematics, page 72) states that
9000   the domain of a matrix $A$ (from $R^n$ to $R^m$ ($m$ rows, $n$ columns) $R^n$ = the direct sum of the null space of $A$, $n(A)$, plus the range of $A^T$, $R(A^T)$.
9001   Similarly $R^m$ = direct sum $n(A^T) + R(A)$.  Hence the linear system $A x = b$ has a solution only if $b$ in $R(A)$ (or correspondingly $b$ is orthogonal to
9002   $n(A^T))$ and if $x$ is a solution then $x + \alpha n(A)$ is a solution for any $\alpha$. The minimum norm solution is orthogonal to $n(A)$. For problems without a solution
9003   the solution that minimizes the norm of the residual (the least squares solution) can be obtained by solving $A x = \hat{b}$ where $\hat{b}$ is $b$ orthogonalized to the $n(A^T)$.
9004   This  $\hat{b}$ can be obtained by calling `MatNullSpaceRemove()` with the null space of the transpose of the matrix.
9005 
9006   If the matrix is known to be symmetric because it is an `MATSBAIJ` matrix or one has called
9007   `MatSetOption`(mat,`MAT_SYMMETRIC` or possibly `MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`); this
9008   routine also automatically calls `MatSetTransposeNullSpace()`.
9009 
9010   The user should call `MatNullSpaceDestroy()`.
9011 
9012 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`,
9013           `KSPSetPCSide()`
9014 @*/
9015 PetscErrorCode MatSetNullSpace(Mat mat, MatNullSpace nullsp)
9016 {
9017   PetscFunctionBegin;
9018   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9019   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9020   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9021   PetscCall(MatNullSpaceDestroy(&mat->nullsp));
9022   mat->nullsp = nullsp;
9023   if (mat->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetTransposeNullSpace(mat, nullsp));
9024   PetscFunctionReturn(PETSC_SUCCESS);
9025 }
9026 
9027 /*@
9028   MatGetTransposeNullSpace - retrieves the null space of the transpose of a matrix.
9029 
9030   Logically Collective
9031 
9032   Input Parameters:
9033 + mat    - the matrix
9034 - nullsp - the null space object
9035 
9036   Level: developer
9037 
9038 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetTransposeNullSpace()`, `MatSetNullSpace()`, `MatGetNullSpace()`
9039 @*/
9040 PetscErrorCode MatGetTransposeNullSpace(Mat mat, MatNullSpace *nullsp)
9041 {
9042   PetscFunctionBegin;
9043   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9044   PetscValidType(mat, 1);
9045   PetscAssertPointer(nullsp, 2);
9046   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->transnullsp) ? mat->nullsp : mat->transnullsp;
9047   PetscFunctionReturn(PETSC_SUCCESS);
9048 }
9049 
9050 /*@
9051   MatSetTransposeNullSpace - attaches the null space of a transpose of a matrix to the matrix
9052 
9053   Logically Collective
9054 
9055   Input Parameters:
9056 + mat    - the matrix
9057 - nullsp - the null space object
9058 
9059   Level: advanced
9060 
9061   Notes:
9062   This allows solving singular linear systems defined by the transpose of the matrix using `KSP` solvers with left preconditioning.
9063 
9064   See `MatSetNullSpace()`
9065 
9066 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`, `KSPSetPCSide()`
9067 @*/
9068 PetscErrorCode MatSetTransposeNullSpace(Mat mat, MatNullSpace nullsp)
9069 {
9070   PetscFunctionBegin;
9071   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9072   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9073   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9074   PetscCall(MatNullSpaceDestroy(&mat->transnullsp));
9075   mat->transnullsp = nullsp;
9076   PetscFunctionReturn(PETSC_SUCCESS);
9077 }
9078 
9079 /*@
9080   MatSetNearNullSpace - attaches a null space to a matrix, which is often the null space (rigid body modes) of the operator without boundary conditions
9081   This null space will be used to provide near null space vectors to a multigrid preconditioner built from this matrix.
9082 
9083   Logically Collective
9084 
9085   Input Parameters:
9086 + mat    - the matrix
9087 - nullsp - the null space object
9088 
9089   Level: advanced
9090 
9091   Notes:
9092   Overwrites any previous near null space that may have been attached
9093 
9094   You can remove the null space by calling this routine with an `nullsp` of `NULL`
9095 
9096 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNullSpace()`, `MatNullSpaceCreateRigidBody()`, `MatGetNearNullSpace()`
9097 @*/
9098 PetscErrorCode MatSetNearNullSpace(Mat mat, MatNullSpace nullsp)
9099 {
9100   PetscFunctionBegin;
9101   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9102   PetscValidType(mat, 1);
9103   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9104   MatCheckPreallocated(mat, 1);
9105   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9106   PetscCall(MatNullSpaceDestroy(&mat->nearnullsp));
9107   mat->nearnullsp = nullsp;
9108   PetscFunctionReturn(PETSC_SUCCESS);
9109 }
9110 
9111 /*@
9112   MatGetNearNullSpace - Get null space attached with `MatSetNearNullSpace()`
9113 
9114   Not Collective
9115 
9116   Input Parameter:
9117 . mat - the matrix
9118 
9119   Output Parameter:
9120 . nullsp - the null space object, `NULL` if not set
9121 
9122   Level: advanced
9123 
9124 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatNullSpaceCreate()`
9125 @*/
9126 PetscErrorCode MatGetNearNullSpace(Mat mat, MatNullSpace *nullsp)
9127 {
9128   PetscFunctionBegin;
9129   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9130   PetscValidType(mat, 1);
9131   PetscAssertPointer(nullsp, 2);
9132   MatCheckPreallocated(mat, 1);
9133   *nullsp = mat->nearnullsp;
9134   PetscFunctionReturn(PETSC_SUCCESS);
9135 }
9136 
9137 /*@
9138   MatICCFactor - Performs in-place incomplete Cholesky factorization of matrix.
9139 
9140   Collective
9141 
9142   Input Parameters:
9143 + mat  - the matrix
9144 . row  - row/column permutation
9145 - info - information on desired factorization process
9146 
9147   Level: developer
9148 
9149   Notes:
9150   Probably really in-place only when level of fill is zero, otherwise allocates
9151   new space to store factored matrix and deletes previous memory.
9152 
9153   Most users should employ the `KSP` interface for linear solvers
9154   instead of working directly with matrix algebra routines such as this.
9155   See, e.g., `KSPCreate()`.
9156 
9157   Fortran Note:
9158   A valid (non-null) `info` argument must be provided
9159 
9160 .seealso: [](ch_matrices), `Mat`, `MatFactorInfo`, `MatGetFactor()`, `MatICCFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
9161 @*/
9162 PetscErrorCode MatICCFactor(Mat mat, IS row, const MatFactorInfo *info)
9163 {
9164   PetscFunctionBegin;
9165   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9166   PetscValidType(mat, 1);
9167   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
9168   PetscAssertPointer(info, 3);
9169   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
9170   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
9171   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9172   MatCheckPreallocated(mat, 1);
9173   PetscUseTypeMethod(mat, iccfactor, row, info);
9174   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9175   PetscFunctionReturn(PETSC_SUCCESS);
9176 }
9177 
9178 /*@
9179   MatDiagonalScaleLocal - Scales columns of a matrix given the scaling values including the
9180   ghosted ones.
9181 
9182   Not Collective
9183 
9184   Input Parameters:
9185 + mat  - the matrix
9186 - diag - the diagonal values, including ghost ones
9187 
9188   Level: developer
9189 
9190   Notes:
9191   Works only for `MATMPIAIJ` and `MATMPIBAIJ` matrices
9192 
9193   This allows one to avoid during communication to perform the scaling that must be done with `MatDiagonalScale()`
9194 
9195 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
9196 @*/
9197 PetscErrorCode MatDiagonalScaleLocal(Mat mat, Vec diag)
9198 {
9199   PetscMPIInt size;
9200 
9201   PetscFunctionBegin;
9202   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9203   PetscValidHeaderSpecific(diag, VEC_CLASSID, 2);
9204   PetscValidType(mat, 1);
9205 
9206   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must be already assembled");
9207   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
9208   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
9209   if (size == 1) {
9210     PetscInt n, m;
9211     PetscCall(VecGetSize(diag, &n));
9212     PetscCall(MatGetSize(mat, NULL, &m));
9213     PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supported for sequential matrices when no ghost points/periodic conditions");
9214     PetscCall(MatDiagonalScale(mat, NULL, diag));
9215   } else {
9216     PetscUseMethod(mat, "MatDiagonalScaleLocal_C", (Mat, Vec), (mat, diag));
9217   }
9218   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
9219   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9220   PetscFunctionReturn(PETSC_SUCCESS);
9221 }
9222 
9223 /*@
9224   MatGetInertia - Gets the inertia from a factored matrix
9225 
9226   Collective
9227 
9228   Input Parameter:
9229 . mat - the matrix
9230 
9231   Output Parameters:
9232 + nneg  - number of negative eigenvalues
9233 . nzero - number of zero eigenvalues
9234 - npos  - number of positive eigenvalues
9235 
9236   Level: advanced
9237 
9238   Note:
9239   Matrix must have been factored by `MatCholeskyFactor()`
9240 
9241 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactor()`
9242 @*/
9243 PetscErrorCode MatGetInertia(Mat mat, PetscInt *nneg, PetscInt *nzero, PetscInt *npos)
9244 {
9245   PetscFunctionBegin;
9246   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9247   PetscValidType(mat, 1);
9248   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9249   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Numeric factor mat is not assembled");
9250   PetscUseTypeMethod(mat, getinertia, nneg, nzero, npos);
9251   PetscFunctionReturn(PETSC_SUCCESS);
9252 }
9253 
9254 /*@C
9255   MatSolves - Solves $A x = b$, given a factored matrix, for a collection of vectors
9256 
9257   Neighbor-wise Collective
9258 
9259   Input Parameters:
9260 + mat - the factored matrix obtained with `MatGetFactor()`
9261 - b   - the right-hand-side vectors
9262 
9263   Output Parameter:
9264 . x - the result vectors
9265 
9266   Level: developer
9267 
9268   Note:
9269   The vectors `b` and `x` cannot be the same.  I.e., one cannot
9270   call `MatSolves`(A,x,x).
9271 
9272 .seealso: [](ch_matrices), `Mat`, `Vecs`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`, `MatSolve()`
9273 @*/
9274 PetscErrorCode MatSolves(Mat mat, Vecs b, Vecs x)
9275 {
9276   PetscFunctionBegin;
9277   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9278   PetscValidType(mat, 1);
9279   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
9280   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9281   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
9282 
9283   MatCheckPreallocated(mat, 1);
9284   PetscCall(PetscLogEventBegin(MAT_Solves, mat, 0, 0, 0));
9285   PetscUseTypeMethod(mat, solves, b, x);
9286   PetscCall(PetscLogEventEnd(MAT_Solves, mat, 0, 0, 0));
9287   PetscFunctionReturn(PETSC_SUCCESS);
9288 }
9289 
9290 /*@
9291   MatIsSymmetric - Test whether a matrix is symmetric
9292 
9293   Collective
9294 
9295   Input Parameters:
9296 + A   - the matrix to test
9297 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact transpose)
9298 
9299   Output Parameter:
9300 . flg - the result
9301 
9302   Level: intermediate
9303 
9304   Notes:
9305   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9306 
9307   If the matrix does not yet know if it is symmetric or not this can be an expensive operation, also available `MatIsSymmetricKnown()`
9308 
9309   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9310   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9311 
9312 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetricKnown()`,
9313           `MAT_SYMMETRIC`, `MAT_SYMMETRY_ETERNAL`
9314 @*/
9315 PetscErrorCode MatIsSymmetric(Mat A, PetscReal tol, PetscBool *flg)
9316 {
9317   PetscFunctionBegin;
9318   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9319   PetscAssertPointer(flg, 3);
9320   if (A->symmetric != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->symmetric);
9321   else {
9322     if (A->ops->issymmetric) PetscUseTypeMethod(A, issymmetric, tol, flg);
9323     else PetscCall(MatIsTranspose(A, A, tol, flg));
9324     if (!tol) PetscCall(MatSetOption(A, MAT_SYMMETRIC, *flg));
9325   }
9326   PetscFunctionReturn(PETSC_SUCCESS);
9327 }
9328 
9329 /*@
9330   MatIsHermitian - Test whether a matrix is Hermitian
9331 
9332   Collective
9333 
9334   Input Parameters:
9335 + A   - the matrix to test
9336 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact Hermitian)
9337 
9338   Output Parameter:
9339 . flg - the result
9340 
9341   Level: intermediate
9342 
9343   Notes:
9344   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9345 
9346   If the matrix does not yet know if it is Hermitian or not this can be an expensive operation, also available `MatIsHermitianKnown()`
9347 
9348   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9349   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMEMTRY_ETERNAL`,`PETSC_TRUE`)
9350 
9351 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetric()`, `MatSetOption()`,
9352           `MatIsSymmetricKnown()`, `MatIsSymmetric()`, `MAT_HERMITIAN`, `MAT_SYMMETRY_ETERNAL`
9353 @*/
9354 PetscErrorCode MatIsHermitian(Mat A, PetscReal tol, PetscBool *flg)
9355 {
9356   PetscFunctionBegin;
9357   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9358   PetscAssertPointer(flg, 3);
9359   if (A->hermitian != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->hermitian);
9360   else {
9361     if (A->ops->ishermitian) PetscUseTypeMethod(A, ishermitian, tol, flg);
9362     else PetscCall(MatIsHermitianTranspose(A, A, tol, flg));
9363     if (!tol) PetscCall(MatSetOption(A, MAT_HERMITIAN, *flg));
9364   }
9365   PetscFunctionReturn(PETSC_SUCCESS);
9366 }
9367 
9368 /*@
9369   MatIsSymmetricKnown - Checks if a matrix knows if it is symmetric or not and its symmetric state
9370 
9371   Not Collective
9372 
9373   Input Parameter:
9374 . A - the matrix to check
9375 
9376   Output Parameters:
9377 + set - `PETSC_TRUE` if the matrix knows its symmetry state (this tells you if the next flag is valid)
9378 - flg - the result (only valid if set is `PETSC_TRUE`)
9379 
9380   Level: advanced
9381 
9382   Notes:
9383   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsSymmetric()`
9384   if you want it explicitly checked
9385 
9386   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9387   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9388 
9389 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9390 @*/
9391 PetscErrorCode MatIsSymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9392 {
9393   PetscFunctionBegin;
9394   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9395   PetscAssertPointer(set, 2);
9396   PetscAssertPointer(flg, 3);
9397   if (A->symmetric != PETSC_BOOL3_UNKNOWN) {
9398     *set = PETSC_TRUE;
9399     *flg = PetscBool3ToBool(A->symmetric);
9400   } else {
9401     *set = PETSC_FALSE;
9402   }
9403   PetscFunctionReturn(PETSC_SUCCESS);
9404 }
9405 
9406 /*@
9407   MatIsSPDKnown - Checks if a matrix knows if it is symmetric positive definite or not and its symmetric positive definite state
9408 
9409   Not Collective
9410 
9411   Input Parameter:
9412 . A - the matrix to check
9413 
9414   Output Parameters:
9415 + set - `PETSC_TRUE` if the matrix knows its symmetric positive definite state (this tells you if the next flag is valid)
9416 - flg - the result (only valid if set is `PETSC_TRUE`)
9417 
9418   Level: advanced
9419 
9420   Notes:
9421   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`).
9422 
9423   One can declare that a matrix is SPD with `MatSetOption`(mat,`MAT_SPD`,`PETSC_TRUE`) and if it is known to remain SPD
9424   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SPD_ETERNAL`,`PETSC_TRUE`)
9425 
9426 .seealso: [](ch_matrices), `Mat`, `MAT_SPD_ETERNAL`, `MAT_SPD`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9427 @*/
9428 PetscErrorCode MatIsSPDKnown(Mat A, PetscBool *set, PetscBool *flg)
9429 {
9430   PetscFunctionBegin;
9431   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9432   PetscAssertPointer(set, 2);
9433   PetscAssertPointer(flg, 3);
9434   if (A->spd != PETSC_BOOL3_UNKNOWN) {
9435     *set = PETSC_TRUE;
9436     *flg = PetscBool3ToBool(A->spd);
9437   } else {
9438     *set = PETSC_FALSE;
9439   }
9440   PetscFunctionReturn(PETSC_SUCCESS);
9441 }
9442 
9443 /*@
9444   MatIsHermitianKnown - Checks if a matrix knows if it is Hermitian or not and its Hermitian state
9445 
9446   Not Collective
9447 
9448   Input Parameter:
9449 . A - the matrix to check
9450 
9451   Output Parameters:
9452 + set - `PETSC_TRUE` if the matrix knows its Hermitian state (this tells you if the next flag is valid)
9453 - flg - the result (only valid if set is `PETSC_TRUE`)
9454 
9455   Level: advanced
9456 
9457   Notes:
9458   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsHermitian()`
9459   if you want it explicitly checked
9460 
9461   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9462   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9463 
9464 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MAT_HERMITIAN`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`
9465 @*/
9466 PetscErrorCode MatIsHermitianKnown(Mat A, PetscBool *set, PetscBool *flg)
9467 {
9468   PetscFunctionBegin;
9469   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9470   PetscAssertPointer(set, 2);
9471   PetscAssertPointer(flg, 3);
9472   if (A->hermitian != PETSC_BOOL3_UNKNOWN) {
9473     *set = PETSC_TRUE;
9474     *flg = PetscBool3ToBool(A->hermitian);
9475   } else {
9476     *set = PETSC_FALSE;
9477   }
9478   PetscFunctionReturn(PETSC_SUCCESS);
9479 }
9480 
9481 /*@
9482   MatIsStructurallySymmetric - Test whether a matrix is structurally symmetric
9483 
9484   Collective
9485 
9486   Input Parameter:
9487 . A - the matrix to test
9488 
9489   Output Parameter:
9490 . flg - the result
9491 
9492   Level: intermediate
9493 
9494   Notes:
9495   If the matrix does yet know it is structurally symmetric this can be an expensive operation, also available `MatIsStructurallySymmetricKnown()`
9496 
9497   One can declare that a matrix is structurally symmetric with `MatSetOption`(mat,`MAT_STRUCTURALLY_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain structurally
9498   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9499 
9500 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsSymmetric()`, `MatSetOption()`, `MatIsStructurallySymmetricKnown()`
9501 @*/
9502 PetscErrorCode MatIsStructurallySymmetric(Mat A, PetscBool *flg)
9503 {
9504   PetscFunctionBegin;
9505   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9506   PetscAssertPointer(flg, 2);
9507   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9508     *flg = PetscBool3ToBool(A->structurally_symmetric);
9509   } else {
9510     PetscUseTypeMethod(A, isstructurallysymmetric, flg);
9511     PetscCall(MatSetOption(A, MAT_STRUCTURALLY_SYMMETRIC, *flg));
9512   }
9513   PetscFunctionReturn(PETSC_SUCCESS);
9514 }
9515 
9516 /*@
9517   MatIsStructurallySymmetricKnown - Checks if a matrix knows if it is structurally symmetric or not and its structurally symmetric state
9518 
9519   Not Collective
9520 
9521   Input Parameter:
9522 . A - the matrix to check
9523 
9524   Output Parameters:
9525 + set - PETSC_TRUE if the matrix knows its structurally symmetric state (this tells you if the next flag is valid)
9526 - flg - the result (only valid if set is PETSC_TRUE)
9527 
9528   Level: advanced
9529 
9530   Notes:
9531   One can declare that a matrix is structurally symmetric with `MatSetOption`(mat,`MAT_STRUCTURALLY_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain structurally
9532   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9533 
9534   Use `MatIsStructurallySymmetric()` to explicitly check if a matrix is structurally symmetric (this is an expensive operation)
9535 
9536 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9537 @*/
9538 PetscErrorCode MatIsStructurallySymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9539 {
9540   PetscFunctionBegin;
9541   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9542   PetscAssertPointer(set, 2);
9543   PetscAssertPointer(flg, 3);
9544   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9545     *set = PETSC_TRUE;
9546     *flg = PetscBool3ToBool(A->structurally_symmetric);
9547   } else {
9548     *set = PETSC_FALSE;
9549   }
9550   PetscFunctionReturn(PETSC_SUCCESS);
9551 }
9552 
9553 /*@
9554   MatStashGetInfo - Gets how many values are currently in the matrix stash, i.e. need
9555   to be communicated to other processors during the `MatAssemblyBegin()`/`MatAssemblyEnd()` process
9556 
9557   Not Collective
9558 
9559   Input Parameter:
9560 . mat - the matrix
9561 
9562   Output Parameters:
9563 + nstash    - the size of the stash
9564 . reallocs  - the number of additional mallocs incurred.
9565 . bnstash   - the size of the block stash
9566 - breallocs - the number of additional mallocs incurred.in the block stash
9567 
9568   Level: advanced
9569 
9570 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashSetInitialSize()`
9571 @*/
9572 PetscErrorCode MatStashGetInfo(Mat mat, PetscInt *nstash, PetscInt *reallocs, PetscInt *bnstash, PetscInt *breallocs)
9573 {
9574   PetscFunctionBegin;
9575   PetscCall(MatStashGetInfo_Private(&mat->stash, nstash, reallocs));
9576   PetscCall(MatStashGetInfo_Private(&mat->bstash, bnstash, breallocs));
9577   PetscFunctionReturn(PETSC_SUCCESS);
9578 }
9579 
9580 /*@
9581   MatCreateVecs - Get vector(s) compatible with the matrix, i.e. with the same
9582   parallel layout, `PetscLayout` for rows and columns
9583 
9584   Collective
9585 
9586   Input Parameter:
9587 . mat - the matrix
9588 
9589   Output Parameters:
9590 + right - (optional) vector that the matrix can be multiplied against
9591 - left  - (optional) vector that the matrix vector product can be stored in
9592 
9593   Level: advanced
9594 
9595   Notes:
9596   The blocksize of the returned vectors is determined by the row and column block sizes set with `MatSetBlockSizes()` or the single blocksize (same for both) set by `MatSetBlockSize()`.
9597 
9598   These are new vectors which are not owned by the mat, they should be destroyed in `VecDestroy()` when no longer needed
9599 
9600 .seealso: [](ch_matrices), `Mat`, `Vec`, `VecCreate()`, `VecDestroy()`, `DMCreateGlobalVector()`
9601 @*/
9602 PetscErrorCode MatCreateVecs(Mat mat, Vec *right, Vec *left)
9603 {
9604   PetscFunctionBegin;
9605   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9606   PetscValidType(mat, 1);
9607   if (mat->ops->getvecs) {
9608     PetscUseTypeMethod(mat, getvecs, right, left);
9609   } else {
9610     if (right) {
9611       PetscCheck(mat->cmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for columns not yet setup");
9612       PetscCall(VecCreateWithLayout_Private(mat->cmap, right));
9613       PetscCall(VecSetType(*right, mat->defaultvectype));
9614 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9615       if (mat->boundtocpu && mat->bindingpropagates) {
9616         PetscCall(VecSetBindingPropagates(*right, PETSC_TRUE));
9617         PetscCall(VecBindToCPU(*right, PETSC_TRUE));
9618       }
9619 #endif
9620     }
9621     if (left) {
9622       PetscCheck(mat->rmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for rows not yet setup");
9623       PetscCall(VecCreateWithLayout_Private(mat->rmap, left));
9624       PetscCall(VecSetType(*left, mat->defaultvectype));
9625 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9626       if (mat->boundtocpu && mat->bindingpropagates) {
9627         PetscCall(VecSetBindingPropagates(*left, PETSC_TRUE));
9628         PetscCall(VecBindToCPU(*left, PETSC_TRUE));
9629       }
9630 #endif
9631     }
9632   }
9633   PetscFunctionReturn(PETSC_SUCCESS);
9634 }
9635 
9636 /*@
9637   MatFactorInfoInitialize - Initializes a `MatFactorInfo` data structure
9638   with default values.
9639 
9640   Not Collective
9641 
9642   Input Parameter:
9643 . info - the `MatFactorInfo` data structure
9644 
9645   Level: developer
9646 
9647   Notes:
9648   The solvers are generally used through the `KSP` and `PC` objects, for example
9649   `PCLU`, `PCILU`, `PCCHOLESKY`, `PCICC`
9650 
9651   Once the data structure is initialized one may change certain entries as desired for the particular factorization to be performed
9652 
9653 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorInfo`
9654 @*/
9655 PetscErrorCode MatFactorInfoInitialize(MatFactorInfo *info)
9656 {
9657   PetscFunctionBegin;
9658   PetscCall(PetscMemzero(info, sizeof(MatFactorInfo)));
9659   PetscFunctionReturn(PETSC_SUCCESS);
9660 }
9661 
9662 /*@
9663   MatFactorSetSchurIS - Set indices corresponding to the Schur complement you wish to have computed
9664 
9665   Collective
9666 
9667   Input Parameters:
9668 + mat - the factored matrix
9669 - is  - the index set defining the Schur indices (0-based)
9670 
9671   Level: advanced
9672 
9673   Notes:
9674   Call `MatFactorSolveSchurComplement()` or `MatFactorSolveSchurComplementTranspose()` after this call to solve a Schur complement system.
9675 
9676   You can call `MatFactorGetSchurComplement()` or `MatFactorCreateSchurComplement()` after this call.
9677 
9678   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9679 
9680 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorGetSchurComplement()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSolveSchurComplement()`,
9681           `MatFactorSolveSchurComplementTranspose()`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9682 @*/
9683 PetscErrorCode MatFactorSetSchurIS(Mat mat, IS is)
9684 {
9685   PetscErrorCode (*f)(Mat, IS);
9686 
9687   PetscFunctionBegin;
9688   PetscValidType(mat, 1);
9689   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9690   PetscValidType(is, 2);
9691   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
9692   PetscCheckSameComm(mat, 1, is, 2);
9693   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
9694   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorSetSchurIS_C", &f));
9695   PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "The selected MatSolverType does not support Schur complement computation. You should use MATSOLVERMUMPS or MATSOLVERMKL_PARDISO");
9696   PetscCall(MatDestroy(&mat->schur));
9697   PetscCall((*f)(mat, is));
9698   PetscCheck(mat->schur, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Schur complement has not been created");
9699   PetscFunctionReturn(PETSC_SUCCESS);
9700 }
9701 
9702 /*@
9703   MatFactorCreateSchurComplement - Create a Schur complement matrix object using Schur data computed during the factorization step
9704 
9705   Logically Collective
9706 
9707   Input Parameters:
9708 + F      - the factored matrix obtained by calling `MatGetFactor()`
9709 . S      - location where to return the Schur complement, can be `NULL`
9710 - status - the status of the Schur complement matrix, can be `NULL`
9711 
9712   Level: advanced
9713 
9714   Notes:
9715   You must call `MatFactorSetSchurIS()` before calling this routine.
9716 
9717   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9718 
9719   The routine provides a copy of the Schur matrix stored within the solver data structures.
9720   The caller must destroy the object when it is no longer needed.
9721   If `MatFactorInvertSchurComplement()` has been called, the routine gets back the inverse.
9722 
9723   Use `MatFactorGetSchurComplement()` to get access to the Schur complement matrix inside the factored matrix instead of making a copy of it (which this function does)
9724 
9725   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9726 
9727   Developer Note:
9728   The reason this routine exists is because the representation of the Schur complement within the factor matrix may be different than a standard PETSc
9729   matrix representation and we normally do not want to use the time or memory to make a copy as a regular PETSc matrix.
9730 
9731 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorSchurStatus`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9732 @*/
9733 PetscErrorCode MatFactorCreateSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9734 {
9735   PetscFunctionBegin;
9736   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9737   if (S) PetscAssertPointer(S, 2);
9738   if (status) PetscAssertPointer(status, 3);
9739   if (S) {
9740     PetscErrorCode (*f)(Mat, Mat *);
9741 
9742     PetscCall(PetscObjectQueryFunction((PetscObject)F, "MatFactorCreateSchurComplement_C", &f));
9743     if (f) {
9744       PetscCall((*f)(F, S));
9745     } else {
9746       PetscCall(MatDuplicate(F->schur, MAT_COPY_VALUES, S));
9747     }
9748   }
9749   if (status) *status = F->schur_status;
9750   PetscFunctionReturn(PETSC_SUCCESS);
9751 }
9752 
9753 /*@
9754   MatFactorGetSchurComplement - Gets access to a Schur complement matrix using the current Schur data within a factored matrix
9755 
9756   Logically Collective
9757 
9758   Input Parameters:
9759 + F      - the factored matrix obtained by calling `MatGetFactor()`
9760 . S      - location where to return the Schur complement, can be `NULL`
9761 - status - the status of the Schur complement matrix, can be `NULL`
9762 
9763   Level: advanced
9764 
9765   Notes:
9766   You must call `MatFactorSetSchurIS()` before calling this routine.
9767 
9768   Schur complement mode is currently implemented for sequential matrices with factor type of `MATSOLVERMUMPS`
9769 
9770   The routine returns a the Schur Complement stored within the data structures of the solver.
9771 
9772   If `MatFactorInvertSchurComplement()` has previously been called, the returned matrix is actually the inverse of the Schur complement.
9773 
9774   The returned matrix should not be destroyed; the caller should call `MatFactorRestoreSchurComplement()` when the object is no longer needed.
9775 
9776   Use `MatFactorCreateSchurComplement()` to create a copy of the Schur complement matrix that is within a factored matrix
9777 
9778   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9779 
9780 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9781 @*/
9782 PetscErrorCode MatFactorGetSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9783 {
9784   PetscFunctionBegin;
9785   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9786   if (S) {
9787     PetscAssertPointer(S, 2);
9788     *S = F->schur;
9789   }
9790   if (status) {
9791     PetscAssertPointer(status, 3);
9792     *status = F->schur_status;
9793   }
9794   PetscFunctionReturn(PETSC_SUCCESS);
9795 }
9796 
9797 static PetscErrorCode MatFactorUpdateSchurStatus_Private(Mat F)
9798 {
9799   Mat S = F->schur;
9800 
9801   PetscFunctionBegin;
9802   switch (F->schur_status) {
9803   case MAT_FACTOR_SCHUR_UNFACTORED: // fall-through
9804   case MAT_FACTOR_SCHUR_INVERTED:
9805     if (S) {
9806       S->ops->solve             = NULL;
9807       S->ops->matsolve          = NULL;
9808       S->ops->solvetranspose    = NULL;
9809       S->ops->matsolvetranspose = NULL;
9810       S->ops->solveadd          = NULL;
9811       S->ops->solvetransposeadd = NULL;
9812       S->factortype             = MAT_FACTOR_NONE;
9813       PetscCall(PetscFree(S->solvertype));
9814     }
9815   case MAT_FACTOR_SCHUR_FACTORED: // fall-through
9816     break;
9817   default:
9818     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9819   }
9820   PetscFunctionReturn(PETSC_SUCCESS);
9821 }
9822 
9823 /*@
9824   MatFactorRestoreSchurComplement - Restore the Schur complement matrix object obtained from a call to `MatFactorGetSchurComplement()`
9825 
9826   Logically Collective
9827 
9828   Input Parameters:
9829 + F      - the factored matrix obtained by calling `MatGetFactor()`
9830 . S      - location where the Schur complement is stored
9831 - status - the status of the Schur complement matrix (see `MatFactorSchurStatus`)
9832 
9833   Level: advanced
9834 
9835 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9836 @*/
9837 PetscErrorCode MatFactorRestoreSchurComplement(Mat F, Mat *S, MatFactorSchurStatus status)
9838 {
9839   PetscFunctionBegin;
9840   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9841   if (S) {
9842     PetscValidHeaderSpecific(*S, MAT_CLASSID, 2);
9843     *S = NULL;
9844   }
9845   F->schur_status = status;
9846   PetscCall(MatFactorUpdateSchurStatus_Private(F));
9847   PetscFunctionReturn(PETSC_SUCCESS);
9848 }
9849 
9850 /*@
9851   MatFactorSolveSchurComplementTranspose - Solve the transpose of the Schur complement system computed during the factorization step
9852 
9853   Logically Collective
9854 
9855   Input Parameters:
9856 + F   - the factored matrix obtained by calling `MatGetFactor()`
9857 . rhs - location where the right-hand side of the Schur complement system is stored
9858 - sol - location where the solution of the Schur complement system has to be returned
9859 
9860   Level: advanced
9861 
9862   Notes:
9863   The sizes of the vectors should match the size of the Schur complement
9864 
9865   Must be called after `MatFactorSetSchurIS()`
9866 
9867 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplement()`
9868 @*/
9869 PetscErrorCode MatFactorSolveSchurComplementTranspose(Mat F, Vec rhs, Vec sol)
9870 {
9871   PetscFunctionBegin;
9872   PetscValidType(F, 1);
9873   PetscValidType(rhs, 2);
9874   PetscValidType(sol, 3);
9875   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9876   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
9877   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
9878   PetscCheckSameComm(F, 1, rhs, 2);
9879   PetscCheckSameComm(F, 1, sol, 3);
9880   PetscCall(MatFactorFactorizeSchurComplement(F));
9881   switch (F->schur_status) {
9882   case MAT_FACTOR_SCHUR_FACTORED:
9883     PetscCall(MatSolveTranspose(F->schur, rhs, sol));
9884     break;
9885   case MAT_FACTOR_SCHUR_INVERTED:
9886     PetscCall(MatMultTranspose(F->schur, rhs, sol));
9887     break;
9888   default:
9889     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9890   }
9891   PetscFunctionReturn(PETSC_SUCCESS);
9892 }
9893 
9894 /*@
9895   MatFactorSolveSchurComplement - Solve the Schur complement system computed during the factorization step
9896 
9897   Logically Collective
9898 
9899   Input Parameters:
9900 + F   - the factored matrix obtained by calling `MatGetFactor()`
9901 . rhs - location where the right-hand side of the Schur complement system is stored
9902 - sol - location where the solution of the Schur complement system has to be returned
9903 
9904   Level: advanced
9905 
9906   Notes:
9907   The sizes of the vectors should match the size of the Schur complement
9908 
9909   Must be called after `MatFactorSetSchurIS()`
9910 
9911 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplementTranspose()`
9912 @*/
9913 PetscErrorCode MatFactorSolveSchurComplement(Mat F, Vec rhs, Vec sol)
9914 {
9915   PetscFunctionBegin;
9916   PetscValidType(F, 1);
9917   PetscValidType(rhs, 2);
9918   PetscValidType(sol, 3);
9919   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9920   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
9921   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
9922   PetscCheckSameComm(F, 1, rhs, 2);
9923   PetscCheckSameComm(F, 1, sol, 3);
9924   PetscCall(MatFactorFactorizeSchurComplement(F));
9925   switch (F->schur_status) {
9926   case MAT_FACTOR_SCHUR_FACTORED:
9927     PetscCall(MatSolve(F->schur, rhs, sol));
9928     break;
9929   case MAT_FACTOR_SCHUR_INVERTED:
9930     PetscCall(MatMult(F->schur, rhs, sol));
9931     break;
9932   default:
9933     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9934   }
9935   PetscFunctionReturn(PETSC_SUCCESS);
9936 }
9937 
9938 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode MatSeqDenseInvertFactors_Private(Mat);
9939 #if PetscDefined(HAVE_CUDA)
9940 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode MatSeqDenseCUDAInvertFactors_Internal(Mat);
9941 #endif
9942 
9943 /* Schur status updated in the interface */
9944 static PetscErrorCode MatFactorInvertSchurComplement_Private(Mat F)
9945 {
9946   Mat S = F->schur;
9947 
9948   PetscFunctionBegin;
9949   if (S) {
9950     PetscMPIInt size;
9951     PetscBool   isdense, isdensecuda;
9952 
9953     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)S), &size));
9954     PetscCheck(size <= 1, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not yet implemented");
9955     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSE, &isdense));
9956     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSECUDA, &isdensecuda));
9957     PetscCheck(isdense || isdensecuda, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not implemented for type %s", ((PetscObject)S)->type_name);
9958     PetscCall(PetscLogEventBegin(MAT_FactorInvS, F, 0, 0, 0));
9959     if (isdense) {
9960       PetscCall(MatSeqDenseInvertFactors_Private(S));
9961     } else if (isdensecuda) {
9962 #if defined(PETSC_HAVE_CUDA)
9963       PetscCall(MatSeqDenseCUDAInvertFactors_Internal(S));
9964 #endif
9965     }
9966     // HIP??????????????
9967     PetscCall(PetscLogEventEnd(MAT_FactorInvS, F, 0, 0, 0));
9968   }
9969   PetscFunctionReturn(PETSC_SUCCESS);
9970 }
9971 
9972 /*@
9973   MatFactorInvertSchurComplement - Invert the Schur complement matrix computed during the factorization step
9974 
9975   Logically Collective
9976 
9977   Input Parameter:
9978 . F - the factored matrix obtained by calling `MatGetFactor()`
9979 
9980   Level: advanced
9981 
9982   Notes:
9983   Must be called after `MatFactorSetSchurIS()`.
9984 
9985   Call `MatFactorGetSchurComplement()` or  `MatFactorCreateSchurComplement()` AFTER this call to actually compute the inverse and get access to it.
9986 
9987 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorCreateSchurComplement()`
9988 @*/
9989 PetscErrorCode MatFactorInvertSchurComplement(Mat F)
9990 {
9991   PetscFunctionBegin;
9992   PetscValidType(F, 1);
9993   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9994   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED) PetscFunctionReturn(PETSC_SUCCESS);
9995   PetscCall(MatFactorFactorizeSchurComplement(F));
9996   PetscCall(MatFactorInvertSchurComplement_Private(F));
9997   F->schur_status = MAT_FACTOR_SCHUR_INVERTED;
9998   PetscFunctionReturn(PETSC_SUCCESS);
9999 }
10000 
10001 /*@
10002   MatFactorFactorizeSchurComplement - Factorize the Schur complement matrix computed during the factorization step
10003 
10004   Logically Collective
10005 
10006   Input Parameter:
10007 . F - the factored matrix obtained by calling `MatGetFactor()`
10008 
10009   Level: advanced
10010 
10011   Note:
10012   Must be called after `MatFactorSetSchurIS()`
10013 
10014 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorInvertSchurComplement()`
10015 @*/
10016 PetscErrorCode MatFactorFactorizeSchurComplement(Mat F)
10017 {
10018   MatFactorInfo info;
10019 
10020   PetscFunctionBegin;
10021   PetscValidType(F, 1);
10022   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
10023   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED || F->schur_status == MAT_FACTOR_SCHUR_FACTORED) PetscFunctionReturn(PETSC_SUCCESS);
10024   PetscCall(PetscLogEventBegin(MAT_FactorFactS, F, 0, 0, 0));
10025   PetscCall(PetscMemzero(&info, sizeof(MatFactorInfo)));
10026   if (F->factortype == MAT_FACTOR_CHOLESKY) { /* LDL^t regarded as Cholesky */
10027     PetscCall(MatCholeskyFactor(F->schur, NULL, &info));
10028   } else {
10029     PetscCall(MatLUFactor(F->schur, NULL, NULL, &info));
10030   }
10031   PetscCall(PetscLogEventEnd(MAT_FactorFactS, F, 0, 0, 0));
10032   F->schur_status = MAT_FACTOR_SCHUR_FACTORED;
10033   PetscFunctionReturn(PETSC_SUCCESS);
10034 }
10035 
10036 /*@
10037   MatPtAP - Creates the matrix product $C = P^T * A * P$
10038 
10039   Neighbor-wise Collective
10040 
10041   Input Parameters:
10042 + A     - the matrix
10043 . P     - the projection matrix
10044 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10045 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(P)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10046           if the result is a dense matrix this is irrelevant
10047 
10048   Output Parameter:
10049 . C - the product matrix
10050 
10051   Level: intermediate
10052 
10053   Notes:
10054   C will be created and must be destroyed by the user with `MatDestroy()`.
10055 
10056   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
10057 
10058   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10059 
10060   Developer Note:
10061   For matrix types without special implementation the function fallbacks to `MatMatMult()` followed by `MatTransposeMatMult()`.
10062 
10063 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatRARt()`
10064 @*/
10065 PetscErrorCode MatPtAP(Mat A, Mat P, MatReuse scall, PetscReal fill, Mat *C)
10066 {
10067   PetscFunctionBegin;
10068   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10069   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10070 
10071   if (scall == MAT_INITIAL_MATRIX) {
10072     PetscCall(MatProductCreate(A, P, NULL, C));
10073     PetscCall(MatProductSetType(*C, MATPRODUCT_PtAP));
10074     PetscCall(MatProductSetAlgorithm(*C, "default"));
10075     PetscCall(MatProductSetFill(*C, fill));
10076 
10077     (*C)->product->api_user = PETSC_TRUE;
10078     PetscCall(MatProductSetFromOptions(*C));
10079     PetscCheck((*C)->ops->productsymbolic, PetscObjectComm((PetscObject)*C), PETSC_ERR_SUP, "MatProduct %s not supported for A %s and P %s", MatProductTypes[MATPRODUCT_PtAP], ((PetscObject)A)->type_name, ((PetscObject)P)->type_name);
10080     PetscCall(MatProductSymbolic(*C));
10081   } else { /* scall == MAT_REUSE_MATRIX */
10082     PetscCall(MatProductReplaceMats(A, P, NULL, *C));
10083   }
10084 
10085   PetscCall(MatProductNumeric(*C));
10086   (*C)->symmetric = A->symmetric;
10087   (*C)->spd       = A->spd;
10088   PetscFunctionReturn(PETSC_SUCCESS);
10089 }
10090 
10091 /*@
10092   MatRARt - Creates the matrix product $C = R * A * R^T$
10093 
10094   Neighbor-wise Collective
10095 
10096   Input Parameters:
10097 + A     - the matrix
10098 . R     - the projection matrix
10099 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10100 - fill  - expected fill as ratio of nnz(C)/nnz(A), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10101           if the result is a dense matrix this is irrelevant
10102 
10103   Output Parameter:
10104 . C - the product matrix
10105 
10106   Level: intermediate
10107 
10108   Notes:
10109   `C` will be created and must be destroyed by the user with `MatDestroy()`.
10110 
10111   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
10112 
10113   This routine is currently only implemented for pairs of `MATAIJ` matrices and classes
10114   which inherit from `MATAIJ`. Due to PETSc sparse matrix block row distribution among processes,
10115   the parallel `MatRARt()` is implemented computing the explicit transpose of `R`, which can be very expensive.
10116   We recommend using `MatPtAP()` when possible.
10117 
10118   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10119 
10120 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatPtAP()`
10121 @*/
10122 PetscErrorCode MatRARt(Mat A, Mat R, MatReuse scall, PetscReal fill, Mat *C)
10123 {
10124   PetscFunctionBegin;
10125   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10126   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10127 
10128   if (scall == MAT_INITIAL_MATRIX) {
10129     PetscCall(MatProductCreate(A, R, NULL, C));
10130     PetscCall(MatProductSetType(*C, MATPRODUCT_RARt));
10131     PetscCall(MatProductSetAlgorithm(*C, "default"));
10132     PetscCall(MatProductSetFill(*C, fill));
10133 
10134     (*C)->product->api_user = PETSC_TRUE;
10135     PetscCall(MatProductSetFromOptions(*C));
10136     PetscCheck((*C)->ops->productsymbolic, PetscObjectComm((PetscObject)*C), PETSC_ERR_SUP, "MatProduct %s not supported for A %s and R %s", MatProductTypes[MATPRODUCT_RARt], ((PetscObject)A)->type_name, ((PetscObject)R)->type_name);
10137     PetscCall(MatProductSymbolic(*C));
10138   } else { /* scall == MAT_REUSE_MATRIX */
10139     PetscCall(MatProductReplaceMats(A, R, NULL, *C));
10140   }
10141 
10142   PetscCall(MatProductNumeric(*C));
10143   if (A->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10144   PetscFunctionReturn(PETSC_SUCCESS);
10145 }
10146 
10147 static PetscErrorCode MatProduct_Private(Mat A, Mat B, MatReuse scall, PetscReal fill, MatProductType ptype, Mat *C)
10148 {
10149   PetscBool flg = PETSC_TRUE;
10150 
10151   PetscFunctionBegin;
10152   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX product not supported");
10153   if (scall == MAT_INITIAL_MATRIX) {
10154     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_INITIAL_MATRIX and product type %s\n", MatProductTypes[ptype]));
10155     PetscCall(MatProductCreate(A, B, NULL, C));
10156     PetscCall(MatProductSetAlgorithm(*C, MATPRODUCTALGORITHMDEFAULT));
10157     PetscCall(MatProductSetFill(*C, fill));
10158   } else { /* scall == MAT_REUSE_MATRIX */
10159     Mat_Product *product = (*C)->product;
10160 
10161     PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)*C, &flg, MATSEQDENSE, MATMPIDENSE, ""));
10162     if (flg && product && product->type != ptype) {
10163       PetscCall(MatProductClear(*C));
10164       product = NULL;
10165     }
10166     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_REUSE_MATRIX %s product present and product type %s\n", product ? "with" : "without", MatProductTypes[ptype]));
10167     if (!product) { /* user provide the dense matrix *C without calling MatProductCreate() or reusing it from previous calls */
10168       PetscCheck(flg, PetscObjectComm((PetscObject)*C), PETSC_ERR_SUP, "Call MatProductCreate() first");
10169       PetscCall(MatProductCreate_Private(A, B, NULL, *C));
10170       product        = (*C)->product;
10171       product->fill  = fill;
10172       product->clear = PETSC_TRUE;
10173     } else { /* user may change input matrices A or B when MAT_REUSE_MATRIX */
10174       flg = PETSC_FALSE;
10175       PetscCall(MatProductReplaceMats(A, B, NULL, *C));
10176     }
10177   }
10178   if (flg) {
10179     (*C)->product->api_user = PETSC_TRUE;
10180     PetscCall(MatProductSetType(*C, ptype));
10181     PetscCall(MatProductSetFromOptions(*C));
10182     PetscCall(MatProductSymbolic(*C));
10183   }
10184   PetscCall(MatProductNumeric(*C));
10185   PetscFunctionReturn(PETSC_SUCCESS);
10186 }
10187 
10188 /*@
10189   MatMatMult - Performs matrix-matrix multiplication C=A*B.
10190 
10191   Neighbor-wise Collective
10192 
10193   Input Parameters:
10194 + A     - the left matrix
10195 . B     - the right matrix
10196 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10197 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10198           if the result is a dense matrix this is irrelevant
10199 
10200   Output Parameter:
10201 . C - the product matrix
10202 
10203   Notes:
10204   Unless scall is `MAT_REUSE_MATRIX` C will be created.
10205 
10206   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call and C was obtained from a previous
10207   call to this function with `MAT_INITIAL_MATRIX`.
10208 
10209   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value actually needed.
10210 
10211   In the special case where matrix `B` (and hence `C`) are dense you can create the correctly sized matrix `C` yourself and then call this routine with `MAT_REUSE_MATRIX`,
10212   rather than first having `MatMatMult()` create it for you. You can NEVER do this if the matrix `C` is sparse.
10213 
10214   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10215 
10216   Example of Usage:
10217 .vb
10218      MatProductCreate(A,B,NULL,&C);
10219      MatProductSetType(C,MATPRODUCT_AB);
10220      MatProductSymbolic(C);
10221      MatProductNumeric(C); // compute C=A * B
10222      MatProductReplaceMats(A1,B1,NULL,C); // compute C=A1 * B1
10223      MatProductNumeric(C);
10224      MatProductReplaceMats(A2,NULL,NULL,C); // compute C=A2 * B1
10225      MatProductNumeric(C);
10226 .ve
10227 
10228   Level: intermediate
10229 
10230 .seealso: [](ch_matrices), `Mat`, `MatProductType`, `MATPRODUCT_AB`, `MatTransposeMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`, `MatProductCreate()`, `MatProductSymbolic()`, `MatProductReplaceMats()`, `MatProductNumeric()`
10231 @*/
10232 PetscErrorCode MatMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10233 {
10234   PetscFunctionBegin;
10235   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AB, C));
10236   PetscFunctionReturn(PETSC_SUCCESS);
10237 }
10238 
10239 /*@
10240   MatMatTransposeMult - Performs matrix-matrix multiplication $C = A*B^T$.
10241 
10242   Neighbor-wise Collective
10243 
10244   Input Parameters:
10245 + A     - the left matrix
10246 . B     - the right matrix
10247 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10248 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10249 
10250   Output Parameter:
10251 . C - the product matrix
10252 
10253   Options Database Key:
10254 . -matmattransmult_mpidense_mpidense_via {allgatherv,cyclic} - Choose between algorithms for `MATMPIDENSE` matrices: the
10255               first redundantly copies the transposed `B` matrix on each process and requires O(log P) communication complexity;
10256               the second never stores more than one portion of the `B` matrix at a time but requires O(P) communication complexity.
10257 
10258   Level: intermediate
10259 
10260   Notes:
10261   C will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10262 
10263   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call
10264 
10265   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10266   actually needed.
10267 
10268   This routine is currently only implemented for pairs of `MATSEQAIJ` matrices, for the `MATSEQDENSE` class,
10269   and for pairs of `MATMPIDENSE` matrices.
10270 
10271   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABt`
10272 
10273   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10274 
10275 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABt`, `MatMatMult()`, `MatTransposeMatMult()` `MatPtAP()`, `MatProductAlgorithm`, `MatProductType`
10276 @*/
10277 PetscErrorCode MatMatTransposeMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10278 {
10279   PetscFunctionBegin;
10280   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_ABt, C));
10281   if (A == B) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10282   PetscFunctionReturn(PETSC_SUCCESS);
10283 }
10284 
10285 /*@
10286   MatTransposeMatMult - Performs matrix-matrix multiplication $C = A^T*B$.
10287 
10288   Neighbor-wise Collective
10289 
10290   Input Parameters:
10291 + A     - the left matrix
10292 . B     - the right matrix
10293 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10294 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10295 
10296   Output Parameter:
10297 . C - the product matrix
10298 
10299   Level: intermediate
10300 
10301   Notes:
10302   `C` will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10303 
10304   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call.
10305 
10306   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_AtB`
10307 
10308   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10309   actually needed.
10310 
10311   This routine is currently implemented for pairs of `MATAIJ` matrices and pairs of `MATSEQDENSE` matrices and classes
10312   which inherit from `MATSEQAIJ`.  `C` will be of the same type as the input matrices.
10313 
10314   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10315 
10316 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_AtB`, `MatMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`
10317 @*/
10318 PetscErrorCode MatTransposeMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10319 {
10320   PetscFunctionBegin;
10321   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AtB, C));
10322   PetscFunctionReturn(PETSC_SUCCESS);
10323 }
10324 
10325 /*@
10326   MatMatMatMult - Performs matrix-matrix-matrix multiplication D=A*B*C.
10327 
10328   Neighbor-wise Collective
10329 
10330   Input Parameters:
10331 + A     - the left matrix
10332 . B     - the middle matrix
10333 . C     - the right matrix
10334 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10335 - fill  - expected fill as ratio of nnz(D)/(nnz(A) + nnz(B)+nnz(C)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10336           if the result is a dense matrix this is irrelevant
10337 
10338   Output Parameter:
10339 . D - the product matrix
10340 
10341   Level: intermediate
10342 
10343   Notes:
10344   Unless `scall` is `MAT_REUSE_MATRIX` `D` will be created.
10345 
10346   `MAT_REUSE_MATRIX` can only be used if the matrices `A`, `B`, and `C` have the same nonzero pattern as in the previous call
10347 
10348   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABC`
10349 
10350   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value
10351   actually needed.
10352 
10353   If you have many matrices with the same non-zero structure to multiply, you
10354   should use `MAT_REUSE_MATRIX` in all calls but the first
10355 
10356   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10357 
10358 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABC`, `MatMatMult`, `MatPtAP()`, `MatMatTransposeMult()`, `MatTransposeMatMult()`
10359 @*/
10360 PetscErrorCode MatMatMatMult(Mat A, Mat B, Mat C, MatReuse scall, PetscReal fill, Mat *D)
10361 {
10362   PetscFunctionBegin;
10363   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*D, 6);
10364   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10365 
10366   if (scall == MAT_INITIAL_MATRIX) {
10367     PetscCall(MatProductCreate(A, B, C, D));
10368     PetscCall(MatProductSetType(*D, MATPRODUCT_ABC));
10369     PetscCall(MatProductSetAlgorithm(*D, "default"));
10370     PetscCall(MatProductSetFill(*D, fill));
10371 
10372     (*D)->product->api_user = PETSC_TRUE;
10373     PetscCall(MatProductSetFromOptions(*D));
10374     PetscCheck((*D)->ops->productsymbolic, PetscObjectComm((PetscObject)*D), PETSC_ERR_SUP, "MatProduct %s not supported for A %s, B %s and C %s", MatProductTypes[MATPRODUCT_ABC], ((PetscObject)A)->type_name, ((PetscObject)B)->type_name,
10375                ((PetscObject)C)->type_name);
10376     PetscCall(MatProductSymbolic(*D));
10377   } else { /* user may change input matrices when REUSE */
10378     PetscCall(MatProductReplaceMats(A, B, C, *D));
10379   }
10380   PetscCall(MatProductNumeric(*D));
10381   PetscFunctionReturn(PETSC_SUCCESS);
10382 }
10383 
10384 /*@
10385   MatCreateRedundantMatrix - Create redundant matrices and put them into processors of subcommunicators.
10386 
10387   Collective
10388 
10389   Input Parameters:
10390 + mat      - the matrix
10391 . nsubcomm - the number of subcommunicators (= number of redundant parallel or sequential matrices)
10392 . subcomm  - MPI communicator split from the communicator where mat resides in (or `MPI_COMM_NULL` if nsubcomm is used)
10393 - reuse    - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10394 
10395   Output Parameter:
10396 . matredundant - redundant matrix
10397 
10398   Level: advanced
10399 
10400   Notes:
10401   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
10402   original matrix has not changed from that last call to `MatCreateRedundantMatrix()`.
10403 
10404   This routine creates the duplicated matrices in the subcommunicators; you should NOT create them before
10405   calling it.
10406 
10407   `PetscSubcommCreate()` can be used to manage the creation of the subcomm but need not be.
10408 
10409 .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `PetscSubcommCreate()`, `PetscSubcomm`
10410 @*/
10411 PetscErrorCode MatCreateRedundantMatrix(Mat mat, PetscInt nsubcomm, MPI_Comm subcomm, MatReuse reuse, Mat *matredundant)
10412 {
10413   MPI_Comm       comm;
10414   PetscMPIInt    size;
10415   PetscInt       mloc_sub, nloc_sub, rstart, rend, M = mat->rmap->N, N = mat->cmap->N, bs = mat->rmap->bs;
10416   Mat_Redundant *redund     = NULL;
10417   PetscSubcomm   psubcomm   = NULL;
10418   MPI_Comm       subcomm_in = subcomm;
10419   Mat           *matseq;
10420   IS             isrow, iscol;
10421   PetscBool      newsubcomm = PETSC_FALSE;
10422 
10423   PetscFunctionBegin;
10424   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10425   if (nsubcomm && reuse == MAT_REUSE_MATRIX) {
10426     PetscAssertPointer(*matredundant, 5);
10427     PetscValidHeaderSpecific(*matredundant, MAT_CLASSID, 5);
10428   }
10429 
10430   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
10431   if (size == 1 || nsubcomm == 1) {
10432     if (reuse == MAT_INITIAL_MATRIX) {
10433       PetscCall(MatDuplicate(mat, MAT_COPY_VALUES, matredundant));
10434     } else {
10435       PetscCheck(*matredundant != mat, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MAT_REUSE_MATRIX means reuse the matrix passed in as the final argument, not the original matrix");
10436       PetscCall(MatCopy(mat, *matredundant, SAME_NONZERO_PATTERN));
10437     }
10438     PetscFunctionReturn(PETSC_SUCCESS);
10439   }
10440 
10441   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10442   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10443   MatCheckPreallocated(mat, 1);
10444 
10445   PetscCall(PetscLogEventBegin(MAT_RedundantMat, mat, 0, 0, 0));
10446   if (subcomm_in == MPI_COMM_NULL && reuse == MAT_INITIAL_MATRIX) { /* get subcomm if user does not provide subcomm */
10447     /* create psubcomm, then get subcomm */
10448     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10449     PetscCallMPI(MPI_Comm_size(comm, &size));
10450     PetscCheck(nsubcomm >= 1 && nsubcomm <= size, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "nsubcomm must between 1 and %d", size);
10451 
10452     PetscCall(PetscSubcommCreate(comm, &psubcomm));
10453     PetscCall(PetscSubcommSetNumber(psubcomm, nsubcomm));
10454     PetscCall(PetscSubcommSetType(psubcomm, PETSC_SUBCOMM_CONTIGUOUS));
10455     PetscCall(PetscSubcommSetFromOptions(psubcomm));
10456     PetscCall(PetscCommDuplicate(PetscSubcommChild(psubcomm), &subcomm, NULL));
10457     newsubcomm = PETSC_TRUE;
10458     PetscCall(PetscSubcommDestroy(&psubcomm));
10459   }
10460 
10461   /* get isrow, iscol and a local sequential matrix matseq[0] */
10462   if (reuse == MAT_INITIAL_MATRIX) {
10463     mloc_sub = PETSC_DECIDE;
10464     nloc_sub = PETSC_DECIDE;
10465     if (bs < 1) {
10466       PetscCall(PetscSplitOwnership(subcomm, &mloc_sub, &M));
10467       PetscCall(PetscSplitOwnership(subcomm, &nloc_sub, &N));
10468     } else {
10469       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &mloc_sub, &M));
10470       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &nloc_sub, &N));
10471     }
10472     PetscCallMPI(MPI_Scan(&mloc_sub, &rend, 1, MPIU_INT, MPI_SUM, subcomm));
10473     rstart = rend - mloc_sub;
10474     PetscCall(ISCreateStride(PETSC_COMM_SELF, mloc_sub, rstart, 1, &isrow));
10475     PetscCall(ISCreateStride(PETSC_COMM_SELF, N, 0, 1, &iscol));
10476     PetscCall(ISSetIdentity(iscol));
10477   } else { /* reuse == MAT_REUSE_MATRIX */
10478     PetscCheck(*matredundant != mat, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MAT_REUSE_MATRIX means reuse the matrix passed in as the final argument, not the original matrix");
10479     /* retrieve subcomm */
10480     PetscCall(PetscObjectGetComm((PetscObject)*matredundant, &subcomm));
10481     redund = (*matredundant)->redundant;
10482     isrow  = redund->isrow;
10483     iscol  = redund->iscol;
10484     matseq = redund->matseq;
10485   }
10486   PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscol, reuse, &matseq));
10487 
10488   /* get matredundant over subcomm */
10489   if (reuse == MAT_INITIAL_MATRIX) {
10490     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], nloc_sub, reuse, matredundant));
10491 
10492     /* create a supporting struct and attach it to C for reuse */
10493     PetscCall(PetscNew(&redund));
10494     (*matredundant)->redundant = redund;
10495     redund->isrow              = isrow;
10496     redund->iscol              = iscol;
10497     redund->matseq             = matseq;
10498     if (newsubcomm) {
10499       redund->subcomm = subcomm;
10500     } else {
10501       redund->subcomm = MPI_COMM_NULL;
10502     }
10503   } else {
10504     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], PETSC_DECIDE, reuse, matredundant));
10505   }
10506 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
10507   if (matseq[0]->boundtocpu && matseq[0]->bindingpropagates) {
10508     PetscCall(MatBindToCPU(*matredundant, PETSC_TRUE));
10509     PetscCall(MatSetBindingPropagates(*matredundant, PETSC_TRUE));
10510   }
10511 #endif
10512   PetscCall(PetscLogEventEnd(MAT_RedundantMat, mat, 0, 0, 0));
10513   PetscFunctionReturn(PETSC_SUCCESS);
10514 }
10515 
10516 /*@C
10517   MatGetMultiProcBlock - Create multiple 'parallel submatrices' from
10518   a given `Mat`. Each submatrix can span multiple procs.
10519 
10520   Collective
10521 
10522   Input Parameters:
10523 + mat     - the matrix
10524 . subComm - the sub communicator obtained as if by `MPI_Comm_split(PetscObjectComm((PetscObject)mat))`
10525 - scall   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10526 
10527   Output Parameter:
10528 . subMat - parallel sub-matrices each spanning a given `subcomm`
10529 
10530   Level: advanced
10531 
10532   Notes:
10533   The submatrix partition across processors is dictated by `subComm` a
10534   communicator obtained by `MPI_comm_split()` or via `PetscSubcommCreate()`. The `subComm`
10535   is not restricted to be grouped with consecutive original MPI processes.
10536 
10537   Due the `MPI_Comm_split()` usage, the parallel layout of the submatrices
10538   map directly to the layout of the original matrix [wrt the local
10539   row,col partitioning]. So the original 'DiagonalMat' naturally maps
10540   into the 'DiagonalMat' of the `subMat`, hence it is used directly from
10541   the `subMat`. However the offDiagMat looses some columns - and this is
10542   reconstructed with `MatSetValues()`
10543 
10544   This is used by `PCBJACOBI` when a single block spans multiple MPI processes.
10545 
10546 .seealso: [](ch_matrices), `Mat`, `MatCreateRedundantMatrix()`, `MatCreateSubMatrices()`, `PCBJACOBI`
10547 @*/
10548 PetscErrorCode MatGetMultiProcBlock(Mat mat, MPI_Comm subComm, MatReuse scall, Mat *subMat)
10549 {
10550   PetscMPIInt commsize, subCommSize;
10551 
10552   PetscFunctionBegin;
10553   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &commsize));
10554   PetscCallMPI(MPI_Comm_size(subComm, &subCommSize));
10555   PetscCheck(subCommSize <= commsize, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "CommSize %d < SubCommZize %d", commsize, subCommSize);
10556 
10557   PetscCheck(scall != MAT_REUSE_MATRIX || *subMat != mat, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MAT_REUSE_MATRIX means reuse the matrix passed in as the final argument, not the original matrix");
10558   PetscCall(PetscLogEventBegin(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10559   PetscUseTypeMethod(mat, getmultiprocblock, subComm, scall, subMat);
10560   PetscCall(PetscLogEventEnd(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10561   PetscFunctionReturn(PETSC_SUCCESS);
10562 }
10563 
10564 /*@
10565   MatGetLocalSubMatrix - Gets a reference to a submatrix specified in local numbering
10566 
10567   Not Collective
10568 
10569   Input Parameters:
10570 + mat   - matrix to extract local submatrix from
10571 . isrow - local row indices for submatrix
10572 - iscol - local column indices for submatrix
10573 
10574   Output Parameter:
10575 . submat - the submatrix
10576 
10577   Level: intermediate
10578 
10579   Notes:
10580   `submat` should be disposed of with `MatRestoreLocalSubMatrix()`.
10581 
10582   Depending on the format of `mat`, the returned `submat` may not implement `MatMult()`.  Its communicator may be
10583   the same as `mat`, it may be `PETSC_COMM_SELF`, or some other sub-communictor of `mat`'s.
10584 
10585   `submat` always implements `MatSetValuesLocal()`.  If `isrow` and `iscol` have the same block size, then
10586   `MatSetValuesBlockedLocal()` will also be implemented.
10587 
10588   `mat` must have had a `ISLocalToGlobalMapping` provided to it with `MatSetLocalToGlobalMapping()`.
10589   Matrices obtained with `DMCreateMatrix()` generally already have the local to global mapping provided.
10590 
10591 .seealso: [](ch_matrices), `Mat`, `MatRestoreLocalSubMatrix()`, `MatCreateLocalRef()`, `MatSetLocalToGlobalMapping()`
10592 @*/
10593 PetscErrorCode MatGetLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10594 {
10595   PetscFunctionBegin;
10596   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10597   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10598   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10599   PetscCheckSameComm(isrow, 2, iscol, 3);
10600   PetscAssertPointer(submat, 4);
10601   PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must have local to global mapping provided before this call");
10602 
10603   if (mat->ops->getlocalsubmatrix) {
10604     PetscUseTypeMethod(mat, getlocalsubmatrix, isrow, iscol, submat);
10605   } else {
10606     PetscCall(MatCreateLocalRef(mat, isrow, iscol, submat));
10607   }
10608   PetscFunctionReturn(PETSC_SUCCESS);
10609 }
10610 
10611 /*@
10612   MatRestoreLocalSubMatrix - Restores a reference to a submatrix specified in local numbering obtained with `MatGetLocalSubMatrix()`
10613 
10614   Not Collective
10615 
10616   Input Parameters:
10617 + mat    - matrix to extract local submatrix from
10618 . isrow  - local row indices for submatrix
10619 . iscol  - local column indices for submatrix
10620 - submat - the submatrix
10621 
10622   Level: intermediate
10623 
10624 .seealso: [](ch_matrices), `Mat`, `MatGetLocalSubMatrix()`
10625 @*/
10626 PetscErrorCode MatRestoreLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10627 {
10628   PetscFunctionBegin;
10629   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10630   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10631   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10632   PetscCheckSameComm(isrow, 2, iscol, 3);
10633   PetscAssertPointer(submat, 4);
10634   if (*submat) PetscValidHeaderSpecific(*submat, MAT_CLASSID, 4);
10635 
10636   if (mat->ops->restorelocalsubmatrix) {
10637     PetscUseTypeMethod(mat, restorelocalsubmatrix, isrow, iscol, submat);
10638   } else {
10639     PetscCall(MatDestroy(submat));
10640   }
10641   *submat = NULL;
10642   PetscFunctionReturn(PETSC_SUCCESS);
10643 }
10644 
10645 /*@
10646   MatFindZeroDiagonals - Finds all the rows of a matrix that have zero or no diagonal entry in the matrix
10647 
10648   Collective
10649 
10650   Input Parameter:
10651 . mat - the matrix
10652 
10653   Output Parameter:
10654 . is - if any rows have zero diagonals this contains the list of them
10655 
10656   Level: developer
10657 
10658 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10659 @*/
10660 PetscErrorCode MatFindZeroDiagonals(Mat mat, IS *is)
10661 {
10662   PetscFunctionBegin;
10663   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10664   PetscValidType(mat, 1);
10665   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10666   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10667 
10668   if (!mat->ops->findzerodiagonals) {
10669     Vec                diag;
10670     const PetscScalar *a;
10671     PetscInt          *rows;
10672     PetscInt           rStart, rEnd, r, nrow = 0;
10673 
10674     PetscCall(MatCreateVecs(mat, &diag, NULL));
10675     PetscCall(MatGetDiagonal(mat, diag));
10676     PetscCall(MatGetOwnershipRange(mat, &rStart, &rEnd));
10677     PetscCall(VecGetArrayRead(diag, &a));
10678     for (r = 0; r < rEnd - rStart; ++r)
10679       if (a[r] == 0.0) ++nrow;
10680     PetscCall(PetscMalloc1(nrow, &rows));
10681     nrow = 0;
10682     for (r = 0; r < rEnd - rStart; ++r)
10683       if (a[r] == 0.0) rows[nrow++] = r + rStart;
10684     PetscCall(VecRestoreArrayRead(diag, &a));
10685     PetscCall(VecDestroy(&diag));
10686     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nrow, rows, PETSC_OWN_POINTER, is));
10687   } else {
10688     PetscUseTypeMethod(mat, findzerodiagonals, is);
10689   }
10690   PetscFunctionReturn(PETSC_SUCCESS);
10691 }
10692 
10693 /*@
10694   MatFindOffBlockDiagonalEntries - Finds all the rows of a matrix that have entries outside of the main diagonal block (defined by the matrix block size)
10695 
10696   Collective
10697 
10698   Input Parameter:
10699 . mat - the matrix
10700 
10701   Output Parameter:
10702 . is - contains the list of rows with off block diagonal entries
10703 
10704   Level: developer
10705 
10706 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10707 @*/
10708 PetscErrorCode MatFindOffBlockDiagonalEntries(Mat mat, IS *is)
10709 {
10710   PetscFunctionBegin;
10711   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10712   PetscValidType(mat, 1);
10713   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10714   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10715 
10716   PetscUseTypeMethod(mat, findoffblockdiagonalentries, is);
10717   PetscFunctionReturn(PETSC_SUCCESS);
10718 }
10719 
10720 /*@C
10721   MatInvertBlockDiagonal - Inverts the block diagonal entries.
10722 
10723   Collective; No Fortran Support
10724 
10725   Input Parameter:
10726 . mat - the matrix
10727 
10728   Output Parameter:
10729 . values - the block inverses in column major order (FORTRAN-like)
10730 
10731   Level: advanced
10732 
10733   Notes:
10734   The size of the blocks is determined by the block size of the matrix.
10735 
10736   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10737 
10738   The blocks all have the same size, use `MatInvertVariableBlockDiagonal()` for variable block size
10739 
10740 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatInvertBlockDiagonalMat()`
10741 @*/
10742 PetscErrorCode MatInvertBlockDiagonal(Mat mat, const PetscScalar *values[])
10743 {
10744   PetscFunctionBegin;
10745   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10746   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10747   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10748   PetscUseTypeMethod(mat, invertblockdiagonal, values);
10749   PetscFunctionReturn(PETSC_SUCCESS);
10750 }
10751 
10752 /*@
10753   MatInvertVariableBlockDiagonal - Inverts the point block diagonal entries.
10754 
10755   Collective; No Fortran Support
10756 
10757   Input Parameters:
10758 + mat     - the matrix
10759 . nblocks - the number of blocks on the process, set with `MatSetVariableBlockSizes()`
10760 - bsizes  - the size of each block on the process, set with `MatSetVariableBlockSizes()`
10761 
10762   Output Parameter:
10763 . values - the block inverses in column major order (FORTRAN-like)
10764 
10765   Level: advanced
10766 
10767   Notes:
10768   Use `MatInvertBlockDiagonal()` if all blocks have the same size
10769 
10770   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10771 
10772 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatSetVariableBlockSizes()`, `MatInvertVariableBlockEnvelope()`
10773 @*/
10774 PetscErrorCode MatInvertVariableBlockDiagonal(Mat mat, PetscInt nblocks, const PetscInt bsizes[], PetscScalar values[])
10775 {
10776   PetscFunctionBegin;
10777   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10778   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10779   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10780   PetscUseTypeMethod(mat, invertvariableblockdiagonal, nblocks, bsizes, values);
10781   PetscFunctionReturn(PETSC_SUCCESS);
10782 }
10783 
10784 /*@
10785   MatInvertBlockDiagonalMat - set the values of matrix C to be the inverted block diagonal of matrix A
10786 
10787   Collective
10788 
10789   Input Parameters:
10790 + A - the matrix
10791 - C - matrix with inverted block diagonal of `A`.  This matrix should be created and may have its type set.
10792 
10793   Level: advanced
10794 
10795   Note:
10796   The blocksize of the matrix is used to determine the blocks on the diagonal of `C`
10797 
10798 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`
10799 @*/
10800 PetscErrorCode MatInvertBlockDiagonalMat(Mat A, Mat C)
10801 {
10802   const PetscScalar *vals;
10803   PetscInt          *dnnz;
10804   PetscInt           m, rstart, rend, bs, i, j;
10805 
10806   PetscFunctionBegin;
10807   PetscCall(MatInvertBlockDiagonal(A, &vals));
10808   PetscCall(MatGetBlockSize(A, &bs));
10809   PetscCall(MatGetLocalSize(A, &m, NULL));
10810   PetscCall(MatSetLayouts(C, A->rmap, A->cmap));
10811   PetscCall(MatSetBlockSizes(C, A->rmap->bs, A->cmap->bs));
10812   PetscCall(PetscMalloc1(m / bs, &dnnz));
10813   for (j = 0; j < m / bs; j++) dnnz[j] = 1;
10814   PetscCall(MatXAIJSetPreallocation(C, bs, dnnz, NULL, NULL, NULL));
10815   PetscCall(PetscFree(dnnz));
10816   PetscCall(MatGetOwnershipRange(C, &rstart, &rend));
10817   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_FALSE));
10818   for (i = rstart / bs; i < rend / bs; i++) PetscCall(MatSetValuesBlocked(C, 1, &i, 1, &i, &vals[(i - rstart / bs) * bs * bs], INSERT_VALUES));
10819   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
10820   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
10821   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_TRUE));
10822   PetscFunctionReturn(PETSC_SUCCESS);
10823 }
10824 
10825 /*@
10826   MatTransposeColoringDestroy - Destroys a coloring context for matrix product $C = A*B^T$ that was created
10827   via `MatTransposeColoringCreate()`.
10828 
10829   Collective
10830 
10831   Input Parameter:
10832 . c - coloring context
10833 
10834   Level: intermediate
10835 
10836 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`
10837 @*/
10838 PetscErrorCode MatTransposeColoringDestroy(MatTransposeColoring *c)
10839 {
10840   MatTransposeColoring matcolor = *c;
10841 
10842   PetscFunctionBegin;
10843   if (!matcolor) PetscFunctionReturn(PETSC_SUCCESS);
10844   if (--((PetscObject)matcolor)->refct > 0) {
10845     matcolor = NULL;
10846     PetscFunctionReturn(PETSC_SUCCESS);
10847   }
10848 
10849   PetscCall(PetscFree3(matcolor->ncolumns, matcolor->nrows, matcolor->colorforrow));
10850   PetscCall(PetscFree(matcolor->rows));
10851   PetscCall(PetscFree(matcolor->den2sp));
10852   PetscCall(PetscFree(matcolor->colorforcol));
10853   PetscCall(PetscFree(matcolor->columns));
10854   if (matcolor->brows > 0) PetscCall(PetscFree(matcolor->lstart));
10855   PetscCall(PetscHeaderDestroy(c));
10856   PetscFunctionReturn(PETSC_SUCCESS);
10857 }
10858 
10859 /*@
10860   MatTransColoringApplySpToDen - Given a symbolic matrix product $C = A*B^T$ for which
10861   a `MatTransposeColoring` context has been created, computes a dense $B^T$ by applying
10862   `MatTransposeColoring` to sparse `B`.
10863 
10864   Collective
10865 
10866   Input Parameters:
10867 + coloring - coloring context created with `MatTransposeColoringCreate()`
10868 - B        - sparse matrix
10869 
10870   Output Parameter:
10871 . Btdense - dense matrix $B^T$
10872 
10873   Level: developer
10874 
10875   Note:
10876   These are used internally for some implementations of `MatRARt()`
10877 
10878 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplyDenToSp()`
10879 @*/
10880 PetscErrorCode MatTransColoringApplySpToDen(MatTransposeColoring coloring, Mat B, Mat Btdense)
10881 {
10882   PetscFunctionBegin;
10883   PetscValidHeaderSpecific(coloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
10884   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
10885   PetscValidHeaderSpecific(Btdense, MAT_CLASSID, 3);
10886 
10887   PetscCall((*B->ops->transcoloringapplysptoden)(coloring, B, Btdense));
10888   PetscFunctionReturn(PETSC_SUCCESS);
10889 }
10890 
10891 /*@
10892   MatTransColoringApplyDenToSp - Given a symbolic matrix product $C_{sp} = A*B^T$ for which
10893   a `MatTransposeColoring` context has been created and a dense matrix $C_{den} = A*B^T_{dense}$
10894   in which `B^T_{dens}` is obtained from `MatTransColoringApplySpToDen()`, recover sparse matrix
10895   $C_{sp}$ from $C_{den}$.
10896 
10897   Collective
10898 
10899   Input Parameters:
10900 + matcoloring - coloring context created with `MatTransposeColoringCreate()`
10901 - Cden        - matrix product of a sparse matrix and a dense matrix Btdense
10902 
10903   Output Parameter:
10904 . Csp - sparse matrix
10905 
10906   Level: developer
10907 
10908   Note:
10909   These are used internally for some implementations of `MatRARt()`
10910 
10911 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`
10912 @*/
10913 PetscErrorCode MatTransColoringApplyDenToSp(MatTransposeColoring matcoloring, Mat Cden, Mat Csp)
10914 {
10915   PetscFunctionBegin;
10916   PetscValidHeaderSpecific(matcoloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
10917   PetscValidHeaderSpecific(Cden, MAT_CLASSID, 2);
10918   PetscValidHeaderSpecific(Csp, MAT_CLASSID, 3);
10919 
10920   PetscCall((*Csp->ops->transcoloringapplydentosp)(matcoloring, Cden, Csp));
10921   PetscCall(MatAssemblyBegin(Csp, MAT_FINAL_ASSEMBLY));
10922   PetscCall(MatAssemblyEnd(Csp, MAT_FINAL_ASSEMBLY));
10923   PetscFunctionReturn(PETSC_SUCCESS);
10924 }
10925 
10926 /*@
10927   MatTransposeColoringCreate - Creates a matrix coloring context for the matrix product $C = A*B^T$.
10928 
10929   Collective
10930 
10931   Input Parameters:
10932 + mat        - the matrix product C
10933 - iscoloring - the coloring of the matrix; usually obtained with `MatColoringCreate()` or `DMCreateColoring()`
10934 
10935   Output Parameter:
10936 . color - the new coloring context
10937 
10938   Level: intermediate
10939 
10940 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`,
10941           `MatTransColoringApplyDenToSp()`
10942 @*/
10943 PetscErrorCode MatTransposeColoringCreate(Mat mat, ISColoring iscoloring, MatTransposeColoring *color)
10944 {
10945   MatTransposeColoring c;
10946   MPI_Comm             comm;
10947 
10948   PetscFunctionBegin;
10949   PetscAssertPointer(color, 3);
10950 
10951   PetscCall(PetscLogEventBegin(MAT_TransposeColoringCreate, mat, 0, 0, 0));
10952   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10953   PetscCall(PetscHeaderCreate(c, MAT_TRANSPOSECOLORING_CLASSID, "MatTransposeColoring", "Matrix product C=A*B^T via coloring", "Mat", comm, MatTransposeColoringDestroy, NULL));
10954   c->ctype = iscoloring->ctype;
10955   PetscUseTypeMethod(mat, transposecoloringcreate, iscoloring, c);
10956   *color = c;
10957   PetscCall(PetscLogEventEnd(MAT_TransposeColoringCreate, mat, 0, 0, 0));
10958   PetscFunctionReturn(PETSC_SUCCESS);
10959 }
10960 
10961 /*@
10962   MatGetNonzeroState - Returns a 64-bit integer representing the current state of nonzeros in the matrix. If the
10963   matrix has had new nonzero locations added to (or removed from) the matrix since the previous call, the value will be larger.
10964 
10965   Not Collective
10966 
10967   Input Parameter:
10968 . mat - the matrix
10969 
10970   Output Parameter:
10971 . state - the current state
10972 
10973   Level: intermediate
10974 
10975   Notes:
10976   You can only compare states from two different calls to the SAME matrix, you cannot compare calls between
10977   different matrices
10978 
10979   Use `PetscObjectStateGet()` to check for changes to the numerical values in a matrix
10980 
10981   Use the result of `PetscObjectGetId()` to compare if a previously checked matrix is the same as the current matrix, do not compare object pointers.
10982 
10983 .seealso: [](ch_matrices), `Mat`, `PetscObjectStateGet()`, `PetscObjectGetId()`
10984 @*/
10985 PetscErrorCode MatGetNonzeroState(Mat mat, PetscObjectState *state)
10986 {
10987   PetscFunctionBegin;
10988   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10989   *state = mat->nonzerostate;
10990   PetscFunctionReturn(PETSC_SUCCESS);
10991 }
10992 
10993 /*@
10994   MatCreateMPIMatConcatenateSeqMat - Creates a single large PETSc matrix by concatenating sequential
10995   matrices from each processor
10996 
10997   Collective
10998 
10999   Input Parameters:
11000 + comm   - the communicators the parallel matrix will live on
11001 . seqmat - the input sequential matrices
11002 . n      - number of local columns (or `PETSC_DECIDE`)
11003 - reuse  - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
11004 
11005   Output Parameter:
11006 . mpimat - the parallel matrix generated
11007 
11008   Level: developer
11009 
11010   Note:
11011   The number of columns of the matrix in EACH processor MUST be the same.
11012 
11013 .seealso: [](ch_matrices), `Mat`
11014 @*/
11015 PetscErrorCode MatCreateMPIMatConcatenateSeqMat(MPI_Comm comm, Mat seqmat, PetscInt n, MatReuse reuse, Mat *mpimat)
11016 {
11017   PetscMPIInt size;
11018 
11019   PetscFunctionBegin;
11020   PetscCallMPI(MPI_Comm_size(comm, &size));
11021   if (size == 1) {
11022     if (reuse == MAT_INITIAL_MATRIX) {
11023       PetscCall(MatDuplicate(seqmat, MAT_COPY_VALUES, mpimat));
11024     } else {
11025       PetscCall(MatCopy(seqmat, *mpimat, SAME_NONZERO_PATTERN));
11026     }
11027     PetscFunctionReturn(PETSC_SUCCESS);
11028   }
11029 
11030   PetscCheck(reuse != MAT_REUSE_MATRIX || seqmat != *mpimat, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MAT_REUSE_MATRIX means reuse the matrix passed in as the final argument, not the original matrix");
11031 
11032   PetscCall(PetscLogEventBegin(MAT_Merge, seqmat, 0, 0, 0));
11033   PetscCall((*seqmat->ops->creatempimatconcatenateseqmat)(comm, seqmat, n, reuse, mpimat));
11034   PetscCall(PetscLogEventEnd(MAT_Merge, seqmat, 0, 0, 0));
11035   PetscFunctionReturn(PETSC_SUCCESS);
11036 }
11037 
11038 /*@
11039   MatSubdomainsCreateCoalesce - Creates index subdomains by coalescing adjacent MPI processes' ownership ranges.
11040 
11041   Collective
11042 
11043   Input Parameters:
11044 + A - the matrix to create subdomains from
11045 - N - requested number of subdomains
11046 
11047   Output Parameters:
11048 + n   - number of subdomains resulting on this MPI process
11049 - iss - `IS` list with indices of subdomains on this MPI process
11050 
11051   Level: advanced
11052 
11053   Note:
11054   The number of subdomains must be smaller than the communicator size
11055 
11056 .seealso: [](ch_matrices), `Mat`, `IS`
11057 @*/
11058 PetscErrorCode MatSubdomainsCreateCoalesce(Mat A, PetscInt N, PetscInt *n, IS *iss[])
11059 {
11060   MPI_Comm    comm, subcomm;
11061   PetscMPIInt size, rank, color;
11062   PetscInt    rstart, rend, k;
11063 
11064   PetscFunctionBegin;
11065   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
11066   PetscCallMPI(MPI_Comm_size(comm, &size));
11067   PetscCallMPI(MPI_Comm_rank(comm, &rank));
11068   PetscCheck(N >= 1 && N < size, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "number of subdomains must be > 0 and < %d, got N = %" PetscInt_FMT, size, N);
11069   *n    = 1;
11070   k     = size / N + (size % N > 0); /* There are up to k ranks to a color */
11071   color = rank / k;
11072   PetscCallMPI(MPI_Comm_split(comm, color, rank, &subcomm));
11073   PetscCall(PetscMalloc1(1, iss));
11074   PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
11075   PetscCall(ISCreateStride(subcomm, rend - rstart, rstart, 1, iss[0]));
11076   PetscCallMPI(MPI_Comm_free(&subcomm));
11077   PetscFunctionReturn(PETSC_SUCCESS);
11078 }
11079 
11080 /*@
11081   MatGalerkin - Constructs the coarse grid problem matrix via Galerkin projection.
11082 
11083   If the interpolation and restriction operators are the same, uses `MatPtAP()`.
11084   If they are not the same, uses `MatMatMatMult()`.
11085 
11086   Once the coarse grid problem is constructed, correct for interpolation operators
11087   that are not of full rank, which can legitimately happen in the case of non-nested
11088   geometric multigrid.
11089 
11090   Input Parameters:
11091 + restrct     - restriction operator
11092 . dA          - fine grid matrix
11093 . interpolate - interpolation operator
11094 . reuse       - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
11095 - fill        - expected fill, use `PETSC_DETERMINE` or `PETSC_DETERMINE` if you do not have a good estimate
11096 
11097   Output Parameter:
11098 . A - the Galerkin coarse matrix
11099 
11100   Options Database Key:
11101 . -pc_mg_galerkin <both,pmat,mat,none> - for what matrices the Galerkin process should be used
11102 
11103   Level: developer
11104 
11105   Note:
11106   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
11107 
11108 .seealso: [](ch_matrices), `Mat`, `MatPtAP()`, `MatMatMatMult()`
11109 @*/
11110 PetscErrorCode MatGalerkin(Mat restrct, Mat dA, Mat interpolate, MatReuse reuse, PetscReal fill, Mat *A)
11111 {
11112   IS  zerorows;
11113   Vec diag;
11114 
11115   PetscFunctionBegin;
11116   PetscCheck(reuse != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
11117   /* Construct the coarse grid matrix */
11118   if (interpolate == restrct) {
11119     PetscCall(MatPtAP(dA, interpolate, reuse, fill, A));
11120   } else {
11121     PetscCall(MatMatMatMult(restrct, dA, interpolate, reuse, fill, A));
11122   }
11123 
11124   /* If the interpolation matrix is not of full rank, A will have zero rows.
11125      This can legitimately happen in the case of non-nested geometric multigrid.
11126      In that event, we set the rows of the matrix to the rows of the identity,
11127      ignoring the equations (as the RHS will also be zero). */
11128 
11129   PetscCall(MatFindZeroRows(*A, &zerorows));
11130 
11131   if (zerorows != NULL) { /* if there are any zero rows */
11132     PetscCall(MatCreateVecs(*A, &diag, NULL));
11133     PetscCall(MatGetDiagonal(*A, diag));
11134     PetscCall(VecISSet(diag, zerorows, 1.0));
11135     PetscCall(MatDiagonalSet(*A, diag, INSERT_VALUES));
11136     PetscCall(VecDestroy(&diag));
11137     PetscCall(ISDestroy(&zerorows));
11138   }
11139   PetscFunctionReturn(PETSC_SUCCESS);
11140 }
11141 
11142 /*@C
11143   MatSetOperation - Allows user to set a matrix operation for any matrix type
11144 
11145   Logically Collective
11146 
11147   Input Parameters:
11148 + mat - the matrix
11149 . op  - the name of the operation
11150 - f   - the function that provides the operation
11151 
11152   Level: developer
11153 
11154   Example Usage:
11155 .vb
11156   extern PetscErrorCode usermult(Mat, Vec, Vec);
11157 
11158   PetscCall(MatCreateXXX(comm, ..., &A));
11159   PetscCall(MatSetOperation(A, MATOP_MULT, (PetscVoidFn *)usermult));
11160 .ve
11161 
11162   Notes:
11163   See the file `include/petscmat.h` for a complete list of matrix
11164   operations, which all have the form MATOP_<OPERATION>, where
11165   <OPERATION> is the name (in all capital letters) of the
11166   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11167 
11168   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
11169   sequence as the usual matrix interface routines, since they
11170   are intended to be accessed via the usual matrix interface
11171   routines, e.g.,
11172 .vb
11173   MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
11174 .ve
11175 
11176   In particular each function MUST return `PETSC_SUCCESS` on success and
11177   nonzero on failure.
11178 
11179   This routine is distinct from `MatShellSetOperation()` in that it can be called on any matrix type.
11180 
11181 .seealso: [](ch_matrices), `Mat`, `MatGetOperation()`, `MatCreateShell()`, `MatShellSetContext()`, `MatShellSetOperation()`
11182 @*/
11183 PetscErrorCode MatSetOperation(Mat mat, MatOperation op, void (*f)(void))
11184 {
11185   PetscFunctionBegin;
11186   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11187   if (op == MATOP_VIEW && !mat->ops->viewnative && f != (void (*)(void))mat->ops->view) mat->ops->viewnative = mat->ops->view;
11188   (((void (**)(void))mat->ops)[op]) = f;
11189   PetscFunctionReturn(PETSC_SUCCESS);
11190 }
11191 
11192 /*@C
11193   MatGetOperation - Gets a matrix operation for any matrix type.
11194 
11195   Not Collective
11196 
11197   Input Parameters:
11198 + mat - the matrix
11199 - op  - the name of the operation
11200 
11201   Output Parameter:
11202 . f - the function that provides the operation
11203 
11204   Level: developer
11205 
11206   Example Usage:
11207 .vb
11208   PetscErrorCode (*usermult)(Mat, Vec, Vec);
11209 
11210   MatGetOperation(A, MATOP_MULT, (void (**)(void))&usermult);
11211 .ve
11212 
11213   Notes:
11214   See the file include/petscmat.h for a complete list of matrix
11215   operations, which all have the form MATOP_<OPERATION>, where
11216   <OPERATION> is the name (in all capital letters) of the
11217   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11218 
11219   This routine is distinct from `MatShellGetOperation()` in that it can be called on any matrix type.
11220 
11221 .seealso: [](ch_matrices), `Mat`, `MatSetOperation()`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
11222 @*/
11223 PetscErrorCode MatGetOperation(Mat mat, MatOperation op, void (**f)(void))
11224 {
11225   PetscFunctionBegin;
11226   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11227   *f = (((void (**)(void))mat->ops)[op]);
11228   PetscFunctionReturn(PETSC_SUCCESS);
11229 }
11230 
11231 /*@
11232   MatHasOperation - Determines whether the given matrix supports the particular operation.
11233 
11234   Not Collective
11235 
11236   Input Parameters:
11237 + mat - the matrix
11238 - op  - the operation, for example, `MATOP_GET_DIAGONAL`
11239 
11240   Output Parameter:
11241 . has - either `PETSC_TRUE` or `PETSC_FALSE`
11242 
11243   Level: advanced
11244 
11245   Note:
11246   See `MatSetOperation()` for additional discussion on naming convention and usage of `op`.
11247 
11248 .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`, `MatGetOperation()`, `MatSetOperation()`
11249 @*/
11250 PetscErrorCode MatHasOperation(Mat mat, MatOperation op, PetscBool *has)
11251 {
11252   PetscFunctionBegin;
11253   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11254   PetscAssertPointer(has, 3);
11255   if (mat->ops->hasoperation) {
11256     PetscUseTypeMethod(mat, hasoperation, op, has);
11257   } else {
11258     if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
11259     else {
11260       *has = PETSC_FALSE;
11261       if (op == MATOP_CREATE_SUBMATRIX) {
11262         PetscMPIInt size;
11263 
11264         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
11265         if (size == 1) PetscCall(MatHasOperation(mat, MATOP_CREATE_SUBMATRICES, has));
11266       }
11267     }
11268   }
11269   PetscFunctionReturn(PETSC_SUCCESS);
11270 }
11271 
11272 /*@
11273   MatHasCongruentLayouts - Determines whether the rows and columns layouts of the matrix are congruent
11274 
11275   Collective
11276 
11277   Input Parameter:
11278 . mat - the matrix
11279 
11280   Output Parameter:
11281 . cong - either `PETSC_TRUE` or `PETSC_FALSE`
11282 
11283   Level: beginner
11284 
11285 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatSetSizes()`, `PetscLayout`
11286 @*/
11287 PetscErrorCode MatHasCongruentLayouts(Mat mat, PetscBool *cong)
11288 {
11289   PetscFunctionBegin;
11290   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11291   PetscValidType(mat, 1);
11292   PetscAssertPointer(cong, 2);
11293   if (!mat->rmap || !mat->cmap) {
11294     *cong = mat->rmap == mat->cmap ? PETSC_TRUE : PETSC_FALSE;
11295     PetscFunctionReturn(PETSC_SUCCESS);
11296   }
11297   if (mat->congruentlayouts == PETSC_DECIDE) { /* first time we compare rows and cols layouts */
11298     PetscCall(PetscLayoutSetUp(mat->rmap));
11299     PetscCall(PetscLayoutSetUp(mat->cmap));
11300     PetscCall(PetscLayoutCompare(mat->rmap, mat->cmap, cong));
11301     if (*cong) mat->congruentlayouts = 1;
11302     else mat->congruentlayouts = 0;
11303   } else *cong = mat->congruentlayouts ? PETSC_TRUE : PETSC_FALSE;
11304   PetscFunctionReturn(PETSC_SUCCESS);
11305 }
11306 
11307 PetscErrorCode MatSetInf(Mat A)
11308 {
11309   PetscFunctionBegin;
11310   PetscUseTypeMethod(A, setinf);
11311   PetscFunctionReturn(PETSC_SUCCESS);
11312 }
11313 
11314 /*@
11315   MatCreateGraph - create a scalar matrix (that is a matrix with one vertex for each block vertex in the original matrix), for use in graph algorithms
11316   and possibly removes small values from the graph structure.
11317 
11318   Collective
11319 
11320   Input Parameters:
11321 + A       - the matrix
11322 . sym     - `PETSC_TRUE` indicates that the graph should be symmetrized
11323 . scale   - `PETSC_TRUE` indicates that the graph edge weights should be symmetrically scaled with the diagonal entry
11324 . filter  - filter value - < 0: does nothing; == 0: removes only 0.0 entries; otherwise: removes entries with abs(entries) <= value
11325 . num_idx - size of 'index' array
11326 - index   - array of block indices to use for graph strength of connection weight
11327 
11328   Output Parameter:
11329 . graph - the resulting graph
11330 
11331   Level: advanced
11332 
11333 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PCGAMG`
11334 @*/
11335 PetscErrorCode MatCreateGraph(Mat A, PetscBool sym, PetscBool scale, PetscReal filter, PetscInt num_idx, PetscInt index[], Mat *graph)
11336 {
11337   PetscFunctionBegin;
11338   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11339   PetscValidType(A, 1);
11340   PetscValidLogicalCollectiveBool(A, scale, 3);
11341   PetscAssertPointer(graph, 7);
11342   PetscCall(PetscLogEventBegin(MAT_CreateGraph, A, 0, 0, 0));
11343   PetscUseTypeMethod(A, creategraph, sym, scale, filter, num_idx, index, graph);
11344   PetscCall(PetscLogEventEnd(MAT_CreateGraph, A, 0, 0, 0));
11345   PetscFunctionReturn(PETSC_SUCCESS);
11346 }
11347 
11348 /*@
11349   MatEliminateZeros - eliminate the nondiagonal zero entries in place from the nonzero structure of a sparse `Mat` in place,
11350   meaning the same memory is used for the matrix, and no new memory is allocated.
11351 
11352   Collective
11353 
11354   Input Parameters:
11355 + A    - the matrix
11356 - keep - if for a given row of `A`, the diagonal coefficient is zero, indicates whether it should be left in the structure or eliminated as well
11357 
11358   Level: intermediate
11359 
11360   Developer Note:
11361   The entries in the sparse matrix data structure are shifted to fill in the unneeded locations in the data. Thus the end
11362   of the arrays in the data structure are unneeded.
11363 
11364 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateGraph()`, `MatFilter()`
11365 @*/
11366 PetscErrorCode MatEliminateZeros(Mat A, PetscBool keep)
11367 {
11368   PetscFunctionBegin;
11369   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11370   PetscUseTypeMethod(A, eliminatezeros, keep);
11371   PetscFunctionReturn(PETSC_SUCCESS);
11372 }
11373