xref: /petsc/src/mat/interface/matrix.c (revision 87fca8443e7ad390b9e7d7605d72068894b12eec)
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   The calling sequence is
586 .vb
587    MatGetRow(matrix,row,ncols,cols,values,ierr)
588          Mat         matrix (input)
589          PetscInt    row    (input)
590          PetscInt    ncols  (output)
591          PetscInt    cols(maxcols) (output)
592          PetscScalar values(maxcols) output
593 .ve
594   where maxcols >= maximum nonzeros in any row of the matrix.
595 
596 .seealso: [](ch_matrices), `Mat`, `MatRestoreRow()`, `MatSetValues()`, `MatGetValues()`, `MatCreateSubMatrices()`, `MatGetDiagonal()`, `MatGetRowIJ()`, `MatRestoreRowIJ()`
597 @*/
598 PetscErrorCode MatGetRow(Mat mat, PetscInt row, PetscInt *ncols, const PetscInt *cols[], const PetscScalar *vals[])
599 {
600   PetscInt incols;
601 
602   PetscFunctionBegin;
603   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
604   PetscValidType(mat, 1);
605   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
606   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
607   MatCheckPreallocated(mat, 1);
608   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);
609   PetscCall(PetscLogEventBegin(MAT_GetRow, mat, 0, 0, 0));
610   PetscUseTypeMethod(mat, getrow, row, &incols, (PetscInt **)cols, (PetscScalar **)vals);
611   if (ncols) *ncols = incols;
612   PetscCall(PetscLogEventEnd(MAT_GetRow, mat, 0, 0, 0));
613   PetscFunctionReturn(PETSC_SUCCESS);
614 }
615 
616 /*@
617   MatConjugate - replaces the matrix values with their complex conjugates
618 
619   Logically Collective
620 
621   Input Parameter:
622 . mat - the matrix
623 
624   Level: advanced
625 
626 .seealso: [](ch_matrices), `Mat`, `MatRealPart()`, `MatImaginaryPart()`, `VecConjugate()`, `MatTranspose()`
627 @*/
628 PetscErrorCode MatConjugate(Mat mat)
629 {
630   PetscFunctionBegin;
631   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
632   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
633   if (PetscDefined(USE_COMPLEX) && mat->hermitian != PETSC_BOOL3_TRUE) {
634     PetscUseTypeMethod(mat, conjugate);
635     PetscCall(PetscObjectStateIncrease((PetscObject)mat));
636   }
637   PetscFunctionReturn(PETSC_SUCCESS);
638 }
639 
640 /*@C
641   MatRestoreRow - Frees any temporary space allocated by `MatGetRow()`.
642 
643   Not Collective
644 
645   Input Parameters:
646 + mat   - the matrix
647 . row   - the row to get
648 . ncols - the number of nonzeros
649 . cols  - the columns of the nonzeros
650 - vals  - if nonzero the column values
651 
652   Level: advanced
653 
654   Notes:
655   This routine should be called after you have finished examining the entries.
656 
657   This routine zeros out `ncols`, `cols`, and `vals`. This is to prevent accidental
658   us of the array after it has been restored. If you pass `NULL`, it will
659   not zero the pointers.  Use of `cols` or `vals` after `MatRestoreRow()` is invalid.
660 
661   Fortran Note:
662   `MatRestoreRow()` MUST be called after `MatGetRow()`
663   before another call to `MatGetRow()` can be made.
664 
665 .seealso: [](ch_matrices), `Mat`, `MatGetRow()`
666 @*/
667 PetscErrorCode MatRestoreRow(Mat mat, PetscInt row, PetscInt *ncols, const PetscInt *cols[], const PetscScalar *vals[])
668 {
669   PetscFunctionBegin;
670   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
671   if (ncols) PetscAssertPointer(ncols, 3);
672   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
673   PetscTryTypeMethod(mat, restorerow, row, ncols, (PetscInt **)cols, (PetscScalar **)vals);
674   if (ncols) *ncols = 0;
675   if (cols) *cols = NULL;
676   if (vals) *vals = NULL;
677   PetscFunctionReturn(PETSC_SUCCESS);
678 }
679 
680 /*@
681   MatGetRowUpperTriangular - Sets a flag to enable calls to `MatGetRow()` for matrix in `MATSBAIJ` format.
682   You should call `MatRestoreRowUpperTriangular()` after calling` MatGetRow()` and `MatRestoreRow()` to disable the flag.
683 
684   Not Collective
685 
686   Input Parameter:
687 . mat - the matrix
688 
689   Level: advanced
690 
691   Note:
692   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.
693 
694 .seealso: [](ch_matrices), `Mat`, `MATSBAIJ`, `MatRestoreRowUpperTriangular()`
695 @*/
696 PetscErrorCode MatGetRowUpperTriangular(Mat mat)
697 {
698   PetscFunctionBegin;
699   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
700   PetscValidType(mat, 1);
701   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
702   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
703   MatCheckPreallocated(mat, 1);
704   PetscTryTypeMethod(mat, getrowuppertriangular);
705   PetscFunctionReturn(PETSC_SUCCESS);
706 }
707 
708 /*@
709   MatRestoreRowUpperTriangular - Disable calls to `MatGetRow()` for matrix in `MATSBAIJ` format.
710 
711   Not Collective
712 
713   Input Parameter:
714 . mat - the matrix
715 
716   Level: advanced
717 
718   Note:
719   This routine should be called after you have finished calls to `MatGetRow()` and `MatRestoreRow()`.
720 
721 .seealso: [](ch_matrices), `Mat`, `MATSBAIJ`, `MatGetRowUpperTriangular()`
722 @*/
723 PetscErrorCode MatRestoreRowUpperTriangular(Mat mat)
724 {
725   PetscFunctionBegin;
726   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
727   PetscValidType(mat, 1);
728   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
729   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
730   MatCheckPreallocated(mat, 1);
731   PetscTryTypeMethod(mat, restorerowuppertriangular);
732   PetscFunctionReturn(PETSC_SUCCESS);
733 }
734 
735 /*@
736   MatSetOptionsPrefix - Sets the prefix used for searching for all
737   `Mat` options in the database.
738 
739   Logically Collective
740 
741   Input Parameters:
742 + A      - the matrix
743 - prefix - the prefix to prepend to all option names
744 
745   Level: advanced
746 
747   Notes:
748   A hyphen (-) must NOT be given at the beginning of the prefix name.
749   The first character of all runtime options is AUTOMATICALLY the hyphen.
750 
751   This is NOT used for options for the factorization of the matrix. Normally the
752   prefix is automatically passed in from the PC calling the factorization. To set
753   it directly use  `MatSetOptionsPrefixFactor()`
754 
755 .seealso: [](ch_matrices), `Mat`, `MatSetFromOptions()`, `MatSetOptionsPrefixFactor()`
756 @*/
757 PetscErrorCode MatSetOptionsPrefix(Mat A, const char prefix[])
758 {
759   PetscFunctionBegin;
760   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
761   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)A, prefix));
762   PetscFunctionReturn(PETSC_SUCCESS);
763 }
764 
765 /*@
766   MatSetOptionsPrefixFactor - Sets the prefix used for searching for all matrix factor options in the database for
767   for matrices created with `MatGetFactor()`
768 
769   Logically Collective
770 
771   Input Parameters:
772 + A      - the matrix
773 - prefix - the prefix to prepend to all option names for the factored matrix
774 
775   Level: developer
776 
777   Notes:
778   A hyphen (-) must NOT be given at the beginning of the prefix name.
779   The first character of all runtime options is AUTOMATICALLY the hyphen.
780 
781   Normally the prefix is automatically passed in from the `PC` calling the factorization. To set
782   it directly when not using `KSP`/`PC` use  `MatSetOptionsPrefixFactor()`
783 
784 .seealso: [](ch_matrices), `Mat`,   [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSetFromOptions()`, `MatSetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`
785 @*/
786 PetscErrorCode MatSetOptionsPrefixFactor(Mat A, const char prefix[])
787 {
788   PetscFunctionBegin;
789   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
790   if (prefix) {
791     PetscAssertPointer(prefix, 2);
792     PetscCheck(prefix[0] != '-', PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
793     if (prefix != A->factorprefix) {
794       PetscCall(PetscFree(A->factorprefix));
795       PetscCall(PetscStrallocpy(prefix, &A->factorprefix));
796     }
797   } else PetscCall(PetscFree(A->factorprefix));
798   PetscFunctionReturn(PETSC_SUCCESS);
799 }
800 
801 /*@
802   MatAppendOptionsPrefixFactor - Appends to the prefix used for searching for all matrix factor options in the database for
803   for matrices created with `MatGetFactor()`
804 
805   Logically Collective
806 
807   Input Parameters:
808 + A      - the matrix
809 - prefix - the prefix to prepend to all option names for the factored matrix
810 
811   Level: developer
812 
813   Notes:
814   A hyphen (-) must NOT be given at the beginning of the prefix name.
815   The first character of all runtime options is AUTOMATICALLY the hyphen.
816 
817   Normally the prefix is automatically passed in from the `PC` calling the factorization. To set
818   it directly when not using `KSP`/`PC` use  `MatAppendOptionsPrefixFactor()`
819 
820 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `PetscOptionsCreate()`, `PetscOptionsDestroy()`, `PetscObjectSetOptionsPrefix()`, `PetscObjectPrependOptionsPrefix()`,
821           `PetscObjectGetOptionsPrefix()`, `TSAppendOptionsPrefix()`, `SNESAppendOptionsPrefix()`, `KSPAppendOptionsPrefix()`, `MatSetOptionsPrefixFactor()`,
822           `MatSetOptionsPrefix()`
823 @*/
824 PetscErrorCode MatAppendOptionsPrefixFactor(Mat A, const char prefix[])
825 {
826   size_t len1, len2, new_len;
827 
828   PetscFunctionBegin;
829   PetscValidHeader(A, 1);
830   if (!prefix) PetscFunctionReturn(PETSC_SUCCESS);
831   if (!A->factorprefix) {
832     PetscCall(MatSetOptionsPrefixFactor(A, prefix));
833     PetscFunctionReturn(PETSC_SUCCESS);
834   }
835   PetscCheck(prefix[0] != '-', PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
836 
837   PetscCall(PetscStrlen(A->factorprefix, &len1));
838   PetscCall(PetscStrlen(prefix, &len2));
839   new_len = len1 + len2 + 1;
840   PetscCall(PetscRealloc(new_len * sizeof(*A->factorprefix), &A->factorprefix));
841   PetscCall(PetscStrncpy(A->factorprefix + len1, prefix, len2 + 1));
842   PetscFunctionReturn(PETSC_SUCCESS);
843 }
844 
845 /*@
846   MatAppendOptionsPrefix - Appends to the prefix used for searching for all
847   matrix options in the database.
848 
849   Logically Collective
850 
851   Input Parameters:
852 + A      - the matrix
853 - prefix - the prefix to prepend to all option names
854 
855   Level: advanced
856 
857   Note:
858   A hyphen (-) must NOT be given at the beginning of the prefix name.
859   The first character of all runtime options is AUTOMATICALLY the hyphen.
860 
861 .seealso: [](ch_matrices), `Mat`, `MatGetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`, `MatSetOptionsPrefix()`
862 @*/
863 PetscErrorCode MatAppendOptionsPrefix(Mat A, const char prefix[])
864 {
865   PetscFunctionBegin;
866   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
867   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)A, prefix));
868   PetscFunctionReturn(PETSC_SUCCESS);
869 }
870 
871 /*@
872   MatGetOptionsPrefix - Gets the prefix used for searching for all
873   matrix options in the database.
874 
875   Not Collective
876 
877   Input Parameter:
878 . A - the matrix
879 
880   Output Parameter:
881 . prefix - pointer to the prefix string used
882 
883   Level: advanced
884 
885   Fortran Note:
886   The user should pass in a string `prefix` of
887   sufficient length to hold the prefix.
888 
889 .seealso: [](ch_matrices), `Mat`, `MatAppendOptionsPrefix()`, `MatSetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`, `MatSetOptionsPrefixFactor()`
890 @*/
891 PetscErrorCode MatGetOptionsPrefix(Mat A, const char *prefix[])
892 {
893   PetscFunctionBegin;
894   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
895   PetscAssertPointer(prefix, 2);
896   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)A, prefix));
897   PetscFunctionReturn(PETSC_SUCCESS);
898 }
899 
900 /*@
901   MatGetState - Gets the state of a `Mat`. Same value as returned by `PetscObjectStateGet()`
902 
903   Not Collective
904 
905   Input Parameter:
906 . A - the matrix
907 
908   Output Parameter:
909 . state - the object state
910 
911   Level: advanced
912 
913   Note:
914   Object state is an integer which gets increased every time
915   the object is changed. By saving and later querying the object state
916   one can determine whether information about the object is still current.
917 
918   See `MatGetNonzeroState()` to determine if the nonzero structure of the matrix has changed.
919 
920 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PetscObjectStateGet()`, `MatGetNonzeroState()`
921 @*/
922 PetscErrorCode MatGetState(Mat A, PetscObjectState *state)
923 {
924   PetscFunctionBegin;
925   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
926   PetscAssertPointer(state, 2);
927   PetscCall(PetscObjectStateGet((PetscObject)A, state));
928   PetscFunctionReturn(PETSC_SUCCESS);
929 }
930 
931 /*@
932   MatResetPreallocation - Reset matrix to use the original preallocation values provided by the user, for example with `MatXAIJSetPreallocation()`
933 
934   Collective
935 
936   Input Parameter:
937 . A - the matrix
938 
939   Level: beginner
940 
941   Notes:
942   After calling `MatAssemblyBegin()` and `MatAssemblyEnd()` with `MAT_FINAL_ASSEMBLY` the matrix data structures represent the nonzeros assigned to the
943   matrix. If that space is less than the preallocated space that extra preallocated space is no longer available to take on new values. `MatResetPreallocation()`
944   makes all of the preallocation space available
945 
946   Current values in the matrix are lost in this call.
947 
948   Currently only supported for  `MATAIJ` matrices.
949 
950 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatXAIJSetPreallocation()`
951 @*/
952 PetscErrorCode MatResetPreallocation(Mat A)
953 {
954   PetscFunctionBegin;
955   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
956   PetscValidType(A, 1);
957   PetscCheck(A->insertmode == NOT_SET_VALUES, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot reset preallocation after setting some values but not yet calling MatAssemblyBegin()/MatAssemblyEnd()");
958   if (A->num_ass == 0) PetscFunctionReturn(PETSC_SUCCESS);
959   PetscUseMethod(A, "MatResetPreallocation_C", (Mat), (A));
960   PetscFunctionReturn(PETSC_SUCCESS);
961 }
962 
963 /*@
964   MatResetHash - Reset the matrix so that it will use a hash table for the next round of `MatSetValues()` and `MatAssemblyBegin()`/`MatAssemblyEnd()`.
965 
966   Collective
967 
968   Input Parameter:
969 . A - the matrix
970 
971   Level: intermediate
972 
973   Notes:
974   The matrix will again delete the hash table data structures after following calls to `MatAssemblyBegin()`/`MatAssemblyEnd()` with `MAT_FINAL_ASSEMBLY`.
975 
976   Currently only supported for `MATAIJ` matrices.
977 
978 .seealso: [](ch_matrices), `Mat`, `MatResetPreallocation()`
979 @*/
980 PetscErrorCode MatResetHash(Mat A)
981 {
982   PetscFunctionBegin;
983   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
984   PetscValidType(A, 1);
985   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()");
986   if (A->num_ass == 0) PetscFunctionReturn(PETSC_SUCCESS);
987   PetscUseMethod(A, "MatResetHash_C", (Mat), (A));
988   /* These flags are used to determine whether certain setups occur */
989   A->was_assembled = PETSC_FALSE;
990   A->assembled     = PETSC_FALSE;
991   /* Log that the state of this object has changed; this will help guarantee that preconditioners get re-setup */
992   PetscCall(PetscObjectStateIncrease((PetscObject)A));
993   PetscFunctionReturn(PETSC_SUCCESS);
994 }
995 
996 /*@
997   MatSetUp - Sets up the internal matrix data structures for later use by the matrix
998 
999   Collective
1000 
1001   Input Parameter:
1002 . A - the matrix
1003 
1004   Level: advanced
1005 
1006   Notes:
1007   If the user has not set preallocation for this matrix then an efficient algorithm will be used for the first round of
1008   setting values in the matrix.
1009 
1010   This routine is called internally by other `Mat` functions when needed so rarely needs to be called by users
1011 
1012 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatCreate()`, `MatDestroy()`, `MatXAIJSetPreallocation()`
1013 @*/
1014 PetscErrorCode MatSetUp(Mat A)
1015 {
1016   PetscFunctionBegin;
1017   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1018   if (!((PetscObject)A)->type_name) {
1019     PetscMPIInt size;
1020 
1021     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
1022     PetscCall(MatSetType(A, size == 1 ? MATSEQAIJ : MATMPIAIJ));
1023   }
1024   if (!A->preallocated) PetscTryTypeMethod(A, setup);
1025   PetscCall(PetscLayoutSetUp(A->rmap));
1026   PetscCall(PetscLayoutSetUp(A->cmap));
1027   A->preallocated = PETSC_TRUE;
1028   PetscFunctionReturn(PETSC_SUCCESS);
1029 }
1030 
1031 #if defined(PETSC_HAVE_SAWS)
1032   #include <petscviewersaws.h>
1033 #endif
1034 
1035 /*
1036    If threadsafety is on extraneous matrices may be printed
1037 
1038    This flag cannot be stored in the matrix because the original matrix in MatView() may assemble a new matrix which is passed into MatViewFromOptions()
1039 */
1040 #if !defined(PETSC_HAVE_THREADSAFETY)
1041 static PetscInt insidematview = 0;
1042 #endif
1043 
1044 /*@
1045   MatViewFromOptions - View properties of the matrix based on options set in the options database
1046 
1047   Collective
1048 
1049   Input Parameters:
1050 + A    - the matrix
1051 . obj  - optional additional object that provides the options prefix to use
1052 - name - command line option
1053 
1054   Options Database Key:
1055 . -mat_view [viewertype]:... - the viewer and its options
1056 
1057   Level: intermediate
1058 
1059   Note:
1060 .vb
1061     If no value is provided ascii:stdout is used
1062        ascii[:[filename][:[format][:append]]]    defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab,
1063                                                   for example ascii::ascii_info prints just the information about the object not all details
1064                                                   unless :append is given filename opens in write mode, overwriting what was already there
1065        binary[:[filename][:[format][:append]]]   defaults to the file binaryoutput
1066        draw[:drawtype[:filename]]                for example, draw:tikz, draw:tikz:figure.tex  or draw:x
1067        socket[:port]                             defaults to the standard output port
1068        saws[:communicatorname]                    publishes object to the Scientific Application Webserver (SAWs)
1069 .ve
1070 
1071 .seealso: [](ch_matrices), `Mat`, `MatView()`, `PetscObjectViewFromOptions()`, `MatCreate()`
1072 @*/
1073 PetscErrorCode MatViewFromOptions(Mat A, PetscObject obj, const char name[])
1074 {
1075   PetscFunctionBegin;
1076   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1077 #if !defined(PETSC_HAVE_THREADSAFETY)
1078   if (insidematview) PetscFunctionReturn(PETSC_SUCCESS);
1079 #endif
1080   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
1081   PetscFunctionReturn(PETSC_SUCCESS);
1082 }
1083 
1084 /*@
1085   MatView - display information about a matrix in a variety ways
1086 
1087   Collective on viewer
1088 
1089   Input Parameters:
1090 + mat    - the matrix
1091 - viewer - visualization context
1092 
1093   Options Database Keys:
1094 + -mat_view ::ascii_info           - Prints info on matrix at conclusion of `MatAssemblyEnd()`
1095 . -mat_view ::ascii_info_detail    - Prints more detailed info
1096 . -mat_view                        - Prints matrix in ASCII format
1097 . -mat_view ::ascii_matlab         - Prints matrix in MATLAB format
1098 . -mat_view draw                   - PetscDraws nonzero structure of matrix, using `MatView()` and `PetscDrawOpenX()`.
1099 . -display <name>                  - Sets display name (default is host)
1100 . -draw_pause <sec>                - Sets number of seconds to pause after display
1101 . -mat_view socket                 - Sends matrix to socket, can be accessed from MATLAB (see Users-Manual: ch_matlab for details)
1102 . -viewer_socket_machine <machine> - -
1103 . -viewer_socket_port <port>       - -
1104 . -mat_view binary                 - save matrix to file in binary format
1105 - -viewer_binary_filename <name>   - -
1106 
1107   Level: beginner
1108 
1109   Notes:
1110   The available visualization contexts include
1111 +    `PETSC_VIEWER_STDOUT_SELF`   - for sequential matrices
1112 .    `PETSC_VIEWER_STDOUT_WORLD`  - for parallel matrices created on `PETSC_COMM_WORLD`
1113 .    `PETSC_VIEWER_STDOUT_`(comm) - for matrices created on MPI communicator comm
1114 -     `PETSC_VIEWER_DRAW_WORLD`   - graphical display of nonzero structure
1115 
1116   The user can open alternative visualization contexts with
1117 +    `PetscViewerASCIIOpen()`  - Outputs matrix to a specified file
1118 .    `PetscViewerBinaryOpen()` - Outputs matrix in binary to a  specified file; corresponding input uses `MatLoad()`
1119 .    `PetscViewerDrawOpen()`   - Outputs nonzero matrix nonzero structure to an X window display
1120 -    `PetscViewerSocketOpen()` - Outputs matrix to Socket viewer, `PETSCVIEWERSOCKET`. Only the `MATSEQDENSE` and `MATAIJ` types support this viewer.
1121 
1122   The user can call `PetscViewerPushFormat()` to specify the output
1123   format of ASCII printed objects (when using `PETSC_VIEWER_STDOUT_SELF`,
1124   `PETSC_VIEWER_STDOUT_WORLD` and `PetscViewerASCIIOpen()`).  Available formats include
1125 +    `PETSC_VIEWER_DEFAULT`           - default, prints matrix contents
1126 .    `PETSC_VIEWER_ASCII_MATLAB`      - prints matrix contents in MATLAB format
1127 .    `PETSC_VIEWER_ASCII_DENSE`       - prints entire matrix including zeros
1128 .    `PETSC_VIEWER_ASCII_COMMON`      - prints matrix contents, using a sparse  format common among all matrix types
1129 .    `PETSC_VIEWER_ASCII_IMPL`        - prints matrix contents, using an implementation-specific format (which is in many cases the same as the default)
1130 .    `PETSC_VIEWER_ASCII_INFO`        - prints basic information about the matrix size and structure (not the matrix entries)
1131 -    `PETSC_VIEWER_ASCII_INFO_DETAIL` - prints more detailed information about the matrix nonzero structure (still not vector or matrix entries)
1132 
1133   The ASCII viewers are only recommended for small matrices on at most a moderate number of processes,
1134   the program will seemingly hang and take hours for larger matrices, for larger matrices one should use the binary format.
1135 
1136   In the debugger you can do "call MatView(mat,0)" to display the matrix. (The same holds for any PETSc object viewer).
1137 
1138   See the manual page for `MatLoad()` for the exact format of the binary file when the binary
1139   viewer is used.
1140 
1141   See share/petsc/matlab/PetscBinaryRead.m for a MATLAB code that can read in the binary file when the binary
1142   viewer is used and lib/petsc/bin/PetscBinaryIO.py for loading them into Python.
1143 
1144   One can use '-mat_view draw -draw_pause -1' to pause the graphical display of matrix nonzero structure,
1145   and then use the following mouse functions.
1146 .vb
1147   left mouse: zoom in
1148   middle mouse: zoom out
1149   right mouse: continue with the simulation
1150 .ve
1151 
1152 .seealso: [](ch_matrices), `Mat`, `PetscViewerPushFormat()`, `PetscViewerASCIIOpen()`, `PetscViewerDrawOpen()`, `PetscViewer`,
1153           `PetscViewerSocketOpen()`, `PetscViewerBinaryOpen()`, `MatLoad()`, `MatViewFromOptions()`
1154 @*/
1155 PetscErrorCode MatView(Mat mat, PetscViewer viewer)
1156 {
1157   PetscInt          rows, cols, rbs, cbs;
1158   PetscBool         isascii, isstring, issaws;
1159   PetscViewerFormat format;
1160   PetscMPIInt       size;
1161 
1162   PetscFunctionBegin;
1163   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1164   PetscValidType(mat, 1);
1165   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat), &viewer));
1166   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1167 
1168   PetscCall(PetscViewerGetFormat(viewer, &format));
1169   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
1170   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
1171 
1172 #if !defined(PETSC_HAVE_THREADSAFETY)
1173   insidematview++;
1174 #endif
1175   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
1176   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1177   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
1178   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");
1179 
1180   PetscCall(PetscLogEventBegin(MAT_View, mat, viewer, 0, 0));
1181   if (isascii) {
1182     if (!mat->preallocated) {
1183       PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix has not been preallocated 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     if (!mat->assembled) {
1191       PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix has not been assembled yet\n"));
1192 #if !defined(PETSC_HAVE_THREADSAFETY)
1193       insidematview--;
1194 #endif
1195       PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1196       PetscFunctionReturn(PETSC_SUCCESS);
1197     }
1198     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)mat, viewer));
1199     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1200       MatNullSpace nullsp, transnullsp;
1201 
1202       PetscCall(PetscViewerASCIIPushTab(viewer));
1203       PetscCall(MatGetSize(mat, &rows, &cols));
1204       PetscCall(MatGetBlockSizes(mat, &rbs, &cbs));
1205       if (rbs != 1 || cbs != 1) {
1206         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" : ""));
1207         else PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT ", bs=%" PetscInt_FMT "%s\n", rows, cols, rbs, mat->bsizes ? " variable blocks set" : ""));
1208       } else PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", rows, cols));
1209       if (mat->factortype) {
1210         MatSolverType solver;
1211         PetscCall(MatFactorGetSolverType(mat, &solver));
1212         PetscCall(PetscViewerASCIIPrintf(viewer, "package used to perform factorization: %s\n", solver));
1213       }
1214       if (mat->ops->getinfo) {
1215         MatInfo info;
1216         PetscCall(MatGetInfo(mat, MAT_GLOBAL_SUM, &info));
1217         PetscCall(PetscViewerASCIIPrintf(viewer, "total: nonzeros=%.f, allocated nonzeros=%.f\n", info.nz_used, info.nz_allocated));
1218         if (!mat->factortype) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of mallocs used during MatSetValues calls=%" PetscInt_FMT "\n", (PetscInt)info.mallocs));
1219       }
1220       PetscCall(MatGetNullSpace(mat, &nullsp));
1221       PetscCall(MatGetTransposeNullSpace(mat, &transnullsp));
1222       if (nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached null space\n"));
1223       if (transnullsp && transnullsp != nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached transposed null space\n"));
1224       PetscCall(MatGetNearNullSpace(mat, &nullsp));
1225       if (nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached near null space\n"));
1226       PetscCall(PetscViewerASCIIPushTab(viewer));
1227       PetscCall(MatProductView(mat, viewer));
1228       PetscCall(PetscViewerASCIIPopTab(viewer));
1229       if (mat->bsizes && format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1230         IS tmp;
1231 
1232         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), mat->nblocks, mat->bsizes, PETSC_USE_POINTER, &tmp));
1233         PetscCall(PetscObjectSetName((PetscObject)tmp, "Block Sizes"));
1234         PetscCall(PetscViewerASCIIPushTab(viewer));
1235         PetscCall(ISView(tmp, viewer));
1236         PetscCall(PetscViewerASCIIPopTab(viewer));
1237         PetscCall(ISDestroy(&tmp));
1238       }
1239     }
1240   } else if (issaws) {
1241 #if defined(PETSC_HAVE_SAWS)
1242     PetscMPIInt rank;
1243 
1244     PetscCall(PetscObjectName((PetscObject)mat));
1245     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1246     if (!((PetscObject)mat)->amsmem && rank == 0) PetscCall(PetscObjectViewSAWs((PetscObject)mat, viewer));
1247 #endif
1248   } else if (isstring) {
1249     const char *type;
1250     PetscCall(MatGetType(mat, &type));
1251     PetscCall(PetscViewerStringSPrintf(viewer, " MatType: %-7.7s", type));
1252     PetscTryTypeMethod(mat, view, viewer);
1253   }
1254   if ((format == PETSC_VIEWER_NATIVE || format == PETSC_VIEWER_LOAD_BALANCE) && mat->ops->viewnative) {
1255     PetscCall(PetscViewerASCIIPushTab(viewer));
1256     PetscUseTypeMethod(mat, viewnative, viewer);
1257     PetscCall(PetscViewerASCIIPopTab(viewer));
1258   } else if (mat->ops->view) {
1259     PetscCall(PetscViewerASCIIPushTab(viewer));
1260     PetscUseTypeMethod(mat, view, viewer);
1261     PetscCall(PetscViewerASCIIPopTab(viewer));
1262   }
1263   if (isascii) {
1264     PetscCall(PetscViewerGetFormat(viewer, &format));
1265     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscCall(PetscViewerASCIIPopTab(viewer));
1266   }
1267   PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1268 #if !defined(PETSC_HAVE_THREADSAFETY)
1269   insidematview--;
1270 #endif
1271   PetscFunctionReturn(PETSC_SUCCESS);
1272 }
1273 
1274 #if defined(PETSC_USE_DEBUG)
1275   #include <../src/sys/totalview/tv_data_display.h>
1276 PETSC_UNUSED static int TV_display_type(const struct _p_Mat *mat)
1277 {
1278   TV_add_row("Local rows", "int", &mat->rmap->n);
1279   TV_add_row("Local columns", "int", &mat->cmap->n);
1280   TV_add_row("Global rows", "int", &mat->rmap->N);
1281   TV_add_row("Global columns", "int", &mat->cmap->N);
1282   TV_add_row("Typename", TV_ascii_string_type, ((PetscObject)mat)->type_name);
1283   return TV_format_OK;
1284 }
1285 #endif
1286 
1287 /*@
1288   MatLoad - Loads a matrix that has been stored in binary/HDF5 format
1289   with `MatView()`.  The matrix format is determined from the options database.
1290   Generates a parallel MPI matrix if the communicator has more than one
1291   processor.  The default matrix type is `MATAIJ`.
1292 
1293   Collective
1294 
1295   Input Parameters:
1296 + mat    - the newly loaded matrix, this needs to have been created with `MatCreate()`
1297             or some related function before a call to `MatLoad()`
1298 - viewer - `PETSCVIEWERBINARY`/`PETSCVIEWERHDF5` file viewer
1299 
1300   Options Database Key:
1301 . -matload_block_size <bs> - set block size
1302 
1303   Level: beginner
1304 
1305   Notes:
1306   If the `Mat` type has not yet been given then `MATAIJ` is used, call `MatSetFromOptions()` on the
1307   `Mat` before calling this routine if you wish to set it from the options database.
1308 
1309   `MatLoad()` automatically loads into the options database any options
1310   given in the file filename.info where filename is the name of the file
1311   that was passed to the `PetscViewerBinaryOpen()`. The options in the info
1312   file will be ignored if you use the -viewer_binary_skip_info option.
1313 
1314   If the type or size of mat is not set before a call to `MatLoad()`, PETSc
1315   sets the default matrix type AIJ and sets the local and global sizes.
1316   If type and/or size is already set, then the same are used.
1317 
1318   In parallel, each processor can load a subset of rows (or the
1319   entire matrix).  This routine is especially useful when a large
1320   matrix is stored on disk and only part of it is desired on each
1321   processor.  For example, a parallel solver may access only some of
1322   the rows from each processor.  The algorithm used here reads
1323   relatively small blocks of data rather than reading the entire
1324   matrix and then subsetting it.
1325 
1326   Viewer's `PetscViewerType` must be either `PETSCVIEWERBINARY` or `PETSCVIEWERHDF5`.
1327   Such viewer can be created using `PetscViewerBinaryOpen()` or `PetscViewerHDF5Open()`,
1328   or the sequence like
1329 .vb
1330     `PetscViewer` v;
1331     `PetscViewerCreate`(`PETSC_COMM_WORLD`,&v);
1332     `PetscViewerSetType`(v,`PETSCVIEWERBINARY`);
1333     `PetscViewerSetFromOptions`(v);
1334     `PetscViewerFileSetMode`(v,`FILE_MODE_READ`);
1335     `PetscViewerFileSetName`(v,"datafile");
1336 .ve
1337   The optional `PetscViewerSetFromOptions()` call allows overriding `PetscViewerSetType()` using the option
1338 $ -viewer_type {binary, hdf5}
1339 
1340   See the example src/ksp/ksp/tutorials/ex27.c with the first approach,
1341   and src/mat/tutorials/ex10.c with the second approach.
1342 
1343   In case of `PETSCVIEWERBINARY`, a native PETSc binary format is used. Each of the blocks
1344   is read onto MPI rank 0 and then shipped to its destination MPI rank, one after another.
1345   Multiple objects, both matrices and vectors, can be stored within the same file.
1346   Their `PetscObject` name is ignored; they are loaded in the order of their storage.
1347 
1348   Most users should not need to know the details of the binary storage
1349   format, since `MatLoad()` and `MatView()` completely hide these details.
1350   But for anyone who is interested, the standard binary matrix storage
1351   format is
1352 
1353 .vb
1354     PetscInt    MAT_FILE_CLASSID
1355     PetscInt    number of rows
1356     PetscInt    number of columns
1357     PetscInt    total number of nonzeros
1358     PetscInt    *number nonzeros in each row
1359     PetscInt    *column indices of all nonzeros (starting index is zero)
1360     PetscScalar *values of all nonzeros
1361 .ve
1362   If PETSc was not configured with `--with-64-bit-indices` then only `MATMPIAIJ` matrices with more than `PETSC_INT_MAX` non-zeros can be
1363   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
1364   case will not fit in a (32-bit) `PetscInt` the value `PETSC_INT_MAX` is used for the header entry `total number of nonzeros`.
1365 
1366   PETSc automatically does the byte swapping for
1367   machines that store the bytes reversed. Thus if you write your own binary
1368   read/write routines you have to swap the bytes; see `PetscBinaryRead()`
1369   and `PetscBinaryWrite()` to see how this may be done.
1370 
1371   In case of `PETSCVIEWERHDF5`, a parallel HDF5 reader is used.
1372   Each processor's chunk is loaded independently by its owning MPI process.
1373   Multiple objects, both matrices and vectors, can be stored within the same file.
1374   They are looked up by their PetscObject name.
1375 
1376   As the MATLAB MAT-File Version 7.3 format is also a HDF5 flavor, we decided to use
1377   by default the same structure and naming of the AIJ arrays and column count
1378   within the HDF5 file. This means that a MAT file saved with -v7.3 flag, e.g.
1379 $    save example.mat A b -v7.3
1380   can be directly read by this routine (see Reference 1 for details).
1381 
1382   Depending on your MATLAB version, this format might be a default,
1383   otherwise you can set it as default in Preferences.
1384 
1385   Unless -nocompression flag is used to save the file in MATLAB,
1386   PETSc must be configured with ZLIB package.
1387 
1388   See also examples src/mat/tutorials/ex10.c and src/ksp/ksp/tutorials/ex27.c
1389 
1390   This reader currently supports only real `MATSEQAIJ`, `MATMPIAIJ`, `MATSEQDENSE` and `MATMPIDENSE` matrices for `PETSCVIEWERHDF5`
1391 
1392   Corresponding `MatView()` is not yet implemented.
1393 
1394   The loaded matrix is actually a transpose of the original one in MATLAB,
1395   unless you push `PETSC_VIEWER_HDF5_MAT` format (see examples above).
1396   With this format, matrix is automatically transposed by PETSc,
1397   unless the matrix is marked as SPD or symmetric
1398   (see `MatSetOption()`, `MAT_SPD`, `MAT_SYMMETRIC`).
1399 
1400   See MATLAB Documentation on `save()`, <https://www.mathworks.com/help/matlab/ref/save.html#btox10b-1-version>
1401 
1402 .seealso: [](ch_matrices), `Mat`, `PetscViewerBinaryOpen()`, `PetscViewerSetType()`, `MatView()`, `VecLoad()`
1403  @*/
1404 PetscErrorCode MatLoad(Mat mat, PetscViewer viewer)
1405 {
1406   PetscBool flg;
1407 
1408   PetscFunctionBegin;
1409   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1410   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1411 
1412   if (!((PetscObject)mat)->type_name) PetscCall(MatSetType(mat, MATAIJ));
1413 
1414   flg = PETSC_FALSE;
1415   PetscCall(PetscOptionsGetBool(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matload_symmetric", &flg, NULL));
1416   if (flg) {
1417     PetscCall(MatSetOption(mat, MAT_SYMMETRIC, PETSC_TRUE));
1418     PetscCall(MatSetOption(mat, MAT_SYMMETRY_ETERNAL, PETSC_TRUE));
1419   }
1420   flg = PETSC_FALSE;
1421   PetscCall(PetscOptionsGetBool(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matload_spd", &flg, NULL));
1422   if (flg) PetscCall(MatSetOption(mat, MAT_SPD, PETSC_TRUE));
1423 
1424   PetscCall(PetscLogEventBegin(MAT_Load, mat, viewer, 0, 0));
1425   PetscUseTypeMethod(mat, load, viewer);
1426   PetscCall(PetscLogEventEnd(MAT_Load, mat, viewer, 0, 0));
1427   PetscFunctionReturn(PETSC_SUCCESS);
1428 }
1429 
1430 static PetscErrorCode MatDestroy_Redundant(Mat_Redundant **redundant)
1431 {
1432   Mat_Redundant *redund = *redundant;
1433 
1434   PetscFunctionBegin;
1435   if (redund) {
1436     if (redund->matseq) { /* via MatCreateSubMatrices()  */
1437       PetscCall(ISDestroy(&redund->isrow));
1438       PetscCall(ISDestroy(&redund->iscol));
1439       PetscCall(MatDestroySubMatrices(1, &redund->matseq));
1440     } else {
1441       PetscCall(PetscFree2(redund->send_rank, redund->recv_rank));
1442       PetscCall(PetscFree(redund->sbuf_j));
1443       PetscCall(PetscFree(redund->sbuf_a));
1444       for (PetscInt i = 0; i < redund->nrecvs; i++) {
1445         PetscCall(PetscFree(redund->rbuf_j[i]));
1446         PetscCall(PetscFree(redund->rbuf_a[i]));
1447       }
1448       PetscCall(PetscFree4(redund->sbuf_nz, redund->rbuf_nz, redund->rbuf_j, redund->rbuf_a));
1449     }
1450 
1451     if (redund->subcomm) PetscCall(PetscCommDestroy(&redund->subcomm));
1452     PetscCall(PetscFree(redund));
1453   }
1454   PetscFunctionReturn(PETSC_SUCCESS);
1455 }
1456 
1457 /*@
1458   MatDestroy - Frees space taken by a matrix.
1459 
1460   Collective
1461 
1462   Input Parameter:
1463 . A - the matrix
1464 
1465   Level: beginner
1466 
1467   Developer Note:
1468   Some special arrays of matrices are not destroyed in this routine but instead by the routines called by
1469   `MatDestroySubMatrices()`. Thus one must be sure that any changes here must also be made in those routines.
1470   `MatHeaderMerge()` and `MatHeaderReplace()` also manipulate the data in the `Mat` object and likely need changes
1471   if changes are needed here.
1472 
1473 .seealso: [](ch_matrices), `Mat`, `MatCreate()`
1474 @*/
1475 PetscErrorCode MatDestroy(Mat *A)
1476 {
1477   PetscFunctionBegin;
1478   if (!*A) PetscFunctionReturn(PETSC_SUCCESS);
1479   PetscValidHeaderSpecific(*A, MAT_CLASSID, 1);
1480   if (--((PetscObject)*A)->refct > 0) {
1481     *A = NULL;
1482     PetscFunctionReturn(PETSC_SUCCESS);
1483   }
1484 
1485   /* if memory was published with SAWs then destroy it */
1486   PetscCall(PetscObjectSAWsViewOff((PetscObject)*A));
1487   PetscTryTypeMethod(*A, destroy);
1488 
1489   PetscCall(PetscFree((*A)->factorprefix));
1490   PetscCall(PetscFree((*A)->defaultvectype));
1491   PetscCall(PetscFree((*A)->defaultrandtype));
1492   PetscCall(PetscFree((*A)->bsizes));
1493   PetscCall(PetscFree((*A)->solvertype));
1494   for (PetscInt i = 0; i < MAT_FACTOR_NUM_TYPES; i++) PetscCall(PetscFree((*A)->preferredordering[i]));
1495   if ((*A)->redundant && (*A)->redundant->matseq[0] == *A) (*A)->redundant->matseq[0] = NULL;
1496   PetscCall(MatDestroy_Redundant(&(*A)->redundant));
1497   PetscCall(MatProductClear(*A));
1498   PetscCall(MatNullSpaceDestroy(&(*A)->nullsp));
1499   PetscCall(MatNullSpaceDestroy(&(*A)->transnullsp));
1500   PetscCall(MatNullSpaceDestroy(&(*A)->nearnullsp));
1501   PetscCall(MatDestroy(&(*A)->schur));
1502   PetscCall(PetscLayoutDestroy(&(*A)->rmap));
1503   PetscCall(PetscLayoutDestroy(&(*A)->cmap));
1504   PetscCall(PetscHeaderDestroy(A));
1505   PetscFunctionReturn(PETSC_SUCCESS);
1506 }
1507 
1508 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1509 /*@
1510   MatSetValues - Inserts or adds a block of values into a matrix.
1511   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
1512   MUST be called after all calls to `MatSetValues()` have been completed.
1513 
1514   Not Collective
1515 
1516   Input Parameters:
1517 + mat  - the matrix
1518 . v    - a logically two-dimensional array of values
1519 . m    - the number of rows
1520 . idxm - the global indices of the rows
1521 . n    - the number of columns
1522 . idxn - the global indices of the columns
1523 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
1524 
1525   Level: beginner
1526 
1527   Notes:
1528   By default the values, `v`, are stored row-oriented. See `MatSetOption()` for other options.
1529 
1530   Calls to `MatSetValues()` with the `INSERT_VALUES` and `ADD_VALUES`
1531   options cannot be mixed without intervening calls to the assembly
1532   routines.
1533 
1534   `MatSetValues()` uses 0-based row and column numbers in Fortran
1535   as well as in C.
1536 
1537   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
1538   simply ignored. This allows easily inserting element stiffness matrices
1539   with homogeneous Dirichlet boundary conditions that you don't want represented
1540   in the matrix.
1541 
1542   Efficiency Alert:
1543   The routine `MatSetValuesBlocked()` may offer much better efficiency
1544   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1545 
1546   Fortran Notes:
1547   If any of `idxm`, `idxn`, and `v` are scalars pass them using, for example,
1548 .vb
1549   MatSetValues(mat, one, [idxm], one, [idxn], [v], INSERT_VALUES)
1550 .ve
1551 
1552   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
1553 
1554   Developer Note:
1555   This is labeled with C so does not automatically generate Fortran stubs and interfaces
1556   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
1557 
1558 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1559           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1560 @*/
1561 PetscErrorCode MatSetValues(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar v[], InsertMode addv)
1562 {
1563   PetscFunctionBeginHot;
1564   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1565   PetscValidType(mat, 1);
1566   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1567   PetscAssertPointer(idxm, 3);
1568   PetscAssertPointer(idxn, 5);
1569   MatCheckPreallocated(mat, 1);
1570 
1571   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
1572   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
1573 
1574   if (PetscDefined(USE_DEBUG)) {
1575     PetscInt i, j;
1576 
1577     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1578     if (v) {
1579       for (i = 0; i < m; i++) {
1580         for (j = 0; j < n; j++) {
1581           if (mat->erroriffailure && PetscIsInfOrNanScalar(v[i * n + j]))
1582 #if defined(PETSC_USE_COMPLEX)
1583             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]);
1584 #else
1585             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]);
1586 #endif
1587         }
1588       }
1589     }
1590     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);
1591     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);
1592   }
1593 
1594   if (mat->assembled) {
1595     mat->was_assembled = PETSC_TRUE;
1596     mat->assembled     = PETSC_FALSE;
1597   }
1598   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
1599   PetscUseTypeMethod(mat, setvalues, m, idxm, n, idxn, v, addv);
1600   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
1601   PetscFunctionReturn(PETSC_SUCCESS);
1602 }
1603 
1604 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1605 /*@
1606   MatSetValuesIS - Inserts or adds a block of values into a matrix using an `IS` to indicate the rows and columns
1607   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
1608   MUST be called after all calls to `MatSetValues()` have been completed.
1609 
1610   Not Collective
1611 
1612   Input Parameters:
1613 + mat  - the matrix
1614 . v    - a logically two-dimensional array of values
1615 . ism  - the rows to provide
1616 . isn  - the columns to provide
1617 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
1618 
1619   Level: beginner
1620 
1621   Notes:
1622   By default the values, `v`, are stored row-oriented. See `MatSetOption()` for other options.
1623 
1624   Calls to `MatSetValues()` with the `INSERT_VALUES` and `ADD_VALUES`
1625   options cannot be mixed without intervening calls to the assembly
1626   routines.
1627 
1628   `MatSetValues()` uses 0-based row and column numbers in Fortran
1629   as well as in C.
1630 
1631   Negative indices may be passed in `ism` and `isn`, these rows and columns are
1632   simply ignored. This allows easily inserting element stiffness matrices
1633   with homogeneous Dirichlet boundary conditions that you don't want represented
1634   in the matrix.
1635 
1636   Efficiency Alert:
1637   The routine `MatSetValuesBlocked()` may offer much better efficiency
1638   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1639 
1640   This is currently not optimized for any particular `ISType`
1641 
1642   Developer Note:
1643   This is labeled with C so does not automatically generate Fortran stubs and interfaces
1644   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
1645 
1646 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatSetValues()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1647           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1648 @*/
1649 PetscErrorCode MatSetValuesIS(Mat mat, IS ism, IS isn, const PetscScalar v[], InsertMode addv)
1650 {
1651   PetscInt        m, n;
1652   const PetscInt *rows, *cols;
1653 
1654   PetscFunctionBeginHot;
1655   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1656   PetscCall(ISGetIndices(ism, &rows));
1657   PetscCall(ISGetIndices(isn, &cols));
1658   PetscCall(ISGetLocalSize(ism, &m));
1659   PetscCall(ISGetLocalSize(isn, &n));
1660   PetscCall(MatSetValues(mat, m, rows, n, cols, v, addv));
1661   PetscCall(ISRestoreIndices(ism, &rows));
1662   PetscCall(ISRestoreIndices(isn, &cols));
1663   PetscFunctionReturn(PETSC_SUCCESS);
1664 }
1665 
1666 /*@
1667   MatSetValuesRowLocal - Inserts a row (block row for `MATBAIJ` matrices) of nonzero
1668   values into a matrix
1669 
1670   Not Collective
1671 
1672   Input Parameters:
1673 + mat - the matrix
1674 . row - the (block) row to set
1675 - v   - a logically two-dimensional array of values
1676 
1677   Level: intermediate
1678 
1679   Notes:
1680   The values, `v`, are column-oriented (for the block version) and sorted
1681 
1682   All the nonzero values in `row` must be provided
1683 
1684   The matrix must have previously had its column indices set, likely by having been assembled.
1685 
1686   `row` must belong to this MPI process
1687 
1688 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1689           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`, `MatSetValues()`, `MatSetValuesRow()`, `MatSetLocalToGlobalMapping()`
1690 @*/
1691 PetscErrorCode MatSetValuesRowLocal(Mat mat, PetscInt row, const PetscScalar v[])
1692 {
1693   PetscInt globalrow;
1694 
1695   PetscFunctionBegin;
1696   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1697   PetscValidType(mat, 1);
1698   PetscAssertPointer(v, 3);
1699   PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, 1, &row, &globalrow));
1700   PetscCall(MatSetValuesRow(mat, globalrow, v));
1701   PetscFunctionReturn(PETSC_SUCCESS);
1702 }
1703 
1704 /*@
1705   MatSetValuesRow - Inserts a row (block row for `MATBAIJ` matrices) of nonzero
1706   values into a matrix
1707 
1708   Not Collective
1709 
1710   Input Parameters:
1711 + mat - the matrix
1712 . row - the (block) row to set
1713 - 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
1714 
1715   Level: advanced
1716 
1717   Notes:
1718   The values, `v`, are column-oriented for the block version.
1719 
1720   All the nonzeros in `row` must be provided
1721 
1722   THE MATRIX MUST HAVE PREVIOUSLY HAD ITS COLUMN INDICES SET. IT IS RARE THAT THIS ROUTINE IS USED, usually `MatSetValues()` is used.
1723 
1724   `row` must belong to this process
1725 
1726 .seealso: [](ch_matrices), `Mat`, `MatSetValues()`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1727           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1728 @*/
1729 PetscErrorCode MatSetValuesRow(Mat mat, PetscInt row, const PetscScalar v[])
1730 {
1731   PetscFunctionBeginHot;
1732   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1733   PetscValidType(mat, 1);
1734   MatCheckPreallocated(mat, 1);
1735   PetscAssertPointer(v, 3);
1736   PetscCheck(mat->insertmode != ADD_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add and insert values");
1737   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1738   mat->insertmode = INSERT_VALUES;
1739 
1740   if (mat->assembled) {
1741     mat->was_assembled = PETSC_TRUE;
1742     mat->assembled     = PETSC_FALSE;
1743   }
1744   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
1745   PetscUseTypeMethod(mat, setvaluesrow, row, v);
1746   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
1747   PetscFunctionReturn(PETSC_SUCCESS);
1748 }
1749 
1750 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1751 /*@
1752   MatSetValuesStencil - Inserts or adds a block of values into a matrix.
1753   Using structured grid indexing
1754 
1755   Not Collective
1756 
1757   Input Parameters:
1758 + mat  - the matrix
1759 . m    - number of rows being entered
1760 . idxm - grid coordinates (and component number when dof > 1) for matrix rows being entered
1761 . n    - number of columns being entered
1762 . idxn - grid coordinates (and component number when dof > 1) for matrix columns being entered
1763 . v    - a logically two-dimensional array of values
1764 - addv - either `ADD_VALUES` to add to existing entries at that location or `INSERT_VALUES` to replace existing entries with new values
1765 
1766   Level: beginner
1767 
1768   Notes:
1769   By default the values, `v`, are row-oriented.  See `MatSetOption()` for other options.
1770 
1771   Calls to `MatSetValuesStencil()` with the `INSERT_VALUES` and `ADD_VALUES`
1772   options cannot be mixed without intervening calls to the assembly
1773   routines.
1774 
1775   The grid coordinates are across the entire grid, not just the local portion
1776 
1777   `MatSetValuesStencil()` uses 0-based row and column numbers in Fortran
1778   as well as in C.
1779 
1780   For setting/accessing vector values via array coordinates you can use the `DMDAVecGetArray()` routine
1781 
1782   In order to use this routine you must either obtain the matrix with `DMCreateMatrix()`
1783   or call `MatSetLocalToGlobalMapping()` and `MatSetStencil()` first.
1784 
1785   The columns and rows in the stencil passed in MUST be contained within the
1786   ghost region of the given process as set with DMDACreateXXX() or `MatSetStencil()`. For example,
1787   if you create a `DMDA` with an overlap of one grid level and on a particular process its first
1788   local nonghost x logical coordinate is 6 (so its first ghost x logical coordinate is 5) the
1789   first i index you can use in your column and row indices in `MatSetStencil()` is 5.
1790 
1791   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
1792   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
1793   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
1794   `DM_BOUNDARY_PERIODIC` boundary type.
1795 
1796   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
1797   a single value per point) you can skip filling those indices.
1798 
1799   Inspired by the structured grid interface to the HYPRE package
1800   (https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods)
1801 
1802   Efficiency Alert:
1803   The routine `MatSetValuesBlockedStencil()` may offer much better efficiency
1804   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1805 
1806 .seealso: [](ch_matrices), `Mat`, `DMDA`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1807           `MatSetValues()`, `MatSetValuesBlockedStencil()`, `MatSetStencil()`, `DMCreateMatrix()`, `DMDAVecGetArray()`, `MatStencil`
1808 @*/
1809 PetscErrorCode MatSetValuesStencil(Mat mat, PetscInt m, const MatStencil idxm[], PetscInt n, const MatStencil idxn[], const PetscScalar v[], InsertMode addv)
1810 {
1811   PetscInt  buf[8192], *bufm = NULL, *bufn = NULL, *jdxm, *jdxn;
1812   PetscInt  j, i, dim = mat->stencil.dim, *dims = mat->stencil.dims + 1, tmp;
1813   PetscInt *starts = mat->stencil.starts, *dxm = (PetscInt *)idxm, *dxn = (PetscInt *)idxn, sdim = dim - (1 - (PetscInt)mat->stencil.noc);
1814 
1815   PetscFunctionBegin;
1816   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1817   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1818   PetscValidType(mat, 1);
1819   PetscAssertPointer(idxm, 3);
1820   PetscAssertPointer(idxn, 5);
1821 
1822   if ((m + n) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
1823     jdxm = buf;
1824     jdxn = buf + m;
1825   } else {
1826     PetscCall(PetscMalloc2(m, &bufm, n, &bufn));
1827     jdxm = bufm;
1828     jdxn = bufn;
1829   }
1830   for (i = 0; i < m; i++) {
1831     for (j = 0; j < 3 - sdim; j++) dxm++;
1832     tmp = *dxm++ - starts[0];
1833     for (j = 0; j < dim - 1; j++) {
1834       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1835       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
1836     }
1837     if (mat->stencil.noc) dxm++;
1838     jdxm[i] = tmp;
1839   }
1840   for (i = 0; i < n; i++) {
1841     for (j = 0; j < 3 - sdim; j++) dxn++;
1842     tmp = *dxn++ - starts[0];
1843     for (j = 0; j < dim - 1; j++) {
1844       if ((*dxn++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1845       else tmp = tmp * dims[j] + *(dxn - 1) - starts[j + 1];
1846     }
1847     if (mat->stencil.noc) dxn++;
1848     jdxn[i] = tmp;
1849   }
1850   PetscCall(MatSetValuesLocal(mat, m, jdxm, n, jdxn, v, addv));
1851   PetscCall(PetscFree2(bufm, bufn));
1852   PetscFunctionReturn(PETSC_SUCCESS);
1853 }
1854 
1855 /*@
1856   MatSetValuesBlockedStencil - Inserts or adds a block of values into a matrix.
1857   Using structured grid indexing
1858 
1859   Not Collective
1860 
1861   Input Parameters:
1862 + mat  - the matrix
1863 . m    - number of rows being entered
1864 . idxm - grid coordinates for matrix rows being entered
1865 . n    - number of columns being entered
1866 . idxn - grid coordinates for matrix columns being entered
1867 . v    - a logically two-dimensional array of values
1868 - addv - either `ADD_VALUES` to add to existing entries or `INSERT_VALUES` to replace existing entries with new values
1869 
1870   Level: beginner
1871 
1872   Notes:
1873   By default the values, `v`, are row-oriented and unsorted.
1874   See `MatSetOption()` for other options.
1875 
1876   Calls to `MatSetValuesBlockedStencil()` with the `INSERT_VALUES` and `ADD_VALUES`
1877   options cannot be mixed without intervening calls to the assembly
1878   routines.
1879 
1880   The grid coordinates are across the entire grid, not just the local portion
1881 
1882   `MatSetValuesBlockedStencil()` uses 0-based row and column numbers in Fortran
1883   as well as in C.
1884 
1885   For setting/accessing vector values via array coordinates you can use the `DMDAVecGetArray()` routine
1886 
1887   In order to use this routine you must either obtain the matrix with `DMCreateMatrix()`
1888   or call `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()` and `MatSetStencil()` first.
1889 
1890   The columns and rows in the stencil passed in MUST be contained within the
1891   ghost region of the given process as set with DMDACreateXXX() or `MatSetStencil()`. For example,
1892   if you create a `DMDA` with an overlap of one grid level and on a particular process its first
1893   local nonghost x logical coordinate is 6 (so its first ghost x logical coordinate is 5) the
1894   first i index you can use in your column and row indices in `MatSetStencil()` is 5.
1895 
1896   Negative indices may be passed in idxm and idxn, these rows and columns are
1897   simply ignored. This allows easily inserting element stiffness matrices
1898   with homogeneous Dirichlet boundary conditions that you don't want represented
1899   in the matrix.
1900 
1901   Inspired by the structured grid interface to the HYPRE package
1902   (https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods)
1903 
1904   Fortran Note:
1905   `idxm` and `idxn` should be declared as
1906 $     MatStencil idxm(4,m),idxn(4,n)
1907   and the values inserted using
1908 .vb
1909     idxm(MatStencil_i,1) = i
1910     idxm(MatStencil_j,1) = j
1911     idxm(MatStencil_k,1) = k
1912    etc
1913 .ve
1914 
1915 .seealso: [](ch_matrices), `Mat`, `DMDA`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1916           `MatSetValues()`, `MatSetValuesStencil()`, `MatSetStencil()`, `DMCreateMatrix()`, `DMDAVecGetArray()`, `MatStencil`,
1917           `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()`
1918 @*/
1919 PetscErrorCode MatSetValuesBlockedStencil(Mat mat, PetscInt m, const MatStencil idxm[], PetscInt n, const MatStencil idxn[], const PetscScalar v[], InsertMode addv)
1920 {
1921   PetscInt  buf[8192], *bufm = NULL, *bufn = NULL, *jdxm, *jdxn;
1922   PetscInt  j, i, dim = mat->stencil.dim, *dims = mat->stencil.dims + 1, tmp;
1923   PetscInt *starts = mat->stencil.starts, *dxm = (PetscInt *)idxm, *dxn = (PetscInt *)idxn, sdim = dim - (1 - (PetscInt)mat->stencil.noc);
1924 
1925   PetscFunctionBegin;
1926   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1927   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1928   PetscValidType(mat, 1);
1929   PetscAssertPointer(idxm, 3);
1930   PetscAssertPointer(idxn, 5);
1931   PetscAssertPointer(v, 6);
1932 
1933   if ((m + n) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
1934     jdxm = buf;
1935     jdxn = buf + m;
1936   } else {
1937     PetscCall(PetscMalloc2(m, &bufm, n, &bufn));
1938     jdxm = bufm;
1939     jdxn = bufn;
1940   }
1941   for (i = 0; i < m; i++) {
1942     for (j = 0; j < 3 - sdim; j++) dxm++;
1943     tmp = *dxm++ - starts[0];
1944     for (j = 0; j < sdim - 1; j++) {
1945       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1946       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
1947     }
1948     dxm++;
1949     jdxm[i] = tmp;
1950   }
1951   for (i = 0; i < n; i++) {
1952     for (j = 0; j < 3 - sdim; j++) dxn++;
1953     tmp = *dxn++ - starts[0];
1954     for (j = 0; j < sdim - 1; j++) {
1955       if ((*dxn++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1956       else tmp = tmp * dims[j] + *(dxn - 1) - starts[j + 1];
1957     }
1958     dxn++;
1959     jdxn[i] = tmp;
1960   }
1961   PetscCall(MatSetValuesBlockedLocal(mat, m, jdxm, n, jdxn, v, addv));
1962   PetscCall(PetscFree2(bufm, bufn));
1963   PetscFunctionReturn(PETSC_SUCCESS);
1964 }
1965 
1966 /*@
1967   MatSetStencil - Sets the grid information for setting values into a matrix via
1968   `MatSetValuesStencil()`
1969 
1970   Not Collective
1971 
1972   Input Parameters:
1973 + mat    - the matrix
1974 . dim    - dimension of the grid 1, 2, or 3
1975 . dims   - number of grid points in x, y, and z direction, including ghost points on your processor
1976 . starts - starting point of ghost nodes on your processor in x, y, and z direction
1977 - dof    - number of degrees of freedom per node
1978 
1979   Level: beginner
1980 
1981   Notes:
1982   Inspired by the structured grid interface to the HYPRE package
1983   (www.llnl.gov/CASC/hyper)
1984 
1985   For matrices generated with `DMCreateMatrix()` this routine is automatically called and so not needed by the
1986   user.
1987 
1988 .seealso: [](ch_matrices), `Mat`, `MatStencil`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1989           `MatSetValues()`, `MatSetValuesBlockedStencil()`, `MatSetValuesStencil()`
1990 @*/
1991 PetscErrorCode MatSetStencil(Mat mat, PetscInt dim, const PetscInt dims[], const PetscInt starts[], PetscInt dof)
1992 {
1993   PetscFunctionBegin;
1994   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1995   PetscAssertPointer(dims, 3);
1996   PetscAssertPointer(starts, 4);
1997 
1998   mat->stencil.dim = dim + (dof > 1);
1999   for (PetscInt i = 0; i < dim; i++) {
2000     mat->stencil.dims[i]   = dims[dim - i - 1]; /* copy the values in backwards */
2001     mat->stencil.starts[i] = starts[dim - i - 1];
2002   }
2003   mat->stencil.dims[dim]   = dof;
2004   mat->stencil.starts[dim] = 0;
2005   mat->stencil.noc         = (PetscBool)(dof == 1);
2006   PetscFunctionReturn(PETSC_SUCCESS);
2007 }
2008 
2009 /*@
2010   MatSetValuesBlocked - Inserts or adds a block of values into a matrix.
2011 
2012   Not Collective
2013 
2014   Input Parameters:
2015 + mat  - the matrix
2016 . v    - a logically two-dimensional array of values
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 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` replaces existing entries with new values
2022 
2023   Level: intermediate
2024 
2025   Notes:
2026   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call
2027   MatXXXXSetPreallocation() or `MatSetUp()` before using this routine.
2028 
2029   The `m` and `n` count the NUMBER of blocks in the row direction and column direction,
2030   NOT the total number of rows/columns; for example, if the block size is 2 and
2031   you are passing in values for rows 2,3,4,5  then `m` would be 2 (not 4).
2032   The values in `idxm` would be 1 2; that is the first index for each block divided by
2033   the block size.
2034 
2035   You must call `MatSetBlockSize()` when constructing this matrix (before
2036   preallocating it).
2037 
2038   By default the values, `v`, are row-oriented, so the layout of
2039   `v` is the same as for `MatSetValues()`. See `MatSetOption()` for other options.
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   MatSetValuesBlocked(mat, one, [idxm], one, [idxn], [v], INSERT_VALUES)
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   Developer Note:
2227   This is labelled with C so does not automatically generate Fortran stubs and interfaces
2228   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
2229 
2230 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetLocalToGlobalMapping()`,
2231           `MatSetValuesLocal()`, `MatGetValues()`
2232 @*/
2233 PetscErrorCode MatGetValuesLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], PetscScalar y[])
2234 {
2235   PetscFunctionBeginHot;
2236   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2237   PetscValidType(mat, 1);
2238   MatCheckPreallocated(mat, 1);
2239   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to retrieve */
2240   PetscAssertPointer(irow, 3);
2241   PetscAssertPointer(icol, 5);
2242   if (PetscDefined(USE_DEBUG)) {
2243     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2244     PetscCheck(mat->ops->getvalueslocal || mat->ops->getvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2245   }
2246   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2247   PetscCall(PetscLogEventBegin(MAT_GetValues, mat, 0, 0, 0));
2248   if (mat->ops->getvalueslocal) PetscUseTypeMethod(mat, getvalueslocal, nrow, irow, ncol, icol, y);
2249   else {
2250     PetscInt buf[8192], *bufr = NULL, *bufc = NULL, *irowm, *icolm;
2251     if ((nrow + ncol) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2252       irowm = buf;
2253       icolm = buf + nrow;
2254     } else {
2255       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2256       irowm = bufr;
2257       icolm = bufc;
2258     }
2259     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MatGetValuesLocal() cannot proceed without local-to-global row mapping (See MatSetLocalToGlobalMapping()).");
2260     PetscCheck(mat->cmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MatGetValuesLocal() cannot proceed without local-to-global column mapping (See MatSetLocalToGlobalMapping()).");
2261     PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, nrow, irow, irowm));
2262     PetscCall(ISLocalToGlobalMappingApply(mat->cmap->mapping, ncol, icol, icolm));
2263     PetscCall(MatGetValues(mat, nrow, irowm, ncol, icolm, y));
2264     PetscCall(PetscFree2(bufr, bufc));
2265   }
2266   PetscCall(PetscLogEventEnd(MAT_GetValues, mat, 0, 0, 0));
2267   PetscFunctionReturn(PETSC_SUCCESS);
2268 }
2269 
2270 /*@
2271   MatSetValuesBatch - Adds (`ADD_VALUES`) many blocks of values into a matrix at once. The blocks must all be square and
2272   the same size. Currently, this can only be called once and creates the given matrix.
2273 
2274   Not Collective
2275 
2276   Input Parameters:
2277 + mat  - the matrix
2278 . nb   - the number of blocks
2279 . bs   - the number of rows (and columns) in each block
2280 . rows - a concatenation of the rows for each block
2281 - v    - a concatenation of logically two-dimensional arrays of values
2282 
2283   Level: advanced
2284 
2285   Notes:
2286   `MatSetPreallocationCOO()` and `MatSetValuesCOO()` may be a better way to provide the values
2287 
2288   In the future, we will extend this routine to handle rectangular blocks, and to allow multiple calls for a given matrix.
2289 
2290 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
2291           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`, `MatSetValues()`, `MatSetPreallocationCOO()`, `MatSetValuesCOO()`
2292 @*/
2293 PetscErrorCode MatSetValuesBatch(Mat mat, PetscInt nb, PetscInt bs, PetscInt rows[], const PetscScalar v[])
2294 {
2295   PetscFunctionBegin;
2296   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2297   PetscValidType(mat, 1);
2298   PetscAssertPointer(rows, 4);
2299   PetscAssertPointer(v, 5);
2300   PetscAssert(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2301 
2302   PetscCall(PetscLogEventBegin(MAT_SetValuesBatch, mat, 0, 0, 0));
2303   if (mat->ops->setvaluesbatch) PetscUseTypeMethod(mat, setvaluesbatch, nb, bs, rows, v);
2304   else {
2305     for (PetscInt b = 0; b < nb; ++b) PetscCall(MatSetValues(mat, bs, &rows[b * bs], bs, &rows[b * bs], &v[b * bs * bs], ADD_VALUES));
2306   }
2307   PetscCall(PetscLogEventEnd(MAT_SetValuesBatch, mat, 0, 0, 0));
2308   PetscFunctionReturn(PETSC_SUCCESS);
2309 }
2310 
2311 /*@
2312   MatSetLocalToGlobalMapping - Sets a local-to-global numbering for use by
2313   the routine `MatSetValuesLocal()` to allow users to insert matrix entries
2314   using a local (per-processor) numbering.
2315 
2316   Not Collective
2317 
2318   Input Parameters:
2319 + x        - the matrix
2320 . rmapping - row mapping created with `ISLocalToGlobalMappingCreate()` or `ISLocalToGlobalMappingCreateIS()`
2321 - cmapping - column mapping
2322 
2323   Level: intermediate
2324 
2325   Note:
2326   If the matrix is obtained with `DMCreateMatrix()` then this may already have been called on the matrix
2327 
2328 .seealso: [](ch_matrices), `Mat`, `DM`, `DMCreateMatrix()`, `MatGetLocalToGlobalMapping()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetValuesLocal()`, `MatGetValuesLocal()`
2329 @*/
2330 PetscErrorCode MatSetLocalToGlobalMapping(Mat x, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2331 {
2332   PetscFunctionBegin;
2333   PetscValidHeaderSpecific(x, MAT_CLASSID, 1);
2334   PetscValidType(x, 1);
2335   if (rmapping) PetscValidHeaderSpecific(rmapping, IS_LTOGM_CLASSID, 2);
2336   if (cmapping) PetscValidHeaderSpecific(cmapping, IS_LTOGM_CLASSID, 3);
2337   if (x->ops->setlocaltoglobalmapping) PetscUseTypeMethod(x, setlocaltoglobalmapping, rmapping, cmapping);
2338   else {
2339     PetscCall(PetscLayoutSetISLocalToGlobalMapping(x->rmap, rmapping));
2340     PetscCall(PetscLayoutSetISLocalToGlobalMapping(x->cmap, cmapping));
2341   }
2342   PetscFunctionReturn(PETSC_SUCCESS);
2343 }
2344 
2345 /*@
2346   MatGetLocalToGlobalMapping - Gets the local-to-global numbering set by `MatSetLocalToGlobalMapping()`
2347 
2348   Not Collective
2349 
2350   Input Parameter:
2351 . A - the matrix
2352 
2353   Output Parameters:
2354 + rmapping - row mapping
2355 - cmapping - column mapping
2356 
2357   Level: advanced
2358 
2359 .seealso: [](ch_matrices), `Mat`, `MatSetLocalToGlobalMapping()`, `MatSetValuesLocal()`
2360 @*/
2361 PetscErrorCode MatGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
2362 {
2363   PetscFunctionBegin;
2364   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2365   PetscValidType(A, 1);
2366   if (rmapping) {
2367     PetscAssertPointer(rmapping, 2);
2368     *rmapping = A->rmap->mapping;
2369   }
2370   if (cmapping) {
2371     PetscAssertPointer(cmapping, 3);
2372     *cmapping = A->cmap->mapping;
2373   }
2374   PetscFunctionReturn(PETSC_SUCCESS);
2375 }
2376 
2377 /*@
2378   MatSetLayouts - Sets the `PetscLayout` objects for rows and columns of a matrix
2379 
2380   Logically Collective
2381 
2382   Input Parameters:
2383 + A    - the matrix
2384 . rmap - row layout
2385 - cmap - column layout
2386 
2387   Level: advanced
2388 
2389   Note:
2390   The `PetscLayout` objects are usually created automatically for the matrix so this routine rarely needs to be called.
2391 
2392 .seealso: [](ch_matrices), `Mat`, `PetscLayout`, `MatCreateVecs()`, `MatGetLocalToGlobalMapping()`, `MatGetLayouts()`
2393 @*/
2394 PetscErrorCode MatSetLayouts(Mat A, PetscLayout rmap, PetscLayout cmap)
2395 {
2396   PetscFunctionBegin;
2397   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2398   PetscCall(PetscLayoutReference(rmap, &A->rmap));
2399   PetscCall(PetscLayoutReference(cmap, &A->cmap));
2400   PetscFunctionReturn(PETSC_SUCCESS);
2401 }
2402 
2403 /*@
2404   MatGetLayouts - Gets the `PetscLayout` objects for rows and columns
2405 
2406   Not Collective
2407 
2408   Input Parameter:
2409 . A - the matrix
2410 
2411   Output Parameters:
2412 + rmap - row layout
2413 - cmap - column layout
2414 
2415   Level: advanced
2416 
2417 .seealso: [](ch_matrices), `Mat`, [Matrix Layouts](sec_matlayout), `PetscLayout`, `MatCreateVecs()`, `MatGetLocalToGlobalMapping()`, `MatSetLayouts()`
2418 @*/
2419 PetscErrorCode MatGetLayouts(Mat A, PetscLayout *rmap, PetscLayout *cmap)
2420 {
2421   PetscFunctionBegin;
2422   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2423   PetscValidType(A, 1);
2424   if (rmap) {
2425     PetscAssertPointer(rmap, 2);
2426     *rmap = A->rmap;
2427   }
2428   if (cmap) {
2429     PetscAssertPointer(cmap, 3);
2430     *cmap = A->cmap;
2431   }
2432   PetscFunctionReturn(PETSC_SUCCESS);
2433 }
2434 
2435 /*@
2436   MatSetValuesLocal - Inserts or adds values into certain locations of a matrix,
2437   using a local numbering of the rows and columns.
2438 
2439   Not Collective
2440 
2441   Input Parameters:
2442 + mat  - the matrix
2443 . nrow - number of rows
2444 . irow - the row local indices
2445 . ncol - number of columns
2446 . icol - the column local indices
2447 . y    - a logically two-dimensional array of values
2448 - addv - either `INSERT_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
2449 
2450   Level: intermediate
2451 
2452   Notes:
2453   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetLocalToGlobalMapping()` before using this routine
2454 
2455   Calls to `MatSetValuesLocal()` with the `INSERT_VALUES` and `ADD_VALUES`
2456   options cannot be mixed without intervening calls to the assembly
2457   routines.
2458 
2459   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
2460   MUST be called after all calls to `MatSetValuesLocal()` have been completed.
2461 
2462   Fortran Notes:
2463   If any of `irow`, `icol`, and `y` are scalars pass them using, for example,
2464 .vb
2465   MatSetValuesLocal(mat, one, [irow], one, [icol], [y], INSERT_VALUES)
2466 .ve
2467 
2468   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2469 
2470   Developer Note:
2471   This is labeled with C so does not automatically generate Fortran stubs and interfaces
2472   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
2473 
2474 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetLocalToGlobalMapping()`,
2475           `MatGetValuesLocal()`
2476 @*/
2477 PetscErrorCode MatSetValuesLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv)
2478 {
2479   PetscFunctionBeginHot;
2480   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2481   PetscValidType(mat, 1);
2482   MatCheckPreallocated(mat, 1);
2483   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2484   PetscAssertPointer(irow, 3);
2485   PetscAssertPointer(icol, 5);
2486   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2487   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2488   if (PetscDefined(USE_DEBUG)) {
2489     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2490     PetscCheck(mat->ops->setvalueslocal || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2491   }
2492 
2493   if (mat->assembled) {
2494     mat->was_assembled = PETSC_TRUE;
2495     mat->assembled     = PETSC_FALSE;
2496   }
2497   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2498   if (mat->ops->setvalueslocal) PetscUseTypeMethod(mat, setvalueslocal, nrow, irow, ncol, icol, y, addv);
2499   else {
2500     PetscInt        buf[8192], *bufr = NULL, *bufc = NULL;
2501     const PetscInt *irowm, *icolm;
2502 
2503     if ((!mat->rmap->mapping && !mat->cmap->mapping) || (nrow + ncol) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2504       bufr  = buf;
2505       bufc  = buf + nrow;
2506       irowm = bufr;
2507       icolm = bufc;
2508     } else {
2509       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2510       irowm = bufr;
2511       icolm = bufc;
2512     }
2513     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, nrow, irow, bufr));
2514     else irowm = irow;
2515     if (mat->cmap->mapping) {
2516       if (mat->cmap->mapping != mat->rmap->mapping || ncol != nrow || icol != irow) {
2517         PetscCall(ISLocalToGlobalMappingApply(mat->cmap->mapping, ncol, icol, bufc));
2518       } else icolm = irowm;
2519     } else icolm = icol;
2520     PetscCall(MatSetValues(mat, nrow, irowm, ncol, icolm, y, addv));
2521     if (bufr != buf) PetscCall(PetscFree2(bufr, bufc));
2522   }
2523   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2524   PetscFunctionReturn(PETSC_SUCCESS);
2525 }
2526 
2527 /*@
2528   MatSetValuesBlockedLocal - Inserts or adds values into certain locations of a matrix,
2529   using a local ordering of the nodes a block at a time.
2530 
2531   Not Collective
2532 
2533   Input Parameters:
2534 + mat  - the matrix
2535 . nrow - number of rows
2536 . irow - the row local indices
2537 . ncol - number of columns
2538 . icol - the column local indices
2539 . y    - a logically two-dimensional array of values
2540 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
2541 
2542   Level: intermediate
2543 
2544   Notes:
2545   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetBlockSize()` and `MatSetLocalToGlobalMapping()`
2546   before using this routineBefore calling `MatSetValuesLocal()`, the user must first set the
2547 
2548   Calls to `MatSetValuesBlockedLocal()` with the `INSERT_VALUES` and `ADD_VALUES`
2549   options cannot be mixed without intervening calls to the assembly
2550   routines.
2551 
2552   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
2553   MUST be called after all calls to `MatSetValuesBlockedLocal()` have been completed.
2554 
2555   Fortran Notes:
2556   If any of `irow`, `icol`, and `y` are scalars pass them using, for example,
2557 .vb
2558   MatSetValuesBlockedLocal(mat, one, [irow], one, [icol], [y], INSERT_VALUES)
2559 .ve
2560 
2561   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2562 
2563   Developer Note:
2564   This is labeled with C so does not automatically generate Fortran stubs and interfaces
2565   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
2566 
2567 .seealso: [](ch_matrices), `Mat`, `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`,
2568           `MatSetValuesLocal()`, `MatSetValuesBlocked()`
2569 @*/
2570 PetscErrorCode MatSetValuesBlockedLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv)
2571 {
2572   PetscFunctionBeginHot;
2573   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2574   PetscValidType(mat, 1);
2575   MatCheckPreallocated(mat, 1);
2576   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2577   PetscAssertPointer(irow, 3);
2578   PetscAssertPointer(icol, 5);
2579   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2580   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2581   if (PetscDefined(USE_DEBUG)) {
2582     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2583     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);
2584   }
2585 
2586   if (mat->assembled) {
2587     mat->was_assembled = PETSC_TRUE;
2588     mat->assembled     = PETSC_FALSE;
2589   }
2590   if (PetscUnlikelyDebug(mat->rmap->mapping)) { /* Condition on the mapping existing, because MatSetValuesBlockedLocal_IS does not require it to be set. */
2591     PetscInt irbs, rbs;
2592     PetscCall(MatGetBlockSizes(mat, &rbs, NULL));
2593     PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &irbs));
2594     PetscCheck(rbs == irbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Different row block sizes! mat %" PetscInt_FMT ", row l2g map %" PetscInt_FMT, rbs, irbs);
2595   }
2596   if (PetscUnlikelyDebug(mat->cmap->mapping)) {
2597     PetscInt icbs, cbs;
2598     PetscCall(MatGetBlockSizes(mat, NULL, &cbs));
2599     PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &icbs));
2600     PetscCheck(cbs == icbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Different col block sizes! mat %" PetscInt_FMT ", col l2g map %" PetscInt_FMT, cbs, icbs);
2601   }
2602   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2603   if (mat->ops->setvaluesblockedlocal) PetscUseTypeMethod(mat, setvaluesblockedlocal, nrow, irow, ncol, icol, y, addv);
2604   else {
2605     PetscInt        buf[8192], *bufr = NULL, *bufc = NULL;
2606     const PetscInt *irowm, *icolm;
2607 
2608     if ((!mat->rmap->mapping && !mat->cmap->mapping) || (nrow + ncol) <= ((PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf))) {
2609       bufr  = buf;
2610       bufc  = buf + nrow;
2611       irowm = bufr;
2612       icolm = bufc;
2613     } else {
2614       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2615       irowm = bufr;
2616       icolm = bufc;
2617     }
2618     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingApplyBlock(mat->rmap->mapping, nrow, irow, bufr));
2619     else irowm = irow;
2620     if (mat->cmap->mapping) {
2621       if (mat->cmap->mapping != mat->rmap->mapping || ncol != nrow || icol != irow) {
2622         PetscCall(ISLocalToGlobalMappingApplyBlock(mat->cmap->mapping, ncol, icol, bufc));
2623       } else icolm = irowm;
2624     } else icolm = icol;
2625     PetscCall(MatSetValuesBlocked(mat, nrow, irowm, ncol, icolm, y, addv));
2626     if (bufr != buf) PetscCall(PetscFree2(bufr, bufc));
2627   }
2628   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2629   PetscFunctionReturn(PETSC_SUCCESS);
2630 }
2631 
2632 /*@
2633   MatMultDiagonalBlock - Computes the matrix-vector product, $y = Dx$. Where `D` is defined by the inode or block structure of the diagonal
2634 
2635   Collective
2636 
2637   Input Parameters:
2638 + mat - the matrix
2639 - x   - the vector to be multiplied
2640 
2641   Output Parameter:
2642 . y - the result
2643 
2644   Level: developer
2645 
2646   Note:
2647   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2648   call `MatMultDiagonalBlock`(A,y,y).
2649 
2650 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
2651 @*/
2652 PetscErrorCode MatMultDiagonalBlock(Mat mat, Vec x, Vec y)
2653 {
2654   PetscFunctionBegin;
2655   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2656   PetscValidType(mat, 1);
2657   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2658   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2659 
2660   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2661   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2662   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2663   MatCheckPreallocated(mat, 1);
2664 
2665   PetscUseTypeMethod(mat, multdiagonalblock, x, y);
2666   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2667   PetscFunctionReturn(PETSC_SUCCESS);
2668 }
2669 
2670 /*@
2671   MatMult - Computes the matrix-vector product, $y = Ax$.
2672 
2673   Neighbor-wise Collective
2674 
2675   Input Parameters:
2676 + mat - the matrix
2677 - x   - the vector to be multiplied
2678 
2679   Output Parameter:
2680 . y - the result
2681 
2682   Level: beginner
2683 
2684   Note:
2685   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2686   call `MatMult`(A,y,y).
2687 
2688 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
2689 @*/
2690 PetscErrorCode MatMult(Mat mat, Vec x, Vec y)
2691 {
2692   PetscFunctionBegin;
2693   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2694   PetscValidType(mat, 1);
2695   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2696   VecCheckAssembled(x);
2697   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2698   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2699   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2700   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2701   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);
2702   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);
2703   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);
2704   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);
2705   PetscCall(VecSetErrorIfLocked(y, 3));
2706   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2707   MatCheckPreallocated(mat, 1);
2708 
2709   PetscCall(VecLockReadPush(x));
2710   PetscCall(PetscLogEventBegin(MAT_Mult, mat, x, y, 0));
2711   PetscUseTypeMethod(mat, mult, x, y);
2712   PetscCall(PetscLogEventEnd(MAT_Mult, mat, x, y, 0));
2713   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(y, 3, PETSC_FALSE));
2714   PetscCall(VecLockReadPop(x));
2715   PetscFunctionReturn(PETSC_SUCCESS);
2716 }
2717 
2718 /*@
2719   MatMultTranspose - Computes matrix transpose times a vector $y = A^T * x$.
2720 
2721   Neighbor-wise Collective
2722 
2723   Input Parameters:
2724 + mat - the matrix
2725 - x   - the vector to be multiplied
2726 
2727   Output Parameter:
2728 . y - the result
2729 
2730   Level: beginner
2731 
2732   Notes:
2733   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2734   call `MatMultTranspose`(A,y,y).
2735 
2736   For complex numbers this does NOT compute the Hermitian (complex conjugate) transpose multiple,
2737   use `MatMultHermitianTranspose()`
2738 
2739 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatMultHermitianTranspose()`, `MatTranspose()`
2740 @*/
2741 PetscErrorCode MatMultTranspose(Mat mat, Vec x, Vec y)
2742 {
2743   PetscErrorCode (*op)(Mat, Vec, Vec) = NULL;
2744 
2745   PetscFunctionBegin;
2746   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2747   PetscValidType(mat, 1);
2748   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2749   VecCheckAssembled(x);
2750   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2751 
2752   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2753   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2754   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2755   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);
2756   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);
2757   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);
2758   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);
2759   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2760   MatCheckPreallocated(mat, 1);
2761 
2762   if (!mat->ops->multtranspose) {
2763     if (mat->symmetric == PETSC_BOOL3_TRUE && mat->ops->mult) op = mat->ops->mult;
2764     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);
2765   } else op = mat->ops->multtranspose;
2766   PetscCall(PetscLogEventBegin(MAT_MultTranspose, mat, x, y, 0));
2767   PetscCall(VecLockReadPush(x));
2768   PetscCall((*op)(mat, x, y));
2769   PetscCall(VecLockReadPop(x));
2770   PetscCall(PetscLogEventEnd(MAT_MultTranspose, mat, x, y, 0));
2771   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2772   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(y, 3, PETSC_FALSE));
2773   PetscFunctionReturn(PETSC_SUCCESS);
2774 }
2775 
2776 /*@
2777   MatMultHermitianTranspose - Computes matrix Hermitian-transpose times a vector $y = A^H * x$.
2778 
2779   Neighbor-wise Collective
2780 
2781   Input Parameters:
2782 + mat - the matrix
2783 - x   - the vector to be multiplied
2784 
2785   Output Parameter:
2786 . y - the result
2787 
2788   Level: beginner
2789 
2790   Notes:
2791   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2792   call `MatMultHermitianTranspose`(A,y,y).
2793 
2794   Also called the conjugate transpose, complex conjugate transpose, or adjoint.
2795 
2796   For real numbers `MatMultTranspose()` and `MatMultHermitianTranspose()` are identical.
2797 
2798 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `MatMultHermitianTransposeAdd()`, `MatMultTranspose()`
2799 @*/
2800 PetscErrorCode MatMultHermitianTranspose(Mat mat, Vec x, Vec y)
2801 {
2802   PetscFunctionBegin;
2803   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2804   PetscValidType(mat, 1);
2805   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2806   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2807 
2808   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2809   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2810   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2811   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);
2812   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);
2813   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);
2814   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);
2815   MatCheckPreallocated(mat, 1);
2816 
2817   PetscCall(PetscLogEventBegin(MAT_MultHermitianTranspose, mat, x, y, 0));
2818 #if defined(PETSC_USE_COMPLEX)
2819   if (mat->ops->multhermitiantranspose || (mat->hermitian == PETSC_BOOL3_TRUE && mat->ops->mult)) {
2820     PetscCall(VecLockReadPush(x));
2821     if (mat->ops->multhermitiantranspose) PetscUseTypeMethod(mat, multhermitiantranspose, x, y);
2822     else PetscUseTypeMethod(mat, mult, x, y);
2823     PetscCall(VecLockReadPop(x));
2824   } else {
2825     Vec w;
2826     PetscCall(VecDuplicate(x, &w));
2827     PetscCall(VecCopy(x, w));
2828     PetscCall(VecConjugate(w));
2829     PetscCall(MatMultTranspose(mat, w, y));
2830     PetscCall(VecDestroy(&w));
2831     PetscCall(VecConjugate(y));
2832   }
2833   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2834 #else
2835   PetscCall(MatMultTranspose(mat, x, y));
2836 #endif
2837   PetscCall(PetscLogEventEnd(MAT_MultHermitianTranspose, mat, x, y, 0));
2838   PetscFunctionReturn(PETSC_SUCCESS);
2839 }
2840 
2841 /*@
2842   MatMultAdd -  Computes $v3 = v2 + A * v1$.
2843 
2844   Neighbor-wise Collective
2845 
2846   Input Parameters:
2847 + mat - the matrix
2848 . v1  - the vector to be multiplied by `mat`
2849 - v2  - the vector to be added to the result
2850 
2851   Output Parameter:
2852 . v3 - the result
2853 
2854   Level: beginner
2855 
2856   Note:
2857   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2858   call `MatMultAdd`(A,v1,v2,v1).
2859 
2860 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMult()`, `MatMultTransposeAdd()`
2861 @*/
2862 PetscErrorCode MatMultAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2863 {
2864   PetscFunctionBegin;
2865   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2866   PetscValidType(mat, 1);
2867   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2868   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2869   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2870 
2871   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2872   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2873   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);
2874   /* 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);
2875      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); */
2876   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);
2877   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);
2878   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2879   MatCheckPreallocated(mat, 1);
2880 
2881   PetscCall(PetscLogEventBegin(MAT_MultAdd, mat, v1, v2, v3));
2882   PetscCall(VecLockReadPush(v1));
2883   PetscUseTypeMethod(mat, multadd, v1, v2, v3);
2884   PetscCall(VecLockReadPop(v1));
2885   PetscCall(PetscLogEventEnd(MAT_MultAdd, mat, v1, v2, v3));
2886   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2887   PetscFunctionReturn(PETSC_SUCCESS);
2888 }
2889 
2890 /*@
2891   MatMultTransposeAdd - Computes $v3 = v2 + A^T * v1$.
2892 
2893   Neighbor-wise Collective
2894 
2895   Input Parameters:
2896 + mat - the matrix
2897 . v1  - the vector to be multiplied by the transpose of the matrix
2898 - v2  - the vector to be added to the result
2899 
2900   Output Parameter:
2901 . v3 - the result
2902 
2903   Level: beginner
2904 
2905   Note:
2906   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2907   call `MatMultTransposeAdd`(A,v1,v2,v1).
2908 
2909 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMult()`
2910 @*/
2911 PetscErrorCode MatMultTransposeAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2912 {
2913   PetscErrorCode (*op)(Mat, Vec, Vec, Vec) = (!mat->ops->multtransposeadd && mat->symmetric) ? mat->ops->multadd : mat->ops->multtransposeadd;
2914 
2915   PetscFunctionBegin;
2916   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2917   PetscValidType(mat, 1);
2918   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2919   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2920   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2921 
2922   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2923   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2924   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);
2925   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);
2926   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);
2927   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2928   PetscCheck(op, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2929   MatCheckPreallocated(mat, 1);
2930 
2931   PetscCall(PetscLogEventBegin(MAT_MultTransposeAdd, mat, v1, v2, v3));
2932   PetscCall(VecLockReadPush(v1));
2933   PetscCall((*op)(mat, v1, v2, v3));
2934   PetscCall(VecLockReadPop(v1));
2935   PetscCall(PetscLogEventEnd(MAT_MultTransposeAdd, mat, v1, v2, v3));
2936   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2937   PetscFunctionReturn(PETSC_SUCCESS);
2938 }
2939 
2940 /*@
2941   MatMultHermitianTransposeAdd - Computes $v3 = v2 + A^H * v1$.
2942 
2943   Neighbor-wise Collective
2944 
2945   Input Parameters:
2946 + mat - the matrix
2947 . v1  - the vector to be multiplied by the Hermitian transpose
2948 - v2  - the vector to be added to the result
2949 
2950   Output Parameter:
2951 . v3 - the result
2952 
2953   Level: beginner
2954 
2955   Note:
2956   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2957   call `MatMultHermitianTransposeAdd`(A,v1,v2,v1).
2958 
2959 .seealso: [](ch_matrices), `Mat`, `MatMultHermitianTranspose()`, `MatMultTranspose()`, `MatMultAdd()`, `MatMult()`
2960 @*/
2961 PetscErrorCode MatMultHermitianTransposeAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2962 {
2963   PetscFunctionBegin;
2964   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2965   PetscValidType(mat, 1);
2966   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2967   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2968   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2969 
2970   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2971   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2972   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2973   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);
2974   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);
2975   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);
2976   MatCheckPreallocated(mat, 1);
2977 
2978   PetscCall(PetscLogEventBegin(MAT_MultHermitianTransposeAdd, mat, v1, v2, v3));
2979   PetscCall(VecLockReadPush(v1));
2980   if (mat->ops->multhermitiantransposeadd) PetscUseTypeMethod(mat, multhermitiantransposeadd, v1, v2, v3);
2981   else {
2982     Vec w, z;
2983     PetscCall(VecDuplicate(v1, &w));
2984     PetscCall(VecCopy(v1, w));
2985     PetscCall(VecConjugate(w));
2986     PetscCall(VecDuplicate(v3, &z));
2987     PetscCall(MatMultTranspose(mat, w, z));
2988     PetscCall(VecDestroy(&w));
2989     PetscCall(VecConjugate(z));
2990     if (v2 != v3) {
2991       PetscCall(VecWAXPY(v3, 1.0, v2, z));
2992     } else {
2993       PetscCall(VecAXPY(v3, 1.0, z));
2994     }
2995     PetscCall(VecDestroy(&z));
2996   }
2997   PetscCall(VecLockReadPop(v1));
2998   PetscCall(PetscLogEventEnd(MAT_MultHermitianTransposeAdd, mat, v1, v2, v3));
2999   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
3000   PetscFunctionReturn(PETSC_SUCCESS);
3001 }
3002 
3003 /*@
3004   MatGetFactorType - gets the type of factorization a matrix is
3005 
3006   Not Collective
3007 
3008   Input Parameter:
3009 . mat - the matrix
3010 
3011   Output Parameter:
3012 . 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`
3013 
3014   Level: intermediate
3015 
3016 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatGetFactor()`, `MatSetFactorType()`, `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`,
3017           `MAT_FACTOR_ICC`,`MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3018 @*/
3019 PetscErrorCode MatGetFactorType(Mat mat, MatFactorType *t)
3020 {
3021   PetscFunctionBegin;
3022   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3023   PetscValidType(mat, 1);
3024   PetscAssertPointer(t, 2);
3025   *t = mat->factortype;
3026   PetscFunctionReturn(PETSC_SUCCESS);
3027 }
3028 
3029 /*@
3030   MatSetFactorType - sets the type of factorization a matrix is
3031 
3032   Logically Collective
3033 
3034   Input Parameters:
3035 + mat - the matrix
3036 - 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`
3037 
3038   Level: intermediate
3039 
3040 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatGetFactor()`, `MatGetFactorType()`, `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`,
3041           `MAT_FACTOR_ICC`,`MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3042 @*/
3043 PetscErrorCode MatSetFactorType(Mat mat, MatFactorType t)
3044 {
3045   PetscFunctionBegin;
3046   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3047   PetscValidType(mat, 1);
3048   mat->factortype = t;
3049   PetscFunctionReturn(PETSC_SUCCESS);
3050 }
3051 
3052 /*@
3053   MatGetInfo - Returns information about matrix storage (number of
3054   nonzeros, memory, etc.).
3055 
3056   Collective if `MAT_GLOBAL_MAX` or `MAT_GLOBAL_SUM` is used as the flag
3057 
3058   Input Parameters:
3059 + mat  - the matrix
3060 - 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)
3061 
3062   Output Parameter:
3063 . info - matrix information context
3064 
3065   Options Database Key:
3066 . -mat_view ::ascii_info - print matrix info to `PETSC_STDOUT`
3067 
3068   Level: intermediate
3069 
3070   Notes:
3071   The `MatInfo` context contains a variety of matrix data, including
3072   number of nonzeros allocated and used, number of mallocs during
3073   matrix assembly, etc.  Additional information for factored matrices
3074   is provided (such as the fill ratio, number of mallocs during
3075   factorization, etc.).
3076 
3077   Example:
3078   See the file ${PETSC_DIR}/include/petscmat.h for a complete list of
3079   data within the `MatInfo` context.  For example,
3080 .vb
3081       MatInfo info;
3082       Mat     A;
3083       double  mal, nz_a, nz_u;
3084 
3085       MatGetInfo(A, MAT_LOCAL, &info);
3086       mal  = info.mallocs;
3087       nz_a = info.nz_allocated;
3088 .ve
3089 
3090 .seealso: [](ch_matrices), `Mat`, `MatInfo`, `MatStashGetInfo()`
3091 @*/
3092 PetscErrorCode MatGetInfo(Mat mat, MatInfoType flag, MatInfo *info)
3093 {
3094   PetscFunctionBegin;
3095   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3096   PetscValidType(mat, 1);
3097   PetscAssertPointer(info, 3);
3098   MatCheckPreallocated(mat, 1);
3099   PetscUseTypeMethod(mat, getinfo, flag, info);
3100   PetscFunctionReturn(PETSC_SUCCESS);
3101 }
3102 
3103 /*
3104    This is used by external packages where it is not easy to get the info from the actual
3105    matrix factorization.
3106 */
3107 PetscErrorCode MatGetInfo_External(Mat A, MatInfoType flag, MatInfo *info)
3108 {
3109   PetscFunctionBegin;
3110   PetscCall(PetscMemzero(info, sizeof(MatInfo)));
3111   PetscFunctionReturn(PETSC_SUCCESS);
3112 }
3113 
3114 /*@
3115   MatLUFactor - Performs in-place LU factorization of matrix.
3116 
3117   Collective
3118 
3119   Input Parameters:
3120 + mat  - the matrix
3121 . row  - row permutation
3122 . col  - column permutation
3123 - info - options for factorization, includes
3124 .vb
3125           fill - expected fill as ratio of original fill.
3126           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3127                    Run with the option -info to determine an optimal value to use
3128 .ve
3129 
3130   Level: developer
3131 
3132   Notes:
3133   Most users should employ the `KSP` interface for linear solvers
3134   instead of working directly with matrix algebra routines such as this.
3135   See, e.g., `KSPCreate()`.
3136 
3137   This changes the state of the matrix to a factored matrix; it cannot be used
3138   for example with `MatSetValues()` unless one first calls `MatSetUnfactored()`.
3139 
3140   This is really in-place only for dense matrices, the preferred approach is to use `MatGetFactor()`, `MatLUFactorSymbolic()`, and `MatLUFactorNumeric()`
3141   when not using `KSP`.
3142 
3143   Developer Note:
3144   The Fortran interface is not autogenerated as the
3145   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3146 
3147 .seealso: [](ch_matrices), [Matrix Factorization](sec_matfactor), `Mat`, `MatFactorType`, `MatLUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`,
3148           `MatGetOrdering()`, `MatSetUnfactored()`, `MatFactorInfo`, `MatGetFactor()`
3149 @*/
3150 PetscErrorCode MatLUFactor(Mat mat, IS row, IS col, const MatFactorInfo *info)
3151 {
3152   MatFactorInfo tinfo;
3153 
3154   PetscFunctionBegin;
3155   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3156   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
3157   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3158   if (info) PetscAssertPointer(info, 4);
3159   PetscValidType(mat, 1);
3160   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3161   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3162   MatCheckPreallocated(mat, 1);
3163   if (!info) {
3164     PetscCall(MatFactorInfoInitialize(&tinfo));
3165     info = &tinfo;
3166   }
3167 
3168   PetscCall(PetscLogEventBegin(MAT_LUFactor, mat, row, col, 0));
3169   PetscUseTypeMethod(mat, lufactor, row, col, info);
3170   PetscCall(PetscLogEventEnd(MAT_LUFactor, mat, row, col, 0));
3171   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3172   PetscFunctionReturn(PETSC_SUCCESS);
3173 }
3174 
3175 /*@
3176   MatILUFactor - Performs in-place ILU factorization of matrix.
3177 
3178   Collective
3179 
3180   Input Parameters:
3181 + mat  - the matrix
3182 . row  - row permutation
3183 . col  - column permutation
3184 - info - structure containing
3185 .vb
3186       levels - number of levels of fill.
3187       expected fill - as ratio of original fill.
3188       1 or 0 - indicating force fill on diagonal (improves robustness for matrices
3189                 missing diagonal entries)
3190 .ve
3191 
3192   Level: developer
3193 
3194   Notes:
3195   Most users should employ the `KSP` interface for linear solvers
3196   instead of working directly with matrix algebra routines such as this.
3197   See, e.g., `KSPCreate()`.
3198 
3199   Probably really in-place only when level of fill is zero, otherwise allocates
3200   new space to store factored matrix and deletes previous memory. The preferred approach is to use `MatGetFactor()`, `MatILUFactorSymbolic()`, and `MatILUFactorNumeric()`
3201   when not using `KSP`.
3202 
3203   Developer Note:
3204   The Fortran interface is not autogenerated as the
3205   interface definition cannot be generated correctly [due to MatFactorInfo]
3206 
3207 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatILUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`
3208 @*/
3209 PetscErrorCode MatILUFactor(Mat mat, IS row, IS col, const MatFactorInfo *info)
3210 {
3211   PetscFunctionBegin;
3212   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3213   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
3214   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3215   PetscAssertPointer(info, 4);
3216   PetscValidType(mat, 1);
3217   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
3218   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3219   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3220   MatCheckPreallocated(mat, 1);
3221 
3222   PetscCall(PetscLogEventBegin(MAT_ILUFactor, mat, row, col, 0));
3223   PetscUseTypeMethod(mat, ilufactor, row, col, info);
3224   PetscCall(PetscLogEventEnd(MAT_ILUFactor, mat, row, col, 0));
3225   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3226   PetscFunctionReturn(PETSC_SUCCESS);
3227 }
3228 
3229 /*@
3230   MatLUFactorSymbolic - Performs symbolic LU factorization of matrix.
3231   Call this routine before calling `MatLUFactorNumeric()` and after `MatGetFactor()`.
3232 
3233   Collective
3234 
3235   Input Parameters:
3236 + fact - the factor matrix obtained with `MatGetFactor()`
3237 . mat  - the matrix
3238 . row  - the row permutation
3239 . col  - the column permutation
3240 - info - options for factorization, includes
3241 .vb
3242           fill - expected fill as ratio of original fill. Run with the option -info to determine an optimal value to use
3243           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3244 .ve
3245 
3246   Level: developer
3247 
3248   Notes:
3249   See [Matrix Factorization](sec_matfactor) for additional information about factorizations
3250 
3251   Most users should employ the simplified `KSP` interface for linear solvers
3252   instead of working directly with matrix algebra routines such as this.
3253   See, e.g., `KSPCreate()`.
3254 
3255   Developer Note:
3256   The Fortran interface is not autogenerated as the
3257   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3258 
3259 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactor()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`, `MatFactorInfoInitialize()`
3260 @*/
3261 PetscErrorCode MatLUFactorSymbolic(Mat fact, Mat mat, IS row, IS col, const MatFactorInfo *info)
3262 {
3263   MatFactorInfo tinfo;
3264 
3265   PetscFunctionBegin;
3266   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3267   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3268   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 3);
3269   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 4);
3270   if (info) PetscAssertPointer(info, 5);
3271   PetscValidType(fact, 1);
3272   PetscValidType(mat, 2);
3273   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3274   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3275   MatCheckPreallocated(mat, 2);
3276   if (!info) {
3277     PetscCall(MatFactorInfoInitialize(&tinfo));
3278     info = &tinfo;
3279   }
3280 
3281   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_LUFactorSymbolic, mat, row, col, 0));
3282   PetscUseTypeMethod(fact, lufactorsymbolic, mat, row, col, info);
3283   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_LUFactorSymbolic, mat, row, col, 0));
3284   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3285   PetscFunctionReturn(PETSC_SUCCESS);
3286 }
3287 
3288 /*@
3289   MatLUFactorNumeric - Performs numeric LU factorization of a matrix.
3290   Call this routine after first calling `MatLUFactorSymbolic()` and `MatGetFactor()`.
3291 
3292   Collective
3293 
3294   Input Parameters:
3295 + fact - the factor matrix obtained with `MatGetFactor()`
3296 . mat  - the matrix
3297 - info - options for factorization
3298 
3299   Level: developer
3300 
3301   Notes:
3302   See `MatLUFactor()` for in-place factorization.  See
3303   `MatCholeskyFactorNumeric()` for the symmetric, positive definite case.
3304 
3305   Most users should employ the `KSP` interface for linear solvers
3306   instead of working directly with matrix algebra routines such as this.
3307   See, e.g., `KSPCreate()`.
3308 
3309   Developer Note:
3310   The Fortran interface is not autogenerated as the
3311   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3312 
3313 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatLUFactorSymbolic()`, `MatLUFactor()`, `MatCholeskyFactor()`
3314 @*/
3315 PetscErrorCode MatLUFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3316 {
3317   MatFactorInfo tinfo;
3318 
3319   PetscFunctionBegin;
3320   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3321   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3322   PetscValidType(fact, 1);
3323   PetscValidType(mat, 2);
3324   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3325   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,
3326              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3327 
3328   MatCheckPreallocated(mat, 2);
3329   if (!info) {
3330     PetscCall(MatFactorInfoInitialize(&tinfo));
3331     info = &tinfo;
3332   }
3333 
3334   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_LUFactorNumeric, mat, fact, 0, 0));
3335   else PetscCall(PetscLogEventBegin(MAT_LUFactor, mat, fact, 0, 0));
3336   PetscUseTypeMethod(fact, lufactornumeric, mat, info);
3337   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_LUFactorNumeric, mat, fact, 0, 0));
3338   else PetscCall(PetscLogEventEnd(MAT_LUFactor, mat, fact, 0, 0));
3339   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3340   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3341   PetscFunctionReturn(PETSC_SUCCESS);
3342 }
3343 
3344 /*@
3345   MatCholeskyFactor - Performs in-place Cholesky factorization of a
3346   symmetric matrix.
3347 
3348   Collective
3349 
3350   Input Parameters:
3351 + mat  - the matrix
3352 . perm - row and column permutations
3353 - info - expected fill as ratio of original fill
3354 
3355   Level: developer
3356 
3357   Notes:
3358   See `MatLUFactor()` for the nonsymmetric case.  See also `MatGetFactor()`,
3359   `MatCholeskyFactorSymbolic()`, and `MatCholeskyFactorNumeric()`.
3360 
3361   Most users should employ the `KSP` interface for linear solvers
3362   instead of working directly with matrix algebra routines such as this.
3363   See, e.g., `KSPCreate()`.
3364 
3365   Developer Note:
3366   The Fortran interface is not autogenerated as the
3367   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3368 
3369 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatLUFactor()`, `MatCholeskyFactorSymbolic()`, `MatCholeskyFactorNumeric()`
3370           `MatGetOrdering()`
3371 @*/
3372 PetscErrorCode MatCholeskyFactor(Mat mat, IS perm, const MatFactorInfo *info)
3373 {
3374   MatFactorInfo tinfo;
3375 
3376   PetscFunctionBegin;
3377   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3378   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 2);
3379   if (info) PetscAssertPointer(info, 3);
3380   PetscValidType(mat, 1);
3381   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Matrix must be square");
3382   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3383   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3384   MatCheckPreallocated(mat, 1);
3385   if (!info) {
3386     PetscCall(MatFactorInfoInitialize(&tinfo));
3387     info = &tinfo;
3388   }
3389 
3390   PetscCall(PetscLogEventBegin(MAT_CholeskyFactor, mat, perm, 0, 0));
3391   PetscUseTypeMethod(mat, choleskyfactor, perm, info);
3392   PetscCall(PetscLogEventEnd(MAT_CholeskyFactor, mat, perm, 0, 0));
3393   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3394   PetscFunctionReturn(PETSC_SUCCESS);
3395 }
3396 
3397 /*@
3398   MatCholeskyFactorSymbolic - Performs symbolic Cholesky factorization
3399   of a symmetric matrix.
3400 
3401   Collective
3402 
3403   Input Parameters:
3404 + fact - the factor matrix obtained with `MatGetFactor()`
3405 . mat  - the matrix
3406 . perm - row and column permutations
3407 - info - options for factorization, includes
3408 .vb
3409           fill - expected fill as ratio of original fill.
3410           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3411                    Run with the option -info to determine an optimal value to use
3412 .ve
3413 
3414   Level: developer
3415 
3416   Notes:
3417   See `MatLUFactorSymbolic()` for the nonsymmetric case.  See also
3418   `MatCholeskyFactor()` and `MatCholeskyFactorNumeric()`.
3419 
3420   Most users should employ the `KSP` interface for linear solvers
3421   instead of working directly with matrix algebra routines such as this.
3422   See, e.g., `KSPCreate()`.
3423 
3424   Developer Note:
3425   The Fortran interface is not autogenerated as the
3426   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3427 
3428 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactor()`, `MatCholeskyFactorNumeric()`
3429           `MatGetOrdering()`
3430 @*/
3431 PetscErrorCode MatCholeskyFactorSymbolic(Mat fact, Mat mat, IS perm, const MatFactorInfo *info)
3432 {
3433   MatFactorInfo tinfo;
3434 
3435   PetscFunctionBegin;
3436   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3437   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3438   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 3);
3439   if (info) PetscAssertPointer(info, 4);
3440   PetscValidType(fact, 1);
3441   PetscValidType(mat, 2);
3442   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Matrix must be square");
3443   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3444   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3445   MatCheckPreallocated(mat, 2);
3446   if (!info) {
3447     PetscCall(MatFactorInfoInitialize(&tinfo));
3448     info = &tinfo;
3449   }
3450 
3451   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_CholeskyFactorSymbolic, mat, perm, 0, 0));
3452   PetscUseTypeMethod(fact, choleskyfactorsymbolic, mat, perm, info);
3453   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_CholeskyFactorSymbolic, mat, perm, 0, 0));
3454   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3455   PetscFunctionReturn(PETSC_SUCCESS);
3456 }
3457 
3458 /*@
3459   MatCholeskyFactorNumeric - Performs numeric Cholesky factorization
3460   of a symmetric matrix. Call this routine after first calling `MatGetFactor()` and
3461   `MatCholeskyFactorSymbolic()`.
3462 
3463   Collective
3464 
3465   Input Parameters:
3466 + fact - the factor matrix obtained with `MatGetFactor()`, where the factored values are stored
3467 . mat  - the initial matrix that is to be factored
3468 - info - options for factorization
3469 
3470   Level: developer
3471 
3472   Note:
3473   Most users should employ the `KSP` interface for linear solvers
3474   instead of working directly with matrix algebra routines such as this.
3475   See, e.g., `KSPCreate()`.
3476 
3477   Developer Note:
3478   The Fortran interface is not autogenerated as the
3479   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3480 
3481 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatCholeskyFactorSymbolic()`, `MatCholeskyFactor()`, `MatLUFactorNumeric()`
3482 @*/
3483 PetscErrorCode MatCholeskyFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3484 {
3485   MatFactorInfo tinfo;
3486 
3487   PetscFunctionBegin;
3488   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3489   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3490   PetscValidType(fact, 1);
3491   PetscValidType(mat, 2);
3492   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3493   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,
3494              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3495   MatCheckPreallocated(mat, 2);
3496   if (!info) {
3497     PetscCall(MatFactorInfoInitialize(&tinfo));
3498     info = &tinfo;
3499   }
3500 
3501   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_CholeskyFactorNumeric, mat, fact, 0, 0));
3502   else PetscCall(PetscLogEventBegin(MAT_CholeskyFactor, mat, fact, 0, 0));
3503   PetscUseTypeMethod(fact, choleskyfactornumeric, mat, info);
3504   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_CholeskyFactorNumeric, mat, fact, 0, 0));
3505   else PetscCall(PetscLogEventEnd(MAT_CholeskyFactor, mat, fact, 0, 0));
3506   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3507   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3508   PetscFunctionReturn(PETSC_SUCCESS);
3509 }
3510 
3511 /*@
3512   MatQRFactor - Performs in-place QR factorization of matrix.
3513 
3514   Collective
3515 
3516   Input Parameters:
3517 + mat  - the matrix
3518 . col  - column permutation
3519 - info - options for factorization, includes
3520 .vb
3521           fill - expected fill as ratio of original fill.
3522           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3523                    Run with the option -info to determine an optimal value to use
3524 .ve
3525 
3526   Level: developer
3527 
3528   Notes:
3529   Most users should employ the `KSP` interface for linear solvers
3530   instead of working directly with matrix algebra routines such as this.
3531   See, e.g., `KSPCreate()`.
3532 
3533   This changes the state of the matrix to a factored matrix; it cannot be used
3534   for example with `MatSetValues()` unless one first calls `MatSetUnfactored()`.
3535 
3536   Developer Note:
3537   The Fortran interface is not autogenerated as the
3538   interface definition cannot be generated correctly [due to MatFactorInfo]
3539 
3540 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatQRFactorSymbolic()`, `MatQRFactorNumeric()`, `MatLUFactor()`,
3541           `MatSetUnfactored()`
3542 @*/
3543 PetscErrorCode MatQRFactor(Mat mat, IS col, const MatFactorInfo *info)
3544 {
3545   PetscFunctionBegin;
3546   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3547   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 2);
3548   if (info) PetscAssertPointer(info, 3);
3549   PetscValidType(mat, 1);
3550   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3551   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3552   MatCheckPreallocated(mat, 1);
3553   PetscCall(PetscLogEventBegin(MAT_QRFactor, mat, col, 0, 0));
3554   PetscUseMethod(mat, "MatQRFactor_C", (Mat, IS, const MatFactorInfo *), (mat, col, info));
3555   PetscCall(PetscLogEventEnd(MAT_QRFactor, mat, col, 0, 0));
3556   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3557   PetscFunctionReturn(PETSC_SUCCESS);
3558 }
3559 
3560 /*@
3561   MatQRFactorSymbolic - Performs symbolic QR factorization of matrix.
3562   Call this routine after `MatGetFactor()` but before calling `MatQRFactorNumeric()`.
3563 
3564   Collective
3565 
3566   Input Parameters:
3567 + fact - the factor matrix obtained with `MatGetFactor()`
3568 . mat  - the matrix
3569 . col  - column permutation
3570 - info - options for factorization, includes
3571 .vb
3572           fill - expected fill as ratio of original fill.
3573           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3574                    Run with the option -info to determine an optimal value to use
3575 .ve
3576 
3577   Level: developer
3578 
3579   Note:
3580   Most users should employ the `KSP` interface for linear solvers
3581   instead of working directly with matrix algebra routines such as this.
3582   See, e.g., `KSPCreate()`.
3583 
3584   Developer Note:
3585   The Fortran interface is not autogenerated as the
3586   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3587 
3588 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatQRFactor()`, `MatQRFactorNumeric()`, `MatLUFactor()`, `MatFactorInfoInitialize()`
3589 @*/
3590 PetscErrorCode MatQRFactorSymbolic(Mat fact, Mat mat, IS col, const MatFactorInfo *info)
3591 {
3592   MatFactorInfo tinfo;
3593 
3594   PetscFunctionBegin;
3595   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3596   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3597   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3598   if (info) PetscAssertPointer(info, 4);
3599   PetscValidType(fact, 1);
3600   PetscValidType(mat, 2);
3601   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3602   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3603   MatCheckPreallocated(mat, 2);
3604   if (!info) {
3605     PetscCall(MatFactorInfoInitialize(&tinfo));
3606     info = &tinfo;
3607   }
3608 
3609   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_QRFactorSymbolic, fact, mat, col, 0));
3610   PetscUseMethod(fact, "MatQRFactorSymbolic_C", (Mat, Mat, IS, const MatFactorInfo *), (fact, mat, col, info));
3611   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_QRFactorSymbolic, fact, mat, col, 0));
3612   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3613   PetscFunctionReturn(PETSC_SUCCESS);
3614 }
3615 
3616 /*@
3617   MatQRFactorNumeric - Performs numeric QR factorization of a matrix.
3618   Call this routine after first calling `MatGetFactor()`, and `MatQRFactorSymbolic()`.
3619 
3620   Collective
3621 
3622   Input Parameters:
3623 + fact - the factor matrix obtained with `MatGetFactor()`
3624 . mat  - the matrix
3625 - info - options for factorization
3626 
3627   Level: developer
3628 
3629   Notes:
3630   See `MatQRFactor()` for in-place factorization.
3631 
3632   Most users should employ the `KSP` interface for linear solvers
3633   instead of working directly with matrix algebra routines such as this.
3634   See, e.g., `KSPCreate()`.
3635 
3636   Developer Note:
3637   The Fortran interface is not autogenerated as the
3638   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3639 
3640 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatQRFactor()`, `MatQRFactorSymbolic()`, `MatLUFactor()`
3641 @*/
3642 PetscErrorCode MatQRFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3643 {
3644   MatFactorInfo tinfo;
3645 
3646   PetscFunctionBegin;
3647   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3648   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3649   PetscValidType(fact, 1);
3650   PetscValidType(mat, 2);
3651   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3652   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,
3653              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3654 
3655   MatCheckPreallocated(mat, 2);
3656   if (!info) {
3657     PetscCall(MatFactorInfoInitialize(&tinfo));
3658     info = &tinfo;
3659   }
3660 
3661   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_QRFactorNumeric, mat, fact, 0, 0));
3662   else PetscCall(PetscLogEventBegin(MAT_QRFactor, mat, fact, 0, 0));
3663   PetscUseMethod(fact, "MatQRFactorNumeric_C", (Mat, Mat, const MatFactorInfo *), (fact, mat, info));
3664   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_QRFactorNumeric, mat, fact, 0, 0));
3665   else PetscCall(PetscLogEventEnd(MAT_QRFactor, mat, fact, 0, 0));
3666   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3667   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3668   PetscFunctionReturn(PETSC_SUCCESS);
3669 }
3670 
3671 /*@
3672   MatSolve - Solves $A x = b$, given a factored matrix.
3673 
3674   Neighbor-wise Collective
3675 
3676   Input Parameters:
3677 + mat - the factored matrix
3678 - b   - the right-hand-side vector
3679 
3680   Output Parameter:
3681 . x - the result vector
3682 
3683   Level: developer
3684 
3685   Notes:
3686   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3687   call `MatSolve`(A,x,x).
3688 
3689   Most users should employ the `KSP` interface for linear solvers
3690   instead of working directly with matrix algebra routines such as this.
3691   See, e.g., `KSPCreate()`.
3692 
3693 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactor()`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`
3694 @*/
3695 PetscErrorCode MatSolve(Mat mat, Vec b, Vec x)
3696 {
3697   PetscFunctionBegin;
3698   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3699   PetscValidType(mat, 1);
3700   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3701   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3702   PetscCheckSameComm(mat, 1, b, 2);
3703   PetscCheckSameComm(mat, 1, x, 3);
3704   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3705   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);
3706   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);
3707   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);
3708   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3709   MatCheckPreallocated(mat, 1);
3710 
3711   PetscCall(PetscLogEventBegin(MAT_Solve, mat, b, x, 0));
3712   PetscCall(VecFlag(x, mat->factorerrortype));
3713   if (mat->factorerrortype) {
3714     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
3715   } else PetscUseTypeMethod(mat, solve, b, x);
3716   PetscCall(PetscLogEventEnd(MAT_Solve, mat, b, x, 0));
3717   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3718   PetscFunctionReturn(PETSC_SUCCESS);
3719 }
3720 
3721 static PetscErrorCode MatMatSolve_Basic(Mat A, Mat B, Mat X, PetscBool trans)
3722 {
3723   Vec      b, x;
3724   PetscInt N, i;
3725   PetscErrorCode (*f)(Mat, Vec, Vec);
3726   PetscBool Abound, Bneedconv = PETSC_FALSE, Xneedconv = PETSC_FALSE;
3727 
3728   PetscFunctionBegin;
3729   if (A->factorerrortype) {
3730     PetscCall(PetscInfo(A, "MatFactorError %d\n", A->factorerrortype));
3731     PetscCall(MatSetInf(X));
3732     PetscFunctionReturn(PETSC_SUCCESS);
3733   }
3734   f = (!trans || (!A->ops->solvetranspose && A->symmetric)) ? A->ops->solve : A->ops->solvetranspose;
3735   PetscCheck(f, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Mat type %s", ((PetscObject)A)->type_name);
3736   PetscCall(MatBoundToCPU(A, &Abound));
3737   if (!Abound) {
3738     PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &Bneedconv, MATSEQDENSE, MATMPIDENSE, ""));
3739     PetscCall(PetscObjectTypeCompareAny((PetscObject)X, &Xneedconv, MATSEQDENSE, MATMPIDENSE, ""));
3740   }
3741 #if PetscDefined(HAVE_CUDA)
3742   if (Bneedconv) PetscCall(MatConvert(B, MATDENSECUDA, MAT_INPLACE_MATRIX, &B));
3743   if (Xneedconv) PetscCall(MatConvert(X, MATDENSECUDA, MAT_INPLACE_MATRIX, &X));
3744 #elif PetscDefined(HAVE_HIP)
3745   if (Bneedconv) PetscCall(MatConvert(B, MATDENSEHIP, MAT_INPLACE_MATRIX, &B));
3746   if (Xneedconv) PetscCall(MatConvert(X, MATDENSEHIP, MAT_INPLACE_MATRIX, &X));
3747 #endif
3748   PetscCall(MatGetSize(B, NULL, &N));
3749   for (i = 0; i < N; i++) {
3750     PetscCall(MatDenseGetColumnVecRead(B, i, &b));
3751     PetscCall(MatDenseGetColumnVecWrite(X, i, &x));
3752     PetscCall((*f)(A, b, x));
3753     PetscCall(MatDenseRestoreColumnVecWrite(X, i, &x));
3754     PetscCall(MatDenseRestoreColumnVecRead(B, i, &b));
3755   }
3756   if (Bneedconv) PetscCall(MatConvert(B, MATDENSE, MAT_INPLACE_MATRIX, &B));
3757   if (Xneedconv) PetscCall(MatConvert(X, MATDENSE, MAT_INPLACE_MATRIX, &X));
3758   PetscFunctionReturn(PETSC_SUCCESS);
3759 }
3760 
3761 /*@
3762   MatMatSolve - Solves $A X = B$, given a factored matrix.
3763 
3764   Neighbor-wise Collective
3765 
3766   Input Parameters:
3767 + A - the factored matrix
3768 - B - the right-hand-side matrix `MATDENSE` (or sparse `MATAIJ`-- when using MUMPS)
3769 
3770   Output Parameter:
3771 . X - the result matrix (dense matrix)
3772 
3773   Level: developer
3774 
3775   Note:
3776   If `B` is a `MATDENSE` matrix then one can call `MatMatSolve`(A,B,B) except with `MATSOLVERMKL_CPARDISO`;
3777   otherwise, `B` and `X` cannot be the same.
3778 
3779 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolve()`, `MatMatSolveTranspose()`, `MatLUFactor()`, `MatCholeskyFactor()`
3780 @*/
3781 PetscErrorCode MatMatSolve(Mat A, Mat B, Mat X)
3782 {
3783   PetscFunctionBegin;
3784   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3785   PetscValidType(A, 1);
3786   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
3787   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3788   PetscCheckSameComm(A, 1, B, 2);
3789   PetscCheckSameComm(A, 1, X, 3);
3790   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);
3791   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);
3792   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");
3793   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3794   MatCheckPreallocated(A, 1);
3795 
3796   PetscCall(PetscLogEventBegin(MAT_MatSolve, A, B, X, 0));
3797   if (!A->ops->matsolve) {
3798     PetscCall(PetscInfo(A, "Mat type %s using basic MatMatSolve\n", ((PetscObject)A)->type_name));
3799     PetscCall(MatMatSolve_Basic(A, B, X, PETSC_FALSE));
3800   } else PetscUseTypeMethod(A, matsolve, B, X);
3801   PetscCall(PetscLogEventEnd(MAT_MatSolve, A, B, X, 0));
3802   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3803   PetscFunctionReturn(PETSC_SUCCESS);
3804 }
3805 
3806 /*@
3807   MatMatSolveTranspose - Solves $A^T X = B $, given a factored matrix.
3808 
3809   Neighbor-wise Collective
3810 
3811   Input Parameters:
3812 + A - the factored matrix
3813 - B - the right-hand-side matrix  (`MATDENSE` matrix)
3814 
3815   Output Parameter:
3816 . X - the result matrix (dense matrix)
3817 
3818   Level: developer
3819 
3820   Note:
3821   The matrices `B` and `X` cannot be the same.  I.e., one cannot
3822   call `MatMatSolveTranspose`(A,X,X).
3823 
3824 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolveTranspose()`, `MatMatSolve()`, `MatLUFactor()`, `MatCholeskyFactor()`
3825 @*/
3826 PetscErrorCode MatMatSolveTranspose(Mat A, Mat B, Mat X)
3827 {
3828   PetscFunctionBegin;
3829   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3830   PetscValidType(A, 1);
3831   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
3832   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3833   PetscCheckSameComm(A, 1, B, 2);
3834   PetscCheckSameComm(A, 1, X, 3);
3835   PetscCheck(X != B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_IDN, "X and B must be different matrices");
3836   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);
3837   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);
3838   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);
3839   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");
3840   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3841   MatCheckPreallocated(A, 1);
3842 
3843   PetscCall(PetscLogEventBegin(MAT_MatSolve, A, B, X, 0));
3844   if (!A->ops->matsolvetranspose) {
3845     PetscCall(PetscInfo(A, "Mat type %s using basic MatMatSolveTranspose\n", ((PetscObject)A)->type_name));
3846     PetscCall(MatMatSolve_Basic(A, B, X, PETSC_TRUE));
3847   } else PetscUseTypeMethod(A, matsolvetranspose, B, X);
3848   PetscCall(PetscLogEventEnd(MAT_MatSolve, A, B, X, 0));
3849   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3850   PetscFunctionReturn(PETSC_SUCCESS);
3851 }
3852 
3853 /*@
3854   MatMatTransposeSolve - Solves $A X = B^T$, given a factored matrix.
3855 
3856   Neighbor-wise Collective
3857 
3858   Input Parameters:
3859 + A  - the factored matrix
3860 - Bt - the transpose of right-hand-side matrix as a `MATDENSE`
3861 
3862   Output Parameter:
3863 . X - the result matrix (dense matrix)
3864 
3865   Level: developer
3866 
3867   Note:
3868   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
3869   format on the host processor and call `MatMatTransposeSolve()` to implement MUMPS' `MatMatSolve()`.
3870 
3871 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatMatSolve()`, `MatMatSolveTranspose()`, `MatLUFactor()`, `MatCholeskyFactor()`
3872 @*/
3873 PetscErrorCode MatMatTransposeSolve(Mat A, Mat Bt, Mat X)
3874 {
3875   PetscFunctionBegin;
3876   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3877   PetscValidType(A, 1);
3878   PetscValidHeaderSpecific(Bt, MAT_CLASSID, 2);
3879   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3880   PetscCheckSameComm(A, 1, Bt, 2);
3881   PetscCheckSameComm(A, 1, X, 3);
3882 
3883   PetscCheck(X != Bt, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_IDN, "X and B must be different matrices");
3884   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);
3885   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);
3886   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");
3887   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3888   PetscCheck(A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
3889   MatCheckPreallocated(A, 1);
3890 
3891   PetscCall(PetscLogEventBegin(MAT_MatTrSolve, A, Bt, X, 0));
3892   PetscUseTypeMethod(A, mattransposesolve, Bt, X);
3893   PetscCall(PetscLogEventEnd(MAT_MatTrSolve, A, Bt, X, 0));
3894   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3895   PetscFunctionReturn(PETSC_SUCCESS);
3896 }
3897 
3898 /*@
3899   MatForwardSolve - Solves $ L x = b $, given a factored matrix, $A = LU $, or
3900   $U^T*D^(1/2) x = b$, given a factored symmetric matrix, $A = U^T*D*U$,
3901 
3902   Neighbor-wise Collective
3903 
3904   Input Parameters:
3905 + mat - the factored matrix
3906 - b   - the right-hand-side vector
3907 
3908   Output Parameter:
3909 . x - the result vector
3910 
3911   Level: developer
3912 
3913   Notes:
3914   `MatSolve()` should be used for most applications, as it performs
3915   a forward solve followed by a backward solve.
3916 
3917   The vectors `b` and `x` cannot be the same,  i.e., one cannot
3918   call `MatForwardSolve`(A,x,x).
3919 
3920   For matrix in `MATSEQBAIJ` format with block size larger than 1,
3921   the diagonal blocks are not implemented as $D = D^(1/2) * D^(1/2)$ yet.
3922   `MatForwardSolve()` solves $U^T*D y = b$, and
3923   `MatBackwardSolve()` solves $U x = y$.
3924   Thus they do not provide a symmetric preconditioner.
3925 
3926 .seealso: [](ch_matrices), `Mat`, `MatBackwardSolve()`, `MatGetFactor()`, `MatSolve()`
3927 @*/
3928 PetscErrorCode MatForwardSolve(Mat mat, Vec b, Vec x)
3929 {
3930   PetscFunctionBegin;
3931   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3932   PetscValidType(mat, 1);
3933   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3934   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3935   PetscCheckSameComm(mat, 1, b, 2);
3936   PetscCheckSameComm(mat, 1, x, 3);
3937   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3938   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);
3939   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);
3940   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);
3941   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3942   MatCheckPreallocated(mat, 1);
3943 
3944   PetscCall(PetscLogEventBegin(MAT_ForwardSolve, mat, b, x, 0));
3945   PetscUseTypeMethod(mat, forwardsolve, b, x);
3946   PetscCall(PetscLogEventEnd(MAT_ForwardSolve, mat, b, x, 0));
3947   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3948   PetscFunctionReturn(PETSC_SUCCESS);
3949 }
3950 
3951 /*@
3952   MatBackwardSolve - Solves $U x = b$, given a factored matrix, $A = LU$.
3953   $D^(1/2) U x = b$, given a factored symmetric matrix, $A = U^T*D*U$,
3954 
3955   Neighbor-wise Collective
3956 
3957   Input Parameters:
3958 + mat - the factored matrix
3959 - b   - the right-hand-side vector
3960 
3961   Output Parameter:
3962 . x - the result vector
3963 
3964   Level: developer
3965 
3966   Notes:
3967   `MatSolve()` should be used for most applications, as it performs
3968   a forward solve followed by a backward solve.
3969 
3970   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3971   call `MatBackwardSolve`(A,x,x).
3972 
3973   For matrix in `MATSEQBAIJ` format with block size larger than 1,
3974   the diagonal blocks are not implemented as $D = D^(1/2) * D^(1/2)$ yet.
3975   `MatForwardSolve()` solves $U^T*D y = b$, and
3976   `MatBackwardSolve()` solves $U x = y$.
3977   Thus they do not provide a symmetric preconditioner.
3978 
3979 .seealso: [](ch_matrices), `Mat`, `MatForwardSolve()`, `MatGetFactor()`, `MatSolve()`
3980 @*/
3981 PetscErrorCode MatBackwardSolve(Mat mat, Vec b, Vec x)
3982 {
3983   PetscFunctionBegin;
3984   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3985   PetscValidType(mat, 1);
3986   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3987   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3988   PetscCheckSameComm(mat, 1, b, 2);
3989   PetscCheckSameComm(mat, 1, x, 3);
3990   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3991   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);
3992   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);
3993   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);
3994   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3995   MatCheckPreallocated(mat, 1);
3996 
3997   PetscCall(PetscLogEventBegin(MAT_BackwardSolve, mat, b, x, 0));
3998   PetscUseTypeMethod(mat, backwardsolve, b, x);
3999   PetscCall(PetscLogEventEnd(MAT_BackwardSolve, mat, b, x, 0));
4000   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4001   PetscFunctionReturn(PETSC_SUCCESS);
4002 }
4003 
4004 /*@
4005   MatSolveAdd - Computes $x = y + A^{-1}*b$, given a factored matrix.
4006 
4007   Neighbor-wise Collective
4008 
4009   Input Parameters:
4010 + mat - the factored matrix
4011 . b   - the right-hand-side vector
4012 - y   - the vector to be added to
4013 
4014   Output Parameter:
4015 . x - the result vector
4016 
4017   Level: developer
4018 
4019   Note:
4020   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4021   call `MatSolveAdd`(A,x,y,x).
4022 
4023 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatSolve()`, `MatGetFactor()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`
4024 @*/
4025 PetscErrorCode MatSolveAdd(Mat mat, Vec b, Vec y, Vec x)
4026 {
4027   PetscScalar one = 1.0;
4028   Vec         tmp;
4029 
4030   PetscFunctionBegin;
4031   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4032   PetscValidType(mat, 1);
4033   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
4034   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4035   PetscValidHeaderSpecific(x, VEC_CLASSID, 4);
4036   PetscCheckSameComm(mat, 1, b, 2);
4037   PetscCheckSameComm(mat, 1, y, 3);
4038   PetscCheckSameComm(mat, 1, x, 4);
4039   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4040   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);
4041   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);
4042   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);
4043   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);
4044   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);
4045   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4046   MatCheckPreallocated(mat, 1);
4047 
4048   PetscCall(PetscLogEventBegin(MAT_SolveAdd, mat, b, x, y));
4049   PetscCall(VecFlag(x, mat->factorerrortype));
4050   if (mat->factorerrortype) {
4051     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4052   } else if (mat->ops->solveadd) {
4053     PetscUseTypeMethod(mat, solveadd, b, y, x);
4054   } else {
4055     /* do the solve then the add manually */
4056     if (x != y) {
4057       PetscCall(MatSolve(mat, b, x));
4058       PetscCall(VecAXPY(x, one, y));
4059     } else {
4060       PetscCall(VecDuplicate(x, &tmp));
4061       PetscCall(VecCopy(x, tmp));
4062       PetscCall(MatSolve(mat, b, x));
4063       PetscCall(VecAXPY(x, one, tmp));
4064       PetscCall(VecDestroy(&tmp));
4065     }
4066   }
4067   PetscCall(PetscLogEventEnd(MAT_SolveAdd, mat, b, x, y));
4068   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4069   PetscFunctionReturn(PETSC_SUCCESS);
4070 }
4071 
4072 /*@
4073   MatSolveTranspose - Solves $A^T x = b$, given a factored matrix.
4074 
4075   Neighbor-wise Collective
4076 
4077   Input Parameters:
4078 + mat - the factored matrix
4079 - b   - the right-hand-side vector
4080 
4081   Output Parameter:
4082 . x - the result vector
4083 
4084   Level: developer
4085 
4086   Notes:
4087   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4088   call `MatSolveTranspose`(A,x,x).
4089 
4090   Most users should employ the `KSP` interface for linear solvers
4091   instead of working directly with matrix algebra routines such as this.
4092   See, e.g., `KSPCreate()`.
4093 
4094 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `KSP`, `MatSolve()`, `MatSolveAdd()`, `MatSolveTransposeAdd()`
4095 @*/
4096 PetscErrorCode MatSolveTranspose(Mat mat, Vec b, Vec x)
4097 {
4098   PetscErrorCode (*f)(Mat, Vec, Vec) = (!mat->ops->solvetranspose && mat->symmetric) ? mat->ops->solve : mat->ops->solvetranspose;
4099 
4100   PetscFunctionBegin;
4101   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4102   PetscValidType(mat, 1);
4103   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4104   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
4105   PetscCheckSameComm(mat, 1, b, 2);
4106   PetscCheckSameComm(mat, 1, x, 3);
4107   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4108   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);
4109   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);
4110   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4111   MatCheckPreallocated(mat, 1);
4112   PetscCall(PetscLogEventBegin(MAT_SolveTranspose, mat, b, x, 0));
4113   PetscCall(VecFlag(x, mat->factorerrortype));
4114   if (mat->factorerrortype) {
4115     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4116   } else {
4117     PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Matrix type %s", ((PetscObject)mat)->type_name);
4118     PetscCall((*f)(mat, b, x));
4119   }
4120   PetscCall(PetscLogEventEnd(MAT_SolveTranspose, mat, b, x, 0));
4121   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4122   PetscFunctionReturn(PETSC_SUCCESS);
4123 }
4124 
4125 /*@
4126   MatSolveTransposeAdd - Computes $x = y + A^{-T} b$
4127   factored matrix.
4128 
4129   Neighbor-wise Collective
4130 
4131   Input Parameters:
4132 + mat - the factored matrix
4133 . b   - the right-hand-side vector
4134 - y   - the vector to be added to
4135 
4136   Output Parameter:
4137 . x - the result vector
4138 
4139   Level: developer
4140 
4141   Note:
4142   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4143   call `MatSolveTransposeAdd`(A,x,y,x).
4144 
4145 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatSolve()`, `MatSolveAdd()`, `MatSolveTranspose()`
4146 @*/
4147 PetscErrorCode MatSolveTransposeAdd(Mat mat, Vec b, Vec y, Vec x)
4148 {
4149   PetscScalar one = 1.0;
4150   Vec         tmp;
4151   PetscErrorCode (*f)(Mat, Vec, Vec, Vec) = (!mat->ops->solvetransposeadd && mat->symmetric) ? mat->ops->solveadd : mat->ops->solvetransposeadd;
4152 
4153   PetscFunctionBegin;
4154   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4155   PetscValidType(mat, 1);
4156   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
4157   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4158   PetscValidHeaderSpecific(x, VEC_CLASSID, 4);
4159   PetscCheckSameComm(mat, 1, b, 2);
4160   PetscCheckSameComm(mat, 1, y, 3);
4161   PetscCheckSameComm(mat, 1, x, 4);
4162   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4163   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);
4164   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);
4165   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);
4166   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);
4167   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4168   MatCheckPreallocated(mat, 1);
4169 
4170   PetscCall(PetscLogEventBegin(MAT_SolveTransposeAdd, mat, b, x, y));
4171   PetscCall(VecFlag(x, mat->factorerrortype));
4172   if (mat->factorerrortype) {
4173     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4174   } else if (f) {
4175     PetscCall((*f)(mat, b, y, x));
4176   } else {
4177     /* do the solve then the add manually */
4178     if (x != y) {
4179       PetscCall(MatSolveTranspose(mat, b, x));
4180       PetscCall(VecAXPY(x, one, y));
4181     } else {
4182       PetscCall(VecDuplicate(x, &tmp));
4183       PetscCall(VecCopy(x, tmp));
4184       PetscCall(MatSolveTranspose(mat, b, x));
4185       PetscCall(VecAXPY(x, one, tmp));
4186       PetscCall(VecDestroy(&tmp));
4187     }
4188   }
4189   PetscCall(PetscLogEventEnd(MAT_SolveTransposeAdd, mat, b, x, y));
4190   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4191   PetscFunctionReturn(PETSC_SUCCESS);
4192 }
4193 
4194 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
4195 /*@
4196   MatSOR - Computes relaxation (SOR, Gauss-Seidel) sweeps.
4197 
4198   Neighbor-wise Collective
4199 
4200   Input Parameters:
4201 + mat   - the matrix
4202 . b     - the right-hand side
4203 . omega - the relaxation factor
4204 . flag  - flag indicating the type of SOR (see below)
4205 . shift - diagonal shift
4206 . its   - the number of iterations
4207 - lits  - the number of local iterations
4208 
4209   Output Parameter:
4210 . x - the solution (can contain an initial guess, use option `SOR_ZERO_INITIAL_GUESS` to indicate no guess)
4211 
4212   SOR Flags:
4213 +     `SOR_FORWARD_SWEEP` - forward SOR
4214 .     `SOR_BACKWARD_SWEEP` - backward SOR
4215 .     `SOR_SYMMETRIC_SWEEP` - SSOR (symmetric SOR)
4216 .     `SOR_LOCAL_FORWARD_SWEEP` - local forward SOR
4217 .     `SOR_LOCAL_BACKWARD_SWEEP` - local forward SOR
4218 .     `SOR_LOCAL_SYMMETRIC_SWEEP` - local SSOR
4219 .     `SOR_EISENSTAT` - SOR with Eisenstat trick
4220 .     `SOR_APPLY_UPPER`, `SOR_APPLY_LOWER` - applies
4221   upper/lower triangular part of matrix to
4222   vector (with omega)
4223 -     `SOR_ZERO_INITIAL_GUESS` - zero initial guess
4224 
4225   Level: developer
4226 
4227   Notes:
4228   `SOR_LOCAL_FORWARD_SWEEP`, `SOR_LOCAL_BACKWARD_SWEEP`, and
4229   `SOR_LOCAL_SYMMETRIC_SWEEP` perform separate independent smoothings
4230   on each processor.
4231 
4232   Application programmers will not generally use `MatSOR()` directly,
4233   but instead will employ the `KSP`/`PC` interface.
4234 
4235   For `MATBAIJ`, `MATSBAIJ`, and `MATAIJ` matrices with Inodes this does a block SOR smoothing, otherwise it does a pointwise smoothing
4236 
4237   Most users should employ the `KSP` interface for linear solvers
4238   instead of working directly with matrix algebra routines such as this.
4239   See, e.g., `KSPCreate()`.
4240 
4241   Vectors `x` and `b` CANNOT be the same
4242 
4243   The flags are implemented as bitwise inclusive or operations.
4244   For example, use (`SOR_ZERO_INITIAL_GUESS` | `SOR_SYMMETRIC_SWEEP`)
4245   to specify a zero initial guess for SSOR.
4246 
4247   Developer Note:
4248   We should add block SOR support for `MATAIJ` matrices with block size set to great than one and no inodes
4249 
4250 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `KSP`, `PC`, `MatGetFactor()`
4251 @*/
4252 PetscErrorCode MatSOR(Mat mat, Vec b, PetscReal omega, MatSORType flag, PetscReal shift, PetscInt its, PetscInt lits, Vec x)
4253 {
4254   PetscFunctionBegin;
4255   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4256   PetscValidType(mat, 1);
4257   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4258   PetscValidHeaderSpecific(x, VEC_CLASSID, 8);
4259   PetscCheckSameComm(mat, 1, b, 2);
4260   PetscCheckSameComm(mat, 1, x, 8);
4261   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4262   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4263   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);
4264   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);
4265   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);
4266   PetscCheck(its > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires global its %" PetscInt_FMT " positive", its);
4267   PetscCheck(lits > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires local its %" PetscInt_FMT " positive", lits);
4268   PetscCheck(b != x, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "b and x vector cannot be the same");
4269 
4270   MatCheckPreallocated(mat, 1);
4271   PetscCall(PetscLogEventBegin(MAT_SOR, mat, b, x, 0));
4272   PetscUseTypeMethod(mat, sor, b, omega, flag, shift, its, lits, x);
4273   PetscCall(PetscLogEventEnd(MAT_SOR, mat, b, x, 0));
4274   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4275   PetscFunctionReturn(PETSC_SUCCESS);
4276 }
4277 
4278 /*
4279       Default matrix copy routine.
4280 */
4281 PetscErrorCode MatCopy_Basic(Mat A, Mat B, MatStructure str)
4282 {
4283   PetscInt           i, rstart = 0, rend = 0, nz;
4284   const PetscInt    *cwork;
4285   const PetscScalar *vwork;
4286 
4287   PetscFunctionBegin;
4288   if (B->assembled) PetscCall(MatZeroEntries(B));
4289   if (str == SAME_NONZERO_PATTERN) {
4290     PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
4291     for (i = rstart; i < rend; i++) {
4292       PetscCall(MatGetRow(A, i, &nz, &cwork, &vwork));
4293       PetscCall(MatSetValues(B, 1, &i, nz, cwork, vwork, INSERT_VALUES));
4294       PetscCall(MatRestoreRow(A, i, &nz, &cwork, &vwork));
4295     }
4296   } else {
4297     PetscCall(MatAYPX(B, 0.0, A, str));
4298   }
4299   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
4300   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
4301   PetscFunctionReturn(PETSC_SUCCESS);
4302 }
4303 
4304 /*@
4305   MatCopy - Copies a matrix to another matrix.
4306 
4307   Collective
4308 
4309   Input Parameters:
4310 + A   - the matrix
4311 - str - `SAME_NONZERO_PATTERN` or `DIFFERENT_NONZERO_PATTERN`
4312 
4313   Output Parameter:
4314 . B - where the copy is put
4315 
4316   Level: intermediate
4317 
4318   Notes:
4319   If you use `SAME_NONZERO_PATTERN`, then the two matrices must have the same nonzero pattern or the routine will crash.
4320 
4321   `MatCopy()` copies the matrix entries of a matrix to another existing
4322   matrix (after first zeroing the second matrix).  A related routine is
4323   `MatConvert()`, which first creates a new matrix and then copies the data.
4324 
4325 .seealso: [](ch_matrices), `Mat`, `MatConvert()`, `MatDuplicate()`
4326 @*/
4327 PetscErrorCode MatCopy(Mat A, Mat B, MatStructure str)
4328 {
4329   PetscInt i;
4330 
4331   PetscFunctionBegin;
4332   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
4333   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
4334   PetscValidType(A, 1);
4335   PetscValidType(B, 2);
4336   PetscCheckSameComm(A, 1, B, 2);
4337   MatCheckPreallocated(B, 2);
4338   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4339   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4340   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,
4341              A->cmap->N, B->cmap->N);
4342   MatCheckPreallocated(A, 1);
4343   if (A == B) PetscFunctionReturn(PETSC_SUCCESS);
4344 
4345   PetscCall(PetscLogEventBegin(MAT_Copy, A, B, 0, 0));
4346   if (A->ops->copy) PetscUseTypeMethod(A, copy, B, str);
4347   else PetscCall(MatCopy_Basic(A, B, str));
4348 
4349   B->stencil.dim = A->stencil.dim;
4350   B->stencil.noc = A->stencil.noc;
4351   for (i = 0; i <= A->stencil.dim + (A->stencil.noc ? 0 : -1); i++) {
4352     B->stencil.dims[i]   = A->stencil.dims[i];
4353     B->stencil.starts[i] = A->stencil.starts[i];
4354   }
4355 
4356   PetscCall(PetscLogEventEnd(MAT_Copy, A, B, 0, 0));
4357   PetscCall(PetscObjectStateIncrease((PetscObject)B));
4358   PetscFunctionReturn(PETSC_SUCCESS);
4359 }
4360 
4361 /*@
4362   MatConvert - Converts a matrix to another matrix, either of the same
4363   or different type.
4364 
4365   Collective
4366 
4367   Input Parameters:
4368 + mat     - the matrix
4369 . newtype - new matrix type.  Use `MATSAME` to create a new matrix of the
4370             same type as the original matrix.
4371 - reuse   - denotes if the destination matrix is to be created or reused.
4372             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
4373             `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).
4374 
4375   Output Parameter:
4376 . M - pointer to place new matrix
4377 
4378   Level: intermediate
4379 
4380   Notes:
4381   `MatConvert()` first creates a new matrix and then copies the data from
4382   the first matrix.  A related routine is `MatCopy()`, which copies the matrix
4383   entries of one matrix to another already existing matrix context.
4384 
4385   Cannot be used to convert a sequential matrix to parallel or parallel to sequential,
4386   the MPI communicator of the generated matrix is always the same as the communicator
4387   of the input matrix.
4388 
4389 .seealso: [](ch_matrices), `Mat`, `MatCopy()`, `MatDuplicate()`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
4390 @*/
4391 PetscErrorCode MatConvert(Mat mat, MatType newtype, MatReuse reuse, Mat *M)
4392 {
4393   PetscBool  sametype, issame, flg;
4394   PetscBool3 issymmetric, ishermitian;
4395   char       convname[256], mtype[256];
4396   Mat        B;
4397 
4398   PetscFunctionBegin;
4399   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4400   PetscValidType(mat, 1);
4401   PetscAssertPointer(M, 4);
4402   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4403   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4404   MatCheckPreallocated(mat, 1);
4405 
4406   PetscCall(PetscOptionsGetString(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matconvert_type", mtype, sizeof(mtype), &flg));
4407   if (flg) newtype = mtype;
4408 
4409   PetscCall(PetscObjectTypeCompare((PetscObject)mat, newtype, &sametype));
4410   PetscCall(PetscStrcmp(newtype, "same", &issame));
4411   PetscCheck(!(reuse == MAT_INPLACE_MATRIX) || !(mat != *M), PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX requires same input and output matrix");
4412   if (reuse == MAT_REUSE_MATRIX) {
4413     PetscValidHeaderSpecific(*M, MAT_CLASSID, 4);
4414     PetscCheck(mat != *M, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_REUSE_MATRIX means reuse matrix in final argument, perhaps you mean MAT_INPLACE_MATRIX");
4415   }
4416 
4417   if ((reuse == MAT_INPLACE_MATRIX) && (issame || sametype)) {
4418     PetscCall(PetscInfo(mat, "Early return for inplace %s %d %d\n", ((PetscObject)mat)->type_name, sametype, issame));
4419     PetscFunctionReturn(PETSC_SUCCESS);
4420   }
4421 
4422   /* Cache Mat options because some converters use MatHeaderReplace  */
4423   issymmetric = mat->symmetric;
4424   ishermitian = mat->hermitian;
4425 
4426   if ((sametype || issame) && (reuse == MAT_INITIAL_MATRIX) && mat->ops->duplicate) {
4427     PetscCall(PetscInfo(mat, "Calling duplicate for initial matrix %s %d %d\n", ((PetscObject)mat)->type_name, sametype, issame));
4428     PetscUseTypeMethod(mat, duplicate, MAT_COPY_VALUES, M);
4429   } else {
4430     PetscErrorCode (*conv)(Mat, MatType, MatReuse, Mat *) = NULL;
4431     const char *prefix[3]                                 = {"seq", "mpi", ""};
4432     PetscInt    i;
4433     /*
4434        Order of precedence:
4435        0) See if newtype is a superclass of the current matrix.
4436        1) See if a specialized converter is known to the current matrix.
4437        2) See if a specialized converter is known to the desired matrix class.
4438        3) See if a good general converter is registered for the desired class
4439           (as of 6/27/03 only MATMPIADJ falls into this category).
4440        4) See if a good general converter is known for the current matrix.
4441        5) Use a really basic converter.
4442     */
4443 
4444     /* 0) See if newtype is a superclass of the current matrix.
4445           i.e mat is mpiaij and newtype is aij */
4446     for (i = 0; i < 2; i++) {
4447       PetscCall(PetscStrncpy(convname, prefix[i], sizeof(convname)));
4448       PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4449       PetscCall(PetscStrcmp(convname, ((PetscObject)mat)->type_name, &flg));
4450       PetscCall(PetscInfo(mat, "Check superclass %s %s -> %d\n", convname, ((PetscObject)mat)->type_name, flg));
4451       if (flg) {
4452         if (reuse == MAT_INPLACE_MATRIX) {
4453           PetscCall(PetscInfo(mat, "Early return\n"));
4454           PetscFunctionReturn(PETSC_SUCCESS);
4455         } else if (reuse == MAT_INITIAL_MATRIX && mat->ops->duplicate) {
4456           PetscCall(PetscInfo(mat, "Calling MatDuplicate\n"));
4457           PetscUseTypeMethod(mat, duplicate, MAT_COPY_VALUES, M);
4458           PetscFunctionReturn(PETSC_SUCCESS);
4459         } else if (reuse == MAT_REUSE_MATRIX && mat->ops->copy) {
4460           PetscCall(PetscInfo(mat, "Calling MatCopy\n"));
4461           PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
4462           PetscFunctionReturn(PETSC_SUCCESS);
4463         }
4464       }
4465     }
4466     /* 1) See if a specialized converter is known to the current matrix and the desired class */
4467     for (i = 0; i < 3; i++) {
4468       PetscCall(PetscStrncpy(convname, "MatConvert_", sizeof(convname)));
4469       PetscCall(PetscStrlcat(convname, ((PetscObject)mat)->type_name, sizeof(convname)));
4470       PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4471       PetscCall(PetscStrlcat(convname, prefix[i], sizeof(convname)));
4472       PetscCall(PetscStrlcat(convname, issame ? ((PetscObject)mat)->type_name : newtype, sizeof(convname)));
4473       PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4474       PetscCall(PetscObjectQueryFunction((PetscObject)mat, convname, &conv));
4475       PetscCall(PetscInfo(mat, "Check specialized (1) %s (%s) -> %d\n", convname, ((PetscObject)mat)->type_name, !!conv));
4476       if (conv) goto foundconv;
4477     }
4478 
4479     /* 2)  See if a specialized converter is known to the desired matrix class. */
4480     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
4481     PetscCall(MatSetSizes(B, mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N));
4482     PetscCall(MatSetType(B, newtype));
4483     for (i = 0; i < 3; i++) {
4484       PetscCall(PetscStrncpy(convname, "MatConvert_", sizeof(convname)));
4485       PetscCall(PetscStrlcat(convname, ((PetscObject)mat)->type_name, sizeof(convname)));
4486       PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4487       PetscCall(PetscStrlcat(convname, prefix[i], sizeof(convname)));
4488       PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4489       PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4490       PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4491       PetscCall(PetscInfo(mat, "Check specialized (2) %s (%s) -> %d\n", convname, ((PetscObject)B)->type_name, !!conv));
4492       if (conv) {
4493         PetscCall(MatDestroy(&B));
4494         goto foundconv;
4495       }
4496     }
4497 
4498     /* 3) See if a good general converter is registered for the desired class */
4499     conv = B->ops->convertfrom;
4500     PetscCall(PetscInfo(mat, "Check convertfrom (%s) -> %d\n", ((PetscObject)B)->type_name, !!conv));
4501     PetscCall(MatDestroy(&B));
4502     if (conv) goto foundconv;
4503 
4504     /* 4) See if a good general converter is known for the current matrix */
4505     if (mat->ops->convert) conv = mat->ops->convert;
4506     PetscCall(PetscInfo(mat, "Check general convert (%s) -> %d\n", ((PetscObject)mat)->type_name, !!conv));
4507     if (conv) goto foundconv;
4508 
4509     /* 5) Use a really basic converter. */
4510     PetscCall(PetscInfo(mat, "Using MatConvert_Basic\n"));
4511     conv = MatConvert_Basic;
4512 
4513   foundconv:
4514     PetscCall(PetscLogEventBegin(MAT_Convert, mat, 0, 0, 0));
4515     PetscCall((*conv)(mat, newtype, reuse, M));
4516     if (mat->rmap->mapping && mat->cmap->mapping && !(*M)->rmap->mapping && !(*M)->cmap->mapping) {
4517       /* the block sizes must be same if the mappings are copied over */
4518       (*M)->rmap->bs = mat->rmap->bs;
4519       (*M)->cmap->bs = mat->cmap->bs;
4520       PetscCall(PetscObjectReference((PetscObject)mat->rmap->mapping));
4521       PetscCall(PetscObjectReference((PetscObject)mat->cmap->mapping));
4522       (*M)->rmap->mapping = mat->rmap->mapping;
4523       (*M)->cmap->mapping = mat->cmap->mapping;
4524     }
4525     (*M)->stencil.dim = mat->stencil.dim;
4526     (*M)->stencil.noc = mat->stencil.noc;
4527     for (i = 0; i <= mat->stencil.dim + (mat->stencil.noc ? 0 : -1); i++) {
4528       (*M)->stencil.dims[i]   = mat->stencil.dims[i];
4529       (*M)->stencil.starts[i] = mat->stencil.starts[i];
4530     }
4531     PetscCall(PetscLogEventEnd(MAT_Convert, mat, 0, 0, 0));
4532   }
4533   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4534 
4535   /* Copy Mat options */
4536   if (issymmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*M, MAT_SYMMETRIC, PETSC_TRUE));
4537   else if (issymmetric == PETSC_BOOL3_FALSE) PetscCall(MatSetOption(*M, MAT_SYMMETRIC, PETSC_FALSE));
4538   if (ishermitian == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*M, MAT_HERMITIAN, PETSC_TRUE));
4539   else if (ishermitian == PETSC_BOOL3_FALSE) PetscCall(MatSetOption(*M, MAT_HERMITIAN, PETSC_FALSE));
4540   PetscFunctionReturn(PETSC_SUCCESS);
4541 }
4542 
4543 /*@
4544   MatFactorGetSolverType - Returns name of the package providing the factorization routines
4545 
4546   Not Collective
4547 
4548   Input Parameter:
4549 . mat - the matrix, must be a factored matrix
4550 
4551   Output Parameter:
4552 . type - the string name of the package (do not free this string)
4553 
4554   Level: intermediate
4555 
4556   Fortran Note:
4557   Pass in an empty string that is long enough and the package name will be copied into it.
4558 
4559 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolverType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`
4560 @*/
4561 PetscErrorCode MatFactorGetSolverType(Mat mat, MatSolverType *type)
4562 {
4563   PetscErrorCode (*conv)(Mat, MatSolverType *);
4564 
4565   PetscFunctionBegin;
4566   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4567   PetscValidType(mat, 1);
4568   PetscAssertPointer(type, 2);
4569   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
4570   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorGetSolverType_C", &conv));
4571   if (conv) PetscCall((*conv)(mat, type));
4572   else *type = MATSOLVERPETSC;
4573   PetscFunctionReturn(PETSC_SUCCESS);
4574 }
4575 
4576 typedef struct _MatSolverTypeForSpecifcType *MatSolverTypeForSpecifcType;
4577 struct _MatSolverTypeForSpecifcType {
4578   MatType mtype;
4579   /* no entry for MAT_FACTOR_NONE */
4580   PetscErrorCode (*createfactor[MAT_FACTOR_NUM_TYPES - 1])(Mat, MatFactorType, Mat *);
4581   MatSolverTypeForSpecifcType next;
4582 };
4583 
4584 typedef struct _MatSolverTypeHolder *MatSolverTypeHolder;
4585 struct _MatSolverTypeHolder {
4586   char                       *name;
4587   MatSolverTypeForSpecifcType handlers;
4588   MatSolverTypeHolder         next;
4589 };
4590 
4591 static MatSolverTypeHolder MatSolverTypeHolders = NULL;
4592 
4593 /*@C
4594   MatSolverTypeRegister - Registers a `MatSolverType` that works for a particular matrix type
4595 
4596   Logically Collective, No Fortran Support
4597 
4598   Input Parameters:
4599 + package      - name of the package, for example petsc or superlu
4600 . mtype        - the matrix type that works with this package
4601 . ftype        - the type of factorization supported by the package
4602 - createfactor - routine that will create the factored matrix ready to be used
4603 
4604   Level: developer
4605 
4606 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorGetSolverType()`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`,
4607   `MatGetFactor()`
4608 @*/
4609 PetscErrorCode MatSolverTypeRegister(MatSolverType package, MatType mtype, MatFactorType ftype, PetscErrorCode (*createfactor)(Mat, MatFactorType, Mat *))
4610 {
4611   MatSolverTypeHolder         next = MatSolverTypeHolders, prev = NULL;
4612   PetscBool                   flg;
4613   MatSolverTypeForSpecifcType inext, iprev = NULL;
4614 
4615   PetscFunctionBegin;
4616   PetscCall(MatInitializePackage());
4617   if (!next) {
4618     PetscCall(PetscNew(&MatSolverTypeHolders));
4619     PetscCall(PetscStrallocpy(package, &MatSolverTypeHolders->name));
4620     PetscCall(PetscNew(&MatSolverTypeHolders->handlers));
4621     PetscCall(PetscStrallocpy(mtype, (char **)&MatSolverTypeHolders->handlers->mtype));
4622     MatSolverTypeHolders->handlers->createfactor[(int)ftype - 1] = createfactor;
4623     PetscFunctionReturn(PETSC_SUCCESS);
4624   }
4625   while (next) {
4626     PetscCall(PetscStrcasecmp(package, next->name, &flg));
4627     if (flg) {
4628       PetscCheck(next->handlers, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatSolverTypeHolder is missing handlers");
4629       inext = next->handlers;
4630       while (inext) {
4631         PetscCall(PetscStrcasecmp(mtype, inext->mtype, &flg));
4632         if (flg) {
4633           inext->createfactor[(int)ftype - 1] = createfactor;
4634           PetscFunctionReturn(PETSC_SUCCESS);
4635         }
4636         iprev = inext;
4637         inext = inext->next;
4638       }
4639       PetscCall(PetscNew(&iprev->next));
4640       PetscCall(PetscStrallocpy(mtype, (char **)&iprev->next->mtype));
4641       iprev->next->createfactor[(int)ftype - 1] = createfactor;
4642       PetscFunctionReturn(PETSC_SUCCESS);
4643     }
4644     prev = next;
4645     next = next->next;
4646   }
4647   PetscCall(PetscNew(&prev->next));
4648   PetscCall(PetscStrallocpy(package, &prev->next->name));
4649   PetscCall(PetscNew(&prev->next->handlers));
4650   PetscCall(PetscStrallocpy(mtype, (char **)&prev->next->handlers->mtype));
4651   prev->next->handlers->createfactor[(int)ftype - 1] = createfactor;
4652   PetscFunctionReturn(PETSC_SUCCESS);
4653 }
4654 
4655 /*@C
4656   MatSolverTypeGet - Gets the function that creates the factor matrix if it exist
4657 
4658   Input Parameters:
4659 + 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
4660 . ftype - the type of factorization supported by the type
4661 - mtype - the matrix type that works with this type
4662 
4663   Output Parameters:
4664 + foundtype    - `PETSC_TRUE` if the type was registered
4665 . foundmtype   - `PETSC_TRUE` if the type supports the requested mtype
4666 - createfactor - routine that will create the factored matrix ready to be used or `NULL` if not found
4667 
4668   Calling sequence of `createfactor`:
4669 + A     - the matrix providing the factor matrix
4670 . ftype - the `MatFactorType` of the factor requested
4671 - B     - the new factor matrix that responds to MatXXFactorSymbolic,Numeric() functions, such as `MatLUFactorSymbolic()`
4672 
4673   Level: developer
4674 
4675   Note:
4676   When `type` is `NULL` the available functions are searched for based on the order of the calls to `MatSolverTypeRegister()` in `MatInitializePackage()`.
4677   Since different PETSc configurations may have different external solvers, seemingly identical runs with different PETSc configurations may use a different solver.
4678   For example if one configuration had `--download-mumps` while a different one had `--download-superlu_dist`.
4679 
4680 .seealso: [](ch_matrices), `Mat`, `MatFactorType`, `MatType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatSolverTypeRegister()`, `MatGetFactor()`,
4681           `MatInitializePackage()`
4682 @*/
4683 PetscErrorCode MatSolverTypeGet(MatSolverType type, MatType mtype, MatFactorType ftype, PetscBool *foundtype, PetscBool *foundmtype, PetscErrorCode (**createfactor)(Mat A, MatFactorType ftype, Mat *B))
4684 {
4685   MatSolverTypeHolder         next = MatSolverTypeHolders;
4686   PetscBool                   flg;
4687   MatSolverTypeForSpecifcType inext;
4688 
4689   PetscFunctionBegin;
4690   if (foundtype) *foundtype = PETSC_FALSE;
4691   if (foundmtype) *foundmtype = PETSC_FALSE;
4692   if (createfactor) *createfactor = NULL;
4693 
4694   if (type) {
4695     while (next) {
4696       PetscCall(PetscStrcasecmp(type, next->name, &flg));
4697       if (flg) {
4698         if (foundtype) *foundtype = PETSC_TRUE;
4699         inext = next->handlers;
4700         while (inext) {
4701           PetscCall(PetscStrbeginswith(mtype, inext->mtype, &flg));
4702           if (flg) {
4703             if (foundmtype) *foundmtype = PETSC_TRUE;
4704             if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4705             PetscFunctionReturn(PETSC_SUCCESS);
4706           }
4707           inext = inext->next;
4708         }
4709       }
4710       next = next->next;
4711     }
4712   } else {
4713     while (next) {
4714       inext = next->handlers;
4715       while (inext) {
4716         PetscCall(PetscStrcmp(mtype, inext->mtype, &flg));
4717         if (flg && inext->createfactor[(int)ftype - 1]) {
4718           if (foundtype) *foundtype = PETSC_TRUE;
4719           if (foundmtype) *foundmtype = PETSC_TRUE;
4720           if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4721           PetscFunctionReturn(PETSC_SUCCESS);
4722         }
4723         inext = inext->next;
4724       }
4725       next = next->next;
4726     }
4727     /* try with base classes inext->mtype */
4728     next = MatSolverTypeHolders;
4729     while (next) {
4730       inext = next->handlers;
4731       while (inext) {
4732         PetscCall(PetscStrbeginswith(mtype, inext->mtype, &flg));
4733         if (flg && inext->createfactor[(int)ftype - 1]) {
4734           if (foundtype) *foundtype = PETSC_TRUE;
4735           if (foundmtype) *foundmtype = PETSC_TRUE;
4736           if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4737           PetscFunctionReturn(PETSC_SUCCESS);
4738         }
4739         inext = inext->next;
4740       }
4741       next = next->next;
4742     }
4743   }
4744   PetscFunctionReturn(PETSC_SUCCESS);
4745 }
4746 
4747 PetscErrorCode MatSolverTypeDestroy(void)
4748 {
4749   MatSolverTypeHolder         next = MatSolverTypeHolders, prev;
4750   MatSolverTypeForSpecifcType inext, iprev;
4751 
4752   PetscFunctionBegin;
4753   while (next) {
4754     PetscCall(PetscFree(next->name));
4755     inext = next->handlers;
4756     while (inext) {
4757       PetscCall(PetscFree(inext->mtype));
4758       iprev = inext;
4759       inext = inext->next;
4760       PetscCall(PetscFree(iprev));
4761     }
4762     prev = next;
4763     next = next->next;
4764     PetscCall(PetscFree(prev));
4765   }
4766   MatSolverTypeHolders = NULL;
4767   PetscFunctionReturn(PETSC_SUCCESS);
4768 }
4769 
4770 /*@
4771   MatFactorGetCanUseOrdering - Indicates if the factorization can use the ordering provided in `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4772 
4773   Logically Collective
4774 
4775   Input Parameter:
4776 . mat - the matrix
4777 
4778   Output Parameter:
4779 . flg - `PETSC_TRUE` if uses the ordering
4780 
4781   Level: developer
4782 
4783   Note:
4784   Most internal PETSc factorizations use the ordering passed to the factorization routine but external
4785   packages do not, thus we want to skip generating the ordering when it is not needed or used.
4786 
4787 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4788 @*/
4789 PetscErrorCode MatFactorGetCanUseOrdering(Mat mat, PetscBool *flg)
4790 {
4791   PetscFunctionBegin;
4792   *flg = mat->canuseordering;
4793   PetscFunctionReturn(PETSC_SUCCESS);
4794 }
4795 
4796 /*@
4797   MatFactorGetPreferredOrdering - The preferred ordering for a particular matrix factor object
4798 
4799   Logically Collective
4800 
4801   Input Parameters:
4802 + mat   - the matrix obtained with `MatGetFactor()`
4803 - ftype - the factorization type to be used
4804 
4805   Output Parameter:
4806 . otype - the preferred ordering type
4807 
4808   Level: developer
4809 
4810 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatOrderingType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4811 @*/
4812 PetscErrorCode MatFactorGetPreferredOrdering(Mat mat, MatFactorType ftype, MatOrderingType *otype)
4813 {
4814   PetscFunctionBegin;
4815   *otype = mat->preferredordering[ftype];
4816   PetscCheck(*otype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatFactor did not have a preferred ordering");
4817   PetscFunctionReturn(PETSC_SUCCESS);
4818 }
4819 
4820 /*@
4821   MatGetFactor - Returns a matrix suitable to calls to MatXXFactorSymbolic,Numeric()
4822 
4823   Collective
4824 
4825   Input Parameters:
4826 + mat   - the matrix
4827 . 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
4828           the other criteria is returned
4829 - ftype - factor type, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`
4830 
4831   Output Parameter:
4832 . f - the factor matrix used with MatXXFactorSymbolic,Numeric() calls. Can be `NULL` in some cases, see notes below.
4833 
4834   Options Database Keys:
4835 + -pc_factor_mat_solver_type <type>             - choose the type at run time. When using `KSP` solvers
4836 - -mat_factor_bind_factorization <host, device> - Where to do matrix factorization? Default is device (might consume more device memory.
4837                                                   One can choose host to save device memory). Currently only supported with `MATSEQAIJCUSPARSE` matrices.
4838 
4839   Level: intermediate
4840 
4841   Notes:
4842   The return matrix can be `NULL` if the requested factorization is not available, since some combinations of matrix types and factorization
4843   types registered with `MatSolverTypeRegister()` cannot be fully tested if not at runtime.
4844 
4845   Users usually access the factorization solvers via `KSP`
4846 
4847   Some PETSc matrix formats have alternative solvers available that are contained in alternative packages
4848   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
4849 
4850   When `type` is `NULL` the available results are searched for based on the order of the calls to `MatSolverTypeRegister()` in `MatInitializePackage()`.
4851   Since different PETSc configurations may have different external solvers, seemingly identical runs with different PETSc configurations may use a different solver.
4852   For example if one configuration had --download-mumps while a different one had --download-superlu_dist.
4853 
4854   Some of the packages have options for controlling the factorization, these are in the form -prefix_mat_packagename_packageoption
4855   where prefix is normally obtained from the calling `KSP`/`PC`. If `MatGetFactor()` is called directly one can set
4856   call `MatSetOptionsPrefixFactor()` on the originating matrix or  `MatSetOptionsPrefix()` on the resulting factor matrix.
4857 
4858   Developer Note:
4859   This should actually be called `MatCreateFactor()` since it creates a new factor object
4860 
4861 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `KSP`, `MatSolverType`, `MatFactorType`, `MatCopy()`, `MatDuplicate()`,
4862           `MatGetFactorAvailable()`, `MatFactorGetCanUseOrdering()`, `MatSolverTypeRegister()`, `MatSolverTypeGet()`
4863           `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`, `MatInitializePackage()`
4864 @*/
4865 PetscErrorCode MatGetFactor(Mat mat, MatSolverType type, MatFactorType ftype, Mat *f)
4866 {
4867   PetscBool foundtype, foundmtype, shell, hasop = PETSC_FALSE;
4868   PetscErrorCode (*conv)(Mat, MatFactorType, Mat *);
4869 
4870   PetscFunctionBegin;
4871   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4872   PetscValidType(mat, 1);
4873 
4874   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4875   MatCheckPreallocated(mat, 1);
4876 
4877   PetscCall(MatIsShell(mat, &shell));
4878   if (shell) PetscCall(MatHasOperation(mat, MATOP_GET_FACTOR, &hasop));
4879   if (hasop) {
4880     PetscUseTypeMethod(mat, getfactor, type, ftype, f);
4881     PetscFunctionReturn(PETSC_SUCCESS);
4882   }
4883 
4884   PetscCall(MatSolverTypeGet(type, ((PetscObject)mat)->type_name, ftype, &foundtype, &foundmtype, &conv));
4885   if (!foundtype) {
4886     if (type) {
4887       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],
4888               ((PetscObject)mat)->type_name, type);
4889     } else {
4890       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);
4891     }
4892   }
4893   PetscCheck(foundmtype, PetscObjectComm((PetscObject)mat), PETSC_ERR_MISSING_FACTOR, "MatSolverType %s does not support matrix type %s", type, ((PetscObject)mat)->type_name);
4894   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);
4895 
4896   PetscCall((*conv)(mat, ftype, f));
4897   if (mat->factorprefix) PetscCall(MatSetOptionsPrefix(*f, mat->factorprefix));
4898   PetscFunctionReturn(PETSC_SUCCESS);
4899 }
4900 
4901 /*@
4902   MatGetFactorAvailable - Returns a flag if matrix supports particular type and factor type
4903 
4904   Not Collective
4905 
4906   Input Parameters:
4907 + mat   - the matrix
4908 . type  - name of solver type, for example, superlu, petsc (to use PETSc's default)
4909 - ftype - factor type, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`
4910 
4911   Output Parameter:
4912 . flg - PETSC_TRUE if the factorization is available
4913 
4914   Level: intermediate
4915 
4916   Notes:
4917   Some PETSc matrix formats have alternative solvers available that are contained in alternative packages
4918   such as pastix, superlu, mumps etc.
4919 
4920   PETSc must have been ./configure to use the external solver, using the option --download-package
4921 
4922   Developer Note:
4923   This should actually be called `MatCreateFactorAvailable()` since `MatGetFactor()` creates a new factor object
4924 
4925 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatSolverType`, `MatFactorType`, `MatGetFactor()`, `MatCopy()`, `MatDuplicate()`, `MatSolverTypeRegister()`,
4926           `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`, `MatSolverTypeGet()`
4927 @*/
4928 PetscErrorCode MatGetFactorAvailable(Mat mat, MatSolverType type, MatFactorType ftype, PetscBool *flg)
4929 {
4930   PetscErrorCode (*gconv)(Mat, MatFactorType, Mat *);
4931 
4932   PetscFunctionBegin;
4933   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4934   PetscAssertPointer(flg, 4);
4935 
4936   *flg = PETSC_FALSE;
4937   if (!((PetscObject)mat)->type_name) PetscFunctionReturn(PETSC_SUCCESS);
4938 
4939   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4940   MatCheckPreallocated(mat, 1);
4941 
4942   PetscCall(MatSolverTypeGet(type, ((PetscObject)mat)->type_name, ftype, NULL, NULL, &gconv));
4943   *flg = gconv ? PETSC_TRUE : PETSC_FALSE;
4944   PetscFunctionReturn(PETSC_SUCCESS);
4945 }
4946 
4947 /*@
4948   MatDuplicate - Duplicates a matrix including the non-zero structure.
4949 
4950   Collective
4951 
4952   Input Parameters:
4953 + mat - the matrix
4954 - op  - One of `MAT_DO_NOT_COPY_VALUES`, `MAT_COPY_VALUES`, or `MAT_SHARE_NONZERO_PATTERN`.
4955         See the manual page for `MatDuplicateOption()` for an explanation of these options.
4956 
4957   Output Parameter:
4958 . M - pointer to place new matrix
4959 
4960   Level: intermediate
4961 
4962   Notes:
4963   You cannot change the nonzero pattern for the parent or child matrix later if you use `MAT_SHARE_NONZERO_PATTERN`.
4964 
4965   If `op` is not `MAT_COPY_VALUES` the numerical values in the new matrix are zeroed.
4966 
4967   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.
4968 
4969   When original mat is a product of matrix operation, e.g., an output of `MatMatMult()` or `MatCreateSubMatrix()`, only the matrix data structure of `mat`
4970   is duplicated and the internal data structures created for the reuse of previous matrix operations are not duplicated.
4971   User should not use `MatDuplicate()` to create new matrix `M` if `M` is intended to be reused as the product of matrix operation.
4972 
4973 .seealso: [](ch_matrices), `Mat`, `MatCopy()`, `MatConvert()`, `MatDuplicateOption`
4974 @*/
4975 PetscErrorCode MatDuplicate(Mat mat, MatDuplicateOption op, Mat *M)
4976 {
4977   Mat         B;
4978   VecType     vtype;
4979   PetscInt    i;
4980   PetscObject dm, container_h, container_d;
4981   void (*viewf)(void);
4982 
4983   PetscFunctionBegin;
4984   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4985   PetscValidType(mat, 1);
4986   PetscAssertPointer(M, 3);
4987   PetscCheck(op != MAT_COPY_VALUES || mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MAT_COPY_VALUES not allowed for unassembled matrix");
4988   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4989   MatCheckPreallocated(mat, 1);
4990 
4991   PetscCall(PetscLogEventBegin(MAT_Convert, mat, 0, 0, 0));
4992   PetscUseTypeMethod(mat, duplicate, op, M);
4993   PetscCall(PetscLogEventEnd(MAT_Convert, mat, 0, 0, 0));
4994   B = *M;
4995 
4996   PetscCall(MatGetOperation(mat, MATOP_VIEW, &viewf));
4997   if (viewf) PetscCall(MatSetOperation(B, MATOP_VIEW, viewf));
4998   PetscCall(MatGetVecType(mat, &vtype));
4999   PetscCall(MatSetVecType(B, vtype));
5000 
5001   B->stencil.dim = mat->stencil.dim;
5002   B->stencil.noc = mat->stencil.noc;
5003   for (i = 0; i <= mat->stencil.dim + (mat->stencil.noc ? 0 : -1); i++) {
5004     B->stencil.dims[i]   = mat->stencil.dims[i];
5005     B->stencil.starts[i] = mat->stencil.starts[i];
5006   }
5007 
5008   B->nooffproczerorows = mat->nooffproczerorows;
5009   B->nooffprocentries  = mat->nooffprocentries;
5010 
5011   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_dm", &dm));
5012   if (dm) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_dm", dm));
5013   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_MatCOOStruct_Host", &container_h));
5014   if (container_h) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_MatCOOStruct_Host", container_h));
5015   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_MatCOOStruct_Device", &container_d));
5016   if (container_d) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_MatCOOStruct_Device", container_d));
5017   if (op == MAT_COPY_VALUES) PetscCall(MatPropagateSymmetryOptions(mat, B));
5018   PetscCall(PetscObjectStateIncrease((PetscObject)B));
5019   PetscFunctionReturn(PETSC_SUCCESS);
5020 }
5021 
5022 /*@
5023   MatGetDiagonal - Gets the diagonal of a matrix as a `Vec`
5024 
5025   Logically Collective
5026 
5027   Input Parameter:
5028 . mat - the matrix
5029 
5030   Output Parameter:
5031 . v - the diagonal of the matrix
5032 
5033   Level: intermediate
5034 
5035   Note:
5036   If `mat` has local sizes `n` x `m`, this routine fills the first `ndiag = min(n, m)` entries
5037   of `v` with the diagonal values. Thus `v` must have local size of at least `ndiag`. If `v`
5038   is larger than `ndiag`, the values of the remaining entries are unspecified.
5039 
5040   Currently only correct in parallel for square matrices.
5041 
5042 .seealso: [](ch_matrices), `Mat`, `Vec`, `MatGetRow()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`
5043 @*/
5044 PetscErrorCode MatGetDiagonal(Mat mat, Vec v)
5045 {
5046   PetscFunctionBegin;
5047   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5048   PetscValidType(mat, 1);
5049   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5050   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5051   MatCheckPreallocated(mat, 1);
5052   if (PetscDefined(USE_DEBUG)) {
5053     PetscInt nv, row, col, ndiag;
5054 
5055     PetscCall(VecGetLocalSize(v, &nv));
5056     PetscCall(MatGetLocalSize(mat, &row, &col));
5057     ndiag = PetscMin(row, col);
5058     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);
5059   }
5060 
5061   PetscUseTypeMethod(mat, getdiagonal, v);
5062   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5063   PetscFunctionReturn(PETSC_SUCCESS);
5064 }
5065 
5066 /*@
5067   MatGetRowMin - Gets the minimum value (of the real part) of each
5068   row of the matrix
5069 
5070   Logically Collective
5071 
5072   Input Parameter:
5073 . mat - the matrix
5074 
5075   Output Parameters:
5076 + v   - the vector for storing the maximums
5077 - idx - the indices of the column found for each row (optional, pass `NULL` if not needed)
5078 
5079   Level: intermediate
5080 
5081   Note:
5082   The result of this call are the same as if one converted the matrix to dense format
5083   and found the minimum value in each row (i.e. the implicit zeros are counted as zeros).
5084 
5085   This code is only implemented for a couple of matrix formats.
5086 
5087 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`, `MatGetRowMinAbs()`,
5088           `MatGetRowMax()`
5089 @*/
5090 PetscErrorCode MatGetRowMin(Mat mat, Vec v, PetscInt idx[])
5091 {
5092   PetscFunctionBegin;
5093   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5094   PetscValidType(mat, 1);
5095   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5096   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5097 
5098   if (!mat->cmap->N) {
5099     PetscCall(VecSet(v, PETSC_MAX_REAL));
5100     if (idx) {
5101       PetscInt i, m = mat->rmap->n;
5102       for (i = 0; i < m; i++) idx[i] = -1;
5103     }
5104   } else {
5105     MatCheckPreallocated(mat, 1);
5106   }
5107   PetscUseTypeMethod(mat, getrowmin, v, idx);
5108   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5109   PetscFunctionReturn(PETSC_SUCCESS);
5110 }
5111 
5112 /*@
5113   MatGetRowMinAbs - Gets the minimum value (in absolute value) of each
5114   row of the matrix
5115 
5116   Logically Collective
5117 
5118   Input Parameter:
5119 . mat - the matrix
5120 
5121   Output Parameters:
5122 + v   - the vector for storing the minimums
5123 - idx - the indices of the column found for each row (or `NULL` if not needed)
5124 
5125   Level: intermediate
5126 
5127   Notes:
5128   if a row is completely empty or has only 0.0 values, then the `idx` value for that
5129   row is 0 (the first column).
5130 
5131   This code is only implemented for a couple of matrix formats.
5132 
5133 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMaxAbs()`, `MatGetRowMin()`
5134 @*/
5135 PetscErrorCode MatGetRowMinAbs(Mat mat, Vec v, PetscInt idx[])
5136 {
5137   PetscFunctionBegin;
5138   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5139   PetscValidType(mat, 1);
5140   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5141   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5142   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5143 
5144   if (!mat->cmap->N) {
5145     PetscCall(VecSet(v, 0.0));
5146     if (idx) {
5147       PetscInt i, m = mat->rmap->n;
5148       for (i = 0; i < m; i++) idx[i] = -1;
5149     }
5150   } else {
5151     MatCheckPreallocated(mat, 1);
5152     if (idx) PetscCall(PetscArrayzero(idx, mat->rmap->n));
5153     PetscUseTypeMethod(mat, getrowminabs, v, idx);
5154   }
5155   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5156   PetscFunctionReturn(PETSC_SUCCESS);
5157 }
5158 
5159 /*@
5160   MatGetRowMax - Gets the maximum value (of the real part) of each
5161   row of the matrix
5162 
5163   Logically Collective
5164 
5165   Input Parameter:
5166 . mat - the matrix
5167 
5168   Output Parameters:
5169 + v   - the vector for storing the maximums
5170 - idx - the indices of the column found for each row (optional, otherwise pass `NULL`)
5171 
5172   Level: intermediate
5173 
5174   Notes:
5175   The result of this call are the same as if one converted the matrix to dense format
5176   and found the minimum value in each row (i.e. the implicit zeros are counted as zeros).
5177 
5178   This code is only implemented for a couple of matrix formats.
5179 
5180 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5181 @*/
5182 PetscErrorCode MatGetRowMax(Mat mat, Vec v, PetscInt idx[])
5183 {
5184   PetscFunctionBegin;
5185   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5186   PetscValidType(mat, 1);
5187   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5188   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5189 
5190   if (!mat->cmap->N) {
5191     PetscCall(VecSet(v, PETSC_MIN_REAL));
5192     if (idx) {
5193       PetscInt i, m = mat->rmap->n;
5194       for (i = 0; i < m; i++) idx[i] = -1;
5195     }
5196   } else {
5197     MatCheckPreallocated(mat, 1);
5198     PetscUseTypeMethod(mat, getrowmax, v, idx);
5199   }
5200   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5201   PetscFunctionReturn(PETSC_SUCCESS);
5202 }
5203 
5204 /*@
5205   MatGetRowMaxAbs - Gets the maximum value (in absolute value) of each
5206   row of the matrix
5207 
5208   Logically Collective
5209 
5210   Input Parameter:
5211 . mat - the matrix
5212 
5213   Output Parameters:
5214 + v   - the vector for storing the maximums
5215 - idx - the indices of the column found for each row (or `NULL` if not needed)
5216 
5217   Level: intermediate
5218 
5219   Notes:
5220   if a row is completely empty or has only 0.0 values, then the `idx` value for that
5221   row is 0 (the first column).
5222 
5223   This code is only implemented for a couple of matrix formats.
5224 
5225 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowSum()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5226 @*/
5227 PetscErrorCode MatGetRowMaxAbs(Mat mat, Vec v, PetscInt idx[])
5228 {
5229   PetscFunctionBegin;
5230   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5231   PetscValidType(mat, 1);
5232   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5233   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5234 
5235   if (!mat->cmap->N) {
5236     PetscCall(VecSet(v, 0.0));
5237     if (idx) {
5238       PetscInt i, m = mat->rmap->n;
5239       for (i = 0; i < m; i++) idx[i] = -1;
5240     }
5241   } else {
5242     MatCheckPreallocated(mat, 1);
5243     if (idx) PetscCall(PetscArrayzero(idx, mat->rmap->n));
5244     PetscUseTypeMethod(mat, getrowmaxabs, v, idx);
5245   }
5246   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5247   PetscFunctionReturn(PETSC_SUCCESS);
5248 }
5249 
5250 /*@
5251   MatGetRowSumAbs - Gets the sum value (in absolute value) of each row of the matrix
5252 
5253   Logically Collective
5254 
5255   Input Parameter:
5256 . mat - the matrix
5257 
5258   Output Parameter:
5259 . v - the vector for storing the sum
5260 
5261   Level: intermediate
5262 
5263   This code is only implemented for a couple of matrix formats.
5264 
5265 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5266 @*/
5267 PetscErrorCode MatGetRowSumAbs(Mat mat, Vec v)
5268 {
5269   PetscFunctionBegin;
5270   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5271   PetscValidType(mat, 1);
5272   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5273   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5274 
5275   if (!mat->cmap->N) {
5276     PetscCall(VecSet(v, 0.0));
5277   } else {
5278     MatCheckPreallocated(mat, 1);
5279     PetscUseTypeMethod(mat, getrowsumabs, v);
5280   }
5281   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5282   PetscFunctionReturn(PETSC_SUCCESS);
5283 }
5284 
5285 /*@
5286   MatGetRowSum - Gets the sum of each row of the matrix
5287 
5288   Logically or Neighborhood Collective
5289 
5290   Input Parameter:
5291 . mat - the matrix
5292 
5293   Output Parameter:
5294 . v - the vector for storing the sum of rows
5295 
5296   Level: intermediate
5297 
5298   Note:
5299   This code is slow since it is not currently specialized for different formats
5300 
5301 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMin()`, `MatGetRowMaxAbs()`, `MatGetRowMinAbs()`, `MatGetRowSumAbs()`
5302 @*/
5303 PetscErrorCode MatGetRowSum(Mat mat, Vec v)
5304 {
5305   Vec ones;
5306 
5307   PetscFunctionBegin;
5308   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5309   PetscValidType(mat, 1);
5310   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5311   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5312   MatCheckPreallocated(mat, 1);
5313   PetscCall(MatCreateVecs(mat, &ones, NULL));
5314   PetscCall(VecSet(ones, 1.));
5315   PetscCall(MatMult(mat, ones, v));
5316   PetscCall(VecDestroy(&ones));
5317   PetscFunctionReturn(PETSC_SUCCESS);
5318 }
5319 
5320 /*@
5321   MatTransposeSetPrecursor - Set the matrix from which the second matrix will receive numerical transpose data with a call to `MatTranspose`(A,`MAT_REUSE_MATRIX`,&B)
5322   when B was not obtained with `MatTranspose`(A,`MAT_INITIAL_MATRIX`,&B)
5323 
5324   Collective
5325 
5326   Input Parameter:
5327 . mat - the matrix to provide the transpose
5328 
5329   Output Parameter:
5330 . 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
5331 
5332   Level: advanced
5333 
5334   Note:
5335   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
5336   routine allows bypassing that call.
5337 
5338 .seealso: [](ch_matrices), `Mat`, `MatTransposeSymbolic()`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
5339 @*/
5340 PetscErrorCode MatTransposeSetPrecursor(Mat mat, Mat B)
5341 {
5342   MatParentState *rb = NULL;
5343 
5344   PetscFunctionBegin;
5345   PetscCall(PetscNew(&rb));
5346   rb->id    = ((PetscObject)mat)->id;
5347   rb->state = 0;
5348   PetscCall(MatGetNonzeroState(mat, &rb->nonzerostate));
5349   PetscCall(PetscObjectContainerCompose((PetscObject)B, "MatTransposeParent", rb, PetscCtxDestroyDefault));
5350   PetscFunctionReturn(PETSC_SUCCESS);
5351 }
5352 
5353 /*@
5354   MatTranspose - Computes the transpose of a matrix, either in-place or out-of-place.
5355 
5356   Collective
5357 
5358   Input Parameters:
5359 + mat   - the matrix to transpose
5360 - reuse - either `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, or `MAT_INPLACE_MATRIX`
5361 
5362   Output Parameter:
5363 . B - the transpose of the matrix
5364 
5365   Level: intermediate
5366 
5367   Notes:
5368   If you use `MAT_INPLACE_MATRIX` then you must pass in `&mat` for `B`
5369 
5370   `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
5371   transpose, call `MatTransposeSetPrecursor(mat, B)` before calling this routine.
5372 
5373   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.
5374 
5375   Consider using `MatCreateTranspose()` instead if you only need a matrix that behaves like the transpose but don't need the storage to be changed.
5376   For example, the result of `MatCreateTranspose()` will compute the transpose of the given matrix times a vector for matrix-vector products computed with `MatMult()`.
5377 
5378   If `mat` is unchanged from the last call this function returns immediately without recomputing the result
5379 
5380   If you only need the symbolic transpose of a matrix, and not the numerical values, use `MatTransposeSymbolic()`
5381 
5382 .seealso: [](ch_matrices), `Mat`, `MatTransposeSetPrecursor()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`,
5383           `MatTransposeSymbolic()`, `MatCreateTranspose()`
5384 @*/
5385 PetscErrorCode MatTranspose(Mat mat, MatReuse reuse, Mat *B)
5386 {
5387   PetscContainer  rB = NULL;
5388   MatParentState *rb = NULL;
5389 
5390   PetscFunctionBegin;
5391   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5392   PetscValidType(mat, 1);
5393   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5394   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5395   PetscCheck(reuse != MAT_INPLACE_MATRIX || mat == *B, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX requires last matrix to match first");
5396   PetscCheck(reuse != MAT_REUSE_MATRIX || mat != *B, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Perhaps you mean MAT_INPLACE_MATRIX");
5397   MatCheckPreallocated(mat, 1);
5398   if (reuse == MAT_REUSE_MATRIX) {
5399     PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
5400     PetscCheck(rB, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose(). Suggest MatTransposeSetPrecursor().");
5401     PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5402     PetscCheck(rb->id == ((PetscObject)mat)->id, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from input matrix");
5403     if (rb->state == ((PetscObject)mat)->state) PetscFunctionReturn(PETSC_SUCCESS);
5404   }
5405 
5406   PetscCall(PetscLogEventBegin(MAT_Transpose, mat, 0, 0, 0));
5407   if (reuse != MAT_INPLACE_MATRIX || mat->symmetric != PETSC_BOOL3_TRUE) {
5408     PetscUseTypeMethod(mat, transpose, reuse, B);
5409     PetscCall(PetscObjectStateIncrease((PetscObject)*B));
5410   }
5411   PetscCall(PetscLogEventEnd(MAT_Transpose, mat, 0, 0, 0));
5412 
5413   if (reuse == MAT_INITIAL_MATRIX) PetscCall(MatTransposeSetPrecursor(mat, *B));
5414   if (reuse != MAT_INPLACE_MATRIX) {
5415     PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
5416     PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5417     rb->state        = ((PetscObject)mat)->state;
5418     rb->nonzerostate = mat->nonzerostate;
5419   }
5420   PetscFunctionReturn(PETSC_SUCCESS);
5421 }
5422 
5423 /*@
5424   MatTransposeSymbolic - Computes the symbolic part of the transpose of a matrix.
5425 
5426   Collective
5427 
5428   Input Parameter:
5429 . A - the matrix to transpose
5430 
5431   Output Parameter:
5432 . 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
5433       numerical portion.
5434 
5435   Level: intermediate
5436 
5437   Note:
5438   This is not supported for many matrix types, use `MatTranspose()` in those cases
5439 
5440 .seealso: [](ch_matrices), `Mat`, `MatTransposeSetPrecursor()`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
5441 @*/
5442 PetscErrorCode MatTransposeSymbolic(Mat A, Mat *B)
5443 {
5444   PetscFunctionBegin;
5445   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5446   PetscValidType(A, 1);
5447   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5448   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5449   PetscCall(PetscLogEventBegin(MAT_Transpose, A, 0, 0, 0));
5450   PetscUseTypeMethod(A, transposesymbolic, B);
5451   PetscCall(PetscLogEventEnd(MAT_Transpose, A, 0, 0, 0));
5452 
5453   PetscCall(MatTransposeSetPrecursor(A, *B));
5454   PetscFunctionReturn(PETSC_SUCCESS);
5455 }
5456 
5457 PetscErrorCode MatTransposeCheckNonzeroState_Private(Mat A, Mat B)
5458 {
5459   PetscContainer  rB;
5460   MatParentState *rb;
5461 
5462   PetscFunctionBegin;
5463   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5464   PetscValidType(A, 1);
5465   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5466   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5467   PetscCall(PetscObjectQuery((PetscObject)B, "MatTransposeParent", (PetscObject *)&rB));
5468   PetscCheck(rB, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose()");
5469   PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5470   PetscCheck(rb->id == ((PetscObject)A)->id, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from input matrix");
5471   PetscCheck(rb->nonzerostate == A->nonzerostate, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Reuse matrix has changed nonzero structure");
5472   PetscFunctionReturn(PETSC_SUCCESS);
5473 }
5474 
5475 /*@
5476   MatIsTranspose - Test whether a matrix is another one's transpose,
5477   or its own, in which case it tests symmetry.
5478 
5479   Collective
5480 
5481   Input Parameters:
5482 + A   - the matrix to test
5483 . B   - the matrix to test against, this can equal the first parameter
5484 - tol - tolerance, differences between entries smaller than this are counted as zero
5485 
5486   Output Parameter:
5487 . flg - the result
5488 
5489   Level: intermediate
5490 
5491   Notes:
5492   The sequential algorithm has a running time of the order of the number of nonzeros; the parallel
5493   test involves parallel copies of the block off-diagonal parts of the matrix.
5494 
5495 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsSymmetric()`, `MatIsHermitian()`
5496 @*/
5497 PetscErrorCode MatIsTranspose(Mat A, Mat B, PetscReal tol, PetscBool *flg)
5498 {
5499   PetscErrorCode (*f)(Mat, Mat, PetscReal, PetscBool *), (*g)(Mat, Mat, PetscReal, PetscBool *);
5500 
5501   PetscFunctionBegin;
5502   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5503   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5504   PetscAssertPointer(flg, 4);
5505   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatIsTranspose_C", &f));
5506   PetscCall(PetscObjectQueryFunction((PetscObject)B, "MatIsTranspose_C", &g));
5507   *flg = PETSC_FALSE;
5508   if (f && g) {
5509     PetscCheck(f == g, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_NOTSAMETYPE, "Matrices do not have the same comparator for symmetry test");
5510     PetscCall((*f)(A, B, tol, flg));
5511   } else {
5512     MatType mattype;
5513 
5514     PetscCall(MatGetType(f ? B : A, &mattype));
5515     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Matrix of type %s does not support checking for transpose", mattype);
5516   }
5517   PetscFunctionReturn(PETSC_SUCCESS);
5518 }
5519 
5520 /*@
5521   MatHermitianTranspose - Computes an in-place or out-of-place Hermitian transpose of a matrix in complex conjugate.
5522 
5523   Collective
5524 
5525   Input Parameters:
5526 + mat   - the matrix to transpose and complex conjugate
5527 - reuse - either `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, or `MAT_INPLACE_MATRIX`
5528 
5529   Output Parameter:
5530 . B - the Hermitian transpose
5531 
5532   Level: intermediate
5533 
5534 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`
5535 @*/
5536 PetscErrorCode MatHermitianTranspose(Mat mat, MatReuse reuse, Mat *B)
5537 {
5538   PetscFunctionBegin;
5539   PetscCall(MatTranspose(mat, reuse, B));
5540 #if defined(PETSC_USE_COMPLEX)
5541   PetscCall(MatConjugate(*B));
5542 #endif
5543   PetscFunctionReturn(PETSC_SUCCESS);
5544 }
5545 
5546 /*@
5547   MatIsHermitianTranspose - Test whether a matrix is another one's Hermitian transpose,
5548 
5549   Collective
5550 
5551   Input Parameters:
5552 + A   - the matrix to test
5553 . B   - the matrix to test against, this can equal the first parameter
5554 - tol - tolerance, differences between entries smaller than this are counted as zero
5555 
5556   Output Parameter:
5557 . flg - the result
5558 
5559   Level: intermediate
5560 
5561   Notes:
5562   Only available for `MATAIJ` matrices.
5563 
5564   The sequential algorithm
5565   has a running time of the order of the number of nonzeros; the parallel
5566   test involves parallel copies of the block off-diagonal parts of the matrix.
5567 
5568 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsTranspose()`
5569 @*/
5570 PetscErrorCode MatIsHermitianTranspose(Mat A, Mat B, PetscReal tol, PetscBool *flg)
5571 {
5572   PetscErrorCode (*f)(Mat, Mat, PetscReal, PetscBool *), (*g)(Mat, Mat, PetscReal, PetscBool *);
5573 
5574   PetscFunctionBegin;
5575   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5576   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5577   PetscAssertPointer(flg, 4);
5578   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatIsHermitianTranspose_C", &f));
5579   PetscCall(PetscObjectQueryFunction((PetscObject)B, "MatIsHermitianTranspose_C", &g));
5580   if (f && g) {
5581     PetscCheck(f != g, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_NOTSAMETYPE, "Matrices do not have the same comparator for Hermitian test");
5582     PetscCall((*f)(A, B, tol, flg));
5583   }
5584   PetscFunctionReturn(PETSC_SUCCESS);
5585 }
5586 
5587 /*@
5588   MatPermute - Creates a new matrix with rows and columns permuted from the
5589   original.
5590 
5591   Collective
5592 
5593   Input Parameters:
5594 + mat - the matrix to permute
5595 . row - row permutation, each processor supplies only the permutation for its rows
5596 - col - column permutation, each processor supplies only the permutation for its columns
5597 
5598   Output Parameter:
5599 . B - the permuted matrix
5600 
5601   Level: advanced
5602 
5603   Note:
5604   The index sets map from row/col of permuted matrix to row/col of original matrix.
5605   The index sets should be on the same communicator as mat and have the same local sizes.
5606 
5607   Developer Note:
5608   If you want to implement `MatPermute()` for a matrix type, and your approach doesn't
5609   exploit the fact that row and col are permutations, consider implementing the
5610   more general `MatCreateSubMatrix()` instead.
5611 
5612 .seealso: [](ch_matrices), `Mat`, `MatGetOrdering()`, `ISAllGather()`, `MatCreateSubMatrix()`
5613 @*/
5614 PetscErrorCode MatPermute(Mat mat, IS row, IS col, Mat *B)
5615 {
5616   PetscFunctionBegin;
5617   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5618   PetscValidType(mat, 1);
5619   PetscValidHeaderSpecific(row, IS_CLASSID, 2);
5620   PetscValidHeaderSpecific(col, IS_CLASSID, 3);
5621   PetscAssertPointer(B, 4);
5622   PetscCheckSameComm(mat, 1, row, 2);
5623   if (row != col) PetscCheckSameComm(row, 2, col, 3);
5624   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5625   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5626   PetscCheck(mat->ops->permute || mat->ops->createsubmatrix, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatPermute not available for Mat type %s", ((PetscObject)mat)->type_name);
5627   MatCheckPreallocated(mat, 1);
5628 
5629   if (mat->ops->permute) {
5630     PetscUseTypeMethod(mat, permute, row, col, B);
5631     PetscCall(PetscObjectStateIncrease((PetscObject)*B));
5632   } else {
5633     PetscCall(MatCreateSubMatrix(mat, row, col, MAT_INITIAL_MATRIX, B));
5634   }
5635   PetscFunctionReturn(PETSC_SUCCESS);
5636 }
5637 
5638 /*@
5639   MatEqual - Compares two matrices.
5640 
5641   Collective
5642 
5643   Input Parameters:
5644 + A - the first matrix
5645 - B - the second matrix
5646 
5647   Output Parameter:
5648 . flg - `PETSC_TRUE` if the matrices are equal; `PETSC_FALSE` otherwise.
5649 
5650   Level: intermediate
5651 
5652   Note:
5653   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
5654   using several randomly created vectors, see `MatMultEqual()`.
5655 
5656 .seealso: [](ch_matrices), `Mat`, `MatMultEqual()`
5657 @*/
5658 PetscErrorCode MatEqual(Mat A, Mat B, PetscBool *flg)
5659 {
5660   PetscFunctionBegin;
5661   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5662   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5663   PetscValidType(A, 1);
5664   PetscValidType(B, 2);
5665   PetscAssertPointer(flg, 3);
5666   PetscCheckSameComm(A, 1, B, 2);
5667   MatCheckPreallocated(A, 1);
5668   MatCheckPreallocated(B, 2);
5669   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5670   PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5671   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,
5672              B->cmap->N);
5673   if (A->ops->equal && A->ops->equal == B->ops->equal) {
5674     PetscUseTypeMethod(A, equal, B, flg);
5675   } else {
5676     PetscCall(MatMultEqual(A, B, 10, flg));
5677   }
5678   PetscFunctionReturn(PETSC_SUCCESS);
5679 }
5680 
5681 /*@
5682   MatDiagonalScale - Scales a matrix on the left and right by diagonal
5683   matrices that are stored as vectors.  Either of the two scaling
5684   matrices can be `NULL`.
5685 
5686   Collective
5687 
5688   Input Parameters:
5689 + mat - the matrix to be scaled
5690 . l   - the left scaling vector (or `NULL`)
5691 - r   - the right scaling vector (or `NULL`)
5692 
5693   Level: intermediate
5694 
5695   Note:
5696   `MatDiagonalScale()` computes $A = LAR$, where
5697   L = a diagonal matrix (stored as a vector), R = a diagonal matrix (stored as a vector)
5698   The L scales the rows of the matrix, the R scales the columns of the matrix.
5699 
5700 .seealso: [](ch_matrices), `Mat`, `MatScale()`, `MatShift()`, `MatDiagonalSet()`
5701 @*/
5702 PetscErrorCode MatDiagonalScale(Mat mat, Vec l, Vec r)
5703 {
5704   PetscFunctionBegin;
5705   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5706   PetscValidType(mat, 1);
5707   if (l) {
5708     PetscValidHeaderSpecific(l, VEC_CLASSID, 2);
5709     PetscCheckSameComm(mat, 1, l, 2);
5710   }
5711   if (r) {
5712     PetscValidHeaderSpecific(r, VEC_CLASSID, 3);
5713     PetscCheckSameComm(mat, 1, r, 3);
5714   }
5715   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5716   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5717   MatCheckPreallocated(mat, 1);
5718   if (!l && !r) PetscFunctionReturn(PETSC_SUCCESS);
5719 
5720   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
5721   PetscUseTypeMethod(mat, diagonalscale, l, r);
5722   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
5723   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5724   if (l != r) mat->symmetric = PETSC_BOOL3_FALSE;
5725   PetscFunctionReturn(PETSC_SUCCESS);
5726 }
5727 
5728 /*@
5729   MatScale - Scales all elements of a matrix by a given number.
5730 
5731   Logically Collective
5732 
5733   Input Parameters:
5734 + mat - the matrix to be scaled
5735 - a   - the scaling value
5736 
5737   Level: intermediate
5738 
5739 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
5740 @*/
5741 PetscErrorCode MatScale(Mat mat, PetscScalar a)
5742 {
5743   PetscFunctionBegin;
5744   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5745   PetscValidType(mat, 1);
5746   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5747   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5748   PetscValidLogicalCollectiveScalar(mat, a, 2);
5749   MatCheckPreallocated(mat, 1);
5750 
5751   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
5752   if (a != (PetscScalar)1.0) {
5753     PetscUseTypeMethod(mat, scale, a);
5754     PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5755   }
5756   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
5757   PetscFunctionReturn(PETSC_SUCCESS);
5758 }
5759 
5760 /*@
5761   MatNorm - Calculates various norms of a matrix.
5762 
5763   Collective
5764 
5765   Input Parameters:
5766 + mat  - the matrix
5767 - type - the type of norm, `NORM_1`, `NORM_FROBENIUS`, `NORM_INFINITY`
5768 
5769   Output Parameter:
5770 . nrm - the resulting norm
5771 
5772   Level: intermediate
5773 
5774 .seealso: [](ch_matrices), `Mat`
5775 @*/
5776 PetscErrorCode MatNorm(Mat mat, NormType type, PetscReal *nrm)
5777 {
5778   PetscFunctionBegin;
5779   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5780   PetscValidType(mat, 1);
5781   PetscAssertPointer(nrm, 3);
5782 
5783   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5784   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5785   MatCheckPreallocated(mat, 1);
5786 
5787   PetscUseTypeMethod(mat, norm, type, nrm);
5788   PetscFunctionReturn(PETSC_SUCCESS);
5789 }
5790 
5791 /*
5792      This variable is used to prevent counting of MatAssemblyBegin() that
5793    are called from within a MatAssemblyEnd().
5794 */
5795 static PetscInt MatAssemblyEnd_InUse = 0;
5796 /*@
5797   MatAssemblyBegin - Begins assembling the matrix.  This routine should
5798   be called after completing all calls to `MatSetValues()`.
5799 
5800   Collective
5801 
5802   Input Parameters:
5803 + mat  - the matrix
5804 - type - type of assembly, either `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY`
5805 
5806   Level: beginner
5807 
5808   Notes:
5809   `MatSetValues()` generally caches the values that belong to other MPI processes.  The matrix is ready to
5810   use only after `MatAssemblyBegin()` and `MatAssemblyEnd()` have been called.
5811 
5812   Use `MAT_FLUSH_ASSEMBLY` when switching between `ADD_VALUES` and `INSERT_VALUES`
5813   in `MatSetValues()`; use `MAT_FINAL_ASSEMBLY` for the final assembly before
5814   using the matrix.
5815 
5816   ALL processes that share a matrix MUST call `MatAssemblyBegin()` and `MatAssemblyEnd()` the SAME NUMBER of times, and each time with the
5817   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
5818   a global collective operation requiring all processes that share the matrix.
5819 
5820   Space for preallocated nonzeros that is not filled by a call to `MatSetValues()` or a related routine are compressed
5821   out by assembly. If you intend to use that extra space on a subsequent assembly, be sure to insert explicit zeros
5822   before `MAT_FINAL_ASSEMBLY` so the space is not compressed out.
5823 
5824 .seealso: [](ch_matrices), `Mat`, `MatAssemblyEnd()`, `MatSetValues()`, `MatAssembled()`
5825 @*/
5826 PetscErrorCode MatAssemblyBegin(Mat mat, MatAssemblyType type)
5827 {
5828   PetscFunctionBegin;
5829   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5830   PetscValidType(mat, 1);
5831   MatCheckPreallocated(mat, 1);
5832   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix. Did you forget to call MatSetUnfactored()?");
5833   if (mat->assembled) {
5834     mat->was_assembled = PETSC_TRUE;
5835     mat->assembled     = PETSC_FALSE;
5836   }
5837 
5838   if (!MatAssemblyEnd_InUse) {
5839     PetscCall(PetscLogEventBegin(MAT_AssemblyBegin, mat, 0, 0, 0));
5840     PetscTryTypeMethod(mat, assemblybegin, type);
5841     PetscCall(PetscLogEventEnd(MAT_AssemblyBegin, mat, 0, 0, 0));
5842   } else PetscTryTypeMethod(mat, assemblybegin, type);
5843   PetscFunctionReturn(PETSC_SUCCESS);
5844 }
5845 
5846 /*@
5847   MatAssembled - Indicates if a matrix has been assembled and is ready for
5848   use; for example, in matrix-vector product.
5849 
5850   Not Collective
5851 
5852   Input Parameter:
5853 . mat - the matrix
5854 
5855   Output Parameter:
5856 . assembled - `PETSC_TRUE` or `PETSC_FALSE`
5857 
5858   Level: advanced
5859 
5860 .seealso: [](ch_matrices), `Mat`, `MatAssemblyEnd()`, `MatSetValues()`, `MatAssemblyBegin()`
5861 @*/
5862 PetscErrorCode MatAssembled(Mat mat, PetscBool *assembled)
5863 {
5864   PetscFunctionBegin;
5865   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5866   PetscAssertPointer(assembled, 2);
5867   *assembled = mat->assembled;
5868   PetscFunctionReturn(PETSC_SUCCESS);
5869 }
5870 
5871 /*@
5872   MatAssemblyEnd - Completes assembling the matrix.  This routine should
5873   be called after `MatAssemblyBegin()`.
5874 
5875   Collective
5876 
5877   Input Parameters:
5878 + mat  - the matrix
5879 - type - type of assembly, either `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY`
5880 
5881   Options Database Keys:
5882 + -mat_view ::ascii_info             - Prints info on matrix at conclusion of `MatAssemblyEnd()`
5883 . -mat_view ::ascii_info_detail      - Prints more detailed info
5884 . -mat_view                          - Prints matrix in ASCII format
5885 . -mat_view ::ascii_matlab           - Prints matrix in MATLAB format
5886 . -mat_view draw                     - draws nonzero structure of matrix, using `MatView()` and `PetscDrawOpenX()`.
5887 . -display <name>                    - Sets display name (default is host)
5888 . -draw_pause <sec>                  - Sets number of seconds to pause after display
5889 . -mat_view socket                   - Sends matrix to socket, can be accessed from MATLAB (See [Using MATLAB with PETSc](ch_matlab))
5890 . -viewer_socket_machine <machine>   - Machine to use for socket
5891 . -viewer_socket_port <port>         - Port number to use for socket
5892 - -mat_view binary:filename[:append] - Save matrix to file in binary format
5893 
5894   Level: beginner
5895 
5896 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatSetValues()`, `PetscDrawOpenX()`, `PetscDrawCreate()`, `MatView()`, `MatAssembled()`, `PetscViewerSocketOpen()`
5897 @*/
5898 PetscErrorCode MatAssemblyEnd(Mat mat, MatAssemblyType type)
5899 {
5900   static PetscInt inassm = 0;
5901   PetscBool       flg    = PETSC_FALSE;
5902 
5903   PetscFunctionBegin;
5904   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5905   PetscValidType(mat, 1);
5906 
5907   inassm++;
5908   MatAssemblyEnd_InUse++;
5909   if (MatAssemblyEnd_InUse == 1) { /* Do the logging only the first time through */
5910     PetscCall(PetscLogEventBegin(MAT_AssemblyEnd, mat, 0, 0, 0));
5911     PetscTryTypeMethod(mat, assemblyend, type);
5912     PetscCall(PetscLogEventEnd(MAT_AssemblyEnd, mat, 0, 0, 0));
5913   } else PetscTryTypeMethod(mat, assemblyend, type);
5914 
5915   /* Flush assembly is not a true assembly */
5916   if (type != MAT_FLUSH_ASSEMBLY) {
5917     if (mat->num_ass) {
5918       if (!mat->symmetry_eternal) {
5919         mat->symmetric = PETSC_BOOL3_UNKNOWN;
5920         mat->hermitian = PETSC_BOOL3_UNKNOWN;
5921       }
5922       if (!mat->structural_symmetry_eternal && mat->ass_nonzerostate != mat->nonzerostate) mat->structurally_symmetric = PETSC_BOOL3_UNKNOWN;
5923       if (!mat->spd_eternal) mat->spd = PETSC_BOOL3_UNKNOWN;
5924     }
5925     mat->num_ass++;
5926     mat->assembled        = PETSC_TRUE;
5927     mat->ass_nonzerostate = mat->nonzerostate;
5928   }
5929 
5930   mat->insertmode = NOT_SET_VALUES;
5931   MatAssemblyEnd_InUse--;
5932   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5933   if (inassm == 1 && type != MAT_FLUSH_ASSEMBLY) {
5934     PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
5935 
5936     if (mat->checksymmetryonassembly) {
5937       PetscCall(MatIsSymmetric(mat, mat->checksymmetrytol, &flg));
5938       if (flg) {
5939         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "Matrix is symmetric (tolerance %g)\n", (double)mat->checksymmetrytol));
5940       } else {
5941         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "Matrix is not symmetric (tolerance %g)\n", (double)mat->checksymmetrytol));
5942       }
5943     }
5944     if (mat->nullsp && mat->checknullspaceonassembly) PetscCall(MatNullSpaceTest(mat->nullsp, mat, NULL));
5945   }
5946   inassm--;
5947   PetscFunctionReturn(PETSC_SUCCESS);
5948 }
5949 
5950 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
5951 /*@
5952   MatSetOption - Sets a parameter option for a matrix. Some options
5953   may be specific to certain storage formats.  Some options
5954   determine how values will be inserted (or added). Sorted,
5955   row-oriented input will generally assemble the fastest. The default
5956   is row-oriented.
5957 
5958   Logically Collective for certain operations, such as `MAT_SPD`, not collective for `MAT_ROW_ORIENTED`, see `MatOption`
5959 
5960   Input Parameters:
5961 + mat - the matrix
5962 . op  - the option, one of those listed below (and possibly others),
5963 - flg - turn the option on (`PETSC_TRUE`) or off (`PETSC_FALSE`)
5964 
5965   Options Describing Matrix Structure:
5966 + `MAT_SPD`                         - symmetric positive definite
5967 . `MAT_SYMMETRIC`                   - symmetric in terms of both structure and value
5968 . `MAT_HERMITIAN`                   - transpose is the complex conjugation
5969 . `MAT_STRUCTURALLY_SYMMETRIC`      - symmetric nonzero structure
5970 . `MAT_SYMMETRY_ETERNAL`            - indicates the symmetry (or Hermitian structure) or its absence will persist through any changes to the matrix
5971 . `MAT_STRUCTURAL_SYMMETRY_ETERNAL` - indicates the structural symmetry or its absence will persist through any changes to the matrix
5972 . `MAT_SPD_ETERNAL`                 - indicates the value of `MAT_SPD` (true or false) will persist through any changes to the matrix
5973 
5974    These are not really options of the matrix, they are knowledge about the structure of the matrix that users may provide so that they
5975    do not need to be computed (usually at a high cost)
5976 
5977    Options For Use with `MatSetValues()`:
5978    Insert a logically dense subblock, which can be
5979 . `MAT_ROW_ORIENTED`                - row-oriented (default)
5980 
5981    These options reflect the data you pass in with `MatSetValues()`; it has
5982    nothing to do with how the data is stored internally in the matrix
5983    data structure.
5984 
5985    When (re)assembling a matrix, we can restrict the input for
5986    efficiency/debugging purposes.  These options include
5987 . `MAT_NEW_NONZERO_LOCATIONS`       - additional insertions will be allowed if they generate a new nonzero (slow)
5988 . `MAT_FORCE_DIAGONAL_ENTRIES`      - forces diagonal entries to be allocated
5989 . `MAT_IGNORE_OFF_PROC_ENTRIES`     - drops off-processor entries
5990 . `MAT_NEW_NONZERO_LOCATION_ERR`    - generates an error for new matrix entry
5991 . `MAT_USE_HASH_TABLE`              - uses a hash table to speed up matrix assembly
5992 . `MAT_NO_OFF_PROC_ENTRIES`         - you know each process will only set values for its own rows, will generate an error if
5993         any process sets values for another process. This avoids all reductions in the MatAssembly routines and thus improves
5994         performance for very large process counts.
5995 - `MAT_SUBSET_OFF_PROC_ENTRIES`     - you know that the first assembly after setting this flag will set a superset
5996         of the off-process entries required for all subsequent assemblies. This avoids a rendezvous step in the MatAssembly
5997         functions, instead sending only neighbor messages.
5998 
5999   Level: intermediate
6000 
6001   Notes:
6002   Except for `MAT_UNUSED_NONZERO_LOCATION_ERR` and  `MAT_ROW_ORIENTED` all processes that share the matrix must pass the same value in flg!
6003 
6004   Some options are relevant only for particular matrix types and
6005   are thus ignored by others.  Other options are not supported by
6006   certain matrix types and will generate an error message if set.
6007 
6008   If using Fortran to compute a matrix, one may need to
6009   use the column-oriented option (or convert to the row-oriented
6010   format).
6011 
6012   `MAT_NEW_NONZERO_LOCATIONS` set to `PETSC_FALSE` indicates that any add or insertion
6013   that would generate a new entry in the nonzero structure is instead
6014   ignored.  Thus, if memory has not already been allocated for this particular
6015   data, then the insertion is ignored. For dense matrices, in which
6016   the entire array is allocated, no entries are ever ignored.
6017   Set after the first `MatAssemblyEnd()`. If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
6018 
6019   `MAT_NEW_NONZERO_LOCATION_ERR` set to PETSC_TRUE indicates that any add or insertion
6020   that would generate a new entry in the nonzero structure instead produces
6021   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
6022 
6023   `MAT_NEW_NONZERO_ALLOCATION_ERR` set to `PETSC_TRUE` indicates that any add or insertion
6024   that would generate a new entry that has not been preallocated will
6025   instead produce an error. (Currently supported for `MATAIJ` and `MATBAIJ` formats
6026   only.) This is a useful flag when debugging matrix memory preallocation.
6027   If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
6028 
6029   `MAT_IGNORE_OFF_PROC_ENTRIES` set to `PETSC_TRUE` indicates entries destined for
6030   other processors should be dropped, rather than stashed.
6031   This is useful if you know that the "owning" processor is also
6032   always generating the correct matrix entries, so that PETSc need
6033   not transfer duplicate entries generated on another processor.
6034 
6035   `MAT_USE_HASH_TABLE` indicates that a hash table be used to improve the
6036   searches during matrix assembly. When this flag is set, the hash table
6037   is created during the first matrix assembly. This hash table is
6038   used the next time through, during `MatSetValues()`/`MatSetValuesBlocked()`
6039   to improve the searching of indices. `MAT_NEW_NONZERO_LOCATIONS` flag
6040   should be used with `MAT_USE_HASH_TABLE` flag. This option is currently
6041   supported by `MATMPIBAIJ` format only.
6042 
6043   `MAT_KEEP_NONZERO_PATTERN` indicates when `MatZeroRows()` is called the zeroed entries
6044   are kept in the nonzero structure. This flag is not used for `MatZeroRowsColumns()`
6045 
6046   `MAT_IGNORE_ZERO_ENTRIES` - for `MATAIJ` and `MATIS` matrices this will stop zero values from creating
6047   a zero location in the matrix
6048 
6049   `MAT_USE_INODES` - indicates using inode version of the code - works with `MATAIJ` matrix types
6050 
6051   `MAT_NO_OFF_PROC_ZERO_ROWS` - you know each process will only zero its own rows. This avoids all reductions in the
6052   zero row routines and thus improves performance for very large process counts.
6053 
6054   `MAT_IGNORE_LOWER_TRIANGULAR` - For `MATSBAIJ` matrices will ignore any insertions you make in the lower triangular
6055   part of the matrix (since they should match the upper triangular part).
6056 
6057   `MAT_SORTED_FULL` - each process provides exactly its local rows; all column indices for a given row are passed in a
6058   single call to `MatSetValues()`, preallocation is perfect, row-oriented, `INSERT_VALUES` is used. Common
6059   with finite difference schemes with non-periodic boundary conditions.
6060 
6061   Developer Note:
6062   `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, and `MAT_SPD_ETERNAL` are used by `MatAssemblyEnd()` and in other
6063   places where otherwise the value of `MAT_SYMMETRIC`, `MAT_STRUCTURALLY_SYMMETRIC` or `MAT_SPD` would need to be changed back
6064   to `PETSC_BOOL3_UNKNOWN` because the matrix values had changed so the code cannot be certain that the related property had
6065   not changed.
6066 
6067 .seealso: [](ch_matrices), `MatOption`, `Mat`, `MatGetOption()`
6068 @*/
6069 PetscErrorCode MatSetOption(Mat mat, MatOption op, PetscBool flg)
6070 {
6071   PetscFunctionBegin;
6072   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6073   if (op > 0) {
6074     PetscValidLogicalCollectiveEnum(mat, op, 2);
6075     PetscValidLogicalCollectiveBool(mat, flg, 3);
6076   }
6077 
6078   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);
6079 
6080   switch (op) {
6081   case MAT_FORCE_DIAGONAL_ENTRIES:
6082     mat->force_diagonals = flg;
6083     PetscFunctionReturn(PETSC_SUCCESS);
6084   case MAT_NO_OFF_PROC_ENTRIES:
6085     mat->nooffprocentries = flg;
6086     PetscFunctionReturn(PETSC_SUCCESS);
6087   case MAT_SUBSET_OFF_PROC_ENTRIES:
6088     mat->assembly_subset = flg;
6089     if (!mat->assembly_subset) { /* See the same logic in VecAssembly wrt VEC_SUBSET_OFF_PROC_ENTRIES */
6090 #if !defined(PETSC_HAVE_MPIUNI)
6091       PetscCall(MatStashScatterDestroy_BTS(&mat->stash));
6092 #endif
6093       mat->stash.first_assembly_done = PETSC_FALSE;
6094     }
6095     PetscFunctionReturn(PETSC_SUCCESS);
6096   case MAT_NO_OFF_PROC_ZERO_ROWS:
6097     mat->nooffproczerorows = flg;
6098     PetscFunctionReturn(PETSC_SUCCESS);
6099   case MAT_SPD:
6100     if (flg) {
6101       mat->spd                    = PETSC_BOOL3_TRUE;
6102       mat->symmetric              = PETSC_BOOL3_TRUE;
6103       mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6104     } else {
6105       mat->spd = PETSC_BOOL3_FALSE;
6106     }
6107     break;
6108   case MAT_SYMMETRIC:
6109     mat->symmetric = PetscBoolToBool3(flg);
6110     if (flg) mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6111 #if !defined(PETSC_USE_COMPLEX)
6112     mat->hermitian = PetscBoolToBool3(flg);
6113 #endif
6114     break;
6115   case MAT_HERMITIAN:
6116     mat->hermitian = PetscBoolToBool3(flg);
6117     if (flg) mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6118 #if !defined(PETSC_USE_COMPLEX)
6119     mat->symmetric = PetscBoolToBool3(flg);
6120 #endif
6121     break;
6122   case MAT_STRUCTURALLY_SYMMETRIC:
6123     mat->structurally_symmetric = PetscBoolToBool3(flg);
6124     break;
6125   case MAT_SYMMETRY_ETERNAL:
6126     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");
6127     mat->symmetry_eternal = flg;
6128     if (flg) mat->structural_symmetry_eternal = PETSC_TRUE;
6129     break;
6130   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
6131     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");
6132     mat->structural_symmetry_eternal = flg;
6133     break;
6134   case MAT_SPD_ETERNAL:
6135     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");
6136     mat->spd_eternal = flg;
6137     if (flg) {
6138       mat->structural_symmetry_eternal = PETSC_TRUE;
6139       mat->symmetry_eternal            = PETSC_TRUE;
6140     }
6141     break;
6142   case MAT_STRUCTURE_ONLY:
6143     mat->structure_only = flg;
6144     break;
6145   case MAT_SORTED_FULL:
6146     mat->sortedfull = flg;
6147     break;
6148   default:
6149     break;
6150   }
6151   PetscTryTypeMethod(mat, setoption, op, flg);
6152   PetscFunctionReturn(PETSC_SUCCESS);
6153 }
6154 
6155 /*@
6156   MatGetOption - Gets a parameter option that has been set for a matrix.
6157 
6158   Logically Collective
6159 
6160   Input Parameters:
6161 + mat - the matrix
6162 - op  - the option, this only responds to certain options, check the code for which ones
6163 
6164   Output Parameter:
6165 . flg - turn the option on (`PETSC_TRUE`) or off (`PETSC_FALSE`)
6166 
6167   Level: intermediate
6168 
6169   Notes:
6170   Can only be called after `MatSetSizes()` and `MatSetType()` have been set.
6171 
6172   Certain option values may be unknown, for those use the routines `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, or
6173   `MatIsSymmetricKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
6174 
6175 .seealso: [](ch_matrices), `Mat`, `MatOption`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`,
6176     `MatIsSymmetricKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
6177 @*/
6178 PetscErrorCode MatGetOption(Mat mat, MatOption op, PetscBool *flg)
6179 {
6180   PetscFunctionBegin;
6181   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6182   PetscValidType(mat, 1);
6183 
6184   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);
6185   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()");
6186 
6187   switch (op) {
6188   case MAT_NO_OFF_PROC_ENTRIES:
6189     *flg = mat->nooffprocentries;
6190     break;
6191   case MAT_NO_OFF_PROC_ZERO_ROWS:
6192     *flg = mat->nooffproczerorows;
6193     break;
6194   case MAT_SYMMETRIC:
6195     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsSymmetric() or MatIsSymmetricKnown()");
6196     break;
6197   case MAT_HERMITIAN:
6198     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsHermitian() or MatIsHermitianKnown()");
6199     break;
6200   case MAT_STRUCTURALLY_SYMMETRIC:
6201     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsStructurallySymmetric() or MatIsStructurallySymmetricKnown()");
6202     break;
6203   case MAT_SPD:
6204     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsSPDKnown()");
6205     break;
6206   case MAT_SYMMETRY_ETERNAL:
6207     *flg = mat->symmetry_eternal;
6208     break;
6209   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
6210     *flg = mat->symmetry_eternal;
6211     break;
6212   default:
6213     break;
6214   }
6215   PetscFunctionReturn(PETSC_SUCCESS);
6216 }
6217 
6218 /*@
6219   MatZeroEntries - Zeros all entries of a matrix.  For sparse matrices
6220   this routine retains the old nonzero structure.
6221 
6222   Logically Collective
6223 
6224   Input Parameter:
6225 . mat - the matrix
6226 
6227   Level: intermediate
6228 
6229   Note:
6230   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.
6231   See the Performance chapter of the users manual for information on preallocating matrices.
6232 
6233 .seealso: [](ch_matrices), `Mat`, `MatZeroRows()`, `MatZeroRowsColumns()`
6234 @*/
6235 PetscErrorCode MatZeroEntries(Mat mat)
6236 {
6237   PetscFunctionBegin;
6238   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6239   PetscValidType(mat, 1);
6240   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6241   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");
6242   MatCheckPreallocated(mat, 1);
6243 
6244   PetscCall(PetscLogEventBegin(MAT_ZeroEntries, mat, 0, 0, 0));
6245   PetscUseTypeMethod(mat, zeroentries);
6246   PetscCall(PetscLogEventEnd(MAT_ZeroEntries, mat, 0, 0, 0));
6247   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6248   PetscFunctionReturn(PETSC_SUCCESS);
6249 }
6250 
6251 /*@
6252   MatZeroRowsColumns - Zeros all entries (except possibly the main diagonal)
6253   of a set of rows and columns of a matrix.
6254 
6255   Collective
6256 
6257   Input Parameters:
6258 + mat     - the matrix
6259 . numRows - the number of rows/columns to zero
6260 . rows    - the global row indices
6261 . diag    - value put in the diagonal of the eliminated rows
6262 . x       - optional vector of the solution for zeroed rows (other entries in vector are not used), these must be set before this call
6263 - b       - optional vector of the right-hand side, that will be adjusted by provided solution entries
6264 
6265   Level: intermediate
6266 
6267   Notes:
6268   This routine, along with `MatZeroRows()`, is typically used to eliminate known Dirichlet boundary conditions from a linear system.
6269 
6270   For each zeroed row, the value of the corresponding `b` is set to diag times the value of the corresponding `x`.
6271   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
6272 
6273   If the resulting linear system is to be solved with `KSP` then one can (but does not have to) call `KSPSetInitialGuessNonzero()` to allow the
6274   Krylov method to take advantage of the known solution on the zeroed rows.
6275 
6276   For the parallel case, all processes that share the matrix (i.e.,
6277   those in the communicator used for matrix creation) MUST call this
6278   routine, regardless of whether any rows being zeroed are owned by
6279   them.
6280 
6281   Unlike `MatZeroRows()`, this ignores the `MAT_KEEP_NONZERO_PATTERN` option value set with `MatSetOption()`, it merely zeros those entries in the matrix, but never
6282   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
6283   missing.
6284 
6285   Each processor can indicate any rows in the entire matrix to be zeroed (i.e. each process does NOT have to
6286   list only rows local to itself).
6287 
6288   The option `MAT_NO_OFF_PROC_ZERO_ROWS` does not apply to this routine.
6289 
6290 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRows()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6291           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6292 @*/
6293 PetscErrorCode MatZeroRowsColumns(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6294 {
6295   PetscFunctionBegin;
6296   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6297   PetscValidType(mat, 1);
6298   if (numRows) PetscAssertPointer(rows, 3);
6299   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6300   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6301   MatCheckPreallocated(mat, 1);
6302 
6303   PetscUseTypeMethod(mat, zerorowscolumns, numRows, rows, diag, x, b);
6304   PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
6305   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6306   PetscFunctionReturn(PETSC_SUCCESS);
6307 }
6308 
6309 /*@
6310   MatZeroRowsColumnsIS - Zeros all entries (except possibly the main diagonal)
6311   of a set of rows and columns of a matrix.
6312 
6313   Collective
6314 
6315   Input Parameters:
6316 + mat  - the matrix
6317 . is   - the rows to zero
6318 . diag - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6319 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6320 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6321 
6322   Level: intermediate
6323 
6324   Note:
6325   See `MatZeroRowsColumns()` for details on how this routine operates.
6326 
6327 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6328           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRows()`, `MatZeroRowsColumnsStencil()`
6329 @*/
6330 PetscErrorCode MatZeroRowsColumnsIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6331 {
6332   PetscInt        numRows;
6333   const PetscInt *rows;
6334 
6335   PetscFunctionBegin;
6336   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6337   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6338   PetscValidType(mat, 1);
6339   PetscValidType(is, 2);
6340   PetscCall(ISGetLocalSize(is, &numRows));
6341   PetscCall(ISGetIndices(is, &rows));
6342   PetscCall(MatZeroRowsColumns(mat, numRows, rows, diag, x, b));
6343   PetscCall(ISRestoreIndices(is, &rows));
6344   PetscFunctionReturn(PETSC_SUCCESS);
6345 }
6346 
6347 /*@
6348   MatZeroRows - Zeros all entries (except possibly the main diagonal)
6349   of a set of rows of a matrix.
6350 
6351   Collective
6352 
6353   Input Parameters:
6354 + mat     - the matrix
6355 . numRows - the number of rows to zero
6356 . rows    - the global row indices
6357 . diag    - value put in the diagonal of the zeroed rows
6358 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used), these must be set before this call
6359 - b       - optional vector of right-hand side, that will be adjusted by provided solution entries
6360 
6361   Level: intermediate
6362 
6363   Notes:
6364   This routine, along with `MatZeroRowsColumns()`, is typically used to eliminate known Dirichlet boundary conditions from a linear system.
6365 
6366   For each zeroed row, the value of the corresponding `b` is set to `diag` times the value of the corresponding `x`.
6367 
6368   If the resulting linear system is to be solved with `KSP` then one can (but does not have to) call `KSPSetInitialGuessNonzero()` to allow the
6369   Krylov method to take advantage of the known solution on the zeroed rows.
6370 
6371   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)
6372   from the matrix.
6373 
6374   Unlike `MatZeroRowsColumns()` for the `MATAIJ` and `MATBAIJ` matrix formats this removes the old nonzero structure, from the eliminated rows of the matrix
6375   but does not release memory.  Because of this removal matrix-vector products with the adjusted matrix will be a bit faster. For the dense
6376   formats this does not alter the nonzero structure.
6377 
6378   If the option `MatSetOption`(mat,`MAT_KEEP_NONZERO_PATTERN`,`PETSC_TRUE`) the nonzero structure
6379   of the matrix is not changed the values are
6380   merely zeroed.
6381 
6382   The user can set a value in the diagonal entry (or for the `MATAIJ` format
6383   formats can optionally remove the main diagonal entry from the
6384   nonzero structure as well, by passing 0.0 as the final argument).
6385 
6386   For the parallel case, all processes that share the matrix (i.e.,
6387   those in the communicator used for matrix creation) MUST call this
6388   routine, regardless of whether any rows being zeroed are owned by
6389   them.
6390 
6391   Each processor can indicate any rows in the entire matrix to be zeroed (i.e. each process does NOT have to
6392   list only rows local to itself).
6393 
6394   You can call `MatSetOption`(mat,`MAT_NO_OFF_PROC_ZERO_ROWS`,`PETSC_TRUE`) if each process indicates only rows it
6395   owns that are to be zeroed. This saves a global synchronization in the implementation.
6396 
6397 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6398           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`, `PCREDISTRIBUTE`, `MAT_KEEP_NONZERO_PATTERN`
6399 @*/
6400 PetscErrorCode MatZeroRows(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6401 {
6402   PetscFunctionBegin;
6403   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6404   PetscValidType(mat, 1);
6405   if (numRows) PetscAssertPointer(rows, 3);
6406   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6407   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6408   MatCheckPreallocated(mat, 1);
6409 
6410   PetscUseTypeMethod(mat, zerorows, numRows, rows, diag, x, b);
6411   PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
6412   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6413   PetscFunctionReturn(PETSC_SUCCESS);
6414 }
6415 
6416 /*@
6417   MatZeroRowsIS - Zeros all entries (except possibly the main diagonal)
6418   of a set of rows of a matrix indicated by an `IS`
6419 
6420   Collective
6421 
6422   Input Parameters:
6423 + mat  - the matrix
6424 . is   - index set, `IS`, of rows to remove (if `NULL` then no row is removed)
6425 . diag - value put in all diagonals of eliminated rows
6426 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6427 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6428 
6429   Level: intermediate
6430 
6431   Note:
6432   See `MatZeroRows()` for details on how this routine operates.
6433 
6434 .seealso: [](ch_matrices), `Mat`, `MatZeroRows()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6435           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`, `IS`
6436 @*/
6437 PetscErrorCode MatZeroRowsIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6438 {
6439   PetscInt        numRows = 0;
6440   const PetscInt *rows    = NULL;
6441 
6442   PetscFunctionBegin;
6443   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6444   PetscValidType(mat, 1);
6445   if (is) {
6446     PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6447     PetscCall(ISGetLocalSize(is, &numRows));
6448     PetscCall(ISGetIndices(is, &rows));
6449   }
6450   PetscCall(MatZeroRows(mat, numRows, rows, diag, x, b));
6451   if (is) PetscCall(ISRestoreIndices(is, &rows));
6452   PetscFunctionReturn(PETSC_SUCCESS);
6453 }
6454 
6455 /*@
6456   MatZeroRowsStencil - Zeros all entries (except possibly the main diagonal)
6457   of a set of rows of a matrix indicated by a `MatStencil`. These rows must be local to the process.
6458 
6459   Collective
6460 
6461   Input Parameters:
6462 + mat     - the matrix
6463 . numRows - the number of rows to remove
6464 . rows    - the grid coordinates (and component number when dof > 1) for matrix rows indicated by an array of `MatStencil`
6465 . diag    - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6466 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6467 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6468 
6469   Level: intermediate
6470 
6471   Notes:
6472   See `MatZeroRows()` for details on how this routine operates.
6473 
6474   The grid coordinates are across the entire grid, not just the local portion
6475 
6476   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
6477   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
6478   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
6479   `DM_BOUNDARY_PERIODIC` boundary type.
6480 
6481   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
6482   a single value per point) you can skip filling those indices.
6483 
6484   Fortran Note:
6485   `idxm` and `idxn` should be declared as
6486 $     MatStencil idxm(4, m)
6487   and the values inserted using
6488 .vb
6489     idxm(MatStencil_i, 1) = i
6490     idxm(MatStencil_j, 1) = j
6491     idxm(MatStencil_k, 1) = k
6492     idxm(MatStencil_c, 1) = c
6493    etc
6494 .ve
6495 
6496 .seealso: [](ch_matrices), `Mat`, `MatStencil`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRows()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6497           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6498 @*/
6499 PetscErrorCode MatZeroRowsStencil(Mat mat, PetscInt numRows, const MatStencil rows[], PetscScalar diag, Vec x, Vec b)
6500 {
6501   PetscInt  dim    = mat->stencil.dim;
6502   PetscInt  sdim   = dim - (1 - (PetscInt)mat->stencil.noc);
6503   PetscInt *dims   = mat->stencil.dims + 1;
6504   PetscInt *starts = mat->stencil.starts;
6505   PetscInt *dxm    = (PetscInt *)rows;
6506   PetscInt *jdxm, i, j, tmp, numNewRows = 0;
6507 
6508   PetscFunctionBegin;
6509   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6510   PetscValidType(mat, 1);
6511   if (numRows) PetscAssertPointer(rows, 3);
6512 
6513   PetscCall(PetscMalloc1(numRows, &jdxm));
6514   for (i = 0; i < numRows; ++i) {
6515     /* Skip unused dimensions (they are ordered k, j, i, c) */
6516     for (j = 0; j < 3 - sdim; ++j) dxm++;
6517     /* Local index in X dir */
6518     tmp = *dxm++ - starts[0];
6519     /* Loop over remaining dimensions */
6520     for (j = 0; j < dim - 1; ++j) {
6521       /* If nonlocal, set index to be negative */
6522       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = PETSC_INT_MIN;
6523       /* Update local index */
6524       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
6525     }
6526     /* Skip component slot if necessary */
6527     if (mat->stencil.noc) dxm++;
6528     /* Local row number */
6529     if (tmp >= 0) jdxm[numNewRows++] = tmp;
6530   }
6531   PetscCall(MatZeroRowsLocal(mat, numNewRows, jdxm, diag, x, b));
6532   PetscCall(PetscFree(jdxm));
6533   PetscFunctionReturn(PETSC_SUCCESS);
6534 }
6535 
6536 /*@
6537   MatZeroRowsColumnsStencil - Zeros all row and column entries (except possibly the main diagonal)
6538   of a set of rows and columns of a matrix.
6539 
6540   Collective
6541 
6542   Input Parameters:
6543 + mat     - the matrix
6544 . numRows - the number of rows/columns to remove
6545 . rows    - the grid coordinates (and component number when dof > 1) for matrix rows
6546 . diag    - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6547 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6548 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6549 
6550   Level: intermediate
6551 
6552   Notes:
6553   See `MatZeroRowsColumns()` for details on how this routine operates.
6554 
6555   The grid coordinates are across the entire grid, not just the local portion
6556 
6557   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
6558   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
6559   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
6560   `DM_BOUNDARY_PERIODIC` boundary type.
6561 
6562   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
6563   a single value per point) you can skip filling those indices.
6564 
6565   Fortran Note:
6566   `idxm` and `idxn` should be declared as
6567 $     MatStencil idxm(4, m)
6568   and the values inserted using
6569 .vb
6570     idxm(MatStencil_i, 1) = i
6571     idxm(MatStencil_j, 1) = j
6572     idxm(MatStencil_k, 1) = k
6573     idxm(MatStencil_c, 1) = c
6574     etc
6575 .ve
6576 
6577 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6578           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRows()`
6579 @*/
6580 PetscErrorCode MatZeroRowsColumnsStencil(Mat mat, PetscInt numRows, const MatStencil rows[], PetscScalar diag, Vec x, Vec b)
6581 {
6582   PetscInt  dim    = mat->stencil.dim;
6583   PetscInt  sdim   = dim - (1 - (PetscInt)mat->stencil.noc);
6584   PetscInt *dims   = mat->stencil.dims + 1;
6585   PetscInt *starts = mat->stencil.starts;
6586   PetscInt *dxm    = (PetscInt *)rows;
6587   PetscInt *jdxm, i, j, tmp, numNewRows = 0;
6588 
6589   PetscFunctionBegin;
6590   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6591   PetscValidType(mat, 1);
6592   if (numRows) PetscAssertPointer(rows, 3);
6593 
6594   PetscCall(PetscMalloc1(numRows, &jdxm));
6595   for (i = 0; i < numRows; ++i) {
6596     /* Skip unused dimensions (they are ordered k, j, i, c) */
6597     for (j = 0; j < 3 - sdim; ++j) dxm++;
6598     /* Local index in X dir */
6599     tmp = *dxm++ - starts[0];
6600     /* Loop over remaining dimensions */
6601     for (j = 0; j < dim - 1; ++j) {
6602       /* If nonlocal, set index to be negative */
6603       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = PETSC_INT_MIN;
6604       /* Update local index */
6605       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
6606     }
6607     /* Skip component slot if necessary */
6608     if (mat->stencil.noc) dxm++;
6609     /* Local row number */
6610     if (tmp >= 0) jdxm[numNewRows++] = tmp;
6611   }
6612   PetscCall(MatZeroRowsColumnsLocal(mat, numNewRows, jdxm, diag, x, b));
6613   PetscCall(PetscFree(jdxm));
6614   PetscFunctionReturn(PETSC_SUCCESS);
6615 }
6616 
6617 /*@
6618   MatZeroRowsLocal - Zeros all entries (except possibly the main diagonal)
6619   of a set of rows of a matrix; using local numbering of rows.
6620 
6621   Collective
6622 
6623   Input Parameters:
6624 + mat     - the matrix
6625 . numRows - the number of rows to remove
6626 . rows    - the local row indices
6627 . diag    - value put in all diagonals of eliminated rows
6628 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6629 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6630 
6631   Level: intermediate
6632 
6633   Notes:
6634   Before calling `MatZeroRowsLocal()`, the user must first set the
6635   local-to-global mapping by calling MatSetLocalToGlobalMapping(), this is often already set for matrices obtained with `DMCreateMatrix()`.
6636 
6637   See `MatZeroRows()` for details on how this routine operates.
6638 
6639 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRows()`, `MatSetOption()`,
6640           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6641 @*/
6642 PetscErrorCode MatZeroRowsLocal(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6643 {
6644   PetscFunctionBegin;
6645   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6646   PetscValidType(mat, 1);
6647   if (numRows) PetscAssertPointer(rows, 3);
6648   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6649   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6650   MatCheckPreallocated(mat, 1);
6651 
6652   if (mat->ops->zerorowslocal) {
6653     PetscUseTypeMethod(mat, zerorowslocal, numRows, rows, diag, x, b);
6654   } else {
6655     IS              is, newis;
6656     const PetscInt *newRows;
6657 
6658     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Need to provide local to global mapping to matrix first");
6659     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numRows, rows, PETSC_COPY_VALUES, &is));
6660     PetscCall(ISLocalToGlobalMappingApplyIS(mat->rmap->mapping, is, &newis));
6661     PetscCall(ISGetIndices(newis, &newRows));
6662     PetscUseTypeMethod(mat, zerorows, numRows, newRows, diag, x, b);
6663     PetscCall(ISRestoreIndices(newis, &newRows));
6664     PetscCall(ISDestroy(&newis));
6665     PetscCall(ISDestroy(&is));
6666   }
6667   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6668   PetscFunctionReturn(PETSC_SUCCESS);
6669 }
6670 
6671 /*@
6672   MatZeroRowsLocalIS - Zeros all entries (except possibly the main diagonal)
6673   of a set of rows of a matrix; using local numbering of rows.
6674 
6675   Collective
6676 
6677   Input Parameters:
6678 + mat  - the matrix
6679 . is   - index set of rows to remove
6680 . diag - value put in all diagonals of eliminated rows
6681 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6682 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6683 
6684   Level: intermediate
6685 
6686   Notes:
6687   Before calling `MatZeroRowsLocalIS()`, the user must first set the
6688   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6689 
6690   See `MatZeroRows()` for details on how this routine operates.
6691 
6692 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRows()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6693           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6694 @*/
6695 PetscErrorCode MatZeroRowsLocalIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6696 {
6697   PetscInt        numRows;
6698   const PetscInt *rows;
6699 
6700   PetscFunctionBegin;
6701   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6702   PetscValidType(mat, 1);
6703   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6704   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6705   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6706   MatCheckPreallocated(mat, 1);
6707 
6708   PetscCall(ISGetLocalSize(is, &numRows));
6709   PetscCall(ISGetIndices(is, &rows));
6710   PetscCall(MatZeroRowsLocal(mat, numRows, rows, diag, x, b));
6711   PetscCall(ISRestoreIndices(is, &rows));
6712   PetscFunctionReturn(PETSC_SUCCESS);
6713 }
6714 
6715 /*@
6716   MatZeroRowsColumnsLocal - Zeros all entries (except possibly the main diagonal)
6717   of a set of rows and columns of a matrix; using local numbering of rows.
6718 
6719   Collective
6720 
6721   Input Parameters:
6722 + mat     - the matrix
6723 . numRows - the number of rows to remove
6724 . rows    - the global row indices
6725 . diag    - value put in all diagonals of eliminated rows
6726 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6727 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6728 
6729   Level: intermediate
6730 
6731   Notes:
6732   Before calling `MatZeroRowsColumnsLocal()`, the user must first set the
6733   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6734 
6735   See `MatZeroRowsColumns()` for details on how this routine operates.
6736 
6737 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6738           `MatZeroRows()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6739 @*/
6740 PetscErrorCode MatZeroRowsColumnsLocal(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6741 {
6742   IS              is, newis;
6743   const PetscInt *newRows;
6744 
6745   PetscFunctionBegin;
6746   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6747   PetscValidType(mat, 1);
6748   if (numRows) PetscAssertPointer(rows, 3);
6749   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6750   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6751   MatCheckPreallocated(mat, 1);
6752 
6753   PetscCheck(mat->cmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Need to provide local to global mapping to matrix first");
6754   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numRows, rows, PETSC_COPY_VALUES, &is));
6755   PetscCall(ISLocalToGlobalMappingApplyIS(mat->cmap->mapping, is, &newis));
6756   PetscCall(ISGetIndices(newis, &newRows));
6757   PetscUseTypeMethod(mat, zerorowscolumns, numRows, newRows, diag, x, b);
6758   PetscCall(ISRestoreIndices(newis, &newRows));
6759   PetscCall(ISDestroy(&newis));
6760   PetscCall(ISDestroy(&is));
6761   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6762   PetscFunctionReturn(PETSC_SUCCESS);
6763 }
6764 
6765 /*@
6766   MatZeroRowsColumnsLocalIS - Zeros all entries (except possibly the main diagonal)
6767   of a set of rows and columns of a matrix; using local numbering of rows.
6768 
6769   Collective
6770 
6771   Input Parameters:
6772 + mat  - the matrix
6773 . is   - index set of rows to remove
6774 . diag - value put in all diagonals of eliminated rows
6775 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6776 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6777 
6778   Level: intermediate
6779 
6780   Notes:
6781   Before calling `MatZeroRowsColumnsLocalIS()`, the user must first set the
6782   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6783 
6784   See `MatZeroRowsColumns()` for details on how this routine operates.
6785 
6786 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6787           `MatZeroRowsColumnsLocal()`, `MatZeroRows()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6788 @*/
6789 PetscErrorCode MatZeroRowsColumnsLocalIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6790 {
6791   PetscInt        numRows;
6792   const PetscInt *rows;
6793 
6794   PetscFunctionBegin;
6795   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6796   PetscValidType(mat, 1);
6797   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6798   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6799   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6800   MatCheckPreallocated(mat, 1);
6801 
6802   PetscCall(ISGetLocalSize(is, &numRows));
6803   PetscCall(ISGetIndices(is, &rows));
6804   PetscCall(MatZeroRowsColumnsLocal(mat, numRows, rows, diag, x, b));
6805   PetscCall(ISRestoreIndices(is, &rows));
6806   PetscFunctionReturn(PETSC_SUCCESS);
6807 }
6808 
6809 /*@
6810   MatGetSize - Returns the numbers of rows and columns in a matrix.
6811 
6812   Not Collective
6813 
6814   Input Parameter:
6815 . mat - the matrix
6816 
6817   Output Parameters:
6818 + m - the number of global rows
6819 - n - the number of global columns
6820 
6821   Level: beginner
6822 
6823   Note:
6824   Both output parameters can be `NULL` on input.
6825 
6826 .seealso: [](ch_matrices), `Mat`, `MatSetSizes()`, `MatGetLocalSize()`
6827 @*/
6828 PetscErrorCode MatGetSize(Mat mat, PetscInt *m, PetscInt *n)
6829 {
6830   PetscFunctionBegin;
6831   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6832   if (m) *m = mat->rmap->N;
6833   if (n) *n = mat->cmap->N;
6834   PetscFunctionReturn(PETSC_SUCCESS);
6835 }
6836 
6837 /*@
6838   MatGetLocalSize - For most matrix formats, excluding `MATELEMENTAL` and `MATSCALAPACK`, Returns the number of local rows and local columns
6839   of a matrix. For all matrices this is the local size of the left and right vectors as returned by `MatCreateVecs()`.
6840 
6841   Not Collective
6842 
6843   Input Parameter:
6844 . mat - the matrix
6845 
6846   Output Parameters:
6847 + m - the number of local rows, use `NULL` to not obtain this value
6848 - n - the number of local columns, use `NULL` to not obtain this value
6849 
6850   Level: beginner
6851 
6852 .seealso: [](ch_matrices), `Mat`, `MatSetSizes()`, `MatGetSize()`
6853 @*/
6854 PetscErrorCode MatGetLocalSize(Mat mat, PetscInt *m, PetscInt *n)
6855 {
6856   PetscFunctionBegin;
6857   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6858   if (m) PetscAssertPointer(m, 2);
6859   if (n) PetscAssertPointer(n, 3);
6860   if (m) *m = mat->rmap->n;
6861   if (n) *n = mat->cmap->n;
6862   PetscFunctionReturn(PETSC_SUCCESS);
6863 }
6864 
6865 /*@
6866   MatGetOwnershipRangeColumn - Returns the range of matrix columns associated with rows of a
6867   vector one multiplies this matrix by that are owned by this processor.
6868 
6869   Not Collective, unless matrix has not been allocated, then collective
6870 
6871   Input Parameter:
6872 . mat - the matrix
6873 
6874   Output Parameters:
6875 + m - the global index of the first local column, use `NULL` to not obtain this value
6876 - n - one more than the global index of the last local column, use `NULL` to not obtain this value
6877 
6878   Level: developer
6879 
6880   Notes:
6881   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6882 
6883   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6884   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6885 
6886   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6887   the local values in the matrix.
6888 
6889   Returns the columns of the "diagonal block" for most sparse matrix formats. See [Matrix
6890   Layouts](sec_matlayout) for details on matrix layouts.
6891 
6892 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`,
6893           `MatSetSizes()`, `MatCreateAIJ()`, `DMDAGetGhostCorners()`, `DM`
6894 @*/
6895 PetscErrorCode MatGetOwnershipRangeColumn(Mat mat, PetscInt *m, PetscInt *n)
6896 {
6897   PetscFunctionBegin;
6898   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6899   PetscValidType(mat, 1);
6900   if (m) PetscAssertPointer(m, 2);
6901   if (n) PetscAssertPointer(n, 3);
6902   MatCheckPreallocated(mat, 1);
6903   if (m) *m = mat->cmap->rstart;
6904   if (n) *n = mat->cmap->rend;
6905   PetscFunctionReturn(PETSC_SUCCESS);
6906 }
6907 
6908 /*@
6909   MatGetOwnershipRange - For matrices that own values by row, excludes `MATELEMENTAL` and `MATSCALAPACK`, returns the range of matrix rows owned by
6910   this MPI process.
6911 
6912   Not Collective
6913 
6914   Input Parameter:
6915 . mat - the matrix
6916 
6917   Output Parameters:
6918 + m - the global index of the first local row, use `NULL` to not obtain this value
6919 - n - one more than the global index of the last local row, use `NULL` to not obtain this value
6920 
6921   Level: beginner
6922 
6923   Notes:
6924   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6925 
6926   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6927   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6928 
6929   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6930   the local values in the matrix.
6931 
6932   The high argument is one more than the last element stored locally.
6933 
6934   For all matrices  it returns the range of matrix rows associated with rows of a vector that
6935   would contain the result of a matrix vector product with this matrix. See [Matrix
6936   Layouts](sec_matlayout) for details on matrix layouts.
6937 
6938 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscSplitOwnership()`,
6939           `PetscSplitOwnershipBlock()`, `PetscLayout`, `MatSetSizes()`, `MatCreateAIJ()`, `DMDAGetGhostCorners()`, `DM`
6940 @*/
6941 PetscErrorCode MatGetOwnershipRange(Mat mat, PetscInt *m, PetscInt *n)
6942 {
6943   PetscFunctionBegin;
6944   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6945   PetscValidType(mat, 1);
6946   if (m) PetscAssertPointer(m, 2);
6947   if (n) PetscAssertPointer(n, 3);
6948   MatCheckPreallocated(mat, 1);
6949   if (m) *m = mat->rmap->rstart;
6950   if (n) *n = mat->rmap->rend;
6951   PetscFunctionReturn(PETSC_SUCCESS);
6952 }
6953 
6954 /*@C
6955   MatGetOwnershipRanges - For matrices that own values by row, excludes `MATELEMENTAL` and
6956   `MATSCALAPACK`, returns the range of matrix rows owned by each process.
6957 
6958   Not Collective, unless matrix has not been allocated
6959 
6960   Input Parameter:
6961 . mat - the matrix
6962 
6963   Output Parameter:
6964 . ranges - start of each processors portion plus one more than the total length at the end, of length `size` + 1
6965            where `size` is the number of MPI processes used by `mat`
6966 
6967   Level: beginner
6968 
6969   Notes:
6970   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6971 
6972   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6973   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6974 
6975   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6976   the local values in the matrix.
6977 
6978   For all matrices  it returns the ranges of matrix rows associated with rows of a vector that
6979   would contain the result of a matrix vector product with this matrix. See [Matrix
6980   Layouts](sec_matlayout) for details on matrix layouts.
6981 
6982 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`,
6983           `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`, `MatSetSizes()`, `MatCreateAIJ()`,
6984           `DMDAGetGhostCorners()`, `DM`
6985 @*/
6986 PetscErrorCode MatGetOwnershipRanges(Mat mat, const PetscInt *ranges[])
6987 {
6988   PetscFunctionBegin;
6989   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6990   PetscValidType(mat, 1);
6991   MatCheckPreallocated(mat, 1);
6992   PetscCall(PetscLayoutGetRanges(mat->rmap, ranges));
6993   PetscFunctionReturn(PETSC_SUCCESS);
6994 }
6995 
6996 /*@C
6997   MatGetOwnershipRangesColumn - Returns the ranges of matrix columns associated with rows of a
6998   vector one multiplies this vector by that are owned by each processor.
6999 
7000   Not Collective, unless matrix has not been allocated
7001 
7002   Input Parameter:
7003 . mat - the matrix
7004 
7005   Output Parameter:
7006 . ranges - start of each processors portion plus one more than the total length at the end
7007 
7008   Level: beginner
7009 
7010   Notes:
7011   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
7012 
7013   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
7014   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
7015 
7016   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
7017   the local values in the matrix.
7018 
7019   Returns the columns of the "diagonal blocks", for most sparse matrix formats. See [Matrix
7020   Layouts](sec_matlayout) for details on matrix layouts.
7021 
7022 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRanges()`,
7023           `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`, `PetscLayout`, `MatSetSizes()`, `MatCreateAIJ()`,
7024           `DMDAGetGhostCorners()`, `DM`
7025 @*/
7026 PetscErrorCode MatGetOwnershipRangesColumn(Mat mat, const PetscInt *ranges[])
7027 {
7028   PetscFunctionBegin;
7029   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7030   PetscValidType(mat, 1);
7031   MatCheckPreallocated(mat, 1);
7032   PetscCall(PetscLayoutGetRanges(mat->cmap, ranges));
7033   PetscFunctionReturn(PETSC_SUCCESS);
7034 }
7035 
7036 /*@
7037   MatGetOwnershipIS - Get row and column ownership of a matrices' values as index sets.
7038 
7039   Not Collective
7040 
7041   Input Parameter:
7042 . A - matrix
7043 
7044   Output Parameters:
7045 + rows - rows in which this process owns elements, , use `NULL` to not obtain this value
7046 - cols - columns in which this process owns elements, use `NULL` to not obtain this value
7047 
7048   Level: intermediate
7049 
7050   Note:
7051   You should call `ISDestroy()` on the returned `IS`
7052 
7053   For most matrices, excluding `MATELEMENTAL` and `MATSCALAPACK`, this corresponds to values
7054   returned by `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`. For `MATELEMENTAL` and
7055   `MATSCALAPACK` the ownership is more complicated. See [Matrix Layouts](sec_matlayout) for
7056   details on matrix layouts.
7057 
7058 .seealso: [](ch_matrices), `IS`, `Mat`, `MatGetOwnershipRanges()`, `MatSetValues()`, `MATELEMENTAL`, `MATSCALAPACK`
7059 @*/
7060 PetscErrorCode MatGetOwnershipIS(Mat A, IS *rows, IS *cols)
7061 {
7062   PetscErrorCode (*f)(Mat, IS *, IS *);
7063 
7064   PetscFunctionBegin;
7065   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
7066   PetscValidType(A, 1);
7067   MatCheckPreallocated(A, 1);
7068   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatGetOwnershipIS_C", &f));
7069   if (f) {
7070     PetscCall((*f)(A, rows, cols));
7071   } else { /* Create a standard row-based partition, each process is responsible for ALL columns in their row block */
7072     if (rows) PetscCall(ISCreateStride(PETSC_COMM_SELF, A->rmap->n, A->rmap->rstart, 1, rows));
7073     if (cols) PetscCall(ISCreateStride(PETSC_COMM_SELF, A->cmap->N, 0, 1, cols));
7074   }
7075   PetscFunctionReturn(PETSC_SUCCESS);
7076 }
7077 
7078 /*@
7079   MatILUFactorSymbolic - Performs symbolic ILU factorization of a matrix obtained with `MatGetFactor()`
7080   Uses levels of fill only, not drop tolerance. Use `MatLUFactorNumeric()`
7081   to complete the factorization.
7082 
7083   Collective
7084 
7085   Input Parameters:
7086 + fact - the factorized matrix obtained with `MatGetFactor()`
7087 . mat  - the matrix
7088 . row  - row permutation
7089 . col  - column permutation
7090 - info - structure containing
7091 .vb
7092       levels - number of levels of fill.
7093       expected fill - as ratio of original fill.
7094       1 or 0 - indicating force fill on diagonal (improves robustness for matrices
7095                 missing diagonal entries)
7096 .ve
7097 
7098   Level: developer
7099 
7100   Notes:
7101   See [Matrix Factorization](sec_matfactor) for additional information.
7102 
7103   Most users should employ the `KSP` interface for linear solvers
7104   instead of working directly with matrix algebra routines such as this.
7105   See, e.g., `KSPCreate()`.
7106 
7107   Uses the definition of level of fill as in Y. Saad, {cite}`saad2003`
7108 
7109   Developer Note:
7110   The Fortran interface is not autogenerated as the
7111   interface definition cannot be generated correctly [due to `MatFactorInfo`]
7112 
7113 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
7114           `MatGetOrdering()`, `MatFactorInfo`
7115 @*/
7116 PetscErrorCode MatILUFactorSymbolic(Mat fact, Mat mat, IS row, IS col, const MatFactorInfo *info)
7117 {
7118   PetscFunctionBegin;
7119   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
7120   PetscValidType(mat, 2);
7121   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 3);
7122   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 4);
7123   PetscAssertPointer(info, 5);
7124   PetscAssertPointer(fact, 1);
7125   PetscCheck(info->levels >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Levels of fill negative %" PetscInt_FMT, (PetscInt)info->levels);
7126   PetscCheck(info->fill >= 1.0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Expected fill less than 1.0 %g", (double)info->fill);
7127   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7128   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7129   MatCheckPreallocated(mat, 2);
7130 
7131   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_ILUFactorSymbolic, mat, row, col, 0));
7132   PetscUseTypeMethod(fact, ilufactorsymbolic, mat, row, col, info);
7133   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_ILUFactorSymbolic, mat, row, col, 0));
7134   PetscFunctionReturn(PETSC_SUCCESS);
7135 }
7136 
7137 /*@
7138   MatICCFactorSymbolic - Performs symbolic incomplete
7139   Cholesky factorization for a symmetric matrix.  Use
7140   `MatCholeskyFactorNumeric()` to complete the factorization.
7141 
7142   Collective
7143 
7144   Input Parameters:
7145 + fact - the factorized matrix obtained with `MatGetFactor()`
7146 . mat  - the matrix to be factored
7147 . perm - row and column permutation
7148 - info - structure containing
7149 .vb
7150       levels - number of levels of fill.
7151       expected fill - as ratio of original fill.
7152 .ve
7153 
7154   Level: developer
7155 
7156   Notes:
7157   Most users should employ the `KSP` interface for linear solvers
7158   instead of working directly with matrix algebra routines such as this.
7159   See, e.g., `KSPCreate()`.
7160 
7161   This uses the definition of level of fill as in Y. Saad {cite}`saad2003`
7162 
7163   Developer Note:
7164   The Fortran interface is not autogenerated as the
7165   interface definition cannot be generated correctly [due to `MatFactorInfo`]
7166 
7167 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`
7168 @*/
7169 PetscErrorCode MatICCFactorSymbolic(Mat fact, Mat mat, IS perm, const MatFactorInfo *info)
7170 {
7171   PetscFunctionBegin;
7172   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
7173   PetscValidType(mat, 2);
7174   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 3);
7175   PetscAssertPointer(info, 4);
7176   PetscAssertPointer(fact, 1);
7177   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7178   PetscCheck(info->levels >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Levels negative %" PetscInt_FMT, (PetscInt)info->levels);
7179   PetscCheck(info->fill >= 1.0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Expected fill less than 1.0 %g", (double)info->fill);
7180   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7181   MatCheckPreallocated(mat, 2);
7182 
7183   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_ICCFactorSymbolic, mat, perm, 0, 0));
7184   PetscUseTypeMethod(fact, iccfactorsymbolic, mat, perm, info);
7185   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_ICCFactorSymbolic, mat, perm, 0, 0));
7186   PetscFunctionReturn(PETSC_SUCCESS);
7187 }
7188 
7189 /*@C
7190   MatCreateSubMatrices - Extracts several submatrices from a matrix. If submat
7191   points to an array of valid matrices, they may be reused to store the new
7192   submatrices.
7193 
7194   Collective
7195 
7196   Input Parameters:
7197 + mat   - the matrix
7198 . n     - the number of submatrixes to be extracted (on this processor, may be zero)
7199 . irow  - index set of rows to extract
7200 . icol  - index set of columns to extract
7201 - scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
7202 
7203   Output Parameter:
7204 . submat - the array of submatrices
7205 
7206   Level: advanced
7207 
7208   Notes:
7209   `MatCreateSubMatrices()` can extract ONLY sequential submatrices
7210   (from both sequential and parallel matrices). Use `MatCreateSubMatrix()`
7211   to extract a parallel submatrix.
7212 
7213   Some matrix types place restrictions on the row and column
7214   indices, such as that they be sorted or that they be equal to each other.
7215 
7216   The index sets may not have duplicate entries.
7217 
7218   When extracting submatrices from a parallel matrix, each processor can
7219   form a different submatrix by setting the rows and columns of its
7220   individual index sets according to the local submatrix desired.
7221 
7222   When finished using the submatrices, the user should destroy
7223   them with `MatDestroySubMatrices()`.
7224 
7225   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
7226   original matrix has not changed from that last call to `MatCreateSubMatrices()`.
7227 
7228   This routine creates the matrices in submat; you should NOT create them before
7229   calling it. It also allocates the array of matrix pointers submat.
7230 
7231   For `MATBAIJ` matrices the index sets must respect the block structure, that is if they
7232   request one row/column in a block, they must request all rows/columns that are in
7233   that block. For example, if the block size is 2 you cannot request just row 0 and
7234   column 0.
7235 
7236   Fortran Note:
7237 .vb
7238   Mat, pointer :: submat(:)
7239 .ve
7240 
7241 .seealso: [](ch_matrices), `Mat`, `MatDestroySubMatrices()`, `MatCreateSubMatrix()`, `MatGetRow()`, `MatGetDiagonal()`, `MatReuse`
7242 @*/
7243 PetscErrorCode MatCreateSubMatrices(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
7244 {
7245   PetscInt  i;
7246   PetscBool eq;
7247 
7248   PetscFunctionBegin;
7249   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7250   PetscValidType(mat, 1);
7251   if (n) {
7252     PetscAssertPointer(irow, 3);
7253     for (i = 0; i < n; i++) PetscValidHeaderSpecific(irow[i], IS_CLASSID, 3);
7254     PetscAssertPointer(icol, 4);
7255     for (i = 0; i < n; i++) PetscValidHeaderSpecific(icol[i], IS_CLASSID, 4);
7256   }
7257   PetscAssertPointer(submat, 6);
7258   if (n && scall == MAT_REUSE_MATRIX) {
7259     PetscAssertPointer(*submat, 6);
7260     for (i = 0; i < n; i++) PetscValidHeaderSpecific((*submat)[i], MAT_CLASSID, 6);
7261   }
7262   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7263   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7264   MatCheckPreallocated(mat, 1);
7265   PetscCall(PetscLogEventBegin(MAT_CreateSubMats, mat, 0, 0, 0));
7266   PetscUseTypeMethod(mat, createsubmatrices, n, irow, icol, scall, submat);
7267   PetscCall(PetscLogEventEnd(MAT_CreateSubMats, mat, 0, 0, 0));
7268   for (i = 0; i < n; i++) {
7269     (*submat)[i]->factortype = MAT_FACTOR_NONE; /* in case in place factorization was previously done on submatrix */
7270     PetscCall(ISEqualUnsorted(irow[i], icol[i], &eq));
7271     if (eq) PetscCall(MatPropagateSymmetryOptions(mat, (*submat)[i]));
7272 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
7273     if (mat->boundtocpu && mat->bindingpropagates) {
7274       PetscCall(MatBindToCPU((*submat)[i], PETSC_TRUE));
7275       PetscCall(MatSetBindingPropagates((*submat)[i], PETSC_TRUE));
7276     }
7277 #endif
7278   }
7279   PetscFunctionReturn(PETSC_SUCCESS);
7280 }
7281 
7282 /*@C
7283   MatCreateSubMatricesMPI - Extracts MPI submatrices across a sub communicator of `mat` (by pairs of `IS` that may live on subcomms).
7284 
7285   Collective
7286 
7287   Input Parameters:
7288 + mat   - the matrix
7289 . n     - the number of submatrixes to be extracted
7290 . irow  - index set of rows to extract
7291 . icol  - index set of columns to extract
7292 - scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
7293 
7294   Output Parameter:
7295 . submat - the array of submatrices
7296 
7297   Level: advanced
7298 
7299   Note:
7300   This is used by `PCGASM`
7301 
7302 .seealso: [](ch_matrices), `Mat`, `PCGASM`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRow()`, `MatGetDiagonal()`, `MatReuse`
7303 @*/
7304 PetscErrorCode MatCreateSubMatricesMPI(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
7305 {
7306   PetscInt  i;
7307   PetscBool eq;
7308 
7309   PetscFunctionBegin;
7310   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7311   PetscValidType(mat, 1);
7312   if (n) {
7313     PetscAssertPointer(irow, 3);
7314     PetscValidHeaderSpecific(*irow, IS_CLASSID, 3);
7315     PetscAssertPointer(icol, 4);
7316     PetscValidHeaderSpecific(*icol, IS_CLASSID, 4);
7317   }
7318   PetscAssertPointer(submat, 6);
7319   if (n && scall == MAT_REUSE_MATRIX) {
7320     PetscAssertPointer(*submat, 6);
7321     PetscValidHeaderSpecific(**submat, MAT_CLASSID, 6);
7322   }
7323   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7324   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7325   MatCheckPreallocated(mat, 1);
7326 
7327   PetscCall(PetscLogEventBegin(MAT_CreateSubMats, mat, 0, 0, 0));
7328   PetscUseTypeMethod(mat, createsubmatricesmpi, n, irow, icol, scall, submat);
7329   PetscCall(PetscLogEventEnd(MAT_CreateSubMats, mat, 0, 0, 0));
7330   for (i = 0; i < n; i++) {
7331     PetscCall(ISEqualUnsorted(irow[i], icol[i], &eq));
7332     if (eq) PetscCall(MatPropagateSymmetryOptions(mat, (*submat)[i]));
7333   }
7334   PetscFunctionReturn(PETSC_SUCCESS);
7335 }
7336 
7337 /*@C
7338   MatDestroyMatrices - Destroys an array of matrices
7339 
7340   Collective
7341 
7342   Input Parameters:
7343 + n   - the number of local matrices
7344 - mat - the matrices (this is a pointer to the array of matrices)
7345 
7346   Level: advanced
7347 
7348   Notes:
7349   Frees not only the matrices, but also the array that contains the matrices
7350 
7351   For matrices obtained with  `MatCreateSubMatrices()` use `MatDestroySubMatrices()`
7352 
7353   Fortran Note:
7354   Does not free the `mat` array.
7355 
7356 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatDestroySubMatrices()`
7357 @*/
7358 PetscErrorCode MatDestroyMatrices(PetscInt n, Mat *mat[])
7359 {
7360   PetscInt i;
7361 
7362   PetscFunctionBegin;
7363   if (!*mat) PetscFunctionReturn(PETSC_SUCCESS);
7364   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy negative number of matrices %" PetscInt_FMT, n);
7365   PetscAssertPointer(mat, 2);
7366 
7367   for (i = 0; i < n; i++) PetscCall(MatDestroy(&(*mat)[i]));
7368 
7369   /* memory is allocated even if n = 0 */
7370   PetscCall(PetscFree(*mat));
7371   PetscFunctionReturn(PETSC_SUCCESS);
7372 }
7373 
7374 /*@C
7375   MatDestroySubMatrices - Destroys a set of matrices obtained with `MatCreateSubMatrices()`.
7376 
7377   Collective
7378 
7379   Input Parameters:
7380 + n   - the number of local matrices
7381 - mat - the matrices (this is a pointer to the array of matrices, to match the calling sequence of `MatCreateSubMatrices()`)
7382 
7383   Level: advanced
7384 
7385   Note:
7386   Frees not only the matrices, but also the array that contains the matrices
7387 
7388 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatDestroyMatrices()`
7389 @*/
7390 PetscErrorCode MatDestroySubMatrices(PetscInt n, Mat *mat[])
7391 {
7392   Mat mat0;
7393 
7394   PetscFunctionBegin;
7395   if (!*mat) PetscFunctionReturn(PETSC_SUCCESS);
7396   /* mat[] is an array of length n+1, see MatCreateSubMatrices_xxx() */
7397   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy negative number of matrices %" PetscInt_FMT, n);
7398   PetscAssertPointer(mat, 2);
7399 
7400   mat0 = (*mat)[0];
7401   if (mat0 && mat0->ops->destroysubmatrices) {
7402     PetscCall((*mat0->ops->destroysubmatrices)(n, mat));
7403   } else {
7404     PetscCall(MatDestroyMatrices(n, mat));
7405   }
7406   PetscFunctionReturn(PETSC_SUCCESS);
7407 }
7408 
7409 /*@
7410   MatGetSeqNonzeroStructure - Extracts the nonzero structure from a matrix and stores it, in its entirety, on each process
7411 
7412   Collective
7413 
7414   Input Parameter:
7415 . mat - the matrix
7416 
7417   Output Parameter:
7418 . matstruct - the sequential matrix with the nonzero structure of `mat`
7419 
7420   Level: developer
7421 
7422 .seealso: [](ch_matrices), `Mat`, `MatDestroySeqNonzeroStructure()`, `MatCreateSubMatrices()`, `MatDestroyMatrices()`
7423 @*/
7424 PetscErrorCode MatGetSeqNonzeroStructure(Mat mat, Mat *matstruct)
7425 {
7426   PetscFunctionBegin;
7427   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7428   PetscAssertPointer(matstruct, 2);
7429 
7430   PetscValidType(mat, 1);
7431   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7432   MatCheckPreallocated(mat, 1);
7433 
7434   PetscCall(PetscLogEventBegin(MAT_GetSeqNonzeroStructure, mat, 0, 0, 0));
7435   PetscUseTypeMethod(mat, getseqnonzerostructure, matstruct);
7436   PetscCall(PetscLogEventEnd(MAT_GetSeqNonzeroStructure, mat, 0, 0, 0));
7437   PetscFunctionReturn(PETSC_SUCCESS);
7438 }
7439 
7440 /*@C
7441   MatDestroySeqNonzeroStructure - Destroys matrix obtained with `MatGetSeqNonzeroStructure()`.
7442 
7443   Collective
7444 
7445   Input Parameter:
7446 . mat - the matrix
7447 
7448   Level: advanced
7449 
7450   Note:
7451   This is not needed, one can just call `MatDestroy()`
7452 
7453 .seealso: [](ch_matrices), `Mat`, `MatGetSeqNonzeroStructure()`
7454 @*/
7455 PetscErrorCode MatDestroySeqNonzeroStructure(Mat *mat)
7456 {
7457   PetscFunctionBegin;
7458   PetscAssertPointer(mat, 1);
7459   PetscCall(MatDestroy(mat));
7460   PetscFunctionReturn(PETSC_SUCCESS);
7461 }
7462 
7463 /*@
7464   MatIncreaseOverlap - Given a set of submatrices indicated by index sets,
7465   replaces the index sets by larger ones that represent submatrices with
7466   additional overlap.
7467 
7468   Collective
7469 
7470   Input Parameters:
7471 + mat - the matrix
7472 . n   - the number of index sets
7473 . is  - the array of index sets (these index sets will changed during the call)
7474 - ov  - the additional overlap requested
7475 
7476   Options Database Key:
7477 . -mat_increase_overlap_scalable - use a scalable algorithm to compute the overlap (supported by MPIAIJ matrix)
7478 
7479   Level: developer
7480 
7481   Note:
7482   The computed overlap preserves the matrix block sizes when the blocks are square.
7483   That is: if a matrix nonzero for a given block would increase the overlap all columns associated with
7484   that block are included in the overlap regardless of whether each specific column would increase the overlap.
7485 
7486 .seealso: [](ch_matrices), `Mat`, `PCASM`, `MatSetBlockSize()`, `MatIncreaseOverlapSplit()`, `MatCreateSubMatrices()`
7487 @*/
7488 PetscErrorCode MatIncreaseOverlap(Mat mat, PetscInt n, IS is[], PetscInt ov)
7489 {
7490   PetscInt i, bs, cbs;
7491 
7492   PetscFunctionBegin;
7493   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7494   PetscValidType(mat, 1);
7495   PetscValidLogicalCollectiveInt(mat, n, 2);
7496   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have one or more domains, you have %" PetscInt_FMT, n);
7497   if (n) {
7498     PetscAssertPointer(is, 3);
7499     for (i = 0; i < n; i++) PetscValidHeaderSpecific(is[i], IS_CLASSID, 3);
7500   }
7501   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7502   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7503   MatCheckPreallocated(mat, 1);
7504 
7505   if (!ov || !n) PetscFunctionReturn(PETSC_SUCCESS);
7506   PetscCall(PetscLogEventBegin(MAT_IncreaseOverlap, mat, 0, 0, 0));
7507   PetscUseTypeMethod(mat, increaseoverlap, n, is, ov);
7508   PetscCall(PetscLogEventEnd(MAT_IncreaseOverlap, mat, 0, 0, 0));
7509   PetscCall(MatGetBlockSizes(mat, &bs, &cbs));
7510   if (bs == cbs) {
7511     for (i = 0; i < n; i++) PetscCall(ISSetBlockSize(is[i], bs));
7512   }
7513   PetscFunctionReturn(PETSC_SUCCESS);
7514 }
7515 
7516 PetscErrorCode MatIncreaseOverlapSplit_Single(Mat, IS *, PetscInt);
7517 
7518 /*@
7519   MatIncreaseOverlapSplit - Given a set of submatrices indicated by index sets across
7520   a sub communicator, replaces the index sets by larger ones that represent submatrices with
7521   additional overlap.
7522 
7523   Collective
7524 
7525   Input Parameters:
7526 + mat - the matrix
7527 . n   - the number of index sets
7528 . is  - the array of index sets (these index sets will changed during the call)
7529 - ov  - the additional overlap requested
7530 
7531   `   Options Database Key:
7532 . -mat_increase_overlap_scalable - use a scalable algorithm to compute the overlap (supported by MPIAIJ matrix)
7533 
7534   Level: developer
7535 
7536 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatIncreaseOverlap()`
7537 @*/
7538 PetscErrorCode MatIncreaseOverlapSplit(Mat mat, PetscInt n, IS is[], PetscInt ov)
7539 {
7540   PetscInt i;
7541 
7542   PetscFunctionBegin;
7543   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7544   PetscValidType(mat, 1);
7545   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have one or more domains, you have %" PetscInt_FMT, n);
7546   if (n) {
7547     PetscAssertPointer(is, 3);
7548     PetscValidHeaderSpecific(*is, IS_CLASSID, 3);
7549   }
7550   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7551   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7552   MatCheckPreallocated(mat, 1);
7553   if (!ov) PetscFunctionReturn(PETSC_SUCCESS);
7554   PetscCall(PetscLogEventBegin(MAT_IncreaseOverlap, mat, 0, 0, 0));
7555   for (i = 0; i < n; i++) PetscCall(MatIncreaseOverlapSplit_Single(mat, &is[i], ov));
7556   PetscCall(PetscLogEventEnd(MAT_IncreaseOverlap, mat, 0, 0, 0));
7557   PetscFunctionReturn(PETSC_SUCCESS);
7558 }
7559 
7560 /*@
7561   MatGetBlockSize - Returns the matrix block size.
7562 
7563   Not Collective
7564 
7565   Input Parameter:
7566 . mat - the matrix
7567 
7568   Output Parameter:
7569 . bs - block size
7570 
7571   Level: intermediate
7572 
7573   Notes:
7574   Block row formats are `MATBAIJ` and `MATSBAIJ` ALWAYS have square block storage in the matrix.
7575 
7576   If the block size has not been set yet this routine returns 1.
7577 
7578 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSizes()`
7579 @*/
7580 PetscErrorCode MatGetBlockSize(Mat mat, PetscInt *bs)
7581 {
7582   PetscFunctionBegin;
7583   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7584   PetscAssertPointer(bs, 2);
7585   *bs = PetscAbs(mat->rmap->bs);
7586   PetscFunctionReturn(PETSC_SUCCESS);
7587 }
7588 
7589 /*@
7590   MatGetBlockSizes - Returns the matrix block row and column sizes.
7591 
7592   Not Collective
7593 
7594   Input Parameter:
7595 . mat - the matrix
7596 
7597   Output Parameters:
7598 + rbs - row block size
7599 - cbs - column block size
7600 
7601   Level: intermediate
7602 
7603   Notes:
7604   Block row formats are `MATBAIJ` and `MATSBAIJ` ALWAYS have square block storage in the matrix.
7605   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
7606 
7607   If a block size has not been set yet this routine returns 1.
7608 
7609 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatSetBlockSizes()`
7610 @*/
7611 PetscErrorCode MatGetBlockSizes(Mat mat, PetscInt *rbs, PetscInt *cbs)
7612 {
7613   PetscFunctionBegin;
7614   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7615   if (rbs) PetscAssertPointer(rbs, 2);
7616   if (cbs) PetscAssertPointer(cbs, 3);
7617   if (rbs) *rbs = PetscAbs(mat->rmap->bs);
7618   if (cbs) *cbs = PetscAbs(mat->cmap->bs);
7619   PetscFunctionReturn(PETSC_SUCCESS);
7620 }
7621 
7622 /*@
7623   MatSetBlockSize - Sets the matrix block size.
7624 
7625   Logically Collective
7626 
7627   Input Parameters:
7628 + mat - the matrix
7629 - bs  - block size
7630 
7631   Level: intermediate
7632 
7633   Notes:
7634   Block row formats are `MATBAIJ` and `MATSBAIJ` formats ALWAYS have square block storage in the matrix.
7635   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
7636 
7637   For `MATAIJ` matrix format, this function can be called at a later stage, provided that the specified block size
7638   is compatible with the matrix local sizes.
7639 
7640 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MATAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`
7641 @*/
7642 PetscErrorCode MatSetBlockSize(Mat mat, PetscInt bs)
7643 {
7644   PetscFunctionBegin;
7645   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7646   PetscValidLogicalCollectiveInt(mat, bs, 2);
7647   PetscCall(MatSetBlockSizes(mat, bs, bs));
7648   PetscFunctionReturn(PETSC_SUCCESS);
7649 }
7650 
7651 typedef struct {
7652   PetscInt         n;
7653   IS              *is;
7654   Mat             *mat;
7655   PetscObjectState nonzerostate;
7656   Mat              C;
7657 } EnvelopeData;
7658 
7659 static PetscErrorCode EnvelopeDataDestroy(void **ptr)
7660 {
7661   EnvelopeData *edata = (EnvelopeData *)*ptr;
7662 
7663   PetscFunctionBegin;
7664   for (PetscInt i = 0; i < edata->n; i++) PetscCall(ISDestroy(&edata->is[i]));
7665   PetscCall(PetscFree(edata->is));
7666   PetscCall(PetscFree(edata));
7667   PetscFunctionReturn(PETSC_SUCCESS);
7668 }
7669 
7670 /*@
7671   MatComputeVariableBlockEnvelope - Given a matrix whose nonzeros are in blocks along the diagonal this computes and stores
7672   the sizes of these blocks in the matrix. An individual block may lie over several processes.
7673 
7674   Collective
7675 
7676   Input Parameter:
7677 . mat - the matrix
7678 
7679   Level: intermediate
7680 
7681   Notes:
7682   There can be zeros within the blocks
7683 
7684   The blocks can overlap between processes, including laying on more than two processes
7685 
7686 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatSetVariableBlockSizes()`
7687 @*/
7688 PetscErrorCode MatComputeVariableBlockEnvelope(Mat mat)
7689 {
7690   PetscInt           n, *sizes, *starts, i = 0, env = 0, tbs = 0, lblocks = 0, rstart, II, ln = 0, cnt = 0, cstart, cend;
7691   PetscInt          *diag, *odiag, sc;
7692   VecScatter         scatter;
7693   PetscScalar       *seqv;
7694   const PetscScalar *parv;
7695   const PetscInt    *ia, *ja;
7696   PetscBool          set, flag, done;
7697   Mat                AA = mat, A;
7698   MPI_Comm           comm;
7699   PetscMPIInt        rank, size, tag;
7700   MPI_Status         status;
7701   PetscContainer     container;
7702   EnvelopeData      *edata;
7703   Vec                seq, par;
7704   IS                 isglobal;
7705 
7706   PetscFunctionBegin;
7707   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7708   PetscCall(MatIsSymmetricKnown(mat, &set, &flag));
7709   if (!set || !flag) {
7710     /* TODO: only needs nonzero structure of transpose */
7711     PetscCall(MatTranspose(mat, MAT_INITIAL_MATRIX, &AA));
7712     PetscCall(MatAXPY(AA, 1.0, mat, DIFFERENT_NONZERO_PATTERN));
7713   }
7714   PetscCall(MatAIJGetLocalMat(AA, &A));
7715   PetscCall(MatGetRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ia, &ja, &done));
7716   PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Unable to get IJ structure from matrix");
7717 
7718   PetscCall(MatGetLocalSize(mat, &n, NULL));
7719   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag));
7720   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
7721   PetscCallMPI(MPI_Comm_size(comm, &size));
7722   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7723 
7724   PetscCall(PetscMalloc2(n, &sizes, n, &starts));
7725 
7726   if (rank > 0) {
7727     PetscCallMPI(MPI_Recv(&env, 1, MPIU_INT, rank - 1, tag, comm, &status));
7728     PetscCallMPI(MPI_Recv(&tbs, 1, MPIU_INT, rank - 1, tag, comm, &status));
7729   }
7730   PetscCall(MatGetOwnershipRange(mat, &rstart, NULL));
7731   for (i = 0; i < n; i++) {
7732     env = PetscMax(env, ja[ia[i + 1] - 1]);
7733     II  = rstart + i;
7734     if (env == II) {
7735       starts[lblocks]  = tbs;
7736       sizes[lblocks++] = 1 + II - tbs;
7737       tbs              = 1 + II;
7738     }
7739   }
7740   if (rank < size - 1) {
7741     PetscCallMPI(MPI_Send(&env, 1, MPIU_INT, rank + 1, tag, comm));
7742     PetscCallMPI(MPI_Send(&tbs, 1, MPIU_INT, rank + 1, tag, comm));
7743   }
7744 
7745   PetscCall(MatRestoreRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ia, &ja, &done));
7746   if (!set || !flag) PetscCall(MatDestroy(&AA));
7747   PetscCall(MatDestroy(&A));
7748 
7749   PetscCall(PetscNew(&edata));
7750   PetscCall(MatGetNonzeroState(mat, &edata->nonzerostate));
7751   edata->n = lblocks;
7752   /* create IS needed for extracting blocks from the original matrix */
7753   PetscCall(PetscMalloc1(lblocks, &edata->is));
7754   for (PetscInt i = 0; i < lblocks; i++) PetscCall(ISCreateStride(PETSC_COMM_SELF, sizes[i], starts[i], 1, &edata->is[i]));
7755 
7756   /* Create the resulting inverse matrix nonzero structure with preallocation information */
7757   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &edata->C));
7758   PetscCall(MatSetSizes(edata->C, mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N));
7759   PetscCall(MatSetBlockSizesFromMats(edata->C, mat, mat));
7760   PetscCall(MatSetType(edata->C, MATAIJ));
7761 
7762   /* Communicate the start and end of each row, from each block to the correct rank */
7763   /* TODO: Use PetscSF instead of VecScatter */
7764   for (PetscInt i = 0; i < lblocks; i++) ln += sizes[i];
7765   PetscCall(VecCreateSeq(PETSC_COMM_SELF, 2 * ln, &seq));
7766   PetscCall(VecGetArrayWrite(seq, &seqv));
7767   for (PetscInt i = 0; i < lblocks; i++) {
7768     for (PetscInt j = 0; j < sizes[i]; j++) {
7769       seqv[cnt]     = starts[i];
7770       seqv[cnt + 1] = starts[i] + sizes[i];
7771       cnt += 2;
7772     }
7773   }
7774   PetscCall(VecRestoreArrayWrite(seq, &seqv));
7775   PetscCallMPI(MPI_Scan(&cnt, &sc, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
7776   sc -= cnt;
7777   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)mat), 2 * mat->rmap->n, 2 * mat->rmap->N, &par));
7778   PetscCall(ISCreateStride(PETSC_COMM_SELF, cnt, sc, 1, &isglobal));
7779   PetscCall(VecScatterCreate(seq, NULL, par, isglobal, &scatter));
7780   PetscCall(ISDestroy(&isglobal));
7781   PetscCall(VecScatterBegin(scatter, seq, par, INSERT_VALUES, SCATTER_FORWARD));
7782   PetscCall(VecScatterEnd(scatter, seq, par, INSERT_VALUES, SCATTER_FORWARD));
7783   PetscCall(VecScatterDestroy(&scatter));
7784   PetscCall(VecDestroy(&seq));
7785   PetscCall(MatGetOwnershipRangeColumn(mat, &cstart, &cend));
7786   PetscCall(PetscMalloc2(mat->rmap->n, &diag, mat->rmap->n, &odiag));
7787   PetscCall(VecGetArrayRead(par, &parv));
7788   cnt = 0;
7789   PetscCall(MatGetSize(mat, NULL, &n));
7790   for (PetscInt i = 0; i < mat->rmap->n; i++) {
7791     PetscInt start, end, d = 0, od = 0;
7792 
7793     start = (PetscInt)PetscRealPart(parv[cnt]);
7794     end   = (PetscInt)PetscRealPart(parv[cnt + 1]);
7795     cnt += 2;
7796 
7797     if (start < cstart) {
7798       od += cstart - start + n - cend;
7799       d += cend - cstart;
7800     } else if (start < cend) {
7801       od += n - cend;
7802       d += cend - start;
7803     } else od += n - start;
7804     if (end <= cstart) {
7805       od -= cstart - end + n - cend;
7806       d -= cend - cstart;
7807     } else if (end < cend) {
7808       od -= n - cend;
7809       d -= cend - end;
7810     } else od -= n - end;
7811 
7812     odiag[i] = od;
7813     diag[i]  = d;
7814   }
7815   PetscCall(VecRestoreArrayRead(par, &parv));
7816   PetscCall(VecDestroy(&par));
7817   PetscCall(MatXAIJSetPreallocation(edata->C, mat->rmap->bs, diag, odiag, NULL, NULL));
7818   PetscCall(PetscFree2(diag, odiag));
7819   PetscCall(PetscFree2(sizes, starts));
7820 
7821   PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container));
7822   PetscCall(PetscContainerSetPointer(container, edata));
7823   PetscCall(PetscContainerSetCtxDestroy(container, EnvelopeDataDestroy));
7824   PetscCall(PetscObjectCompose((PetscObject)mat, "EnvelopeData", (PetscObject)container));
7825   PetscCall(PetscObjectDereference((PetscObject)container));
7826   PetscFunctionReturn(PETSC_SUCCESS);
7827 }
7828 
7829 /*@
7830   MatInvertVariableBlockEnvelope - set matrix C to be the inverted block diagonal of matrix A
7831 
7832   Collective
7833 
7834   Input Parameters:
7835 + A     - the matrix
7836 - reuse - indicates if the `C` matrix was obtained from a previous call to this routine
7837 
7838   Output Parameter:
7839 . C - matrix with inverted block diagonal of `A`
7840 
7841   Level: advanced
7842 
7843   Note:
7844   For efficiency the matrix `A` should have all the nonzero entries clustered in smallish blocks along the diagonal.
7845 
7846 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatComputeBlockDiagonal()`
7847 @*/
7848 PetscErrorCode MatInvertVariableBlockEnvelope(Mat A, MatReuse reuse, Mat *C)
7849 {
7850   PetscContainer   container;
7851   EnvelopeData    *edata;
7852   PetscObjectState nonzerostate;
7853 
7854   PetscFunctionBegin;
7855   PetscCall(PetscObjectQuery((PetscObject)A, "EnvelopeData", (PetscObject *)&container));
7856   if (!container) {
7857     PetscCall(MatComputeVariableBlockEnvelope(A));
7858     PetscCall(PetscObjectQuery((PetscObject)A, "EnvelopeData", (PetscObject *)&container));
7859   }
7860   PetscCall(PetscContainerGetPointer(container, (void **)&edata));
7861   PetscCall(MatGetNonzeroState(A, &nonzerostate));
7862   PetscCheck(nonzerostate <= edata->nonzerostate, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot handle changes to matrix nonzero structure");
7863   PetscCheck(reuse != MAT_REUSE_MATRIX || *C == edata->C, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "C matrix must be the same as previously output");
7864 
7865   PetscCall(MatCreateSubMatrices(A, edata->n, edata->is, edata->is, MAT_INITIAL_MATRIX, &edata->mat));
7866   *C = edata->C;
7867 
7868   for (PetscInt i = 0; i < edata->n; i++) {
7869     Mat          D;
7870     PetscScalar *dvalues;
7871 
7872     PetscCall(MatConvert(edata->mat[i], MATSEQDENSE, MAT_INITIAL_MATRIX, &D));
7873     PetscCall(MatSetOption(*C, MAT_ROW_ORIENTED, PETSC_FALSE));
7874     PetscCall(MatSeqDenseInvert(D));
7875     PetscCall(MatDenseGetArray(D, &dvalues));
7876     PetscCall(MatSetValuesIS(*C, edata->is[i], edata->is[i], dvalues, INSERT_VALUES));
7877     PetscCall(MatDestroy(&D));
7878   }
7879   PetscCall(MatDestroySubMatrices(edata->n, &edata->mat));
7880   PetscCall(MatAssemblyBegin(*C, MAT_FINAL_ASSEMBLY));
7881   PetscCall(MatAssemblyEnd(*C, MAT_FINAL_ASSEMBLY));
7882   PetscFunctionReturn(PETSC_SUCCESS);
7883 }
7884 
7885 /*@
7886   MatSetVariableBlockSizes - Sets diagonal point-blocks of the matrix that need not be of the same size
7887 
7888   Not Collective
7889 
7890   Input Parameters:
7891 + mat     - the matrix
7892 . nblocks - the number of blocks on this process, each block can only exist on a single process
7893 - bsizes  - the block sizes
7894 
7895   Level: intermediate
7896 
7897   Notes:
7898   Currently used by `PCVPBJACOBI` for `MATAIJ` matrices
7899 
7900   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.
7901 
7902 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`, `MatGetVariableBlockSizes()`,
7903           `MatComputeVariableBlockEnvelope()`, `PCVPBJACOBI`
7904 @*/
7905 PetscErrorCode MatSetVariableBlockSizes(Mat mat, PetscInt nblocks, const PetscInt bsizes[])
7906 {
7907   PetscInt ncnt = 0, nlocal;
7908 
7909   PetscFunctionBegin;
7910   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7911   PetscCall(MatGetLocalSize(mat, &nlocal, NULL));
7912   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);
7913   for (PetscInt i = 0; i < nblocks; i++) ncnt += bsizes[i];
7914   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);
7915   PetscCall(PetscFree(mat->bsizes));
7916   mat->nblocks = nblocks;
7917   PetscCall(PetscMalloc1(nblocks, &mat->bsizes));
7918   PetscCall(PetscArraycpy(mat->bsizes, bsizes, nblocks));
7919   PetscFunctionReturn(PETSC_SUCCESS);
7920 }
7921 
7922 /*@C
7923   MatGetVariableBlockSizes - Gets a diagonal blocks of the matrix that need not be of the same size
7924 
7925   Not Collective; No Fortran Support
7926 
7927   Input Parameter:
7928 . mat - the matrix
7929 
7930   Output Parameters:
7931 + nblocks - the number of blocks on this process
7932 - bsizes  - the block sizes
7933 
7934   Level: intermediate
7935 
7936 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`, `MatSetVariableBlockSizes()`, `MatComputeVariableBlockEnvelope()`
7937 @*/
7938 PetscErrorCode MatGetVariableBlockSizes(Mat mat, PetscInt *nblocks, const PetscInt *bsizes[])
7939 {
7940   PetscFunctionBegin;
7941   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7942   if (nblocks) *nblocks = mat->nblocks;
7943   if (bsizes) *bsizes = mat->bsizes;
7944   PetscFunctionReturn(PETSC_SUCCESS);
7945 }
7946 
7947 /*@
7948   MatSetBlockSizes - Sets the matrix block row and column sizes.
7949 
7950   Logically Collective
7951 
7952   Input Parameters:
7953 + mat - the matrix
7954 . rbs - row block size
7955 - cbs - column block size
7956 
7957   Level: intermediate
7958 
7959   Notes:
7960   Block row formats are `MATBAIJ` and  `MATSBAIJ`. These formats ALWAYS have square block storage in the matrix.
7961   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
7962   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
7963 
7964   For `MATAIJ` matrix this function can be called at a later stage, provided that the specified block sizes
7965   are compatible with the matrix local sizes.
7966 
7967   The row and column block size determine the blocksize of the "row" and "column" vectors returned by `MatCreateVecs()`.
7968 
7969 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatGetBlockSizes()`
7970 @*/
7971 PetscErrorCode MatSetBlockSizes(Mat mat, PetscInt rbs, PetscInt cbs)
7972 {
7973   PetscFunctionBegin;
7974   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7975   PetscValidLogicalCollectiveInt(mat, rbs, 2);
7976   PetscValidLogicalCollectiveInt(mat, cbs, 3);
7977   PetscTryTypeMethod(mat, setblocksizes, rbs, cbs);
7978   if (mat->rmap->refcnt) {
7979     ISLocalToGlobalMapping l2g  = NULL;
7980     PetscLayout            nmap = NULL;
7981 
7982     PetscCall(PetscLayoutDuplicate(mat->rmap, &nmap));
7983     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->rmap->mapping, &l2g));
7984     PetscCall(PetscLayoutDestroy(&mat->rmap));
7985     mat->rmap          = nmap;
7986     mat->rmap->mapping = l2g;
7987   }
7988   if (mat->cmap->refcnt) {
7989     ISLocalToGlobalMapping l2g  = NULL;
7990     PetscLayout            nmap = NULL;
7991 
7992     PetscCall(PetscLayoutDuplicate(mat->cmap, &nmap));
7993     if (mat->cmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->cmap->mapping, &l2g));
7994     PetscCall(PetscLayoutDestroy(&mat->cmap));
7995     mat->cmap          = nmap;
7996     mat->cmap->mapping = l2g;
7997   }
7998   PetscCall(PetscLayoutSetBlockSize(mat->rmap, rbs));
7999   PetscCall(PetscLayoutSetBlockSize(mat->cmap, cbs));
8000   PetscFunctionReturn(PETSC_SUCCESS);
8001 }
8002 
8003 /*@
8004   MatSetBlockSizesFromMats - Sets the matrix block row and column sizes to match a pair of matrices
8005 
8006   Logically Collective
8007 
8008   Input Parameters:
8009 + mat     - the matrix
8010 . fromRow - matrix from which to copy row block size
8011 - fromCol - matrix from which to copy column block size (can be same as fromRow)
8012 
8013   Level: developer
8014 
8015 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`
8016 @*/
8017 PetscErrorCode MatSetBlockSizesFromMats(Mat mat, Mat fromRow, Mat fromCol)
8018 {
8019   PetscFunctionBegin;
8020   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8021   PetscValidHeaderSpecific(fromRow, MAT_CLASSID, 2);
8022   PetscValidHeaderSpecific(fromCol, MAT_CLASSID, 3);
8023   if (fromRow->rmap->bs > 0) PetscCall(PetscLayoutSetBlockSize(mat->rmap, fromRow->rmap->bs));
8024   if (fromCol->cmap->bs > 0) PetscCall(PetscLayoutSetBlockSize(mat->cmap, fromCol->cmap->bs));
8025   PetscFunctionReturn(PETSC_SUCCESS);
8026 }
8027 
8028 /*@
8029   MatResidual - Default routine to calculate the residual r = b - Ax
8030 
8031   Collective
8032 
8033   Input Parameters:
8034 + mat - the matrix
8035 . b   - the right-hand-side
8036 - x   - the approximate solution
8037 
8038   Output Parameter:
8039 . r - location to store the residual
8040 
8041   Level: developer
8042 
8043 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `PCMGSetResidual()`
8044 @*/
8045 PetscErrorCode MatResidual(Mat mat, Vec b, Vec x, Vec r)
8046 {
8047   PetscFunctionBegin;
8048   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8049   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
8050   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
8051   PetscValidHeaderSpecific(r, VEC_CLASSID, 4);
8052   PetscValidType(mat, 1);
8053   MatCheckPreallocated(mat, 1);
8054   PetscCall(PetscLogEventBegin(MAT_Residual, mat, 0, 0, 0));
8055   if (!mat->ops->residual) {
8056     PetscCall(MatMult(mat, x, r));
8057     PetscCall(VecAYPX(r, -1.0, b));
8058   } else {
8059     PetscUseTypeMethod(mat, residual, b, x, r);
8060   }
8061   PetscCall(PetscLogEventEnd(MAT_Residual, mat, 0, 0, 0));
8062   PetscFunctionReturn(PETSC_SUCCESS);
8063 }
8064 
8065 /*@C
8066   MatGetRowIJ - Returns the compressed row storage i and j indices for the local rows of a sparse matrix
8067 
8068   Collective
8069 
8070   Input Parameters:
8071 + mat             - the matrix
8072 . shift           - 0 or 1 indicating we want the indices starting at 0 or 1
8073 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8074 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE`  indicating if the nonzero structure of the
8075                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8076                  always used.
8077 
8078   Output Parameters:
8079 + n    - number of local rows in the (possibly compressed) matrix, use `NULL` if not needed
8080 . 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
8081 . ja   - the column indices, use `NULL` if not needed
8082 - done - indicates if the routine actually worked and returned appropriate ia[] and ja[] arrays; callers
8083            are responsible for handling the case when done == `PETSC_FALSE` and ia and ja are not set
8084 
8085   Level: developer
8086 
8087   Notes:
8088   You CANNOT change any of the ia[] or ja[] values.
8089 
8090   Use `MatRestoreRowIJ()` when you are finished accessing the ia[] and ja[] values.
8091 
8092   Fortran Notes:
8093   Use
8094 .vb
8095     PetscInt, pointer :: ia(:),ja(:)
8096     call MatGetRowIJ(mat,shift,symmetric,inodecompressed,n,ia,ja,done,ierr)
8097     ! Access the ith and jth entries via ia(i) and ja(j)
8098 .ve
8099 
8100 .seealso: [](ch_matrices), `Mat`, `MATAIJ`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`, `MatSeqAIJGetArray()`
8101 @*/
8102 PetscErrorCode MatGetRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8103 {
8104   PetscFunctionBegin;
8105   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8106   PetscValidType(mat, 1);
8107   if (n) PetscAssertPointer(n, 5);
8108   if (ia) PetscAssertPointer(ia, 6);
8109   if (ja) PetscAssertPointer(ja, 7);
8110   if (done) PetscAssertPointer(done, 8);
8111   MatCheckPreallocated(mat, 1);
8112   if (!mat->ops->getrowij && done) *done = PETSC_FALSE;
8113   else {
8114     if (done) *done = PETSC_TRUE;
8115     PetscCall(PetscLogEventBegin(MAT_GetRowIJ, mat, 0, 0, 0));
8116     PetscUseTypeMethod(mat, getrowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8117     PetscCall(PetscLogEventEnd(MAT_GetRowIJ, mat, 0, 0, 0));
8118   }
8119   PetscFunctionReturn(PETSC_SUCCESS);
8120 }
8121 
8122 /*@C
8123   MatGetColumnIJ - Returns the compressed column storage i and j indices for sequential matrices.
8124 
8125   Collective
8126 
8127   Input Parameters:
8128 + mat             - the matrix
8129 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8130 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be
8131                 symmetrized
8132 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8133                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8134                  always used.
8135 . n               - number of columns in the (possibly compressed) matrix
8136 . ia              - the column pointers; that is ia[0] = 0, ia[col] = i[col-1] + number of elements in that col of the matrix
8137 - ja              - the row indices
8138 
8139   Output Parameter:
8140 . done - `PETSC_TRUE` or `PETSC_FALSE`, indicating whether the values have been returned
8141 
8142   Level: developer
8143 
8144 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8145 @*/
8146 PetscErrorCode MatGetColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8147 {
8148   PetscFunctionBegin;
8149   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8150   PetscValidType(mat, 1);
8151   PetscAssertPointer(n, 5);
8152   if (ia) PetscAssertPointer(ia, 6);
8153   if (ja) PetscAssertPointer(ja, 7);
8154   PetscAssertPointer(done, 8);
8155   MatCheckPreallocated(mat, 1);
8156   if (!mat->ops->getcolumnij) *done = PETSC_FALSE;
8157   else {
8158     *done = PETSC_TRUE;
8159     PetscUseTypeMethod(mat, getcolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8160   }
8161   PetscFunctionReturn(PETSC_SUCCESS);
8162 }
8163 
8164 /*@C
8165   MatRestoreRowIJ - Call after you are completed with the ia,ja indices obtained with `MatGetRowIJ()`.
8166 
8167   Collective
8168 
8169   Input Parameters:
8170 + mat             - the matrix
8171 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8172 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8173 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8174                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8175                     always used.
8176 . n               - size of (possibly compressed) matrix
8177 . ia              - the row pointers
8178 - ja              - the column indices
8179 
8180   Output Parameter:
8181 . done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8182 
8183   Level: developer
8184 
8185   Note:
8186   This routine zeros out `n`, `ia`, and `ja`. This is to prevent accidental
8187   us of the array after it has been restored. If you pass `NULL`, it will
8188   not zero the pointers.  Use of ia or ja after `MatRestoreRowIJ()` is invalid.
8189 
8190 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8191 @*/
8192 PetscErrorCode MatRestoreRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8193 {
8194   PetscFunctionBegin;
8195   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8196   PetscValidType(mat, 1);
8197   if (ia) PetscAssertPointer(ia, 6);
8198   if (ja) PetscAssertPointer(ja, 7);
8199   if (done) PetscAssertPointer(done, 8);
8200   MatCheckPreallocated(mat, 1);
8201 
8202   if (!mat->ops->restorerowij && done) *done = PETSC_FALSE;
8203   else {
8204     if (done) *done = PETSC_TRUE;
8205     PetscUseTypeMethod(mat, restorerowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8206     if (n) *n = 0;
8207     if (ia) *ia = NULL;
8208     if (ja) *ja = NULL;
8209   }
8210   PetscFunctionReturn(PETSC_SUCCESS);
8211 }
8212 
8213 /*@C
8214   MatRestoreColumnIJ - Call after you are completed with the ia,ja indices obtained with `MatGetColumnIJ()`.
8215 
8216   Collective
8217 
8218   Input Parameters:
8219 + mat             - the matrix
8220 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8221 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8222 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8223                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8224                     always used.
8225 
8226   Output Parameters:
8227 + n    - size of (possibly compressed) matrix
8228 . ia   - the column pointers
8229 . ja   - the row indices
8230 - done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8231 
8232   Level: developer
8233 
8234 .seealso: [](ch_matrices), `Mat`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`
8235 @*/
8236 PetscErrorCode MatRestoreColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8237 {
8238   PetscFunctionBegin;
8239   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8240   PetscValidType(mat, 1);
8241   if (ia) PetscAssertPointer(ia, 6);
8242   if (ja) PetscAssertPointer(ja, 7);
8243   PetscAssertPointer(done, 8);
8244   MatCheckPreallocated(mat, 1);
8245 
8246   if (!mat->ops->restorecolumnij) *done = PETSC_FALSE;
8247   else {
8248     *done = PETSC_TRUE;
8249     PetscUseTypeMethod(mat, restorecolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8250     if (n) *n = 0;
8251     if (ia) *ia = NULL;
8252     if (ja) *ja = NULL;
8253   }
8254   PetscFunctionReturn(PETSC_SUCCESS);
8255 }
8256 
8257 /*@
8258   MatColoringPatch - Used inside matrix coloring routines that use `MatGetRowIJ()` and/or
8259   `MatGetColumnIJ()`.
8260 
8261   Collective
8262 
8263   Input Parameters:
8264 + mat        - the matrix
8265 . ncolors    - maximum color value
8266 . n          - number of entries in colorarray
8267 - colorarray - array indicating color for each column
8268 
8269   Output Parameter:
8270 . iscoloring - coloring generated using colorarray information
8271 
8272   Level: developer
8273 
8274 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatGetColumnIJ()`
8275 @*/
8276 PetscErrorCode MatColoringPatch(Mat mat, PetscInt ncolors, PetscInt n, ISColoringValue colorarray[], ISColoring *iscoloring)
8277 {
8278   PetscFunctionBegin;
8279   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8280   PetscValidType(mat, 1);
8281   PetscAssertPointer(colorarray, 4);
8282   PetscAssertPointer(iscoloring, 5);
8283   MatCheckPreallocated(mat, 1);
8284 
8285   if (!mat->ops->coloringpatch) {
8286     PetscCall(ISColoringCreate(PetscObjectComm((PetscObject)mat), ncolors, n, colorarray, PETSC_OWN_POINTER, iscoloring));
8287   } else {
8288     PetscUseTypeMethod(mat, coloringpatch, ncolors, n, colorarray, iscoloring);
8289   }
8290   PetscFunctionReturn(PETSC_SUCCESS);
8291 }
8292 
8293 /*@
8294   MatSetUnfactored - Resets a factored matrix to be treated as unfactored.
8295 
8296   Logically Collective
8297 
8298   Input Parameter:
8299 . mat - the factored matrix to be reset
8300 
8301   Level: developer
8302 
8303   Notes:
8304   This routine should be used only with factored matrices formed by in-place
8305   factorization via ILU(0) (or by in-place LU factorization for the `MATSEQDENSE`
8306   format).  This option can save memory, for example, when solving nonlinear
8307   systems with a matrix-free Newton-Krylov method and a matrix-based, in-place
8308   ILU(0) preconditioner.
8309 
8310   One can specify in-place ILU(0) factorization by calling
8311 .vb
8312      PCType(pc,PCILU);
8313      PCFactorSeUseInPlace(pc);
8314 .ve
8315   or by using the options -pc_type ilu -pc_factor_in_place
8316 
8317   In-place factorization ILU(0) can also be used as a local
8318   solver for the blocks within the block Jacobi or additive Schwarz
8319   methods (runtime option: -sub_pc_factor_in_place).  See Users-Manual: ch_pc
8320   for details on setting local solver options.
8321 
8322   Most users should employ the `KSP` interface for linear solvers
8323   instead of working directly with matrix algebra routines such as this.
8324   See, e.g., `KSPCreate()`.
8325 
8326 .seealso: [](ch_matrices), `Mat`, `PCFactorSetUseInPlace()`, `PCFactorGetUseInPlace()`
8327 @*/
8328 PetscErrorCode MatSetUnfactored(Mat mat)
8329 {
8330   PetscFunctionBegin;
8331   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8332   PetscValidType(mat, 1);
8333   MatCheckPreallocated(mat, 1);
8334   mat->factortype = MAT_FACTOR_NONE;
8335   if (!mat->ops->setunfactored) PetscFunctionReturn(PETSC_SUCCESS);
8336   PetscUseTypeMethod(mat, setunfactored);
8337   PetscFunctionReturn(PETSC_SUCCESS);
8338 }
8339 
8340 /*@
8341   MatCreateSubMatrix - Gets a single submatrix on the same number of processors
8342   as the original matrix.
8343 
8344   Collective
8345 
8346   Input Parameters:
8347 + mat   - the original matrix
8348 . isrow - parallel `IS` containing the rows this processor should obtain
8349 . 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.
8350 - cll   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
8351 
8352   Output Parameter:
8353 . newmat - the new submatrix, of the same type as the original matrix
8354 
8355   Level: advanced
8356 
8357   Notes:
8358   The submatrix will be able to be multiplied with vectors using the same layout as `iscol`.
8359 
8360   Some matrix types place restrictions on the row and column indices, such
8361   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;
8362   for example, if the block size is 3 one cannot select the 0 and 2 rows without selecting the 1 row.
8363 
8364   The index sets may not have duplicate entries.
8365 
8366   The first time this is called you should use a cll of `MAT_INITIAL_MATRIX`,
8367   the `MatCreateSubMatrix()` routine will create the newmat for you. Any additional calls
8368   to this routine with a mat of the same nonzero structure and with a call of `MAT_REUSE_MATRIX`
8369   will reuse the matrix generated the first time.  You should call `MatDestroy()` on `newmat` when
8370   you are finished using it.
8371 
8372   The communicator of the newly obtained matrix is ALWAYS the same as the communicator of
8373   the input matrix.
8374 
8375   If `iscol` is `NULL` then all columns are obtained (not supported in Fortran).
8376 
8377   If `isrow` and `iscol` have a nontrivial block-size, then the resulting matrix has this block-size as well. This feature
8378   is used by `PCFIELDSPLIT` to allow easy nesting of its use.
8379 
8380   Example usage:
8381   Consider the following 8x8 matrix with 34 non-zero values, that is
8382   assembled across 3 processors. Let's assume that proc0 owns 3 rows,
8383   proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
8384   as follows
8385 .vb
8386             1  2  0  |  0  3  0  |  0  4
8387     Proc0   0  5  6  |  7  0  0  |  8  0
8388             9  0 10  | 11  0  0  | 12  0
8389     -------------------------------------
8390            13  0 14  | 15 16 17  |  0  0
8391     Proc1   0 18  0  | 19 20 21  |  0  0
8392             0  0  0  | 22 23  0  | 24  0
8393     -------------------------------------
8394     Proc2  25 26 27  |  0  0 28  | 29  0
8395            30  0  0  | 31 32 33  |  0 34
8396 .ve
8397 
8398   Suppose `isrow` = [0 1 | 4 | 6 7] and `iscol` = [1 2 | 3 4 5 | 6].  The resulting submatrix is
8399 
8400 .vb
8401             2  0  |  0  3  0  |  0
8402     Proc0   5  6  |  7  0  0  |  8
8403     -------------------------------
8404     Proc1  18  0  | 19 20 21  |  0
8405     -------------------------------
8406     Proc2  26 27  |  0  0 28  | 29
8407             0  0  | 31 32 33  |  0
8408 .ve
8409 
8410 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatCreateSubMatricesMPI()`, `MatCreateSubMatrixVirtual()`, `MatSubMatrixVirtualUpdate()`
8411 @*/
8412 PetscErrorCode MatCreateSubMatrix(Mat mat, IS isrow, IS iscol, MatReuse cll, Mat *newmat)
8413 {
8414   PetscMPIInt size;
8415   Mat        *local;
8416   IS          iscoltmp;
8417   PetscBool   flg;
8418 
8419   PetscFunctionBegin;
8420   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8421   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
8422   if (iscol) PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
8423   PetscAssertPointer(newmat, 5);
8424   if (cll == MAT_REUSE_MATRIX) PetscValidHeaderSpecific(*newmat, MAT_CLASSID, 5);
8425   PetscValidType(mat, 1);
8426   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
8427   PetscCheck(cll != MAT_IGNORE_MATRIX, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot use MAT_IGNORE_MATRIX");
8428 
8429   MatCheckPreallocated(mat, 1);
8430   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
8431 
8432   if (!iscol || isrow == iscol) {
8433     PetscBool   stride;
8434     PetscMPIInt grabentirematrix = 0, grab;
8435     PetscCall(PetscObjectTypeCompare((PetscObject)isrow, ISSTRIDE, &stride));
8436     if (stride) {
8437       PetscInt first, step, n, rstart, rend;
8438       PetscCall(ISStrideGetInfo(isrow, &first, &step));
8439       if (step == 1) {
8440         PetscCall(MatGetOwnershipRange(mat, &rstart, &rend));
8441         if (rstart == first) {
8442           PetscCall(ISGetLocalSize(isrow, &n));
8443           if (n == rend - rstart) grabentirematrix = 1;
8444         }
8445       }
8446     }
8447     PetscCallMPI(MPIU_Allreduce(&grabentirematrix, &grab, 1, MPI_INT, MPI_MIN, PetscObjectComm((PetscObject)mat)));
8448     if (grab) {
8449       PetscCall(PetscInfo(mat, "Getting entire matrix as submatrix\n"));
8450       if (cll == MAT_INITIAL_MATRIX) {
8451         *newmat = mat;
8452         PetscCall(PetscObjectReference((PetscObject)mat));
8453       }
8454       PetscFunctionReturn(PETSC_SUCCESS);
8455     }
8456   }
8457 
8458   if (!iscol) {
8459     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)mat), mat->cmap->n, mat->cmap->rstart, 1, &iscoltmp));
8460   } else {
8461     iscoltmp = iscol;
8462   }
8463 
8464   /* if original matrix is on just one processor then use submatrix generated */
8465   if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1 && cll == MAT_REUSE_MATRIX) {
8466     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_REUSE_MATRIX, &newmat));
8467     goto setproperties;
8468   } else if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1) {
8469     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_INITIAL_MATRIX, &local));
8470     *newmat = *local;
8471     PetscCall(PetscFree(local));
8472     goto setproperties;
8473   } else if (!mat->ops->createsubmatrix) {
8474     /* Create a new matrix type that implements the operation using the full matrix */
8475     PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8476     switch (cll) {
8477     case MAT_INITIAL_MATRIX:
8478       PetscCall(MatCreateSubMatrixVirtual(mat, isrow, iscoltmp, newmat));
8479       break;
8480     case MAT_REUSE_MATRIX:
8481       PetscCall(MatSubMatrixVirtualUpdate(*newmat, mat, isrow, iscoltmp));
8482       break;
8483     default:
8484       SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Invalid MatReuse, must be either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX");
8485     }
8486     PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8487     goto setproperties;
8488   }
8489 
8490   PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8491   PetscUseTypeMethod(mat, createsubmatrix, isrow, iscoltmp, cll, newmat);
8492   PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8493 
8494 setproperties:
8495   if ((*newmat)->symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->structurally_symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->spd == PETSC_BOOL3_UNKNOWN && (*newmat)->hermitian == PETSC_BOOL3_UNKNOWN) {
8496     PetscCall(ISEqualUnsorted(isrow, iscoltmp, &flg));
8497     if (flg) PetscCall(MatPropagateSymmetryOptions(mat, *newmat));
8498   }
8499   if (!iscol) PetscCall(ISDestroy(&iscoltmp));
8500   if (*newmat && cll == MAT_INITIAL_MATRIX) PetscCall(PetscObjectStateIncrease((PetscObject)*newmat));
8501   PetscFunctionReturn(PETSC_SUCCESS);
8502 }
8503 
8504 /*@
8505   MatPropagateSymmetryOptions - Propagates symmetry options set on a matrix to another matrix
8506 
8507   Not Collective
8508 
8509   Input Parameters:
8510 + A - the matrix we wish to propagate options from
8511 - B - the matrix we wish to propagate options to
8512 
8513   Level: beginner
8514 
8515   Note:
8516   Propagates the options associated to `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_HERMITIAN`, `MAT_SPD`, `MAT_SYMMETRIC`, and `MAT_STRUCTURAL_SYMMETRY_ETERNAL`
8517 
8518 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatIsSymmetricKnown()`, `MatIsSPDKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
8519 @*/
8520 PetscErrorCode MatPropagateSymmetryOptions(Mat A, Mat B)
8521 {
8522   PetscFunctionBegin;
8523   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8524   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
8525   B->symmetry_eternal            = A->symmetry_eternal;
8526   B->structural_symmetry_eternal = A->structural_symmetry_eternal;
8527   B->symmetric                   = A->symmetric;
8528   B->structurally_symmetric      = A->structurally_symmetric;
8529   B->spd                         = A->spd;
8530   B->hermitian                   = A->hermitian;
8531   PetscFunctionReturn(PETSC_SUCCESS);
8532 }
8533 
8534 /*@
8535   MatStashSetInitialSize - sets the sizes of the matrix stash, that is
8536   used during the assembly process to store values that belong to
8537   other processors.
8538 
8539   Not Collective
8540 
8541   Input Parameters:
8542 + mat   - the matrix
8543 . size  - the initial size of the stash.
8544 - bsize - the initial size of the block-stash(if used).
8545 
8546   Options Database Keys:
8547 + -matstash_initial_size <size> or <size0,size1,...sizep-1>            - set initial size
8548 - -matstash_block_initial_size <bsize>  or <bsize0,bsize1,...bsizep-1> - set initial block size
8549 
8550   Level: intermediate
8551 
8552   Notes:
8553   The block-stash is used for values set with `MatSetValuesBlocked()` while
8554   the stash is used for values set with `MatSetValues()`
8555 
8556   Run with the option -info and look for output of the form
8557   MatAssemblyBegin_MPIXXX:Stash has MM entries, uses nn mallocs.
8558   to determine the appropriate value, MM, to use for size and
8559   MatAssemblyBegin_MPIXXX:Block-Stash has BMM entries, uses nn mallocs.
8560   to determine the value, BMM to use for bsize
8561 
8562 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashGetInfo()`
8563 @*/
8564 PetscErrorCode MatStashSetInitialSize(Mat mat, PetscInt size, PetscInt bsize)
8565 {
8566   PetscFunctionBegin;
8567   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8568   PetscValidType(mat, 1);
8569   PetscCall(MatStashSetInitialSize_Private(&mat->stash, size));
8570   PetscCall(MatStashSetInitialSize_Private(&mat->bstash, bsize));
8571   PetscFunctionReturn(PETSC_SUCCESS);
8572 }
8573 
8574 /*@
8575   MatInterpolateAdd - $w = y + A*x$ or $A^T*x$ depending on the shape of
8576   the matrix
8577 
8578   Neighbor-wise Collective
8579 
8580   Input Parameters:
8581 + A - the matrix
8582 . x - the vector to be multiplied by the interpolation operator
8583 - y - the vector to be added to the result
8584 
8585   Output Parameter:
8586 . w - the resulting vector
8587 
8588   Level: intermediate
8589 
8590   Notes:
8591   `w` may be the same vector as `y`.
8592 
8593   This allows one to use either the restriction or interpolation (its transpose)
8594   matrix to do the interpolation
8595 
8596 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8597 @*/
8598 PetscErrorCode MatInterpolateAdd(Mat A, Vec x, Vec y, Vec w)
8599 {
8600   PetscInt M, N, Ny;
8601 
8602   PetscFunctionBegin;
8603   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8604   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8605   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8606   PetscValidHeaderSpecific(w, VEC_CLASSID, 4);
8607   PetscCall(MatGetSize(A, &M, &N));
8608   PetscCall(VecGetSize(y, &Ny));
8609   if (M == Ny) {
8610     PetscCall(MatMultAdd(A, x, y, w));
8611   } else {
8612     PetscCall(MatMultTransposeAdd(A, x, y, w));
8613   }
8614   PetscFunctionReturn(PETSC_SUCCESS);
8615 }
8616 
8617 /*@
8618   MatInterpolate - $y = A*x$ or $A^T*x$ depending on the shape of
8619   the matrix
8620 
8621   Neighbor-wise Collective
8622 
8623   Input Parameters:
8624 + A - the matrix
8625 - x - the vector to be interpolated
8626 
8627   Output Parameter:
8628 . y - the resulting vector
8629 
8630   Level: intermediate
8631 
8632   Note:
8633   This allows one to use either the restriction or interpolation (its transpose)
8634   matrix to do the interpolation
8635 
8636 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8637 @*/
8638 PetscErrorCode MatInterpolate(Mat A, Vec x, Vec y)
8639 {
8640   PetscInt M, N, Ny;
8641 
8642   PetscFunctionBegin;
8643   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8644   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8645   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8646   PetscCall(MatGetSize(A, &M, &N));
8647   PetscCall(VecGetSize(y, &Ny));
8648   if (M == Ny) {
8649     PetscCall(MatMult(A, x, y));
8650   } else {
8651     PetscCall(MatMultTranspose(A, x, y));
8652   }
8653   PetscFunctionReturn(PETSC_SUCCESS);
8654 }
8655 
8656 /*@
8657   MatRestrict - $y = A*x$ or $A^T*x$
8658 
8659   Neighbor-wise Collective
8660 
8661   Input Parameters:
8662 + A - the matrix
8663 - x - the vector to be restricted
8664 
8665   Output Parameter:
8666 . y - the resulting vector
8667 
8668   Level: intermediate
8669 
8670   Note:
8671   This allows one to use either the restriction or interpolation (its transpose)
8672   matrix to do the restriction
8673 
8674 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatInterpolate()`, `PCMG`
8675 @*/
8676 PetscErrorCode MatRestrict(Mat A, Vec x, Vec y)
8677 {
8678   PetscInt M, N, Nx;
8679 
8680   PetscFunctionBegin;
8681   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8682   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8683   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8684   PetscCall(MatGetSize(A, &M, &N));
8685   PetscCall(VecGetSize(x, &Nx));
8686   if (M == Nx) {
8687     PetscCall(MatMultTranspose(A, x, y));
8688   } else {
8689     PetscCall(MatMult(A, x, y));
8690   }
8691   PetscFunctionReturn(PETSC_SUCCESS);
8692 }
8693 
8694 /*@
8695   MatMatInterpolateAdd - $Y = W + A*X$ or $W + A^T*X$ depending on the shape of `A`
8696 
8697   Neighbor-wise Collective
8698 
8699   Input Parameters:
8700 + A - the matrix
8701 . x - the input dense matrix to be multiplied
8702 - w - the input dense matrix to be added to the result
8703 
8704   Output Parameter:
8705 . y - the output dense matrix
8706 
8707   Level: intermediate
8708 
8709   Note:
8710   This allows one to use either the restriction or interpolation (its transpose)
8711   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8712   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8713 
8714 .seealso: [](ch_matrices), `Mat`, `MatInterpolateAdd()`, `MatMatInterpolate()`, `MatMatRestrict()`, `PCMG`
8715 @*/
8716 PetscErrorCode MatMatInterpolateAdd(Mat A, Mat x, Mat w, Mat *y)
8717 {
8718   PetscInt  M, N, Mx, Nx, Mo, My = 0, Ny = 0;
8719   PetscBool trans = PETSC_TRUE;
8720   MatReuse  reuse = MAT_INITIAL_MATRIX;
8721 
8722   PetscFunctionBegin;
8723   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8724   PetscValidHeaderSpecific(x, MAT_CLASSID, 2);
8725   PetscValidType(x, 2);
8726   if (w) PetscValidHeaderSpecific(w, MAT_CLASSID, 3);
8727   if (*y) PetscValidHeaderSpecific(*y, MAT_CLASSID, 4);
8728   PetscCall(MatGetSize(A, &M, &N));
8729   PetscCall(MatGetSize(x, &Mx, &Nx));
8730   if (N == Mx) trans = PETSC_FALSE;
8731   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);
8732   Mo = trans ? N : M;
8733   if (*y) {
8734     PetscCall(MatGetSize(*y, &My, &Ny));
8735     if (Mo == My && Nx == Ny) {
8736       reuse = MAT_REUSE_MATRIX;
8737     } else {
8738       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);
8739       PetscCall(MatDestroy(y));
8740     }
8741   }
8742 
8743   if (w && *y == w) { /* this is to minimize changes in PCMG */
8744     PetscBool flg;
8745 
8746     PetscCall(PetscObjectQuery((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject *)&w));
8747     if (w) {
8748       PetscInt My, Ny, Mw, Nw;
8749 
8750       PetscCall(PetscObjectTypeCompare((PetscObject)*y, ((PetscObject)w)->type_name, &flg));
8751       PetscCall(MatGetSize(*y, &My, &Ny));
8752       PetscCall(MatGetSize(w, &Mw, &Nw));
8753       if (!flg || My != Mw || Ny != Nw) w = NULL;
8754     }
8755     if (!w) {
8756       PetscCall(MatDuplicate(*y, MAT_COPY_VALUES, &w));
8757       PetscCall(PetscObjectCompose((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject)w));
8758       PetscCall(PetscObjectDereference((PetscObject)w));
8759     } else {
8760       PetscCall(MatCopy(*y, w, UNKNOWN_NONZERO_PATTERN));
8761     }
8762   }
8763   if (!trans) {
8764     PetscCall(MatMatMult(A, x, reuse, PETSC_DETERMINE, y));
8765   } else {
8766     PetscCall(MatTransposeMatMult(A, x, reuse, PETSC_DETERMINE, y));
8767   }
8768   if (w) PetscCall(MatAXPY(*y, 1.0, w, UNKNOWN_NONZERO_PATTERN));
8769   PetscFunctionReturn(PETSC_SUCCESS);
8770 }
8771 
8772 /*@
8773   MatMatInterpolate - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8774 
8775   Neighbor-wise Collective
8776 
8777   Input Parameters:
8778 + A - the matrix
8779 - x - the input dense matrix
8780 
8781   Output Parameter:
8782 . y - the output dense matrix
8783 
8784   Level: intermediate
8785 
8786   Note:
8787   This allows one to use either the restriction or interpolation (its transpose)
8788   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8789   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8790 
8791 .seealso: [](ch_matrices), `Mat`, `MatInterpolate()`, `MatRestrict()`, `MatMatRestrict()`, `PCMG`
8792 @*/
8793 PetscErrorCode MatMatInterpolate(Mat A, Mat x, Mat *y)
8794 {
8795   PetscFunctionBegin;
8796   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8797   PetscFunctionReturn(PETSC_SUCCESS);
8798 }
8799 
8800 /*@
8801   MatMatRestrict - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8802 
8803   Neighbor-wise Collective
8804 
8805   Input Parameters:
8806 + A - the matrix
8807 - x - the input dense matrix
8808 
8809   Output Parameter:
8810 . y - the output dense matrix
8811 
8812   Level: intermediate
8813 
8814   Note:
8815   This allows one to use either the restriction or interpolation (its transpose)
8816   matrix to do the restriction. `y` matrix can be reused if already created with the proper sizes,
8817   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8818 
8819 .seealso: [](ch_matrices), `Mat`, `MatRestrict()`, `MatInterpolate()`, `MatMatInterpolate()`, `PCMG`
8820 @*/
8821 PetscErrorCode MatMatRestrict(Mat A, Mat x, Mat *y)
8822 {
8823   PetscFunctionBegin;
8824   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8825   PetscFunctionReturn(PETSC_SUCCESS);
8826 }
8827 
8828 /*@
8829   MatGetNullSpace - retrieves the null space of a matrix.
8830 
8831   Logically Collective
8832 
8833   Input Parameters:
8834 + mat    - the matrix
8835 - nullsp - the null space object
8836 
8837   Level: developer
8838 
8839 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetNullSpace()`, `MatNullSpace`
8840 @*/
8841 PetscErrorCode MatGetNullSpace(Mat mat, MatNullSpace *nullsp)
8842 {
8843   PetscFunctionBegin;
8844   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8845   PetscAssertPointer(nullsp, 2);
8846   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->nullsp) ? mat->transnullsp : mat->nullsp;
8847   PetscFunctionReturn(PETSC_SUCCESS);
8848 }
8849 
8850 /*@C
8851   MatGetNullSpaces - gets the null spaces, transpose null spaces, and near null spaces from an array of matrices
8852 
8853   Logically Collective
8854 
8855   Input Parameters:
8856 + n   - the number of matrices
8857 - mat - the array of matrices
8858 
8859   Output Parameters:
8860 . nullsp - an array of null spaces, `NULL` for each matrix that does not have a null space, length 3 * `n`
8861 
8862   Level: developer
8863 
8864   Note:
8865   Call `MatRestoreNullspaces()` to provide these to another array of matrices
8866 
8867 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
8868           `MatNullSpaceRemove()`, `MatRestoreNullSpaces()`
8869 @*/
8870 PetscErrorCode MatGetNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
8871 {
8872   PetscFunctionBegin;
8873   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
8874   PetscAssertPointer(mat, 2);
8875   PetscAssertPointer(nullsp, 3);
8876 
8877   PetscCall(PetscCalloc1(3 * n, nullsp));
8878   for (PetscInt i = 0; i < n; i++) {
8879     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
8880     (*nullsp)[i] = mat[i]->nullsp;
8881     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[i]));
8882     (*nullsp)[n + i] = mat[i]->nearnullsp;
8883     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[n + i]));
8884     (*nullsp)[2 * n + i] = mat[i]->transnullsp;
8885     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[2 * n + i]));
8886   }
8887   PetscFunctionReturn(PETSC_SUCCESS);
8888 }
8889 
8890 /*@C
8891   MatRestoreNullSpaces - sets the null spaces, transpose null spaces, and near null spaces obtained with `MatGetNullSpaces()` for an array of matrices
8892 
8893   Logically Collective
8894 
8895   Input Parameters:
8896 + n      - the number of matrices
8897 . mat    - the array of matrices
8898 - nullsp - an array of null spaces
8899 
8900   Level: developer
8901 
8902   Note:
8903   Call `MatGetNullSpaces()` to create `nullsp`
8904 
8905 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
8906           `MatNullSpaceRemove()`, `MatGetNullSpaces()`
8907 @*/
8908 PetscErrorCode MatRestoreNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
8909 {
8910   PetscFunctionBegin;
8911   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
8912   PetscAssertPointer(mat, 2);
8913   PetscAssertPointer(nullsp, 3);
8914   PetscAssertPointer(*nullsp, 3);
8915 
8916   for (PetscInt i = 0; i < n; i++) {
8917     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
8918     PetscCall(MatSetNullSpace(mat[i], (*nullsp)[i]));
8919     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[i]));
8920     PetscCall(MatSetNearNullSpace(mat[i], (*nullsp)[n + i]));
8921     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[n + i]));
8922     PetscCall(MatSetTransposeNullSpace(mat[i], (*nullsp)[2 * n + i]));
8923     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[2 * n + i]));
8924   }
8925   PetscCall(PetscFree(*nullsp));
8926   PetscFunctionReturn(PETSC_SUCCESS);
8927 }
8928 
8929 /*@
8930   MatSetNullSpace - attaches a null space to a matrix.
8931 
8932   Logically Collective
8933 
8934   Input Parameters:
8935 + mat    - the matrix
8936 - nullsp - the null space object
8937 
8938   Level: advanced
8939 
8940   Notes:
8941   This null space is used by the `KSP` linear solvers to solve singular systems.
8942 
8943   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`
8944 
8945   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
8946   to zero but the linear system will still be solved in a least squares sense.
8947 
8948   The fundamental theorem of linear algebra (Gilbert Strang, Introduction to Applied Mathematics, page 72) states that
8949   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), + the range of $A^T$, $R(A^T)$.
8950   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
8951   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
8952   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$).
8953   This  \hat{b} can be obtained by calling `MatNullSpaceRemove()` with the null space of the transpose of the matrix.
8954 
8955   If the matrix is known to be symmetric because it is an `MATSBAIJ` matrix or one as called
8956   `MatSetOption`(mat,`MAT_SYMMETRIC` or possibly `MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`); this
8957   routine also automatically calls `MatSetTransposeNullSpace()`.
8958 
8959   The user should call `MatNullSpaceDestroy()`.
8960 
8961 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`,
8962           `KSPSetPCSide()`
8963 @*/
8964 PetscErrorCode MatSetNullSpace(Mat mat, MatNullSpace nullsp)
8965 {
8966   PetscFunctionBegin;
8967   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8968   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
8969   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
8970   PetscCall(MatNullSpaceDestroy(&mat->nullsp));
8971   mat->nullsp = nullsp;
8972   if (mat->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetTransposeNullSpace(mat, nullsp));
8973   PetscFunctionReturn(PETSC_SUCCESS);
8974 }
8975 
8976 /*@
8977   MatGetTransposeNullSpace - retrieves the null space of the transpose of a matrix.
8978 
8979   Logically Collective
8980 
8981   Input Parameters:
8982 + mat    - the matrix
8983 - nullsp - the null space object
8984 
8985   Level: developer
8986 
8987 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetTransposeNullSpace()`, `MatSetNullSpace()`, `MatGetNullSpace()`
8988 @*/
8989 PetscErrorCode MatGetTransposeNullSpace(Mat mat, MatNullSpace *nullsp)
8990 {
8991   PetscFunctionBegin;
8992   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8993   PetscValidType(mat, 1);
8994   PetscAssertPointer(nullsp, 2);
8995   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->transnullsp) ? mat->nullsp : mat->transnullsp;
8996   PetscFunctionReturn(PETSC_SUCCESS);
8997 }
8998 
8999 /*@
9000   MatSetTransposeNullSpace - attaches the null space of a transpose of a matrix to the matrix
9001 
9002   Logically Collective
9003 
9004   Input Parameters:
9005 + mat    - the matrix
9006 - nullsp - the null space object
9007 
9008   Level: advanced
9009 
9010   Notes:
9011   This allows solving singular linear systems defined by the transpose of the matrix using `KSP` solvers with left preconditioning.
9012 
9013   See `MatSetNullSpace()`
9014 
9015 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`, `KSPSetPCSide()`
9016 @*/
9017 PetscErrorCode MatSetTransposeNullSpace(Mat mat, MatNullSpace nullsp)
9018 {
9019   PetscFunctionBegin;
9020   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9021   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9022   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9023   PetscCall(MatNullSpaceDestroy(&mat->transnullsp));
9024   mat->transnullsp = nullsp;
9025   PetscFunctionReturn(PETSC_SUCCESS);
9026 }
9027 
9028 /*@
9029   MatSetNearNullSpace - attaches a null space to a matrix, which is often the null space (rigid body modes) of the operator without boundary conditions
9030   This null space will be used to provide near null space vectors to a multigrid preconditioner built from this matrix.
9031 
9032   Logically Collective
9033 
9034   Input Parameters:
9035 + mat    - the matrix
9036 - nullsp - the null space object
9037 
9038   Level: advanced
9039 
9040   Notes:
9041   Overwrites any previous near null space that may have been attached
9042 
9043   You can remove the null space by calling this routine with an `nullsp` of `NULL`
9044 
9045 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNullSpace()`, `MatNullSpaceCreateRigidBody()`, `MatGetNearNullSpace()`
9046 @*/
9047 PetscErrorCode MatSetNearNullSpace(Mat mat, MatNullSpace nullsp)
9048 {
9049   PetscFunctionBegin;
9050   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9051   PetscValidType(mat, 1);
9052   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9053   MatCheckPreallocated(mat, 1);
9054   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9055   PetscCall(MatNullSpaceDestroy(&mat->nearnullsp));
9056   mat->nearnullsp = nullsp;
9057   PetscFunctionReturn(PETSC_SUCCESS);
9058 }
9059 
9060 /*@
9061   MatGetNearNullSpace - Get null space attached with `MatSetNearNullSpace()`
9062 
9063   Not Collective
9064 
9065   Input Parameter:
9066 . mat - the matrix
9067 
9068   Output Parameter:
9069 . nullsp - the null space object, `NULL` if not set
9070 
9071   Level: advanced
9072 
9073 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatNullSpaceCreate()`
9074 @*/
9075 PetscErrorCode MatGetNearNullSpace(Mat mat, MatNullSpace *nullsp)
9076 {
9077   PetscFunctionBegin;
9078   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9079   PetscValidType(mat, 1);
9080   PetscAssertPointer(nullsp, 2);
9081   MatCheckPreallocated(mat, 1);
9082   *nullsp = mat->nearnullsp;
9083   PetscFunctionReturn(PETSC_SUCCESS);
9084 }
9085 
9086 /*@
9087   MatICCFactor - Performs in-place incomplete Cholesky factorization of matrix.
9088 
9089   Collective
9090 
9091   Input Parameters:
9092 + mat  - the matrix
9093 . row  - row/column permutation
9094 - info - information on desired factorization process
9095 
9096   Level: developer
9097 
9098   Notes:
9099   Probably really in-place only when level of fill is zero, otherwise allocates
9100   new space to store factored matrix and deletes previous memory.
9101 
9102   Most users should employ the `KSP` interface for linear solvers
9103   instead of working directly with matrix algebra routines such as this.
9104   See, e.g., `KSPCreate()`.
9105 
9106   Developer Note:
9107   The Fortran interface is not autogenerated as the
9108   interface definition cannot be generated correctly [due to `MatFactorInfo`]
9109 
9110 .seealso: [](ch_matrices), `Mat`, `MatFactorInfo`, `MatGetFactor()`, `MatICCFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
9111 @*/
9112 PetscErrorCode MatICCFactor(Mat mat, IS row, const MatFactorInfo *info)
9113 {
9114   PetscFunctionBegin;
9115   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9116   PetscValidType(mat, 1);
9117   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
9118   PetscAssertPointer(info, 3);
9119   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
9120   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
9121   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9122   MatCheckPreallocated(mat, 1);
9123   PetscUseTypeMethod(mat, iccfactor, row, info);
9124   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9125   PetscFunctionReturn(PETSC_SUCCESS);
9126 }
9127 
9128 /*@
9129   MatDiagonalScaleLocal - Scales columns of a matrix given the scaling values including the
9130   ghosted ones.
9131 
9132   Not Collective
9133 
9134   Input Parameters:
9135 + mat  - the matrix
9136 - diag - the diagonal values, including ghost ones
9137 
9138   Level: developer
9139 
9140   Notes:
9141   Works only for `MATMPIAIJ` and `MATMPIBAIJ` matrices
9142 
9143   This allows one to avoid during communication to perform the scaling that must be done with `MatDiagonalScale()`
9144 
9145 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
9146 @*/
9147 PetscErrorCode MatDiagonalScaleLocal(Mat mat, Vec diag)
9148 {
9149   PetscMPIInt size;
9150 
9151   PetscFunctionBegin;
9152   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9153   PetscValidHeaderSpecific(diag, VEC_CLASSID, 2);
9154   PetscValidType(mat, 1);
9155 
9156   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must be already assembled");
9157   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
9158   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
9159   if (size == 1) {
9160     PetscInt n, m;
9161     PetscCall(VecGetSize(diag, &n));
9162     PetscCall(MatGetSize(mat, NULL, &m));
9163     PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supported for sequential matrices when no ghost points/periodic conditions");
9164     PetscCall(MatDiagonalScale(mat, NULL, diag));
9165   } else {
9166     PetscUseMethod(mat, "MatDiagonalScaleLocal_C", (Mat, Vec), (mat, diag));
9167   }
9168   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
9169   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9170   PetscFunctionReturn(PETSC_SUCCESS);
9171 }
9172 
9173 /*@
9174   MatGetInertia - Gets the inertia from a factored matrix
9175 
9176   Collective
9177 
9178   Input Parameter:
9179 . mat - the matrix
9180 
9181   Output Parameters:
9182 + nneg  - number of negative eigenvalues
9183 . nzero - number of zero eigenvalues
9184 - npos  - number of positive eigenvalues
9185 
9186   Level: advanced
9187 
9188   Note:
9189   Matrix must have been factored by `MatCholeskyFactor()`
9190 
9191 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactor()`
9192 @*/
9193 PetscErrorCode MatGetInertia(Mat mat, PetscInt *nneg, PetscInt *nzero, PetscInt *npos)
9194 {
9195   PetscFunctionBegin;
9196   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9197   PetscValidType(mat, 1);
9198   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9199   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Numeric factor mat is not assembled");
9200   PetscUseTypeMethod(mat, getinertia, nneg, nzero, npos);
9201   PetscFunctionReturn(PETSC_SUCCESS);
9202 }
9203 
9204 /*@C
9205   MatSolves - Solves $A x = b$, given a factored matrix, for a collection of vectors
9206 
9207   Neighbor-wise Collective
9208 
9209   Input Parameters:
9210 + mat - the factored matrix obtained with `MatGetFactor()`
9211 - b   - the right-hand-side vectors
9212 
9213   Output Parameter:
9214 . x - the result vectors
9215 
9216   Level: developer
9217 
9218   Note:
9219   The vectors `b` and `x` cannot be the same.  I.e., one cannot
9220   call `MatSolves`(A,x,x).
9221 
9222 .seealso: [](ch_matrices), `Mat`, `Vecs`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`, `MatSolve()`
9223 @*/
9224 PetscErrorCode MatSolves(Mat mat, Vecs b, Vecs x)
9225 {
9226   PetscFunctionBegin;
9227   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9228   PetscValidType(mat, 1);
9229   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
9230   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9231   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
9232 
9233   MatCheckPreallocated(mat, 1);
9234   PetscCall(PetscLogEventBegin(MAT_Solves, mat, 0, 0, 0));
9235   PetscUseTypeMethod(mat, solves, b, x);
9236   PetscCall(PetscLogEventEnd(MAT_Solves, mat, 0, 0, 0));
9237   PetscFunctionReturn(PETSC_SUCCESS);
9238 }
9239 
9240 /*@
9241   MatIsSymmetric - Test whether a matrix is symmetric
9242 
9243   Collective
9244 
9245   Input Parameters:
9246 + A   - the matrix to test
9247 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact transpose)
9248 
9249   Output Parameter:
9250 . flg - the result
9251 
9252   Level: intermediate
9253 
9254   Notes:
9255   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9256 
9257   If the matrix does not yet know if it is symmetric or not this can be an expensive operation, also available `MatIsSymmetricKnown()`
9258 
9259   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9260   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9261 
9262 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetricKnown()`,
9263           `MAT_SYMMETRIC`, `MAT_SYMMETRY_ETERNAL`
9264 @*/
9265 PetscErrorCode MatIsSymmetric(Mat A, PetscReal tol, PetscBool *flg)
9266 {
9267   PetscFunctionBegin;
9268   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9269   PetscAssertPointer(flg, 3);
9270   if (A->symmetric != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->symmetric);
9271   else {
9272     if (A->ops->issymmetric) PetscUseTypeMethod(A, issymmetric, tol, flg);
9273     else PetscCall(MatIsTranspose(A, A, tol, flg));
9274     if (!tol) PetscCall(MatSetOption(A, MAT_SYMMETRIC, *flg));
9275   }
9276   PetscFunctionReturn(PETSC_SUCCESS);
9277 }
9278 
9279 /*@
9280   MatIsHermitian - Test whether a matrix is Hermitian
9281 
9282   Collective
9283 
9284   Input Parameters:
9285 + A   - the matrix to test
9286 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact Hermitian)
9287 
9288   Output Parameter:
9289 . flg - the result
9290 
9291   Level: intermediate
9292 
9293   Notes:
9294   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9295 
9296   If the matrix does not yet know if it is Hermitian or not this can be an expensive operation, also available `MatIsHermitianKnown()`
9297 
9298   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9299   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMEMTRY_ETERNAL`,`PETSC_TRUE`)
9300 
9301 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetric()`, `MatSetOption()`,
9302           `MatIsSymmetricKnown()`, `MatIsSymmetric()`, `MAT_HERMITIAN`, `MAT_SYMMETRY_ETERNAL`
9303 @*/
9304 PetscErrorCode MatIsHermitian(Mat A, PetscReal tol, PetscBool *flg)
9305 {
9306   PetscFunctionBegin;
9307   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9308   PetscAssertPointer(flg, 3);
9309   if (A->hermitian != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->hermitian);
9310   else {
9311     if (A->ops->ishermitian) PetscUseTypeMethod(A, ishermitian, tol, flg);
9312     else PetscCall(MatIsHermitianTranspose(A, A, tol, flg));
9313     if (!tol) PetscCall(MatSetOption(A, MAT_HERMITIAN, *flg));
9314   }
9315   PetscFunctionReturn(PETSC_SUCCESS);
9316 }
9317 
9318 /*@
9319   MatIsSymmetricKnown - Checks if a matrix knows if it is symmetric or not and its symmetric state
9320 
9321   Not Collective
9322 
9323   Input Parameter:
9324 . A - the matrix to check
9325 
9326   Output Parameters:
9327 + set - `PETSC_TRUE` if the matrix knows its symmetry state (this tells you if the next flag is valid)
9328 - flg - the result (only valid if set is `PETSC_TRUE`)
9329 
9330   Level: advanced
9331 
9332   Notes:
9333   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsSymmetric()`
9334   if you want it explicitly checked
9335 
9336   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9337   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9338 
9339 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9340 @*/
9341 PetscErrorCode MatIsSymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9342 {
9343   PetscFunctionBegin;
9344   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9345   PetscAssertPointer(set, 2);
9346   PetscAssertPointer(flg, 3);
9347   if (A->symmetric != PETSC_BOOL3_UNKNOWN) {
9348     *set = PETSC_TRUE;
9349     *flg = PetscBool3ToBool(A->symmetric);
9350   } else {
9351     *set = PETSC_FALSE;
9352   }
9353   PetscFunctionReturn(PETSC_SUCCESS);
9354 }
9355 
9356 /*@
9357   MatIsSPDKnown - Checks if a matrix knows if it is symmetric positive definite or not and its symmetric positive definite state
9358 
9359   Not Collective
9360 
9361   Input Parameter:
9362 . A - the matrix to check
9363 
9364   Output Parameters:
9365 + set - `PETSC_TRUE` if the matrix knows its symmetric positive definite state (this tells you if the next flag is valid)
9366 - flg - the result (only valid if set is `PETSC_TRUE`)
9367 
9368   Level: advanced
9369 
9370   Notes:
9371   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`).
9372 
9373   One can declare that a matrix is SPD with `MatSetOption`(mat,`MAT_SPD`,`PETSC_TRUE`) and if it is known to remain SPD
9374   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SPD_ETERNAL`,`PETSC_TRUE`)
9375 
9376 .seealso: [](ch_matrices), `Mat`, `MAT_SPD_ETERNAL`, `MAT_SPD`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9377 @*/
9378 PetscErrorCode MatIsSPDKnown(Mat A, PetscBool *set, PetscBool *flg)
9379 {
9380   PetscFunctionBegin;
9381   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9382   PetscAssertPointer(set, 2);
9383   PetscAssertPointer(flg, 3);
9384   if (A->spd != PETSC_BOOL3_UNKNOWN) {
9385     *set = PETSC_TRUE;
9386     *flg = PetscBool3ToBool(A->spd);
9387   } else {
9388     *set = PETSC_FALSE;
9389   }
9390   PetscFunctionReturn(PETSC_SUCCESS);
9391 }
9392 
9393 /*@
9394   MatIsHermitianKnown - Checks if a matrix knows if it is Hermitian or not and its Hermitian state
9395 
9396   Not Collective
9397 
9398   Input Parameter:
9399 . A - the matrix to check
9400 
9401   Output Parameters:
9402 + set - `PETSC_TRUE` if the matrix knows its Hermitian state (this tells you if the next flag is valid)
9403 - flg - the result (only valid if set is `PETSC_TRUE`)
9404 
9405   Level: advanced
9406 
9407   Notes:
9408   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsHermitian()`
9409   if you want it explicitly checked
9410 
9411   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9412   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9413 
9414 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MAT_HERMITIAN`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`
9415 @*/
9416 PetscErrorCode MatIsHermitianKnown(Mat A, PetscBool *set, PetscBool *flg)
9417 {
9418   PetscFunctionBegin;
9419   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9420   PetscAssertPointer(set, 2);
9421   PetscAssertPointer(flg, 3);
9422   if (A->hermitian != PETSC_BOOL3_UNKNOWN) {
9423     *set = PETSC_TRUE;
9424     *flg = PetscBool3ToBool(A->hermitian);
9425   } else {
9426     *set = PETSC_FALSE;
9427   }
9428   PetscFunctionReturn(PETSC_SUCCESS);
9429 }
9430 
9431 /*@
9432   MatIsStructurallySymmetric - Test whether a matrix is structurally symmetric
9433 
9434   Collective
9435 
9436   Input Parameter:
9437 . A - the matrix to test
9438 
9439   Output Parameter:
9440 . flg - the result
9441 
9442   Level: intermediate
9443 
9444   Notes:
9445   If the matrix does yet know it is structurally symmetric this can be an expensive operation, also available `MatIsStructurallySymmetricKnown()`
9446 
9447   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
9448   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9449 
9450 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsSymmetric()`, `MatSetOption()`, `MatIsStructurallySymmetricKnown()`
9451 @*/
9452 PetscErrorCode MatIsStructurallySymmetric(Mat A, PetscBool *flg)
9453 {
9454   PetscFunctionBegin;
9455   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9456   PetscAssertPointer(flg, 2);
9457   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9458     *flg = PetscBool3ToBool(A->structurally_symmetric);
9459   } else {
9460     PetscUseTypeMethod(A, isstructurallysymmetric, flg);
9461     PetscCall(MatSetOption(A, MAT_STRUCTURALLY_SYMMETRIC, *flg));
9462   }
9463   PetscFunctionReturn(PETSC_SUCCESS);
9464 }
9465 
9466 /*@
9467   MatIsStructurallySymmetricKnown - Checks if a matrix knows if it is structurally symmetric or not and its structurally symmetric state
9468 
9469   Not Collective
9470 
9471   Input Parameter:
9472 . A - the matrix to check
9473 
9474   Output Parameters:
9475 + set - PETSC_TRUE if the matrix knows its structurally symmetric state (this tells you if the next flag is valid)
9476 - flg - the result (only valid if set is PETSC_TRUE)
9477 
9478   Level: advanced
9479 
9480   Notes:
9481   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
9482   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9483 
9484   Use `MatIsStructurallySymmetric()` to explicitly check if a matrix is structurally symmetric (this is an expensive operation)
9485 
9486 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9487 @*/
9488 PetscErrorCode MatIsStructurallySymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9489 {
9490   PetscFunctionBegin;
9491   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9492   PetscAssertPointer(set, 2);
9493   PetscAssertPointer(flg, 3);
9494   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9495     *set = PETSC_TRUE;
9496     *flg = PetscBool3ToBool(A->structurally_symmetric);
9497   } else {
9498     *set = PETSC_FALSE;
9499   }
9500   PetscFunctionReturn(PETSC_SUCCESS);
9501 }
9502 
9503 /*@
9504   MatStashGetInfo - Gets how many values are currently in the matrix stash, i.e. need
9505   to be communicated to other processors during the `MatAssemblyBegin()`/`MatAssemblyEnd()` process
9506 
9507   Not Collective
9508 
9509   Input Parameter:
9510 . mat - the matrix
9511 
9512   Output Parameters:
9513 + nstash    - the size of the stash
9514 . reallocs  - the number of additional mallocs incurred.
9515 . bnstash   - the size of the block stash
9516 - breallocs - the number of additional mallocs incurred.in the block stash
9517 
9518   Level: advanced
9519 
9520 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashSetInitialSize()`
9521 @*/
9522 PetscErrorCode MatStashGetInfo(Mat mat, PetscInt *nstash, PetscInt *reallocs, PetscInt *bnstash, PetscInt *breallocs)
9523 {
9524   PetscFunctionBegin;
9525   PetscCall(MatStashGetInfo_Private(&mat->stash, nstash, reallocs));
9526   PetscCall(MatStashGetInfo_Private(&mat->bstash, bnstash, breallocs));
9527   PetscFunctionReturn(PETSC_SUCCESS);
9528 }
9529 
9530 /*@
9531   MatCreateVecs - Get vector(s) compatible with the matrix, i.e. with the same
9532   parallel layout, `PetscLayout` for rows and columns
9533 
9534   Collective
9535 
9536   Input Parameter:
9537 . mat - the matrix
9538 
9539   Output Parameters:
9540 + right - (optional) vector that the matrix can be multiplied against
9541 - left  - (optional) vector that the matrix vector product can be stored in
9542 
9543   Level: advanced
9544 
9545   Notes:
9546   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()`.
9547 
9548   These are new vectors which are not owned by the mat, they should be destroyed in `VecDestroy()` when no longer needed
9549 
9550 .seealso: [](ch_matrices), `Mat`, `Vec`, `VecCreate()`, `VecDestroy()`, `DMCreateGlobalVector()`
9551 @*/
9552 PetscErrorCode MatCreateVecs(Mat mat, Vec *right, Vec *left)
9553 {
9554   PetscFunctionBegin;
9555   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9556   PetscValidType(mat, 1);
9557   if (mat->ops->getvecs) {
9558     PetscUseTypeMethod(mat, getvecs, right, left);
9559   } else {
9560     if (right) {
9561       PetscCheck(mat->cmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for columns not yet setup");
9562       PetscCall(VecCreateWithLayout_Private(mat->cmap, right));
9563       PetscCall(VecSetType(*right, mat->defaultvectype));
9564 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9565       if (mat->boundtocpu && mat->bindingpropagates) {
9566         PetscCall(VecSetBindingPropagates(*right, PETSC_TRUE));
9567         PetscCall(VecBindToCPU(*right, PETSC_TRUE));
9568       }
9569 #endif
9570     }
9571     if (left) {
9572       PetscCheck(mat->rmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for rows not yet setup");
9573       PetscCall(VecCreateWithLayout_Private(mat->rmap, left));
9574       PetscCall(VecSetType(*left, mat->defaultvectype));
9575 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9576       if (mat->boundtocpu && mat->bindingpropagates) {
9577         PetscCall(VecSetBindingPropagates(*left, PETSC_TRUE));
9578         PetscCall(VecBindToCPU(*left, PETSC_TRUE));
9579       }
9580 #endif
9581     }
9582   }
9583   PetscFunctionReturn(PETSC_SUCCESS);
9584 }
9585 
9586 /*@
9587   MatFactorInfoInitialize - Initializes a `MatFactorInfo` data structure
9588   with default values.
9589 
9590   Not Collective
9591 
9592   Input Parameter:
9593 . info - the `MatFactorInfo` data structure
9594 
9595   Level: developer
9596 
9597   Notes:
9598   The solvers are generally used through the `KSP` and `PC` objects, for example
9599   `PCLU`, `PCILU`, `PCCHOLESKY`, `PCICC`
9600 
9601   Once the data structure is initialized one may change certain entries as desired for the particular factorization to be performed
9602 
9603 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorInfo`
9604 @*/
9605 PetscErrorCode MatFactorInfoInitialize(MatFactorInfo *info)
9606 {
9607   PetscFunctionBegin;
9608   PetscCall(PetscMemzero(info, sizeof(MatFactorInfo)));
9609   PetscFunctionReturn(PETSC_SUCCESS);
9610 }
9611 
9612 /*@
9613   MatFactorSetSchurIS - Set indices corresponding to the Schur complement you wish to have computed
9614 
9615   Collective
9616 
9617   Input Parameters:
9618 + mat - the factored matrix
9619 - is  - the index set defining the Schur indices (0-based)
9620 
9621   Level: advanced
9622 
9623   Notes:
9624   Call `MatFactorSolveSchurComplement()` or `MatFactorSolveSchurComplementTranspose()` after this call to solve a Schur complement system.
9625 
9626   You can call `MatFactorGetSchurComplement()` or `MatFactorCreateSchurComplement()` after this call.
9627 
9628   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9629 
9630 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorGetSchurComplement()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSolveSchurComplement()`,
9631           `MatFactorSolveSchurComplementTranspose()`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9632 @*/
9633 PetscErrorCode MatFactorSetSchurIS(Mat mat, IS is)
9634 {
9635   PetscErrorCode (*f)(Mat, IS);
9636 
9637   PetscFunctionBegin;
9638   PetscValidType(mat, 1);
9639   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9640   PetscValidType(is, 2);
9641   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
9642   PetscCheckSameComm(mat, 1, is, 2);
9643   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
9644   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorSetSchurIS_C", &f));
9645   PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "The selected MatSolverType does not support Schur complement computation. You should use MATSOLVERMUMPS or MATSOLVERMKL_PARDISO");
9646   PetscCall(MatDestroy(&mat->schur));
9647   PetscCall((*f)(mat, is));
9648   PetscCheck(mat->schur, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Schur complement has not been created");
9649   PetscFunctionReturn(PETSC_SUCCESS);
9650 }
9651 
9652 /*@
9653   MatFactorCreateSchurComplement - Create a Schur complement matrix object using Schur data computed during the factorization step
9654 
9655   Logically Collective
9656 
9657   Input Parameters:
9658 + F      - the factored matrix obtained by calling `MatGetFactor()`
9659 . S      - location where to return the Schur complement, can be `NULL`
9660 - status - the status of the Schur complement matrix, can be `NULL`
9661 
9662   Level: advanced
9663 
9664   Notes:
9665   You must call `MatFactorSetSchurIS()` before calling this routine.
9666 
9667   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9668 
9669   The routine provides a copy of the Schur matrix stored within the solver data structures.
9670   The caller must destroy the object when it is no longer needed.
9671   If `MatFactorInvertSchurComplement()` has been called, the routine gets back the inverse.
9672 
9673   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)
9674 
9675   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9676 
9677   Developer Note:
9678   The reason this routine exists is because the representation of the Schur complement within the factor matrix may be different than a standard PETSc
9679   matrix representation and we normally do not want to use the time or memory to make a copy as a regular PETSc matrix.
9680 
9681 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorSchurStatus`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9682 @*/
9683 PetscErrorCode MatFactorCreateSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9684 {
9685   PetscFunctionBegin;
9686   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9687   if (S) PetscAssertPointer(S, 2);
9688   if (status) PetscAssertPointer(status, 3);
9689   if (S) {
9690     PetscErrorCode (*f)(Mat, Mat *);
9691 
9692     PetscCall(PetscObjectQueryFunction((PetscObject)F, "MatFactorCreateSchurComplement_C", &f));
9693     if (f) {
9694       PetscCall((*f)(F, S));
9695     } else {
9696       PetscCall(MatDuplicate(F->schur, MAT_COPY_VALUES, S));
9697     }
9698   }
9699   if (status) *status = F->schur_status;
9700   PetscFunctionReturn(PETSC_SUCCESS);
9701 }
9702 
9703 /*@
9704   MatFactorGetSchurComplement - Gets access to a Schur complement matrix using the current Schur data within a factored matrix
9705 
9706   Logically Collective
9707 
9708   Input Parameters:
9709 + F      - the factored matrix obtained by calling `MatGetFactor()`
9710 . S      - location where to return the Schur complement, can be `NULL`
9711 - status - the status of the Schur complement matrix, can be `NULL`
9712 
9713   Level: advanced
9714 
9715   Notes:
9716   You must call `MatFactorSetSchurIS()` before calling this routine.
9717 
9718   Schur complement mode is currently implemented for sequential matrices with factor type of `MATSOLVERMUMPS`
9719 
9720   The routine returns a the Schur Complement stored within the data structures of the solver.
9721 
9722   If `MatFactorInvertSchurComplement()` has previously been called, the returned matrix is actually the inverse of the Schur complement.
9723 
9724   The returned matrix should not be destroyed; the caller should call `MatFactorRestoreSchurComplement()` when the object is no longer needed.
9725 
9726   Use `MatFactorCreateSchurComplement()` to create a copy of the Schur complement matrix that is within a factored matrix
9727 
9728   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9729 
9730 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9731 @*/
9732 PetscErrorCode MatFactorGetSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9733 {
9734   PetscFunctionBegin;
9735   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9736   if (S) {
9737     PetscAssertPointer(S, 2);
9738     *S = F->schur;
9739   }
9740   if (status) {
9741     PetscAssertPointer(status, 3);
9742     *status = F->schur_status;
9743   }
9744   PetscFunctionReturn(PETSC_SUCCESS);
9745 }
9746 
9747 static PetscErrorCode MatFactorUpdateSchurStatus_Private(Mat F)
9748 {
9749   Mat S = F->schur;
9750 
9751   PetscFunctionBegin;
9752   switch (F->schur_status) {
9753   case MAT_FACTOR_SCHUR_UNFACTORED: // fall-through
9754   case MAT_FACTOR_SCHUR_INVERTED:
9755     if (S) {
9756       S->ops->solve             = NULL;
9757       S->ops->matsolve          = NULL;
9758       S->ops->solvetranspose    = NULL;
9759       S->ops->matsolvetranspose = NULL;
9760       S->ops->solveadd          = NULL;
9761       S->ops->solvetransposeadd = NULL;
9762       S->factortype             = MAT_FACTOR_NONE;
9763       PetscCall(PetscFree(S->solvertype));
9764     }
9765   case MAT_FACTOR_SCHUR_FACTORED: // fall-through
9766     break;
9767   default:
9768     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9769   }
9770   PetscFunctionReturn(PETSC_SUCCESS);
9771 }
9772 
9773 /*@
9774   MatFactorRestoreSchurComplement - Restore the Schur complement matrix object obtained from a call to `MatFactorGetSchurComplement()`
9775 
9776   Logically Collective
9777 
9778   Input Parameters:
9779 + F      - the factored matrix obtained by calling `MatGetFactor()`
9780 . S      - location where the Schur complement is stored
9781 - status - the status of the Schur complement matrix (see `MatFactorSchurStatus`)
9782 
9783   Level: advanced
9784 
9785 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9786 @*/
9787 PetscErrorCode MatFactorRestoreSchurComplement(Mat F, Mat *S, MatFactorSchurStatus status)
9788 {
9789   PetscFunctionBegin;
9790   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9791   if (S) {
9792     PetscValidHeaderSpecific(*S, MAT_CLASSID, 2);
9793     *S = NULL;
9794   }
9795   F->schur_status = status;
9796   PetscCall(MatFactorUpdateSchurStatus_Private(F));
9797   PetscFunctionReturn(PETSC_SUCCESS);
9798 }
9799 
9800 /*@
9801   MatFactorSolveSchurComplementTranspose - Solve the transpose of the Schur complement system computed during the factorization step
9802 
9803   Logically Collective
9804 
9805   Input Parameters:
9806 + F   - the factored matrix obtained by calling `MatGetFactor()`
9807 . rhs - location where the right-hand side of the Schur complement system is stored
9808 - sol - location where the solution of the Schur complement system has to be returned
9809 
9810   Level: advanced
9811 
9812   Notes:
9813   The sizes of the vectors should match the size of the Schur complement
9814 
9815   Must be called after `MatFactorSetSchurIS()`
9816 
9817 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplement()`
9818 @*/
9819 PetscErrorCode MatFactorSolveSchurComplementTranspose(Mat F, Vec rhs, Vec sol)
9820 {
9821   PetscFunctionBegin;
9822   PetscValidType(F, 1);
9823   PetscValidType(rhs, 2);
9824   PetscValidType(sol, 3);
9825   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9826   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
9827   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
9828   PetscCheckSameComm(F, 1, rhs, 2);
9829   PetscCheckSameComm(F, 1, sol, 3);
9830   PetscCall(MatFactorFactorizeSchurComplement(F));
9831   switch (F->schur_status) {
9832   case MAT_FACTOR_SCHUR_FACTORED:
9833     PetscCall(MatSolveTranspose(F->schur, rhs, sol));
9834     break;
9835   case MAT_FACTOR_SCHUR_INVERTED:
9836     PetscCall(MatMultTranspose(F->schur, rhs, sol));
9837     break;
9838   default:
9839     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9840   }
9841   PetscFunctionReturn(PETSC_SUCCESS);
9842 }
9843 
9844 /*@
9845   MatFactorSolveSchurComplement - Solve the Schur complement system computed during the factorization step
9846 
9847   Logically Collective
9848 
9849   Input Parameters:
9850 + F   - the factored matrix obtained by calling `MatGetFactor()`
9851 . rhs - location where the right-hand side of the Schur complement system is stored
9852 - sol - location where the solution of the Schur complement system has to be returned
9853 
9854   Level: advanced
9855 
9856   Notes:
9857   The sizes of the vectors should match the size of the Schur complement
9858 
9859   Must be called after `MatFactorSetSchurIS()`
9860 
9861 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplementTranspose()`
9862 @*/
9863 PetscErrorCode MatFactorSolveSchurComplement(Mat F, Vec rhs, Vec sol)
9864 {
9865   PetscFunctionBegin;
9866   PetscValidType(F, 1);
9867   PetscValidType(rhs, 2);
9868   PetscValidType(sol, 3);
9869   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9870   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
9871   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
9872   PetscCheckSameComm(F, 1, rhs, 2);
9873   PetscCheckSameComm(F, 1, sol, 3);
9874   PetscCall(MatFactorFactorizeSchurComplement(F));
9875   switch (F->schur_status) {
9876   case MAT_FACTOR_SCHUR_FACTORED:
9877     PetscCall(MatSolve(F->schur, rhs, sol));
9878     break;
9879   case MAT_FACTOR_SCHUR_INVERTED:
9880     PetscCall(MatMult(F->schur, rhs, sol));
9881     break;
9882   default:
9883     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9884   }
9885   PetscFunctionReturn(PETSC_SUCCESS);
9886 }
9887 
9888 PETSC_EXTERN PetscErrorCode MatSeqDenseInvertFactors_Private(Mat);
9889 #if PetscDefined(HAVE_CUDA)
9890 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode MatSeqDenseCUDAInvertFactors_Internal(Mat);
9891 #endif
9892 
9893 /* Schur status updated in the interface */
9894 static PetscErrorCode MatFactorInvertSchurComplement_Private(Mat F)
9895 {
9896   Mat S = F->schur;
9897 
9898   PetscFunctionBegin;
9899   if (S) {
9900     PetscMPIInt size;
9901     PetscBool   isdense, isdensecuda;
9902 
9903     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)S), &size));
9904     PetscCheck(size <= 1, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not yet implemented");
9905     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSE, &isdense));
9906     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSECUDA, &isdensecuda));
9907     PetscCheck(isdense || isdensecuda, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not implemented for type %s", ((PetscObject)S)->type_name);
9908     PetscCall(PetscLogEventBegin(MAT_FactorInvS, F, 0, 0, 0));
9909     if (isdense) {
9910       PetscCall(MatSeqDenseInvertFactors_Private(S));
9911     } else if (isdensecuda) {
9912 #if defined(PETSC_HAVE_CUDA)
9913       PetscCall(MatSeqDenseCUDAInvertFactors_Internal(S));
9914 #endif
9915     }
9916     // HIP??????????????
9917     PetscCall(PetscLogEventEnd(MAT_FactorInvS, F, 0, 0, 0));
9918   }
9919   PetscFunctionReturn(PETSC_SUCCESS);
9920 }
9921 
9922 /*@
9923   MatFactorInvertSchurComplement - Invert the Schur complement matrix computed during the factorization step
9924 
9925   Logically Collective
9926 
9927   Input Parameter:
9928 . F - the factored matrix obtained by calling `MatGetFactor()`
9929 
9930   Level: advanced
9931 
9932   Notes:
9933   Must be called after `MatFactorSetSchurIS()`.
9934 
9935   Call `MatFactorGetSchurComplement()` or  `MatFactorCreateSchurComplement()` AFTER this call to actually compute the inverse and get access to it.
9936 
9937 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorCreateSchurComplement()`
9938 @*/
9939 PetscErrorCode MatFactorInvertSchurComplement(Mat F)
9940 {
9941   PetscFunctionBegin;
9942   PetscValidType(F, 1);
9943   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9944   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED) PetscFunctionReturn(PETSC_SUCCESS);
9945   PetscCall(MatFactorFactorizeSchurComplement(F));
9946   PetscCall(MatFactorInvertSchurComplement_Private(F));
9947   F->schur_status = MAT_FACTOR_SCHUR_INVERTED;
9948   PetscFunctionReturn(PETSC_SUCCESS);
9949 }
9950 
9951 /*@
9952   MatFactorFactorizeSchurComplement - Factorize the Schur complement matrix computed during the factorization step
9953 
9954   Logically Collective
9955 
9956   Input Parameter:
9957 . F - the factored matrix obtained by calling `MatGetFactor()`
9958 
9959   Level: advanced
9960 
9961   Note:
9962   Must be called after `MatFactorSetSchurIS()`
9963 
9964 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorInvertSchurComplement()`
9965 @*/
9966 PetscErrorCode MatFactorFactorizeSchurComplement(Mat F)
9967 {
9968   MatFactorInfo info;
9969 
9970   PetscFunctionBegin;
9971   PetscValidType(F, 1);
9972   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9973   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED || F->schur_status == MAT_FACTOR_SCHUR_FACTORED) PetscFunctionReturn(PETSC_SUCCESS);
9974   PetscCall(PetscLogEventBegin(MAT_FactorFactS, F, 0, 0, 0));
9975   PetscCall(PetscMemzero(&info, sizeof(MatFactorInfo)));
9976   if (F->factortype == MAT_FACTOR_CHOLESKY) { /* LDL^t regarded as Cholesky */
9977     PetscCall(MatCholeskyFactor(F->schur, NULL, &info));
9978   } else {
9979     PetscCall(MatLUFactor(F->schur, NULL, NULL, &info));
9980   }
9981   PetscCall(PetscLogEventEnd(MAT_FactorFactS, F, 0, 0, 0));
9982   F->schur_status = MAT_FACTOR_SCHUR_FACTORED;
9983   PetscFunctionReturn(PETSC_SUCCESS);
9984 }
9985 
9986 /*@
9987   MatPtAP - Creates the matrix product $C = P^T * A * P$
9988 
9989   Neighbor-wise Collective
9990 
9991   Input Parameters:
9992 + A     - the matrix
9993 . P     - the projection matrix
9994 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
9995 - 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
9996           if the result is a dense matrix this is irrelevant
9997 
9998   Output Parameter:
9999 . C - the product matrix
10000 
10001   Level: intermediate
10002 
10003   Notes:
10004   C will be created and must be destroyed by the user with `MatDestroy()`.
10005 
10006   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
10007 
10008   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10009 
10010   Developer Note:
10011   For matrix types without special implementation the function fallbacks to `MatMatMult()` followed by `MatTransposeMatMult()`.
10012 
10013 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatRARt()`
10014 @*/
10015 PetscErrorCode MatPtAP(Mat A, Mat P, MatReuse scall, PetscReal fill, Mat *C)
10016 {
10017   PetscFunctionBegin;
10018   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10019   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10020 
10021   if (scall == MAT_INITIAL_MATRIX) {
10022     PetscCall(MatProductCreate(A, P, NULL, C));
10023     PetscCall(MatProductSetType(*C, MATPRODUCT_PtAP));
10024     PetscCall(MatProductSetAlgorithm(*C, "default"));
10025     PetscCall(MatProductSetFill(*C, fill));
10026 
10027     (*C)->product->api_user = PETSC_TRUE;
10028     PetscCall(MatProductSetFromOptions(*C));
10029     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);
10030     PetscCall(MatProductSymbolic(*C));
10031   } else { /* scall == MAT_REUSE_MATRIX */
10032     PetscCall(MatProductReplaceMats(A, P, NULL, *C));
10033   }
10034 
10035   PetscCall(MatProductNumeric(*C));
10036   (*C)->symmetric = A->symmetric;
10037   (*C)->spd       = A->spd;
10038   PetscFunctionReturn(PETSC_SUCCESS);
10039 }
10040 
10041 /*@
10042   MatRARt - Creates the matrix product $C = R * A * R^T$
10043 
10044   Neighbor-wise Collective
10045 
10046   Input Parameters:
10047 + A     - the matrix
10048 . R     - the projection matrix
10049 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10050 - fill  - expected fill as ratio of nnz(C)/nnz(A), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10051           if the result is a dense matrix this is irrelevant
10052 
10053   Output Parameter:
10054 . C - the product matrix
10055 
10056   Level: intermediate
10057 
10058   Notes:
10059   `C` will be created and must be destroyed by the user with `MatDestroy()`.
10060 
10061   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
10062 
10063   This routine is currently only implemented for pairs of `MATAIJ` matrices and classes
10064   which inherit from `MATAIJ`. Due to PETSc sparse matrix block row distribution among processes,
10065   the parallel `MatRARt()` is implemented computing the explicit transpose of `R`, which can be very expensive.
10066   We recommend using `MatPtAP()` when possible.
10067 
10068   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10069 
10070 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatPtAP()`
10071 @*/
10072 PetscErrorCode MatRARt(Mat A, Mat R, MatReuse scall, PetscReal fill, Mat *C)
10073 {
10074   PetscFunctionBegin;
10075   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10076   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10077 
10078   if (scall == MAT_INITIAL_MATRIX) {
10079     PetscCall(MatProductCreate(A, R, NULL, C));
10080     PetscCall(MatProductSetType(*C, MATPRODUCT_RARt));
10081     PetscCall(MatProductSetAlgorithm(*C, "default"));
10082     PetscCall(MatProductSetFill(*C, fill));
10083 
10084     (*C)->product->api_user = PETSC_TRUE;
10085     PetscCall(MatProductSetFromOptions(*C));
10086     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);
10087     PetscCall(MatProductSymbolic(*C));
10088   } else { /* scall == MAT_REUSE_MATRIX */
10089     PetscCall(MatProductReplaceMats(A, R, NULL, *C));
10090   }
10091 
10092   PetscCall(MatProductNumeric(*C));
10093   if (A->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10094   PetscFunctionReturn(PETSC_SUCCESS);
10095 }
10096 
10097 static PetscErrorCode MatProduct_Private(Mat A, Mat B, MatReuse scall, PetscReal fill, MatProductType ptype, Mat *C)
10098 {
10099   PetscBool flg = PETSC_TRUE;
10100 
10101   PetscFunctionBegin;
10102   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX product not supported");
10103   if (scall == MAT_INITIAL_MATRIX) {
10104     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_INITIAL_MATRIX and product type %s\n", MatProductTypes[ptype]));
10105     PetscCall(MatProductCreate(A, B, NULL, C));
10106     PetscCall(MatProductSetAlgorithm(*C, MATPRODUCTALGORITHMDEFAULT));
10107     PetscCall(MatProductSetFill(*C, fill));
10108   } else { /* scall == MAT_REUSE_MATRIX */
10109     Mat_Product *product = (*C)->product;
10110 
10111     PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)*C, &flg, MATSEQDENSE, MATMPIDENSE, ""));
10112     if (flg && product && product->type != ptype) {
10113       PetscCall(MatProductClear(*C));
10114       product = NULL;
10115     }
10116     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_REUSE_MATRIX %s product present and product type %s\n", product ? "with" : "without", MatProductTypes[ptype]));
10117     if (!product) { /* user provide the dense matrix *C without calling MatProductCreate() or reusing it from previous calls */
10118       PetscCheck(flg, PetscObjectComm((PetscObject)*C), PETSC_ERR_SUP, "Call MatProductCreate() first");
10119       PetscCall(MatProductCreate_Private(A, B, NULL, *C));
10120       product        = (*C)->product;
10121       product->fill  = fill;
10122       product->clear = PETSC_TRUE;
10123     } else { /* user may change input matrices A or B when MAT_REUSE_MATRIX */
10124       flg = PETSC_FALSE;
10125       PetscCall(MatProductReplaceMats(A, B, NULL, *C));
10126     }
10127   }
10128   if (flg) {
10129     (*C)->product->api_user = PETSC_TRUE;
10130     PetscCall(MatProductSetType(*C, ptype));
10131     PetscCall(MatProductSetFromOptions(*C));
10132     PetscCall(MatProductSymbolic(*C));
10133   }
10134   PetscCall(MatProductNumeric(*C));
10135   PetscFunctionReturn(PETSC_SUCCESS);
10136 }
10137 
10138 /*@
10139   MatMatMult - Performs matrix-matrix multiplication C=A*B.
10140 
10141   Neighbor-wise Collective
10142 
10143   Input Parameters:
10144 + A     - the left matrix
10145 . B     - the right matrix
10146 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10147 - 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
10148           if the result is a dense matrix this is irrelevant
10149 
10150   Output Parameter:
10151 . C - the product matrix
10152 
10153   Notes:
10154   Unless scall is `MAT_REUSE_MATRIX` C will be created.
10155 
10156   `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
10157   call to this function with `MAT_INITIAL_MATRIX`.
10158 
10159   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value actually needed.
10160 
10161   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`,
10162   rather than first having `MatMatMult()` create it for you. You can NEVER do this if the matrix `C` is sparse.
10163 
10164   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10165 
10166   Example of Usage:
10167 .vb
10168      MatProductCreate(A,B,NULL,&C);
10169      MatProductSetType(C,MATPRODUCT_AB);
10170      MatProductSymbolic(C);
10171      MatProductNumeric(C); // compute C=A * B
10172      MatProductReplaceMats(A1,B1,NULL,C); // compute C=A1 * B1
10173      MatProductNumeric(C);
10174      MatProductReplaceMats(A2,NULL,NULL,C); // compute C=A2 * B1
10175      MatProductNumeric(C);
10176 .ve
10177 
10178   Level: intermediate
10179 
10180 .seealso: [](ch_matrices), `Mat`, `MatProductType`, `MATPRODUCT_AB`, `MatTransposeMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`, `MatProductCreate()`, `MatProductSymbolic()`, `MatProductReplaceMats()`, `MatProductNumeric()`
10181 @*/
10182 PetscErrorCode MatMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10183 {
10184   PetscFunctionBegin;
10185   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AB, C));
10186   PetscFunctionReturn(PETSC_SUCCESS);
10187 }
10188 
10189 /*@
10190   MatMatTransposeMult - Performs matrix-matrix multiplication $C = A*B^T$.
10191 
10192   Neighbor-wise Collective
10193 
10194   Input Parameters:
10195 + A     - the left matrix
10196 . B     - the right matrix
10197 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10198 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10199 
10200   Output Parameter:
10201 . C - the product matrix
10202 
10203   Options Database Key:
10204 . -matmattransmult_mpidense_mpidense_via {allgatherv,cyclic} - Choose between algorithms for `MATMPIDENSE` matrices: the
10205               first redundantly copies the transposed `B` matrix on each process and requires O(log P) communication complexity;
10206               the second never stores more than one portion of the `B` matrix at a time but requires O(P) communication complexity.
10207 
10208   Level: intermediate
10209 
10210   Notes:
10211   C will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10212 
10213   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call
10214 
10215   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10216   actually needed.
10217 
10218   This routine is currently only implemented for pairs of `MATSEQAIJ` matrices, for the `MATSEQDENSE` class,
10219   and for pairs of `MATMPIDENSE` matrices.
10220 
10221   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABt`
10222 
10223   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10224 
10225 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABt`, `MatMatMult()`, `MatTransposeMatMult()` `MatPtAP()`, `MatProductAlgorithm`, `MatProductType`
10226 @*/
10227 PetscErrorCode MatMatTransposeMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10228 {
10229   PetscFunctionBegin;
10230   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_ABt, C));
10231   if (A == B) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10232   PetscFunctionReturn(PETSC_SUCCESS);
10233 }
10234 
10235 /*@
10236   MatTransposeMatMult - Performs matrix-matrix multiplication $C = A^T*B$.
10237 
10238   Neighbor-wise Collective
10239 
10240   Input Parameters:
10241 + A     - the left matrix
10242 . B     - the right matrix
10243 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10244 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10245 
10246   Output Parameter:
10247 . C - the product matrix
10248 
10249   Level: intermediate
10250 
10251   Notes:
10252   `C` will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10253 
10254   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call.
10255 
10256   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_AtB`
10257 
10258   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10259   actually needed.
10260 
10261   This routine is currently implemented for pairs of `MATAIJ` matrices and pairs of `MATSEQDENSE` matrices and classes
10262   which inherit from `MATSEQAIJ`.  `C` will be of the same type as the input matrices.
10263 
10264   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10265 
10266 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_AtB`, `MatMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`
10267 @*/
10268 PetscErrorCode MatTransposeMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10269 {
10270   PetscFunctionBegin;
10271   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AtB, C));
10272   PetscFunctionReturn(PETSC_SUCCESS);
10273 }
10274 
10275 /*@
10276   MatMatMatMult - Performs matrix-matrix-matrix multiplication D=A*B*C.
10277 
10278   Neighbor-wise Collective
10279 
10280   Input Parameters:
10281 + A     - the left matrix
10282 . B     - the middle matrix
10283 . C     - the right matrix
10284 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10285 - 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
10286           if the result is a dense matrix this is irrelevant
10287 
10288   Output Parameter:
10289 . D - the product matrix
10290 
10291   Level: intermediate
10292 
10293   Notes:
10294   Unless `scall` is `MAT_REUSE_MATRIX` `D` will be created.
10295 
10296   `MAT_REUSE_MATRIX` can only be used if the matrices `A`, `B`, and `C` have the same nonzero pattern as in the previous call
10297 
10298   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABC`
10299 
10300   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value
10301   actually needed.
10302 
10303   If you have many matrices with the same non-zero structure to multiply, you
10304   should use `MAT_REUSE_MATRIX` in all calls but the first
10305 
10306   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10307 
10308 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABC`, `MatMatMult`, `MatPtAP()`, `MatMatTransposeMult()`, `MatTransposeMatMult()`
10309 @*/
10310 PetscErrorCode MatMatMatMult(Mat A, Mat B, Mat C, MatReuse scall, PetscReal fill, Mat *D)
10311 {
10312   PetscFunctionBegin;
10313   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*D, 6);
10314   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10315 
10316   if (scall == MAT_INITIAL_MATRIX) {
10317     PetscCall(MatProductCreate(A, B, C, D));
10318     PetscCall(MatProductSetType(*D, MATPRODUCT_ABC));
10319     PetscCall(MatProductSetAlgorithm(*D, "default"));
10320     PetscCall(MatProductSetFill(*D, fill));
10321 
10322     (*D)->product->api_user = PETSC_TRUE;
10323     PetscCall(MatProductSetFromOptions(*D));
10324     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,
10325                ((PetscObject)C)->type_name);
10326     PetscCall(MatProductSymbolic(*D));
10327   } else { /* user may change input matrices when REUSE */
10328     PetscCall(MatProductReplaceMats(A, B, C, *D));
10329   }
10330   PetscCall(MatProductNumeric(*D));
10331   PetscFunctionReturn(PETSC_SUCCESS);
10332 }
10333 
10334 /*@
10335   MatCreateRedundantMatrix - Create redundant matrices and put them into processors of subcommunicators.
10336 
10337   Collective
10338 
10339   Input Parameters:
10340 + mat      - the matrix
10341 . nsubcomm - the number of subcommunicators (= number of redundant parallel or sequential matrices)
10342 . subcomm  - MPI communicator split from the communicator where mat resides in (or `MPI_COMM_NULL` if nsubcomm is used)
10343 - reuse    - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10344 
10345   Output Parameter:
10346 . matredundant - redundant matrix
10347 
10348   Level: advanced
10349 
10350   Notes:
10351   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
10352   original matrix has not changed from that last call to `MatCreateRedundantMatrix()`.
10353 
10354   This routine creates the duplicated matrices in the subcommunicators; you should NOT create them before
10355   calling it.
10356 
10357   `PetscSubcommCreate()` can be used to manage the creation of the subcomm but need not be.
10358 
10359 .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `PetscSubcommCreate()`, `PetscSubcomm`
10360 @*/
10361 PetscErrorCode MatCreateRedundantMatrix(Mat mat, PetscInt nsubcomm, MPI_Comm subcomm, MatReuse reuse, Mat *matredundant)
10362 {
10363   MPI_Comm       comm;
10364   PetscMPIInt    size;
10365   PetscInt       mloc_sub, nloc_sub, rstart, rend, M = mat->rmap->N, N = mat->cmap->N, bs = mat->rmap->bs;
10366   Mat_Redundant *redund     = NULL;
10367   PetscSubcomm   psubcomm   = NULL;
10368   MPI_Comm       subcomm_in = subcomm;
10369   Mat           *matseq;
10370   IS             isrow, iscol;
10371   PetscBool      newsubcomm = PETSC_FALSE;
10372 
10373   PetscFunctionBegin;
10374   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10375   if (nsubcomm && reuse == MAT_REUSE_MATRIX) {
10376     PetscAssertPointer(*matredundant, 5);
10377     PetscValidHeaderSpecific(*matredundant, MAT_CLASSID, 5);
10378   }
10379 
10380   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
10381   if (size == 1 || nsubcomm == 1) {
10382     if (reuse == MAT_INITIAL_MATRIX) {
10383       PetscCall(MatDuplicate(mat, MAT_COPY_VALUES, matredundant));
10384     } else {
10385       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");
10386       PetscCall(MatCopy(mat, *matredundant, SAME_NONZERO_PATTERN));
10387     }
10388     PetscFunctionReturn(PETSC_SUCCESS);
10389   }
10390 
10391   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10392   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10393   MatCheckPreallocated(mat, 1);
10394 
10395   PetscCall(PetscLogEventBegin(MAT_RedundantMat, mat, 0, 0, 0));
10396   if (subcomm_in == MPI_COMM_NULL && reuse == MAT_INITIAL_MATRIX) { /* get subcomm if user does not provide subcomm */
10397     /* create psubcomm, then get subcomm */
10398     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10399     PetscCallMPI(MPI_Comm_size(comm, &size));
10400     PetscCheck(nsubcomm >= 1 && nsubcomm <= size, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "nsubcomm must between 1 and %d", size);
10401 
10402     PetscCall(PetscSubcommCreate(comm, &psubcomm));
10403     PetscCall(PetscSubcommSetNumber(psubcomm, nsubcomm));
10404     PetscCall(PetscSubcommSetType(psubcomm, PETSC_SUBCOMM_CONTIGUOUS));
10405     PetscCall(PetscSubcommSetFromOptions(psubcomm));
10406     PetscCall(PetscCommDuplicate(PetscSubcommChild(psubcomm), &subcomm, NULL));
10407     newsubcomm = PETSC_TRUE;
10408     PetscCall(PetscSubcommDestroy(&psubcomm));
10409   }
10410 
10411   /* get isrow, iscol and a local sequential matrix matseq[0] */
10412   if (reuse == MAT_INITIAL_MATRIX) {
10413     mloc_sub = PETSC_DECIDE;
10414     nloc_sub = PETSC_DECIDE;
10415     if (bs < 1) {
10416       PetscCall(PetscSplitOwnership(subcomm, &mloc_sub, &M));
10417       PetscCall(PetscSplitOwnership(subcomm, &nloc_sub, &N));
10418     } else {
10419       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &mloc_sub, &M));
10420       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &nloc_sub, &N));
10421     }
10422     PetscCallMPI(MPI_Scan(&mloc_sub, &rend, 1, MPIU_INT, MPI_SUM, subcomm));
10423     rstart = rend - mloc_sub;
10424     PetscCall(ISCreateStride(PETSC_COMM_SELF, mloc_sub, rstart, 1, &isrow));
10425     PetscCall(ISCreateStride(PETSC_COMM_SELF, N, 0, 1, &iscol));
10426     PetscCall(ISSetIdentity(iscol));
10427   } else { /* reuse == MAT_REUSE_MATRIX */
10428     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");
10429     /* retrieve subcomm */
10430     PetscCall(PetscObjectGetComm((PetscObject)*matredundant, &subcomm));
10431     redund = (*matredundant)->redundant;
10432     isrow  = redund->isrow;
10433     iscol  = redund->iscol;
10434     matseq = redund->matseq;
10435   }
10436   PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscol, reuse, &matseq));
10437 
10438   /* get matredundant over subcomm */
10439   if (reuse == MAT_INITIAL_MATRIX) {
10440     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], nloc_sub, reuse, matredundant));
10441 
10442     /* create a supporting struct and attach it to C for reuse */
10443     PetscCall(PetscNew(&redund));
10444     (*matredundant)->redundant = redund;
10445     redund->isrow              = isrow;
10446     redund->iscol              = iscol;
10447     redund->matseq             = matseq;
10448     if (newsubcomm) {
10449       redund->subcomm = subcomm;
10450     } else {
10451       redund->subcomm = MPI_COMM_NULL;
10452     }
10453   } else {
10454     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], PETSC_DECIDE, reuse, matredundant));
10455   }
10456 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
10457   if (matseq[0]->boundtocpu && matseq[0]->bindingpropagates) {
10458     PetscCall(MatBindToCPU(*matredundant, PETSC_TRUE));
10459     PetscCall(MatSetBindingPropagates(*matredundant, PETSC_TRUE));
10460   }
10461 #endif
10462   PetscCall(PetscLogEventEnd(MAT_RedundantMat, mat, 0, 0, 0));
10463   PetscFunctionReturn(PETSC_SUCCESS);
10464 }
10465 
10466 /*@C
10467   MatGetMultiProcBlock - Create multiple 'parallel submatrices' from
10468   a given `Mat`. Each submatrix can span multiple procs.
10469 
10470   Collective
10471 
10472   Input Parameters:
10473 + mat     - the matrix
10474 . subComm - the sub communicator obtained as if by `MPI_Comm_split(PetscObjectComm((PetscObject)mat))`
10475 - scall   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10476 
10477   Output Parameter:
10478 . subMat - parallel sub-matrices each spanning a given `subcomm`
10479 
10480   Level: advanced
10481 
10482   Notes:
10483   The submatrix partition across processors is dictated by `subComm` a
10484   communicator obtained by `MPI_comm_split()` or via `PetscSubcommCreate()`. The `subComm`
10485   is not restricted to be grouped with consecutive original MPI processes.
10486 
10487   Due the `MPI_Comm_split()` usage, the parallel layout of the submatrices
10488   map directly to the layout of the original matrix [wrt the local
10489   row,col partitioning]. So the original 'DiagonalMat' naturally maps
10490   into the 'DiagonalMat' of the `subMat`, hence it is used directly from
10491   the `subMat`. However the offDiagMat looses some columns - and this is
10492   reconstructed with `MatSetValues()`
10493 
10494   This is used by `PCBJACOBI` when a single block spans multiple MPI processes.
10495 
10496 .seealso: [](ch_matrices), `Mat`, `MatCreateRedundantMatrix()`, `MatCreateSubMatrices()`, `PCBJACOBI`
10497 @*/
10498 PetscErrorCode MatGetMultiProcBlock(Mat mat, MPI_Comm subComm, MatReuse scall, Mat *subMat)
10499 {
10500   PetscMPIInt commsize, subCommSize;
10501 
10502   PetscFunctionBegin;
10503   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &commsize));
10504   PetscCallMPI(MPI_Comm_size(subComm, &subCommSize));
10505   PetscCheck(subCommSize <= commsize, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "CommSize %d < SubCommZize %d", commsize, subCommSize);
10506 
10507   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");
10508   PetscCall(PetscLogEventBegin(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10509   PetscUseTypeMethod(mat, getmultiprocblock, subComm, scall, subMat);
10510   PetscCall(PetscLogEventEnd(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10511   PetscFunctionReturn(PETSC_SUCCESS);
10512 }
10513 
10514 /*@
10515   MatGetLocalSubMatrix - Gets a reference to a submatrix specified in local numbering
10516 
10517   Not Collective
10518 
10519   Input Parameters:
10520 + mat   - matrix to extract local submatrix from
10521 . isrow - local row indices for submatrix
10522 - iscol - local column indices for submatrix
10523 
10524   Output Parameter:
10525 . submat - the submatrix
10526 
10527   Level: intermediate
10528 
10529   Notes:
10530   `submat` should be disposed of with `MatRestoreLocalSubMatrix()`.
10531 
10532   Depending on the format of `mat`, the returned `submat` may not implement `MatMult()`.  Its communicator may be
10533   the same as `mat`, it may be `PETSC_COMM_SELF`, or some other sub-communictor of `mat`'s.
10534 
10535   `submat` always implements `MatSetValuesLocal()`.  If `isrow` and `iscol` have the same block size, then
10536   `MatSetValuesBlockedLocal()` will also be implemented.
10537 
10538   `mat` must have had a `ISLocalToGlobalMapping` provided to it with `MatSetLocalToGlobalMapping()`.
10539   Matrices obtained with `DMCreateMatrix()` generally already have the local to global mapping provided.
10540 
10541 .seealso: [](ch_matrices), `Mat`, `MatRestoreLocalSubMatrix()`, `MatCreateLocalRef()`, `MatSetLocalToGlobalMapping()`
10542 @*/
10543 PetscErrorCode MatGetLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10544 {
10545   PetscFunctionBegin;
10546   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10547   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10548   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10549   PetscCheckSameComm(isrow, 2, iscol, 3);
10550   PetscAssertPointer(submat, 4);
10551   PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must have local to global mapping provided before this call");
10552 
10553   if (mat->ops->getlocalsubmatrix) {
10554     PetscUseTypeMethod(mat, getlocalsubmatrix, isrow, iscol, submat);
10555   } else {
10556     PetscCall(MatCreateLocalRef(mat, isrow, iscol, submat));
10557   }
10558   PetscFunctionReturn(PETSC_SUCCESS);
10559 }
10560 
10561 /*@
10562   MatRestoreLocalSubMatrix - Restores a reference to a submatrix specified in local numbering obtained with `MatGetLocalSubMatrix()`
10563 
10564   Not Collective
10565 
10566   Input Parameters:
10567 + mat    - matrix to extract local submatrix from
10568 . isrow  - local row indices for submatrix
10569 . iscol  - local column indices for submatrix
10570 - submat - the submatrix
10571 
10572   Level: intermediate
10573 
10574 .seealso: [](ch_matrices), `Mat`, `MatGetLocalSubMatrix()`
10575 @*/
10576 PetscErrorCode MatRestoreLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10577 {
10578   PetscFunctionBegin;
10579   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10580   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10581   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10582   PetscCheckSameComm(isrow, 2, iscol, 3);
10583   PetscAssertPointer(submat, 4);
10584   if (*submat) PetscValidHeaderSpecific(*submat, MAT_CLASSID, 4);
10585 
10586   if (mat->ops->restorelocalsubmatrix) {
10587     PetscUseTypeMethod(mat, restorelocalsubmatrix, isrow, iscol, submat);
10588   } else {
10589     PetscCall(MatDestroy(submat));
10590   }
10591   *submat = NULL;
10592   PetscFunctionReturn(PETSC_SUCCESS);
10593 }
10594 
10595 /*@
10596   MatFindZeroDiagonals - Finds all the rows of a matrix that have zero or no diagonal entry in the matrix
10597 
10598   Collective
10599 
10600   Input Parameter:
10601 . mat - the matrix
10602 
10603   Output Parameter:
10604 . is - if any rows have zero diagonals this contains the list of them
10605 
10606   Level: developer
10607 
10608 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10609 @*/
10610 PetscErrorCode MatFindZeroDiagonals(Mat mat, IS *is)
10611 {
10612   PetscFunctionBegin;
10613   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10614   PetscValidType(mat, 1);
10615   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10616   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10617 
10618   if (!mat->ops->findzerodiagonals) {
10619     Vec                diag;
10620     const PetscScalar *a;
10621     PetscInt          *rows;
10622     PetscInt           rStart, rEnd, r, nrow = 0;
10623 
10624     PetscCall(MatCreateVecs(mat, &diag, NULL));
10625     PetscCall(MatGetDiagonal(mat, diag));
10626     PetscCall(MatGetOwnershipRange(mat, &rStart, &rEnd));
10627     PetscCall(VecGetArrayRead(diag, &a));
10628     for (r = 0; r < rEnd - rStart; ++r)
10629       if (a[r] == 0.0) ++nrow;
10630     PetscCall(PetscMalloc1(nrow, &rows));
10631     nrow = 0;
10632     for (r = 0; r < rEnd - rStart; ++r)
10633       if (a[r] == 0.0) rows[nrow++] = r + rStart;
10634     PetscCall(VecRestoreArrayRead(diag, &a));
10635     PetscCall(VecDestroy(&diag));
10636     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nrow, rows, PETSC_OWN_POINTER, is));
10637   } else {
10638     PetscUseTypeMethod(mat, findzerodiagonals, is);
10639   }
10640   PetscFunctionReturn(PETSC_SUCCESS);
10641 }
10642 
10643 /*@
10644   MatFindOffBlockDiagonalEntries - Finds all the rows of a matrix that have entries outside of the main diagonal block (defined by the matrix block size)
10645 
10646   Collective
10647 
10648   Input Parameter:
10649 . mat - the matrix
10650 
10651   Output Parameter:
10652 . is - contains the list of rows with off block diagonal entries
10653 
10654   Level: developer
10655 
10656 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10657 @*/
10658 PetscErrorCode MatFindOffBlockDiagonalEntries(Mat mat, IS *is)
10659 {
10660   PetscFunctionBegin;
10661   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10662   PetscValidType(mat, 1);
10663   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10664   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10665 
10666   PetscUseTypeMethod(mat, findoffblockdiagonalentries, is);
10667   PetscFunctionReturn(PETSC_SUCCESS);
10668 }
10669 
10670 /*@C
10671   MatInvertBlockDiagonal - Inverts the block diagonal entries.
10672 
10673   Collective; No Fortran Support
10674 
10675   Input Parameter:
10676 . mat - the matrix
10677 
10678   Output Parameter:
10679 . values - the block inverses in column major order (FORTRAN-like)
10680 
10681   Level: advanced
10682 
10683   Notes:
10684   The size of the blocks is determined by the block size of the matrix.
10685 
10686   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10687 
10688   The blocks all have the same size, use `MatInvertVariableBlockDiagonal()` for variable block size
10689 
10690 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatInvertBlockDiagonalMat()`
10691 @*/
10692 PetscErrorCode MatInvertBlockDiagonal(Mat mat, const PetscScalar *values[])
10693 {
10694   PetscFunctionBegin;
10695   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10696   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10697   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10698   PetscUseTypeMethod(mat, invertblockdiagonal, values);
10699   PetscFunctionReturn(PETSC_SUCCESS);
10700 }
10701 
10702 /*@
10703   MatInvertVariableBlockDiagonal - Inverts the point block diagonal entries.
10704 
10705   Collective; No Fortran Support
10706 
10707   Input Parameters:
10708 + mat     - the matrix
10709 . nblocks - the number of blocks on the process, set with `MatSetVariableBlockSizes()`
10710 - bsizes  - the size of each block on the process, set with `MatSetVariableBlockSizes()`
10711 
10712   Output Parameter:
10713 . values - the block inverses in column major order (FORTRAN-like)
10714 
10715   Level: advanced
10716 
10717   Notes:
10718   Use `MatInvertBlockDiagonal()` if all blocks have the same size
10719 
10720   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10721 
10722 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatSetVariableBlockSizes()`, `MatInvertVariableBlockEnvelope()`
10723 @*/
10724 PetscErrorCode MatInvertVariableBlockDiagonal(Mat mat, PetscInt nblocks, const PetscInt bsizes[], PetscScalar values[])
10725 {
10726   PetscFunctionBegin;
10727   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10728   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10729   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10730   PetscUseTypeMethod(mat, invertvariableblockdiagonal, nblocks, bsizes, values);
10731   PetscFunctionReturn(PETSC_SUCCESS);
10732 }
10733 
10734 /*@
10735   MatInvertBlockDiagonalMat - set the values of matrix C to be the inverted block diagonal of matrix A
10736 
10737   Collective
10738 
10739   Input Parameters:
10740 + A - the matrix
10741 - C - matrix with inverted block diagonal of `A`.  This matrix should be created and may have its type set.
10742 
10743   Level: advanced
10744 
10745   Note:
10746   The blocksize of the matrix is used to determine the blocks on the diagonal of `C`
10747 
10748 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`
10749 @*/
10750 PetscErrorCode MatInvertBlockDiagonalMat(Mat A, Mat C)
10751 {
10752   const PetscScalar *vals;
10753   PetscInt          *dnnz;
10754   PetscInt           m, rstart, rend, bs, i, j;
10755 
10756   PetscFunctionBegin;
10757   PetscCall(MatInvertBlockDiagonal(A, &vals));
10758   PetscCall(MatGetBlockSize(A, &bs));
10759   PetscCall(MatGetLocalSize(A, &m, NULL));
10760   PetscCall(MatSetLayouts(C, A->rmap, A->cmap));
10761   if (A->rmap->bs > 1) PetscCall(MatSetBlockSizes(C, A->rmap->bs, A->cmap->bs)); // mpiaij to A and B
10762   PetscCall(PetscMalloc1(m / bs, &dnnz));
10763   for (j = 0; j < m / bs; j++) dnnz[j] = 1;
10764   PetscCall(MatXAIJSetPreallocation(C, bs, dnnz, NULL, NULL, NULL));
10765   PetscCall(PetscFree(dnnz));
10766   PetscCall(MatGetOwnershipRange(C, &rstart, &rend));
10767   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_FALSE));
10768   for (i = rstart / bs; i < rend / bs; i++) PetscCall(MatSetValuesBlocked(C, 1, &i, 1, &i, &vals[(i - rstart / bs) * bs * bs], INSERT_VALUES));
10769   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
10770   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
10771   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_TRUE));
10772   PetscFunctionReturn(PETSC_SUCCESS);
10773 }
10774 
10775 /*@
10776   MatTransposeColoringDestroy - Destroys a coloring context for matrix product $C = A*B^T$ that was created
10777   via `MatTransposeColoringCreate()`.
10778 
10779   Collective
10780 
10781   Input Parameter:
10782 . c - coloring context
10783 
10784   Level: intermediate
10785 
10786 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`
10787 @*/
10788 PetscErrorCode MatTransposeColoringDestroy(MatTransposeColoring *c)
10789 {
10790   MatTransposeColoring matcolor = *c;
10791 
10792   PetscFunctionBegin;
10793   if (!matcolor) PetscFunctionReturn(PETSC_SUCCESS);
10794   if (--((PetscObject)matcolor)->refct > 0) {
10795     matcolor = NULL;
10796     PetscFunctionReturn(PETSC_SUCCESS);
10797   }
10798 
10799   PetscCall(PetscFree3(matcolor->ncolumns, matcolor->nrows, matcolor->colorforrow));
10800   PetscCall(PetscFree(matcolor->rows));
10801   PetscCall(PetscFree(matcolor->den2sp));
10802   PetscCall(PetscFree(matcolor->colorforcol));
10803   PetscCall(PetscFree(matcolor->columns));
10804   if (matcolor->brows > 0) PetscCall(PetscFree(matcolor->lstart));
10805   PetscCall(PetscHeaderDestroy(c));
10806   PetscFunctionReturn(PETSC_SUCCESS);
10807 }
10808 
10809 /*@
10810   MatTransColoringApplySpToDen - Given a symbolic matrix product $C = A*B^T$ for which
10811   a `MatTransposeColoring` context has been created, computes a dense $B^T$ by applying
10812   `MatTransposeColoring` to sparse `B`.
10813 
10814   Collective
10815 
10816   Input Parameters:
10817 + coloring - coloring context created with `MatTransposeColoringCreate()`
10818 - B        - sparse matrix
10819 
10820   Output Parameter:
10821 . Btdense - dense matrix $B^T$
10822 
10823   Level: developer
10824 
10825   Note:
10826   These are used internally for some implementations of `MatRARt()`
10827 
10828 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplyDenToSp()`
10829 @*/
10830 PetscErrorCode MatTransColoringApplySpToDen(MatTransposeColoring coloring, Mat B, Mat Btdense)
10831 {
10832   PetscFunctionBegin;
10833   PetscValidHeaderSpecific(coloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
10834   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
10835   PetscValidHeaderSpecific(Btdense, MAT_CLASSID, 3);
10836 
10837   PetscCall((*B->ops->transcoloringapplysptoden)(coloring, B, Btdense));
10838   PetscFunctionReturn(PETSC_SUCCESS);
10839 }
10840 
10841 /*@
10842   MatTransColoringApplyDenToSp - Given a symbolic matrix product $C_{sp} = A*B^T$ for which
10843   a `MatTransposeColoring` context has been created and a dense matrix $C_{den} = A*B^T_{dense}$
10844   in which `B^T_{dens}` is obtained from `MatTransColoringApplySpToDen()`, recover sparse matrix
10845   $C_{sp}$ from $C_{den}$.
10846 
10847   Collective
10848 
10849   Input Parameters:
10850 + matcoloring - coloring context created with `MatTransposeColoringCreate()`
10851 - Cden        - matrix product of a sparse matrix and a dense matrix Btdense
10852 
10853   Output Parameter:
10854 . Csp - sparse matrix
10855 
10856   Level: developer
10857 
10858   Note:
10859   These are used internally for some implementations of `MatRARt()`
10860 
10861 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`
10862 @*/
10863 PetscErrorCode MatTransColoringApplyDenToSp(MatTransposeColoring matcoloring, Mat Cden, Mat Csp)
10864 {
10865   PetscFunctionBegin;
10866   PetscValidHeaderSpecific(matcoloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
10867   PetscValidHeaderSpecific(Cden, MAT_CLASSID, 2);
10868   PetscValidHeaderSpecific(Csp, MAT_CLASSID, 3);
10869 
10870   PetscCall((*Csp->ops->transcoloringapplydentosp)(matcoloring, Cden, Csp));
10871   PetscCall(MatAssemblyBegin(Csp, MAT_FINAL_ASSEMBLY));
10872   PetscCall(MatAssemblyEnd(Csp, MAT_FINAL_ASSEMBLY));
10873   PetscFunctionReturn(PETSC_SUCCESS);
10874 }
10875 
10876 /*@
10877   MatTransposeColoringCreate - Creates a matrix coloring context for the matrix product $C = A*B^T$.
10878 
10879   Collective
10880 
10881   Input Parameters:
10882 + mat        - the matrix product C
10883 - iscoloring - the coloring of the matrix; usually obtained with `MatColoringCreate()` or `DMCreateColoring()`
10884 
10885   Output Parameter:
10886 . color - the new coloring context
10887 
10888   Level: intermediate
10889 
10890 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`,
10891           `MatTransColoringApplyDenToSp()`
10892 @*/
10893 PetscErrorCode MatTransposeColoringCreate(Mat mat, ISColoring iscoloring, MatTransposeColoring *color)
10894 {
10895   MatTransposeColoring c;
10896   MPI_Comm             comm;
10897 
10898   PetscFunctionBegin;
10899   PetscAssertPointer(color, 3);
10900 
10901   PetscCall(PetscLogEventBegin(MAT_TransposeColoringCreate, mat, 0, 0, 0));
10902   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10903   PetscCall(PetscHeaderCreate(c, MAT_TRANSPOSECOLORING_CLASSID, "MatTransposeColoring", "Matrix product C=A*B^T via coloring", "Mat", comm, MatTransposeColoringDestroy, NULL));
10904   c->ctype = iscoloring->ctype;
10905   PetscUseTypeMethod(mat, transposecoloringcreate, iscoloring, c);
10906   *color = c;
10907   PetscCall(PetscLogEventEnd(MAT_TransposeColoringCreate, mat, 0, 0, 0));
10908   PetscFunctionReturn(PETSC_SUCCESS);
10909 }
10910 
10911 /*@
10912   MatGetNonzeroState - Returns a 64-bit integer representing the current state of nonzeros in the matrix. If the
10913   matrix has had new nonzero locations added to (or removed from) the matrix since the previous call, the value will be larger.
10914 
10915   Not Collective
10916 
10917   Input Parameter:
10918 . mat - the matrix
10919 
10920   Output Parameter:
10921 . state - the current state
10922 
10923   Level: intermediate
10924 
10925   Notes:
10926   You can only compare states from two different calls to the SAME matrix, you cannot compare calls between
10927   different matrices
10928 
10929   Use `PetscObjectStateGet()` to check for changes to the numerical values in a matrix
10930 
10931   Use the result of `PetscObjectGetId()` to compare if a previously checked matrix is the same as the current matrix, do not compare object pointers.
10932 
10933 .seealso: [](ch_matrices), `Mat`, `PetscObjectStateGet()`, `PetscObjectGetId()`
10934 @*/
10935 PetscErrorCode MatGetNonzeroState(Mat mat, PetscObjectState *state)
10936 {
10937   PetscFunctionBegin;
10938   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10939   *state = mat->nonzerostate;
10940   PetscFunctionReturn(PETSC_SUCCESS);
10941 }
10942 
10943 /*@
10944   MatCreateMPIMatConcatenateSeqMat - Creates a single large PETSc matrix by concatenating sequential
10945   matrices from each processor
10946 
10947   Collective
10948 
10949   Input Parameters:
10950 + comm   - the communicators the parallel matrix will live on
10951 . seqmat - the input sequential matrices
10952 . n      - number of local columns (or `PETSC_DECIDE`)
10953 - reuse  - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10954 
10955   Output Parameter:
10956 . mpimat - the parallel matrix generated
10957 
10958   Level: developer
10959 
10960   Note:
10961   The number of columns of the matrix in EACH processor MUST be the same.
10962 
10963 .seealso: [](ch_matrices), `Mat`
10964 @*/
10965 PetscErrorCode MatCreateMPIMatConcatenateSeqMat(MPI_Comm comm, Mat seqmat, PetscInt n, MatReuse reuse, Mat *mpimat)
10966 {
10967   PetscMPIInt size;
10968 
10969   PetscFunctionBegin;
10970   PetscCallMPI(MPI_Comm_size(comm, &size));
10971   if (size == 1) {
10972     if (reuse == MAT_INITIAL_MATRIX) {
10973       PetscCall(MatDuplicate(seqmat, MAT_COPY_VALUES, mpimat));
10974     } else {
10975       PetscCall(MatCopy(seqmat, *mpimat, SAME_NONZERO_PATTERN));
10976     }
10977     PetscFunctionReturn(PETSC_SUCCESS);
10978   }
10979 
10980   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");
10981 
10982   PetscCall(PetscLogEventBegin(MAT_Merge, seqmat, 0, 0, 0));
10983   PetscCall((*seqmat->ops->creatempimatconcatenateseqmat)(comm, seqmat, n, reuse, mpimat));
10984   PetscCall(PetscLogEventEnd(MAT_Merge, seqmat, 0, 0, 0));
10985   PetscFunctionReturn(PETSC_SUCCESS);
10986 }
10987 
10988 /*@
10989   MatSubdomainsCreateCoalesce - Creates index subdomains by coalescing adjacent MPI processes' ownership ranges.
10990 
10991   Collective
10992 
10993   Input Parameters:
10994 + A - the matrix to create subdomains from
10995 - N - requested number of subdomains
10996 
10997   Output Parameters:
10998 + n   - number of subdomains resulting on this MPI process
10999 - iss - `IS` list with indices of subdomains on this MPI process
11000 
11001   Level: advanced
11002 
11003   Note:
11004   The number of subdomains must be smaller than the communicator size
11005 
11006 .seealso: [](ch_matrices), `Mat`, `IS`
11007 @*/
11008 PetscErrorCode MatSubdomainsCreateCoalesce(Mat A, PetscInt N, PetscInt *n, IS *iss[])
11009 {
11010   MPI_Comm    comm, subcomm;
11011   PetscMPIInt size, rank, color;
11012   PetscInt    rstart, rend, k;
11013 
11014   PetscFunctionBegin;
11015   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
11016   PetscCallMPI(MPI_Comm_size(comm, &size));
11017   PetscCallMPI(MPI_Comm_rank(comm, &rank));
11018   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);
11019   *n    = 1;
11020   k     = size / N + (size % N > 0); /* There are up to k ranks to a color */
11021   color = rank / k;
11022   PetscCallMPI(MPI_Comm_split(comm, color, rank, &subcomm));
11023   PetscCall(PetscMalloc1(1, iss));
11024   PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
11025   PetscCall(ISCreateStride(subcomm, rend - rstart, rstart, 1, iss[0]));
11026   PetscCallMPI(MPI_Comm_free(&subcomm));
11027   PetscFunctionReturn(PETSC_SUCCESS);
11028 }
11029 
11030 /*@
11031   MatGalerkin - Constructs the coarse grid problem matrix via Galerkin projection.
11032 
11033   If the interpolation and restriction operators are the same, uses `MatPtAP()`.
11034   If they are not the same, uses `MatMatMatMult()`.
11035 
11036   Once the coarse grid problem is constructed, correct for interpolation operators
11037   that are not of full rank, which can legitimately happen in the case of non-nested
11038   geometric multigrid.
11039 
11040   Input Parameters:
11041 + restrct     - restriction operator
11042 . dA          - fine grid matrix
11043 . interpolate - interpolation operator
11044 . reuse       - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
11045 - fill        - expected fill, use `PETSC_DETERMINE` or `PETSC_DETERMINE` if you do not have a good estimate
11046 
11047   Output Parameter:
11048 . A - the Galerkin coarse matrix
11049 
11050   Options Database Key:
11051 . -pc_mg_galerkin <both,pmat,mat,none> - for what matrices the Galerkin process should be used
11052 
11053   Level: developer
11054 
11055   Note:
11056   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
11057 
11058 .seealso: [](ch_matrices), `Mat`, `MatPtAP()`, `MatMatMatMult()`
11059 @*/
11060 PetscErrorCode MatGalerkin(Mat restrct, Mat dA, Mat interpolate, MatReuse reuse, PetscReal fill, Mat *A)
11061 {
11062   IS  zerorows;
11063   Vec diag;
11064 
11065   PetscFunctionBegin;
11066   PetscCheck(reuse != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
11067   /* Construct the coarse grid matrix */
11068   if (interpolate == restrct) {
11069     PetscCall(MatPtAP(dA, interpolate, reuse, fill, A));
11070   } else {
11071     PetscCall(MatMatMatMult(restrct, dA, interpolate, reuse, fill, A));
11072   }
11073 
11074   /* If the interpolation matrix is not of full rank, A will have zero rows.
11075      This can legitimately happen in the case of non-nested geometric multigrid.
11076      In that event, we set the rows of the matrix to the rows of the identity,
11077      ignoring the equations (as the RHS will also be zero). */
11078 
11079   PetscCall(MatFindZeroRows(*A, &zerorows));
11080 
11081   if (zerorows != NULL) { /* if there are any zero rows */
11082     PetscCall(MatCreateVecs(*A, &diag, NULL));
11083     PetscCall(MatGetDiagonal(*A, diag));
11084     PetscCall(VecISSet(diag, zerorows, 1.0));
11085     PetscCall(MatDiagonalSet(*A, diag, INSERT_VALUES));
11086     PetscCall(VecDestroy(&diag));
11087     PetscCall(ISDestroy(&zerorows));
11088   }
11089   PetscFunctionReturn(PETSC_SUCCESS);
11090 }
11091 
11092 /*@C
11093   MatSetOperation - Allows user to set a matrix operation for any matrix type
11094 
11095   Logically Collective
11096 
11097   Input Parameters:
11098 + mat - the matrix
11099 . op  - the name of the operation
11100 - f   - the function that provides the operation
11101 
11102   Level: developer
11103 
11104   Example Usage:
11105 .vb
11106   extern PetscErrorCode usermult(Mat, Vec, Vec);
11107 
11108   PetscCall(MatCreateXXX(comm, ..., &A));
11109   PetscCall(MatSetOperation(A, MATOP_MULT, (PetscVoidFn *)usermult));
11110 .ve
11111 
11112   Notes:
11113   See the file `include/petscmat.h` for a complete list of matrix
11114   operations, which all have the form MATOP_<OPERATION>, where
11115   <OPERATION> is the name (in all capital letters) of the
11116   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11117 
11118   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
11119   sequence as the usual matrix interface routines, since they
11120   are intended to be accessed via the usual matrix interface
11121   routines, e.g.,
11122 .vb
11123   MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
11124 .ve
11125 
11126   In particular each function MUST return `PETSC_SUCCESS` on success and
11127   nonzero on failure.
11128 
11129   This routine is distinct from `MatShellSetOperation()` in that it can be called on any matrix type.
11130 
11131 .seealso: [](ch_matrices), `Mat`, `MatGetOperation()`, `MatCreateShell()`, `MatShellSetContext()`, `MatShellSetOperation()`
11132 @*/
11133 PetscErrorCode MatSetOperation(Mat mat, MatOperation op, void (*f)(void))
11134 {
11135   PetscFunctionBegin;
11136   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11137   if (op == MATOP_VIEW && !mat->ops->viewnative && f != (void (*)(void))mat->ops->view) mat->ops->viewnative = mat->ops->view;
11138   (((void (**)(void))mat->ops)[op]) = f;
11139   PetscFunctionReturn(PETSC_SUCCESS);
11140 }
11141 
11142 /*@C
11143   MatGetOperation - Gets a matrix operation for any matrix type.
11144 
11145   Not Collective
11146 
11147   Input Parameters:
11148 + mat - the matrix
11149 - op  - the name of the operation
11150 
11151   Output Parameter:
11152 . f - the function that provides the operation
11153 
11154   Level: developer
11155 
11156   Example Usage:
11157 .vb
11158   PetscErrorCode (*usermult)(Mat, Vec, Vec);
11159 
11160   MatGetOperation(A, MATOP_MULT, (void (**)(void))&usermult);
11161 .ve
11162 
11163   Notes:
11164   See the file include/petscmat.h for a complete list of matrix
11165   operations, which all have the form MATOP_<OPERATION>, where
11166   <OPERATION> is the name (in all capital letters) of the
11167   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11168 
11169   This routine is distinct from `MatShellGetOperation()` in that it can be called on any matrix type.
11170 
11171 .seealso: [](ch_matrices), `Mat`, `MatSetOperation()`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
11172 @*/
11173 PetscErrorCode MatGetOperation(Mat mat, MatOperation op, void (**f)(void))
11174 {
11175   PetscFunctionBegin;
11176   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11177   *f = (((void (**)(void))mat->ops)[op]);
11178   PetscFunctionReturn(PETSC_SUCCESS);
11179 }
11180 
11181 /*@
11182   MatHasOperation - Determines whether the given matrix supports the particular operation.
11183 
11184   Not Collective
11185 
11186   Input Parameters:
11187 + mat - the matrix
11188 - op  - the operation, for example, `MATOP_GET_DIAGONAL`
11189 
11190   Output Parameter:
11191 . has - either `PETSC_TRUE` or `PETSC_FALSE`
11192 
11193   Level: advanced
11194 
11195   Note:
11196   See `MatSetOperation()` for additional discussion on naming convention and usage of `op`.
11197 
11198 .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`, `MatGetOperation()`, `MatSetOperation()`
11199 @*/
11200 PetscErrorCode MatHasOperation(Mat mat, MatOperation op, PetscBool *has)
11201 {
11202   PetscFunctionBegin;
11203   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11204   PetscAssertPointer(has, 3);
11205   if (mat->ops->hasoperation) {
11206     PetscUseTypeMethod(mat, hasoperation, op, has);
11207   } else {
11208     if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
11209     else {
11210       *has = PETSC_FALSE;
11211       if (op == MATOP_CREATE_SUBMATRIX) {
11212         PetscMPIInt size;
11213 
11214         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
11215         if (size == 1) PetscCall(MatHasOperation(mat, MATOP_CREATE_SUBMATRICES, has));
11216       }
11217     }
11218   }
11219   PetscFunctionReturn(PETSC_SUCCESS);
11220 }
11221 
11222 /*@
11223   MatHasCongruentLayouts - Determines whether the rows and columns layouts of the matrix are congruent
11224 
11225   Collective
11226 
11227   Input Parameter:
11228 . mat - the matrix
11229 
11230   Output Parameter:
11231 . cong - either `PETSC_TRUE` or `PETSC_FALSE`
11232 
11233   Level: beginner
11234 
11235 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatSetSizes()`, `PetscLayout`
11236 @*/
11237 PetscErrorCode MatHasCongruentLayouts(Mat mat, PetscBool *cong)
11238 {
11239   PetscFunctionBegin;
11240   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11241   PetscValidType(mat, 1);
11242   PetscAssertPointer(cong, 2);
11243   if (!mat->rmap || !mat->cmap) {
11244     *cong = mat->rmap == mat->cmap ? PETSC_TRUE : PETSC_FALSE;
11245     PetscFunctionReturn(PETSC_SUCCESS);
11246   }
11247   if (mat->congruentlayouts == PETSC_DECIDE) { /* first time we compare rows and cols layouts */
11248     PetscCall(PetscLayoutSetUp(mat->rmap));
11249     PetscCall(PetscLayoutSetUp(mat->cmap));
11250     PetscCall(PetscLayoutCompare(mat->rmap, mat->cmap, cong));
11251     if (*cong) mat->congruentlayouts = 1;
11252     else mat->congruentlayouts = 0;
11253   } else *cong = mat->congruentlayouts ? PETSC_TRUE : PETSC_FALSE;
11254   PetscFunctionReturn(PETSC_SUCCESS);
11255 }
11256 
11257 PetscErrorCode MatSetInf(Mat A)
11258 {
11259   PetscFunctionBegin;
11260   PetscUseTypeMethod(A, setinf);
11261   PetscFunctionReturn(PETSC_SUCCESS);
11262 }
11263 
11264 /*@
11265   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
11266   and possibly removes small values from the graph structure.
11267 
11268   Collective
11269 
11270   Input Parameters:
11271 + A       - the matrix
11272 . sym     - `PETSC_TRUE` indicates that the graph should be symmetrized
11273 . scale   - `PETSC_TRUE` indicates that the graph edge weights should be symmetrically scaled with the diagonal entry
11274 . filter  - filter value - < 0: does nothing; == 0: removes only 0.0 entries; otherwise: removes entries with abs(entries) <= value
11275 . num_idx - size of 'index' array
11276 - index   - array of block indices to use for graph strength of connection weight
11277 
11278   Output Parameter:
11279 . graph - the resulting graph
11280 
11281   Level: advanced
11282 
11283 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PCGAMG`
11284 @*/
11285 PetscErrorCode MatCreateGraph(Mat A, PetscBool sym, PetscBool scale, PetscReal filter, PetscInt num_idx, PetscInt index[], Mat *graph)
11286 {
11287   PetscFunctionBegin;
11288   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11289   PetscValidType(A, 1);
11290   PetscValidLogicalCollectiveBool(A, scale, 3);
11291   PetscAssertPointer(graph, 7);
11292   PetscCall(PetscLogEventBegin(MAT_CreateGraph, A, 0, 0, 0));
11293   PetscUseTypeMethod(A, creategraph, sym, scale, filter, num_idx, index, graph);
11294   PetscCall(PetscLogEventEnd(MAT_CreateGraph, A, 0, 0, 0));
11295   PetscFunctionReturn(PETSC_SUCCESS);
11296 }
11297 
11298 /*@
11299   MatEliminateZeros - eliminate the nondiagonal zero entries in place from the nonzero structure of a sparse `Mat` in place,
11300   meaning the same memory is used for the matrix, and no new memory is allocated.
11301 
11302   Collective
11303 
11304   Input Parameters:
11305 + A    - the matrix
11306 - 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
11307 
11308   Level: intermediate
11309 
11310   Developer Note:
11311   The entries in the sparse matrix data structure are shifted to fill in the unneeded locations in the data. Thus the end
11312   of the arrays in the data structure are unneeded.
11313 
11314 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateGraph()`, `MatFilter()`
11315 @*/
11316 PetscErrorCode MatEliminateZeros(Mat A, PetscBool keep)
11317 {
11318   PetscFunctionBegin;
11319   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11320   PetscUseTypeMethod(A, eliminatezeros, keep);
11321   PetscFunctionReturn(PETSC_SUCCESS);
11322 }
11323