xref: /petsc/src/mat/interface/matrix.c (revision d016bdde269de9549a736fe23cc3868ea52c341b)
1 /*
2    This is where the abstract matrix operations are defined
3    Portions of this code are under:
4    Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
5 */
6 
7 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
8 #include <petsc/private/isimpl.h>
9 #include <petsc/private/vecimpl.h>
10 
11 /* Logging support */
12 PetscClassId MAT_CLASSID;
13 PetscClassId MAT_COLORING_CLASSID;
14 PetscClassId MAT_FDCOLORING_CLASSID;
15 PetscClassId MAT_TRANSPOSECOLORING_CLASSID;
16 
17 PetscLogEvent MAT_Mult, MAT_MultAdd, MAT_MultTranspose;
18 PetscLogEvent MAT_MultTransposeAdd, MAT_Solve, MAT_Solves, MAT_SolveAdd, MAT_SolveTranspose, MAT_MatSolve, MAT_MatTrSolve;
19 PetscLogEvent MAT_SolveTransposeAdd, MAT_SOR, MAT_ForwardSolve, MAT_BackwardSolve, MAT_LUFactor, MAT_LUFactorSymbolic;
20 PetscLogEvent MAT_LUFactorNumeric, MAT_CholeskyFactor, MAT_CholeskyFactorSymbolic, MAT_CholeskyFactorNumeric, MAT_ILUFactor;
21 PetscLogEvent MAT_ILUFactorSymbolic, MAT_ICCFactorSymbolic, MAT_Copy, MAT_Convert, MAT_Scale, MAT_AssemblyBegin;
22 PetscLogEvent MAT_QRFactorNumeric, MAT_QRFactorSymbolic, MAT_QRFactor;
23 PetscLogEvent MAT_AssemblyEnd, MAT_SetValues, MAT_GetValues, MAT_GetRow, MAT_GetRowIJ, MAT_CreateSubMats, MAT_GetOrdering, MAT_RedundantMat, MAT_GetSeqNonzeroStructure;
24 PetscLogEvent MAT_IncreaseOverlap, MAT_Partitioning, MAT_PartitioningND, MAT_Coarsen, MAT_ZeroEntries, MAT_Load, MAT_View, MAT_AXPY, MAT_FDColoringCreate;
25 PetscLogEvent MAT_FDColoringSetUp, MAT_FDColoringApply, MAT_Transpose, MAT_FDColoringFunction, MAT_CreateSubMat;
26 PetscLogEvent MAT_TransposeColoringCreate;
27 PetscLogEvent MAT_MatMult, MAT_MatMultSymbolic, MAT_MatMultNumeric;
28 PetscLogEvent MAT_PtAP, MAT_PtAPSymbolic, MAT_PtAPNumeric, MAT_RARt, MAT_RARtSymbolic, MAT_RARtNumeric;
29 PetscLogEvent MAT_MatTransposeMult, MAT_MatTransposeMultSymbolic, MAT_MatTransposeMultNumeric;
30 PetscLogEvent MAT_TransposeMatMult, MAT_TransposeMatMultSymbolic, MAT_TransposeMatMultNumeric;
31 PetscLogEvent MAT_MatMatMult, MAT_MatMatMultSymbolic, MAT_MatMatMultNumeric;
32 PetscLogEvent MAT_MultHermitianTranspose, MAT_MultHermitianTransposeAdd;
33 PetscLogEvent MAT_Getsymtransreduced, MAT_GetBrowsOfAcols;
34 PetscLogEvent MAT_GetBrowsOfAocols, MAT_Getlocalmat, MAT_Getlocalmatcondensed, MAT_Seqstompi, MAT_Seqstompinum, MAT_Seqstompisym;
35 PetscLogEvent MAT_GetMultiProcBlock;
36 PetscLogEvent MAT_CUSPARSECopyToGPU, MAT_CUSPARSECopyFromGPU, MAT_CUSPARSEGenerateTranspose, MAT_CUSPARSESolveAnalysis;
37 PetscLogEvent MAT_HIPSPARSECopyToGPU, MAT_HIPSPARSECopyFromGPU, MAT_HIPSPARSEGenerateTranspose, MAT_HIPSPARSESolveAnalysis;
38 PetscLogEvent MAT_PreallCOO, MAT_SetVCOO;
39 PetscLogEvent MAT_CreateGraph;
40 PetscLogEvent MAT_SetValuesBatch;
41 PetscLogEvent MAT_ViennaCLCopyToGPU;
42 PetscLogEvent MAT_CUDACopyToGPU, MAT_HIPCopyToGPU;
43 PetscLogEvent MAT_DenseCopyToGPU, MAT_DenseCopyFromGPU;
44 PetscLogEvent MAT_Merge, MAT_Residual, MAT_SetRandom;
45 PetscLogEvent MAT_FactorFactS, MAT_FactorInvS;
46 PetscLogEvent MATCOLORING_Apply, MATCOLORING_Comm, MATCOLORING_Local, MATCOLORING_ISCreate, MATCOLORING_SetUp, MATCOLORING_Weights;
47 PetscLogEvent MAT_H2Opus_Build, MAT_H2Opus_Compress, MAT_H2Opus_Orthog, MAT_H2Opus_LR;
48 
49 const char *const MatFactorTypes[] = {"NONE", "LU", "CHOLESKY", "ILU", "ICC", "ILUDT", "QR", "MatFactorType", "MAT_FACTOR_", NULL};
50 
51 /*@
52   MatSetRandom - Sets all components of a matrix to random numbers.
53 
54   Logically Collective
55 
56   Input Parameters:
57 + x    - the matrix
58 - rctx - the `PetscRandom` object, formed by `PetscRandomCreate()`, or `NULL` and
59           it will create one internally.
60 
61   Example:
62 .vb
63      PetscRandomCreate(PETSC_COMM_WORLD,&rctx);
64      MatSetRandom(x,rctx);
65      PetscRandomDestroy(rctx);
66 .ve
67 
68   Level: intermediate
69 
70   Notes:
71   For sparse matrices that have been preallocated but not been assembled, it randomly selects appropriate locations,
72 
73   for sparse matrices that already have nonzero locations, it fills the locations with random numbers.
74 
75   It generates an error if used on unassembled sparse matrices that have not been preallocated.
76 
77 .seealso: [](ch_matrices), `Mat`, `PetscRandom`, `PetscRandomCreate()`, `MatZeroEntries()`, `MatSetValues()`, `PetscRandomDestroy()`
78 @*/
79 PetscErrorCode MatSetRandom(Mat x, PetscRandom rctx)
80 {
81   PetscRandom randObj = NULL;
82 
83   PetscFunctionBegin;
84   PetscValidHeaderSpecific(x, MAT_CLASSID, 1);
85   if (rctx) PetscValidHeaderSpecific(rctx, PETSC_RANDOM_CLASSID, 2);
86   PetscValidType(x, 1);
87   MatCheckPreallocated(x, 1);
88 
89   if (!rctx) {
90     MPI_Comm comm;
91     PetscCall(PetscObjectGetComm((PetscObject)x, &comm));
92     PetscCall(PetscRandomCreate(comm, &randObj));
93     PetscCall(PetscRandomSetType(randObj, x->defaultrandtype));
94     PetscCall(PetscRandomSetFromOptions(randObj));
95     rctx = randObj;
96   }
97   PetscCall(PetscLogEventBegin(MAT_SetRandom, x, rctx, 0, 0));
98   PetscUseTypeMethod(x, setrandom, rctx);
99   PetscCall(PetscLogEventEnd(MAT_SetRandom, x, rctx, 0, 0));
100 
101   PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
102   PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
103   PetscCall(PetscRandomDestroy(&randObj));
104   PetscFunctionReturn(PETSC_SUCCESS);
105 }
106 
107 /*@
108   MatCopyHashToXAIJ - copy hash table entries into an XAIJ matrix type
109 
110   Logically Collective
111 
112   Input Parameter:
113 . A - A matrix in unassembled, hash table form
114 
115   Output Parameter:
116 . B - The XAIJ matrix. This can either be `A` or some matrix of equivalent size, e.g. obtained from `A` via `MatDuplicate()`
117 
118   Example:
119 .vb
120      PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &B));
121      PetscCall(MatCopyHashToXAIJ(A, B));
122 .ve
123 
124   Level: advanced
125 
126   Notes:
127   If `B` is `A`, then the hash table data structure will be destroyed. `B` is assembled
128 
129 .seealso: [](ch_matrices), `Mat`, `MAT_USE_HASH_TABLE`
130 @*/
131 PetscErrorCode MatCopyHashToXAIJ(Mat A, Mat B)
132 {
133   PetscFunctionBegin;
134   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
135   PetscUseTypeMethod(A, copyhashtoxaij, B);
136   PetscFunctionReturn(PETSC_SUCCESS);
137 }
138 
139 /*@
140   MatFactorGetErrorZeroPivot - returns the pivot value that was determined to be zero and the row it occurred in
141 
142   Logically Collective
143 
144   Input Parameter:
145 . mat - the factored matrix
146 
147   Output Parameters:
148 + pivot - the pivot value computed
149 - row   - the row that the zero pivot occurred. This row value must be interpreted carefully due to row reorderings and which processes
150          the share the matrix
151 
152   Level: advanced
153 
154   Notes:
155   This routine does not work for factorizations done with external packages.
156 
157   This routine should only be called if `MatGetFactorError()` returns a value of `MAT_FACTOR_NUMERIC_ZEROPIVOT`
158 
159   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
160 
161 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`,
162 `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`, `MatFactorClearError()`,
163 `MAT_FACTOR_NUMERIC_ZEROPIVOT`
164 @*/
165 PetscErrorCode MatFactorGetErrorZeroPivot(Mat mat, PetscReal *pivot, PetscInt *row)
166 {
167   PetscFunctionBegin;
168   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
169   PetscAssertPointer(pivot, 2);
170   PetscAssertPointer(row, 3);
171   *pivot = mat->factorerror_zeropivot_value;
172   *row   = mat->factorerror_zeropivot_row;
173   PetscFunctionReturn(PETSC_SUCCESS);
174 }
175 
176 /*@
177   MatFactorGetError - gets the error code from a factorization
178 
179   Logically Collective
180 
181   Input Parameter:
182 . mat - the factored matrix
183 
184   Output Parameter:
185 . err - the error code
186 
187   Level: advanced
188 
189   Note:
190   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
191 
192 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`,
193           `MatFactorClearError()`, `MatFactorGetErrorZeroPivot()`, `MatFactorError`
194 @*/
195 PetscErrorCode MatFactorGetError(Mat mat, MatFactorError *err)
196 {
197   PetscFunctionBegin;
198   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
199   PetscAssertPointer(err, 2);
200   *err = mat->factorerrortype;
201   PetscFunctionReturn(PETSC_SUCCESS);
202 }
203 
204 /*@
205   MatFactorClearError - clears the error code in a factorization
206 
207   Logically Collective
208 
209   Input Parameter:
210 . mat - the factored matrix
211 
212   Level: developer
213 
214   Note:
215   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
216 
217 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`, `MatFactorGetError()`, `MatFactorGetErrorZeroPivot()`,
218           `MatGetErrorCode()`, `MatFactorError`
219 @*/
220 PetscErrorCode MatFactorClearError(Mat mat)
221 {
222   PetscFunctionBegin;
223   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
224   mat->factorerrortype             = MAT_FACTOR_NOERROR;
225   mat->factorerror_zeropivot_value = 0.0;
226   mat->factorerror_zeropivot_row   = 0;
227   PetscFunctionReturn(PETSC_SUCCESS);
228 }
229 
230 PetscErrorCode MatFindNonzeroRowsOrCols_Basic(Mat mat, PetscBool cols, PetscReal tol, IS *nonzero)
231 {
232   Vec                r, l;
233   const PetscScalar *al;
234   PetscInt           i, nz, gnz, N, n, st;
235 
236   PetscFunctionBegin;
237   PetscCall(MatCreateVecs(mat, &r, &l));
238   if (!cols) { /* nonzero rows */
239     PetscCall(MatGetOwnershipRange(mat, &st, NULL));
240     PetscCall(MatGetSize(mat, &N, NULL));
241     PetscCall(MatGetLocalSize(mat, &n, NULL));
242     PetscCall(VecSet(l, 0.0));
243     PetscCall(VecSetRandom(r, NULL));
244     PetscCall(MatMult(mat, r, l));
245     PetscCall(VecGetArrayRead(l, &al));
246   } else { /* nonzero columns */
247     PetscCall(MatGetOwnershipRangeColumn(mat, &st, NULL));
248     PetscCall(MatGetSize(mat, NULL, &N));
249     PetscCall(MatGetLocalSize(mat, NULL, &n));
250     PetscCall(VecSet(r, 0.0));
251     PetscCall(VecSetRandom(l, NULL));
252     PetscCall(MatMultTranspose(mat, l, r));
253     PetscCall(VecGetArrayRead(r, &al));
254   }
255   if (tol <= 0.0) {
256     for (i = 0, nz = 0; i < n; i++)
257       if (al[i] != 0.0) nz++;
258   } else {
259     for (i = 0, nz = 0; i < n; i++)
260       if (PetscAbsScalar(al[i]) > tol) nz++;
261   }
262   PetscCallMPI(MPIU_Allreduce(&nz, &gnz, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
263   if (gnz != N) {
264     PetscInt *nzr;
265     PetscCall(PetscMalloc1(nz, &nzr));
266     if (nz) {
267       if (tol < 0) {
268         for (i = 0, nz = 0; i < n; i++)
269           if (al[i] != 0.0) nzr[nz++] = i + st;
270       } else {
271         for (i = 0, nz = 0; i < n; i++)
272           if (PetscAbsScalar(al[i]) > tol) nzr[nz++] = i + st;
273       }
274     }
275     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nz, nzr, PETSC_OWN_POINTER, nonzero));
276   } else *nonzero = NULL;
277   if (!cols) { /* nonzero rows */
278     PetscCall(VecRestoreArrayRead(l, &al));
279   } else {
280     PetscCall(VecRestoreArrayRead(r, &al));
281   }
282   PetscCall(VecDestroy(&l));
283   PetscCall(VecDestroy(&r));
284   PetscFunctionReturn(PETSC_SUCCESS);
285 }
286 
287 /*@
288   MatFindNonzeroRows - Locate all rows that are not completely zero in the matrix
289 
290   Input Parameter:
291 . mat - the matrix
292 
293   Output Parameter:
294 . keptrows - the rows that are not completely zero
295 
296   Level: intermediate
297 
298   Note:
299   `keptrows` is set to `NULL` if all rows are nonzero.
300 
301   Developer Note:
302   If `keptrows` is not `NULL`, it must be sorted.
303 
304 .seealso: [](ch_matrices), `Mat`, `MatFindZeroRows()`
305  @*/
306 PetscErrorCode MatFindNonzeroRows(Mat mat, IS *keptrows)
307 {
308   PetscFunctionBegin;
309   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
310   PetscValidType(mat, 1);
311   PetscAssertPointer(keptrows, 2);
312   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
313   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
314   if (mat->ops->findnonzerorows) PetscUseTypeMethod(mat, findnonzerorows, keptrows);
315   else PetscCall(MatFindNonzeroRowsOrCols_Basic(mat, PETSC_FALSE, 0.0, keptrows));
316   if (keptrows && *keptrows) PetscCall(ISSetInfo(*keptrows, IS_SORTED, IS_GLOBAL, PETSC_FALSE, PETSC_TRUE));
317   PetscFunctionReturn(PETSC_SUCCESS);
318 }
319 
320 /*@
321   MatFindZeroRows - Locate all rows that are completely zero in the matrix
322 
323   Input Parameter:
324 . mat - the matrix
325 
326   Output Parameter:
327 . zerorows - the rows that are completely zero
328 
329   Level: intermediate
330 
331   Note:
332   `zerorows` is set to `NULL` if no rows are zero.
333 
334 .seealso: [](ch_matrices), `Mat`, `MatFindNonzeroRows()`
335  @*/
336 PetscErrorCode MatFindZeroRows(Mat mat, IS *zerorows)
337 {
338   IS       keptrows;
339   PetscInt m, n;
340 
341   PetscFunctionBegin;
342   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
343   PetscValidType(mat, 1);
344   PetscAssertPointer(zerorows, 2);
345   PetscCall(MatFindNonzeroRows(mat, &keptrows));
346   /* MatFindNonzeroRows sets keptrows to NULL if there are no zero rows.
347      In keeping with this convention, we set zerorows to NULL if there are no zero
348      rows. */
349   if (keptrows == NULL) {
350     *zerorows = NULL;
351   } else {
352     PetscCall(MatGetOwnershipRange(mat, &m, &n));
353     PetscCall(ISComplement(keptrows, m, n, zerorows));
354     PetscCall(ISDestroy(&keptrows));
355   }
356   PetscFunctionReturn(PETSC_SUCCESS);
357 }
358 
359 /*@
360   MatGetDiagonalBlock - Returns the part of the matrix associated with the on-process coupling
361 
362   Not Collective
363 
364   Input Parameter:
365 . A - the matrix
366 
367   Output Parameter:
368 . a - the diagonal part (which is a SEQUENTIAL matrix)
369 
370   Level: advanced
371 
372   Notes:
373   See `MatCreateAIJ()` for more information on the "diagonal part" of the matrix.
374 
375   Use caution, as the reference count on the returned matrix is not incremented and it is used as part of `A`'s normal operation.
376 
377 .seealso: [](ch_matrices), `Mat`, `MatCreateAIJ()`, `MATAIJ`, `MATBAIJ`, `MATSBAIJ`
378 @*/
379 PetscErrorCode MatGetDiagonalBlock(Mat A, Mat *a)
380 {
381   PetscFunctionBegin;
382   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
383   PetscValidType(A, 1);
384   PetscAssertPointer(a, 2);
385   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
386   if (A->ops->getdiagonalblock) PetscUseTypeMethod(A, getdiagonalblock, a);
387   else {
388     PetscMPIInt size;
389 
390     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
391     PetscCheck(size == 1, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for parallel matrix type %s", ((PetscObject)A)->type_name);
392     *a = A;
393   }
394   PetscFunctionReturn(PETSC_SUCCESS);
395 }
396 
397 /*@
398   MatGetTrace - Gets the trace of a matrix. The sum of the diagonal entries.
399 
400   Collective
401 
402   Input Parameter:
403 . mat - the matrix
404 
405   Output Parameter:
406 . trace - the sum of the diagonal entries
407 
408   Level: advanced
409 
410 .seealso: [](ch_matrices), `Mat`
411 @*/
412 PetscErrorCode MatGetTrace(Mat mat, PetscScalar *trace)
413 {
414   Vec diag;
415 
416   PetscFunctionBegin;
417   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
418   PetscAssertPointer(trace, 2);
419   PetscCall(MatCreateVecs(mat, &diag, NULL));
420   PetscCall(MatGetDiagonal(mat, diag));
421   PetscCall(VecSum(diag, trace));
422   PetscCall(VecDestroy(&diag));
423   PetscFunctionReturn(PETSC_SUCCESS);
424 }
425 
426 /*@
427   MatRealPart - Zeros out the imaginary part of the matrix
428 
429   Logically Collective
430 
431   Input Parameter:
432 . mat - the matrix
433 
434   Level: advanced
435 
436 .seealso: [](ch_matrices), `Mat`, `MatImaginaryPart()`
437 @*/
438 PetscErrorCode MatRealPart(Mat mat)
439 {
440   PetscFunctionBegin;
441   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
442   PetscValidType(mat, 1);
443   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
444   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
445   MatCheckPreallocated(mat, 1);
446   PetscUseTypeMethod(mat, realpart);
447   PetscFunctionReturn(PETSC_SUCCESS);
448 }
449 
450 /*@C
451   MatGetGhosts - Get the global indices of all ghost nodes defined by the sparse matrix
452 
453   Collective
454 
455   Input Parameter:
456 . mat - the matrix
457 
458   Output Parameters:
459 + nghosts - number of ghosts (for `MATBAIJ` and `MATSBAIJ` matrices there is one ghost for each matrix block)
460 - ghosts  - the global indices of the ghost points
461 
462   Level: advanced
463 
464   Note:
465   `nghosts` and `ghosts` are suitable to pass into `VecCreateGhost()` or `VecCreateGhostBlock()`
466 
467 .seealso: [](ch_matrices), `Mat`, `VecCreateGhost()`, `VecCreateGhostBlock()`
468 @*/
469 PetscErrorCode MatGetGhosts(Mat mat, PetscInt *nghosts, const PetscInt *ghosts[])
470 {
471   PetscFunctionBegin;
472   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
473   PetscValidType(mat, 1);
474   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
475   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
476   if (mat->ops->getghosts) PetscUseTypeMethod(mat, getghosts, nghosts, ghosts);
477   else {
478     if (nghosts) *nghosts = 0;
479     if (ghosts) *ghosts = NULL;
480   }
481   PetscFunctionReturn(PETSC_SUCCESS);
482 }
483 
484 /*@
485   MatImaginaryPart - Moves the imaginary part of the matrix to the real part and zeros the imaginary part
486 
487   Logically Collective
488 
489   Input Parameter:
490 . mat - the matrix
491 
492   Level: advanced
493 
494 .seealso: [](ch_matrices), `Mat`, `MatRealPart()`
495 @*/
496 PetscErrorCode MatImaginaryPart(Mat mat)
497 {
498   PetscFunctionBegin;
499   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
500   PetscValidType(mat, 1);
501   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
502   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
503   MatCheckPreallocated(mat, 1);
504   PetscUseTypeMethod(mat, imaginarypart);
505   PetscFunctionReturn(PETSC_SUCCESS);
506 }
507 
508 /*@
509   MatMissingDiagonal - Determine if sparse matrix is missing a diagonal entry (or block entry for `MATBAIJ` and `MATSBAIJ` matrices) in the nonzero structure
510 
511   Not Collective
512 
513   Input Parameter:
514 . mat - the matrix
515 
516   Output Parameters:
517 + missing - is any diagonal entry missing
518 - dd      - first diagonal entry that is missing (optional) on this process
519 
520   Level: advanced
521 
522   Note:
523   This does not return diagonal entries that are in the nonzero structure but happen to have a zero numerical value
524 
525 .seealso: [](ch_matrices), `Mat`
526 @*/
527 PetscErrorCode MatMissingDiagonal(Mat mat, PetscBool *missing, PetscInt *dd)
528 {
529   PetscFunctionBegin;
530   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
531   PetscValidType(mat, 1);
532   PetscAssertPointer(missing, 2);
533   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix %s", ((PetscObject)mat)->type_name);
534   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
535   PetscUseTypeMethod(mat, missingdiagonal, missing, dd);
536   PetscFunctionReturn(PETSC_SUCCESS);
537 }
538 
539 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
540 /*@C
541   MatGetRow - Gets a row of a matrix.  You MUST call `MatRestoreRow()`
542   for each row that you get to ensure that your application does
543   not bleed memory.
544 
545   Not Collective
546 
547   Input Parameters:
548 + mat - the matrix
549 - row - the row to get
550 
551   Output Parameters:
552 + ncols - if not `NULL`, the number of nonzeros in `row`
553 . cols  - if not `NULL`, the column numbers
554 - vals  - if not `NULL`, the numerical values
555 
556   Level: advanced
557 
558   Notes:
559   This routine is provided for people who need to have direct access
560   to the structure of a matrix.  We hope that we provide enough
561   high-level matrix routines that few users will need it.
562 
563   `MatGetRow()` always returns 0-based column indices, regardless of
564   whether the internal representation is 0-based (default) or 1-based.
565 
566   For better efficiency, set `cols` and/or `vals` to `NULL` if you do
567   not wish to extract these quantities.
568 
569   The user can only examine the values extracted with `MatGetRow()`;
570   the values CANNOT be altered.  To change the matrix entries, one
571   must use `MatSetValues()`.
572 
573   You can only have one call to `MatGetRow()` outstanding for a particular
574   matrix at a time, per processor. `MatGetRow()` can only obtain rows
575   associated with the given processor, it cannot get rows from the
576   other processors; for that we suggest using `MatCreateSubMatrices()`, then
577   `MatGetRow()` on the submatrix. The row index passed to `MatGetRow()`
578   is in the global number of rows.
579 
580   Use `MatGetRowIJ()` and `MatRestoreRowIJ()` to access all the local indices of the sparse matrix.
581 
582   Use `MatSeqAIJGetArray()` and similar functions to access the numerical values for certain matrix types directly.
583 
584   Fortran Note:
585 .vb
586   PetscInt, pointer :: cols(:)
587   PetscScalar, pointer :: vals(:)
588 .ve
589 
590 .seealso: [](ch_matrices), `Mat`, `MatRestoreRow()`, `MatSetValues()`, `MatGetValues()`, `MatCreateSubMatrices()`, `MatGetDiagonal()`, `MatGetRowIJ()`, `MatRestoreRowIJ()`
591 @*/
592 PetscErrorCode MatGetRow(Mat mat, PetscInt row, PetscInt *ncols, const PetscInt *cols[], const PetscScalar *vals[])
593 {
594   PetscInt incols;
595 
596   PetscFunctionBegin;
597   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
598   PetscValidType(mat, 1);
599   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
600   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
601   MatCheckPreallocated(mat, 1);
602   PetscCheck(row >= mat->rmap->rstart && row < mat->rmap->rend, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Only for local rows, %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ")", row, mat->rmap->rstart, mat->rmap->rend);
603   PetscCall(PetscLogEventBegin(MAT_GetRow, mat, 0, 0, 0));
604   PetscUseTypeMethod(mat, getrow, row, &incols, (PetscInt **)cols, (PetscScalar **)vals);
605   if (ncols) *ncols = incols;
606   PetscCall(PetscLogEventEnd(MAT_GetRow, mat, 0, 0, 0));
607   PetscFunctionReturn(PETSC_SUCCESS);
608 }
609 
610 /*@
611   MatConjugate - replaces the matrix values with their complex conjugates
612 
613   Logically Collective
614 
615   Input Parameter:
616 . mat - the matrix
617 
618   Level: advanced
619 
620 .seealso: [](ch_matrices), `Mat`, `MatRealPart()`, `MatImaginaryPart()`, `VecConjugate()`, `MatTranspose()`
621 @*/
622 PetscErrorCode MatConjugate(Mat mat)
623 {
624   PetscFunctionBegin;
625   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
626   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
627   if (PetscDefined(USE_COMPLEX) && mat->hermitian != PETSC_BOOL3_TRUE) {
628     PetscUseTypeMethod(mat, conjugate);
629     PetscCall(PetscObjectStateIncrease((PetscObject)mat));
630   }
631   PetscFunctionReturn(PETSC_SUCCESS);
632 }
633 
634 /*@C
635   MatRestoreRow - Frees any temporary space allocated by `MatGetRow()`.
636 
637   Not Collective
638 
639   Input Parameters:
640 + mat   - the matrix
641 . row   - the row to get
642 . ncols - the number of nonzeros
643 . cols  - the columns of the nonzeros
644 - vals  - if nonzero the column values
645 
646   Level: advanced
647 
648   Notes:
649   This routine should be called after you have finished examining the entries.
650 
651   This routine zeros out `ncols`, `cols`, and `vals`. This is to prevent accidental
652   us of the array after it has been restored. If you pass `NULL`, it will
653   not zero the pointers.  Use of `cols` or `vals` after `MatRestoreRow()` is invalid.
654 
655   Fortran Note:
656 .vb
657   PetscInt, pointer :: cols(:)
658   PetscScalar, pointer :: vals(:)
659 .ve
660 
661 .seealso: [](ch_matrices), `Mat`, `MatGetRow()`
662 @*/
663 PetscErrorCode MatRestoreRow(Mat mat, PetscInt row, PetscInt *ncols, const PetscInt *cols[], const PetscScalar *vals[])
664 {
665   PetscFunctionBegin;
666   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
667   if (ncols) PetscAssertPointer(ncols, 3);
668   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
669   PetscTryTypeMethod(mat, restorerow, row, ncols, (PetscInt **)cols, (PetscScalar **)vals);
670   if (ncols) *ncols = 0;
671   if (cols) *cols = NULL;
672   if (vals) *vals = NULL;
673   PetscFunctionReturn(PETSC_SUCCESS);
674 }
675 
676 /*@
677   MatGetRowUpperTriangular - Sets a flag to enable calls to `MatGetRow()` for matrix in `MATSBAIJ` format.
678   You should call `MatRestoreRowUpperTriangular()` after calling` MatGetRow()` and `MatRestoreRow()` to disable the flag.
679 
680   Not Collective
681 
682   Input Parameter:
683 . mat - the matrix
684 
685   Level: advanced
686 
687   Note:
688   The flag is to ensure that users are aware that `MatGetRow()` only provides the upper triangular part of the row for the matrices in `MATSBAIJ` format.
689 
690 .seealso: [](ch_matrices), `Mat`, `MATSBAIJ`, `MatRestoreRowUpperTriangular()`
691 @*/
692 PetscErrorCode MatGetRowUpperTriangular(Mat mat)
693 {
694   PetscFunctionBegin;
695   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
696   PetscValidType(mat, 1);
697   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
698   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
699   MatCheckPreallocated(mat, 1);
700   PetscTryTypeMethod(mat, getrowuppertriangular);
701   PetscFunctionReturn(PETSC_SUCCESS);
702 }
703 
704 /*@
705   MatRestoreRowUpperTriangular - Disable calls to `MatGetRow()` for matrix in `MATSBAIJ` format.
706 
707   Not Collective
708 
709   Input Parameter:
710 . mat - the matrix
711 
712   Level: advanced
713 
714   Note:
715   This routine should be called after you have finished calls to `MatGetRow()` and `MatRestoreRow()`.
716 
717 .seealso: [](ch_matrices), `Mat`, `MATSBAIJ`, `MatGetRowUpperTriangular()`
718 @*/
719 PetscErrorCode MatRestoreRowUpperTriangular(Mat mat)
720 {
721   PetscFunctionBegin;
722   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
723   PetscValidType(mat, 1);
724   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
725   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
726   MatCheckPreallocated(mat, 1);
727   PetscTryTypeMethod(mat, restorerowuppertriangular);
728   PetscFunctionReturn(PETSC_SUCCESS);
729 }
730 
731 /*@
732   MatSetOptionsPrefix - Sets the prefix used for searching for all
733   `Mat` options in the database.
734 
735   Logically Collective
736 
737   Input Parameters:
738 + A      - the matrix
739 - prefix - the prefix to prepend to all option names
740 
741   Level: advanced
742 
743   Notes:
744   A hyphen (-) must NOT be given at the beginning of the prefix name.
745   The first character of all runtime options is AUTOMATICALLY the hyphen.
746 
747   This is NOT used for options for the factorization of the matrix. Normally the
748   prefix is automatically passed in from the PC calling the factorization. To set
749   it directly use  `MatSetOptionsPrefixFactor()`
750 
751 .seealso: [](ch_matrices), `Mat`, `MatSetFromOptions()`, `MatSetOptionsPrefixFactor()`
752 @*/
753 PetscErrorCode MatSetOptionsPrefix(Mat A, const char prefix[])
754 {
755   PetscFunctionBegin;
756   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
757   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)A, prefix));
758   PetscFunctionReturn(PETSC_SUCCESS);
759 }
760 
761 /*@
762   MatSetOptionsPrefixFactor - Sets the prefix used for searching for all matrix factor options in the database for
763   for matrices created with `MatGetFactor()`
764 
765   Logically Collective
766 
767   Input Parameters:
768 + A      - the matrix
769 - prefix - the prefix to prepend to all option names for the factored matrix
770 
771   Level: developer
772 
773   Notes:
774   A hyphen (-) must NOT be given at the beginning of the prefix name.
775   The first character of all runtime options is AUTOMATICALLY the hyphen.
776 
777   Normally the prefix is automatically passed in from the `PC` calling the factorization. To set
778   it directly when not using `KSP`/`PC` use  `MatSetOptionsPrefixFactor()`
779 
780 .seealso: [](ch_matrices), `Mat`,   [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSetFromOptions()`, `MatSetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`
781 @*/
782 PetscErrorCode MatSetOptionsPrefixFactor(Mat A, const char prefix[])
783 {
784   PetscFunctionBegin;
785   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
786   if (prefix) {
787     PetscAssertPointer(prefix, 2);
788     PetscCheck(prefix[0] != '-', PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
789     if (prefix != A->factorprefix) {
790       PetscCall(PetscFree(A->factorprefix));
791       PetscCall(PetscStrallocpy(prefix, &A->factorprefix));
792     }
793   } else PetscCall(PetscFree(A->factorprefix));
794   PetscFunctionReturn(PETSC_SUCCESS);
795 }
796 
797 /*@
798   MatAppendOptionsPrefixFactor - Appends to the prefix used for searching for all matrix factor options in the database for
799   for matrices created with `MatGetFactor()`
800 
801   Logically Collective
802 
803   Input Parameters:
804 + A      - the matrix
805 - prefix - the prefix to prepend to all option names for the factored matrix
806 
807   Level: developer
808 
809   Notes:
810   A hyphen (-) must NOT be given at the beginning of the prefix name.
811   The first character of all runtime options is AUTOMATICALLY the hyphen.
812 
813   Normally the prefix is automatically passed in from the `PC` calling the factorization. To set
814   it directly when not using `KSP`/`PC` use  `MatAppendOptionsPrefixFactor()`
815 
816 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `PetscOptionsCreate()`, `PetscOptionsDestroy()`, `PetscObjectSetOptionsPrefix()`, `PetscObjectPrependOptionsPrefix()`,
817           `PetscObjectGetOptionsPrefix()`, `TSAppendOptionsPrefix()`, `SNESAppendOptionsPrefix()`, `KSPAppendOptionsPrefix()`, `MatSetOptionsPrefixFactor()`,
818           `MatSetOptionsPrefix()`
819 @*/
820 PetscErrorCode MatAppendOptionsPrefixFactor(Mat A, const char prefix[])
821 {
822   size_t len1, len2, new_len;
823 
824   PetscFunctionBegin;
825   PetscValidHeader(A, 1);
826   if (!prefix) PetscFunctionReturn(PETSC_SUCCESS);
827   if (!A->factorprefix) {
828     PetscCall(MatSetOptionsPrefixFactor(A, prefix));
829     PetscFunctionReturn(PETSC_SUCCESS);
830   }
831   PetscCheck(prefix[0] != '-', PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
832 
833   PetscCall(PetscStrlen(A->factorprefix, &len1));
834   PetscCall(PetscStrlen(prefix, &len2));
835   new_len = len1 + len2 + 1;
836   PetscCall(PetscRealloc(new_len * sizeof(*A->factorprefix), &A->factorprefix));
837   PetscCall(PetscStrncpy(A->factorprefix + len1, prefix, len2 + 1));
838   PetscFunctionReturn(PETSC_SUCCESS);
839 }
840 
841 /*@
842   MatAppendOptionsPrefix - Appends to the prefix used for searching for all
843   matrix options in the database.
844 
845   Logically Collective
846 
847   Input Parameters:
848 + A      - the matrix
849 - prefix - the prefix to prepend to all option names
850 
851   Level: advanced
852 
853   Note:
854   A hyphen (-) must NOT be given at the beginning of the prefix name.
855   The first character of all runtime options is AUTOMATICALLY the hyphen.
856 
857 .seealso: [](ch_matrices), `Mat`, `MatGetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`, `MatSetOptionsPrefix()`
858 @*/
859 PetscErrorCode MatAppendOptionsPrefix(Mat A, const char prefix[])
860 {
861   PetscFunctionBegin;
862   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
863   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)A, prefix));
864   PetscFunctionReturn(PETSC_SUCCESS);
865 }
866 
867 /*@
868   MatGetOptionsPrefix - Gets the prefix used for searching for all
869   matrix options in the database.
870 
871   Not Collective
872 
873   Input Parameter:
874 . A - the matrix
875 
876   Output Parameter:
877 . prefix - pointer to the prefix string used
878 
879   Level: advanced
880 
881 .seealso: [](ch_matrices), `Mat`, `MatAppendOptionsPrefix()`, `MatSetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`, `MatSetOptionsPrefixFactor()`
882 @*/
883 PetscErrorCode MatGetOptionsPrefix(Mat A, const char *prefix[])
884 {
885   PetscFunctionBegin;
886   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
887   PetscAssertPointer(prefix, 2);
888   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)A, prefix));
889   PetscFunctionReturn(PETSC_SUCCESS);
890 }
891 
892 /*@
893   MatGetState - Gets the state of a `Mat`. Same value as returned by `PetscObjectStateGet()`
894 
895   Not Collective
896 
897   Input Parameter:
898 . A - the matrix
899 
900   Output Parameter:
901 . state - the object state
902 
903   Level: advanced
904 
905   Note:
906   Object state is an integer which gets increased every time
907   the object is changed. By saving and later querying the object state
908   one can determine whether information about the object is still current.
909 
910   See `MatGetNonzeroState()` to determine if the nonzero structure of the matrix has changed.
911 
912 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PetscObjectStateGet()`, `MatGetNonzeroState()`
913 @*/
914 PetscErrorCode MatGetState(Mat A, PetscObjectState *state)
915 {
916   PetscFunctionBegin;
917   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
918   PetscAssertPointer(state, 2);
919   PetscCall(PetscObjectStateGet((PetscObject)A, state));
920   PetscFunctionReturn(PETSC_SUCCESS);
921 }
922 
923 /*@
924   MatResetPreallocation - Reset matrix to use the original preallocation values provided by the user, for example with `MatXAIJSetPreallocation()`
925 
926   Collective
927 
928   Input Parameter:
929 . A - the matrix
930 
931   Level: beginner
932 
933   Notes:
934   After calling `MatAssemblyBegin()` and `MatAssemblyEnd()` with `MAT_FINAL_ASSEMBLY` the matrix data structures represent the nonzeros assigned to the
935   matrix. If that space is less than the preallocated space that extra preallocated space is no longer available to take on new values. `MatResetPreallocation()`
936   makes all of the preallocation space available
937 
938   Current values in the matrix are lost in this call
939 
940   Currently only supported for  `MATAIJ` matrices.
941 
942 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatXAIJSetPreallocation()`
943 @*/
944 PetscErrorCode MatResetPreallocation(Mat A)
945 {
946   PetscFunctionBegin;
947   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
948   PetscValidType(A, 1);
949   PetscUseMethod(A, "MatResetPreallocation_C", (Mat), (A));
950   PetscFunctionReturn(PETSC_SUCCESS);
951 }
952 
953 /*@
954   MatResetHash - Reset the matrix so that it will use a hash table for the next round of `MatSetValues()` and `MatAssemblyBegin()`/`MatAssemblyEnd()`.
955 
956   Collective
957 
958   Input Parameter:
959 . A - the matrix
960 
961   Level: intermediate
962 
963   Notes:
964   The matrix will again delete the hash table data structures after following calls to `MatAssemblyBegin()`/`MatAssemblyEnd()` with `MAT_FINAL_ASSEMBLY`.
965 
966   Currently only supported for `MATAIJ` matrices.
967 
968 .seealso: [](ch_matrices), `Mat`, `MatResetPreallocation()`
969 @*/
970 PetscErrorCode MatResetHash(Mat A)
971 {
972   PetscFunctionBegin;
973   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
974   PetscValidType(A, 1);
975   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()");
976   if (A->num_ass == 0) PetscFunctionReturn(PETSC_SUCCESS);
977   PetscUseMethod(A, "MatResetHash_C", (Mat), (A));
978   /* These flags are used to determine whether certain setups occur */
979   A->was_assembled = PETSC_FALSE;
980   A->assembled     = PETSC_FALSE;
981   /* Log that the state of this object has changed; this will help guarantee that preconditioners get re-setup */
982   PetscCall(PetscObjectStateIncrease((PetscObject)A));
983   PetscFunctionReturn(PETSC_SUCCESS);
984 }
985 
986 /*@
987   MatSetUp - Sets up the internal matrix data structures for later use by the matrix
988 
989   Collective
990 
991   Input Parameter:
992 . A - the matrix
993 
994   Level: advanced
995 
996   Notes:
997   If the user has not set preallocation for this matrix then an efficient algorithm will be used for the first round of
998   setting values in the matrix.
999 
1000   This routine is called internally by other `Mat` functions when needed so rarely needs to be called by users
1001 
1002 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatCreate()`, `MatDestroy()`, `MatXAIJSetPreallocation()`
1003 @*/
1004 PetscErrorCode MatSetUp(Mat A)
1005 {
1006   PetscFunctionBegin;
1007   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1008   if (!((PetscObject)A)->type_name) {
1009     PetscMPIInt size;
1010 
1011     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
1012     PetscCall(MatSetType(A, size == 1 ? MATSEQAIJ : MATMPIAIJ));
1013   }
1014   if (!A->preallocated) PetscTryTypeMethod(A, setup);
1015   PetscCall(PetscLayoutSetUp(A->rmap));
1016   PetscCall(PetscLayoutSetUp(A->cmap));
1017   A->preallocated = PETSC_TRUE;
1018   PetscFunctionReturn(PETSC_SUCCESS);
1019 }
1020 
1021 #if defined(PETSC_HAVE_SAWS)
1022   #include <petscviewersaws.h>
1023 #endif
1024 
1025 /*
1026    If threadsafety is on extraneous matrices may be printed
1027 
1028    This flag cannot be stored in the matrix because the original matrix in MatView() may assemble a new matrix which is passed into MatViewFromOptions()
1029 */
1030 #if !defined(PETSC_HAVE_THREADSAFETY)
1031 static PetscInt insidematview = 0;
1032 #endif
1033 
1034 /*@
1035   MatViewFromOptions - View properties of the matrix based on options set in the options database
1036 
1037   Collective
1038 
1039   Input Parameters:
1040 + A    - the matrix
1041 . obj  - optional additional object that provides the options prefix to use
1042 - name - command line option
1043 
1044   Options Database Key:
1045 . -mat_view [viewertype]:... - the viewer and its options
1046 
1047   Level: intermediate
1048 
1049   Note:
1050 .vb
1051     If no value is provided ascii:stdout is used
1052        ascii[:[filename][:[format][:append]]]    defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab,
1053                                                   for example ascii::ascii_info prints just the information about the object not all details
1054                                                   unless :append is given filename opens in write mode, overwriting what was already there
1055        binary[:[filename][:[format][:append]]]   defaults to the file binaryoutput
1056        draw[:drawtype[:filename]]                for example, draw:tikz, draw:tikz:figure.tex  or draw:x
1057        socket[:port]                             defaults to the standard output port
1058        saws[:communicatorname]                    publishes object to the Scientific Application Webserver (SAWs)
1059 .ve
1060 
1061 .seealso: [](ch_matrices), `Mat`, `MatView()`, `PetscObjectViewFromOptions()`, `MatCreate()`
1062 @*/
1063 PetscErrorCode MatViewFromOptions(Mat A, PetscObject obj, const char name[])
1064 {
1065   PetscFunctionBegin;
1066   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1067 #if !defined(PETSC_HAVE_THREADSAFETY)
1068   if (insidematview) PetscFunctionReturn(PETSC_SUCCESS);
1069 #endif
1070   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
1071   PetscFunctionReturn(PETSC_SUCCESS);
1072 }
1073 
1074 /*@
1075   MatView - display information about a matrix in a variety ways
1076 
1077   Collective on viewer
1078 
1079   Input Parameters:
1080 + mat    - the matrix
1081 - viewer - visualization context
1082 
1083   Options Database Keys:
1084 + -mat_view ::ascii_info           - Prints info on matrix at conclusion of `MatAssemblyEnd()`
1085 . -mat_view ::ascii_info_detail    - Prints more detailed info
1086 . -mat_view                        - Prints matrix in ASCII format
1087 . -mat_view ::ascii_matlab         - Prints matrix in MATLAB format
1088 . -mat_view draw                   - PetscDraws nonzero structure of matrix, using `MatView()` and `PetscDrawOpenX()`.
1089 . -display <name>                  - Sets display name (default is host)
1090 . -draw_pause <sec>                - Sets number of seconds to pause after display
1091 . -mat_view socket                 - Sends matrix to socket, can be accessed from MATLAB (see Users-Manual: ch_matlab for details)
1092 . -viewer_socket_machine <machine> - -
1093 . -viewer_socket_port <port>       - -
1094 . -mat_view binary                 - save matrix to file in binary format
1095 - -viewer_binary_filename <name>   - -
1096 
1097   Level: beginner
1098 
1099   Notes:
1100   The available visualization contexts include
1101 +    `PETSC_VIEWER_STDOUT_SELF`   - for sequential matrices
1102 .    `PETSC_VIEWER_STDOUT_WORLD`  - for parallel matrices created on `PETSC_COMM_WORLD`
1103 .    `PETSC_VIEWER_STDOUT_`(comm) - for matrices created on MPI communicator comm
1104 -     `PETSC_VIEWER_DRAW_WORLD`   - graphical display of nonzero structure
1105 
1106   The user can open alternative visualization contexts with
1107 +    `PetscViewerASCIIOpen()`  - Outputs matrix to a specified file
1108 .    `PetscViewerBinaryOpen()` - Outputs matrix in binary to a  specified file; corresponding input uses `MatLoad()`
1109 .    `PetscViewerDrawOpen()`   - Outputs nonzero matrix nonzero structure to an X window display
1110 -    `PetscViewerSocketOpen()` - Outputs matrix to Socket viewer, `PETSCVIEWERSOCKET`. Only the `MATSEQDENSE` and `MATAIJ` types support this viewer.
1111 
1112   The user can call `PetscViewerPushFormat()` to specify the output
1113   format of ASCII printed objects (when using `PETSC_VIEWER_STDOUT_SELF`,
1114   `PETSC_VIEWER_STDOUT_WORLD` and `PetscViewerASCIIOpen()`).  Available formats include
1115 +    `PETSC_VIEWER_DEFAULT`           - default, prints matrix contents
1116 .    `PETSC_VIEWER_ASCII_MATLAB`      - prints matrix contents in MATLAB format
1117 .    `PETSC_VIEWER_ASCII_DENSE`       - prints entire matrix including zeros
1118 .    `PETSC_VIEWER_ASCII_COMMON`      - prints matrix contents, using a sparse  format common among all matrix types
1119 .    `PETSC_VIEWER_ASCII_IMPL`        - prints matrix contents, using an implementation-specific format (which is in many cases the same as the default)
1120 .    `PETSC_VIEWER_ASCII_INFO`        - prints basic information about the matrix size and structure (not the matrix entries)
1121 -    `PETSC_VIEWER_ASCII_INFO_DETAIL` - prints more detailed information about the matrix nonzero structure (still not vector or matrix entries)
1122 
1123   The ASCII viewers are only recommended for small matrices on at most a moderate number of processes,
1124   the program will seemingly hang and take hours for larger matrices, for larger matrices one should use the binary format.
1125 
1126   In the debugger you can do "call MatView(mat,0)" to display the matrix. (The same holds for any PETSc object viewer).
1127 
1128   See the manual page for `MatLoad()` for the exact format of the binary file when the binary
1129   viewer is used.
1130 
1131   See share/petsc/matlab/PetscBinaryRead.m for a MATLAB code that can read in the binary file when the binary
1132   viewer is used and lib/petsc/bin/PetscBinaryIO.py for loading them into Python.
1133 
1134   One can use '-mat_view draw -draw_pause -1' to pause the graphical display of matrix nonzero structure,
1135   and then use the following mouse functions.
1136 .vb
1137   left mouse: zoom in
1138   middle mouse: zoom out
1139   right mouse: continue with the simulation
1140 .ve
1141 
1142 .seealso: [](ch_matrices), `Mat`, `PetscViewerPushFormat()`, `PetscViewerASCIIOpen()`, `PetscViewerDrawOpen()`, `PetscViewer`,
1143           `PetscViewerSocketOpen()`, `PetscViewerBinaryOpen()`, `MatLoad()`, `MatViewFromOptions()`
1144 @*/
1145 PetscErrorCode MatView(Mat mat, PetscViewer viewer)
1146 {
1147   PetscInt          rows, cols, rbs, cbs;
1148   PetscBool         isascii, isstring, issaws;
1149   PetscViewerFormat format;
1150   PetscMPIInt       size;
1151 
1152   PetscFunctionBegin;
1153   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1154   PetscValidType(mat, 1);
1155   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat), &viewer));
1156   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1157 
1158   PetscCall(PetscViewerGetFormat(viewer, &format));
1159   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
1160   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
1161 
1162 #if !defined(PETSC_HAVE_THREADSAFETY)
1163   insidematview++;
1164 #endif
1165   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
1166   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1167   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
1168   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");
1169 
1170   PetscCall(PetscLogEventBegin(MAT_View, mat, viewer, 0, 0));
1171   if (isascii) {
1172     if (!mat->preallocated) {
1173       PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix has not been preallocated yet\n"));
1174 #if !defined(PETSC_HAVE_THREADSAFETY)
1175       insidematview--;
1176 #endif
1177       PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1178       PetscFunctionReturn(PETSC_SUCCESS);
1179     }
1180     if (!mat->assembled) {
1181       PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix has not been assembled yet\n"));
1182 #if !defined(PETSC_HAVE_THREADSAFETY)
1183       insidematview--;
1184 #endif
1185       PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1186       PetscFunctionReturn(PETSC_SUCCESS);
1187     }
1188     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)mat, viewer));
1189     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1190       MatNullSpace nullsp, transnullsp;
1191 
1192       PetscCall(PetscViewerASCIIPushTab(viewer));
1193       PetscCall(MatGetSize(mat, &rows, &cols));
1194       PetscCall(MatGetBlockSizes(mat, &rbs, &cbs));
1195       if (rbs != 1 || cbs != 1) {
1196         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" : ""));
1197         else PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT ", bs=%" PetscInt_FMT "%s\n", rows, cols, rbs, mat->bsizes ? " variable blocks set" : ""));
1198       } else PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", rows, cols));
1199       if (mat->factortype) {
1200         MatSolverType solver;
1201         PetscCall(MatFactorGetSolverType(mat, &solver));
1202         PetscCall(PetscViewerASCIIPrintf(viewer, "package used to perform factorization: %s\n", solver));
1203       }
1204       if (mat->ops->getinfo) {
1205         PetscBool is_constant_or_diagonal;
1206 
1207         // Don't print nonzero information for constant or diagonal matrices, it just adds noise to the output
1208         PetscCall(PetscObjectTypeCompareAny((PetscObject)mat, &is_constant_or_diagonal, MATCONSTANTDIAGONAL, MATDIAGONAL, ""));
1209         if (!is_constant_or_diagonal) {
1210           MatInfo info;
1211 
1212           PetscCall(MatGetInfo(mat, MAT_GLOBAL_SUM, &info));
1213           PetscCall(PetscViewerASCIIPrintf(viewer, "total: nonzeros=%.f, allocated nonzeros=%.f\n", info.nz_used, info.nz_allocated));
1214           if (!mat->factortype) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of mallocs used during MatSetValues calls=%" PetscInt_FMT "\n", (PetscInt)info.mallocs));
1215         }
1216       }
1217       PetscCall(MatGetNullSpace(mat, &nullsp));
1218       PetscCall(MatGetTransposeNullSpace(mat, &transnullsp));
1219       if (nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached null space\n"));
1220       if (transnullsp && transnullsp != nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached transposed null space\n"));
1221       PetscCall(MatGetNearNullSpace(mat, &nullsp));
1222       if (nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached near null space\n"));
1223       PetscCall(PetscViewerASCIIPushTab(viewer));
1224       PetscCall(MatProductView(mat, viewer));
1225       PetscCall(PetscViewerASCIIPopTab(viewer));
1226       if (mat->bsizes && format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1227         IS tmp;
1228 
1229         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), mat->nblocks, mat->bsizes, PETSC_USE_POINTER, &tmp));
1230         PetscCall(PetscObjectSetName((PetscObject)tmp, "Block Sizes"));
1231         PetscCall(PetscViewerASCIIPushTab(viewer));
1232         PetscCall(ISView(tmp, viewer));
1233         PetscCall(PetscViewerASCIIPopTab(viewer));
1234         PetscCall(ISDestroy(&tmp));
1235       }
1236     }
1237   } else if (issaws) {
1238 #if defined(PETSC_HAVE_SAWS)
1239     PetscMPIInt rank;
1240 
1241     PetscCall(PetscObjectName((PetscObject)mat));
1242     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1243     if (!((PetscObject)mat)->amsmem && rank == 0) PetscCall(PetscObjectViewSAWs((PetscObject)mat, viewer));
1244 #endif
1245   } else if (isstring) {
1246     const char *type;
1247     PetscCall(MatGetType(mat, &type));
1248     PetscCall(PetscViewerStringSPrintf(viewer, " MatType: %-7.7s", type));
1249     PetscTryTypeMethod(mat, view, viewer);
1250   }
1251   if ((format == PETSC_VIEWER_NATIVE || format == PETSC_VIEWER_LOAD_BALANCE) && mat->ops->viewnative) {
1252     PetscCall(PetscViewerASCIIPushTab(viewer));
1253     PetscUseTypeMethod(mat, viewnative, viewer);
1254     PetscCall(PetscViewerASCIIPopTab(viewer));
1255   } else if (mat->ops->view) {
1256     PetscCall(PetscViewerASCIIPushTab(viewer));
1257     PetscUseTypeMethod(mat, view, viewer);
1258     PetscCall(PetscViewerASCIIPopTab(viewer));
1259   }
1260   if (isascii) {
1261     PetscCall(PetscViewerGetFormat(viewer, &format));
1262     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscCall(PetscViewerASCIIPopTab(viewer));
1263   }
1264   PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1265 #if !defined(PETSC_HAVE_THREADSAFETY)
1266   insidematview--;
1267 #endif
1268   PetscFunctionReturn(PETSC_SUCCESS);
1269 }
1270 
1271 #if defined(PETSC_USE_DEBUG)
1272   #include <../src/sys/totalview/tv_data_display.h>
1273 PETSC_UNUSED static int TV_display_type(const struct _p_Mat *mat)
1274 {
1275   TV_add_row("Local rows", "int", &mat->rmap->n);
1276   TV_add_row("Local columns", "int", &mat->cmap->n);
1277   TV_add_row("Global rows", "int", &mat->rmap->N);
1278   TV_add_row("Global columns", "int", &mat->cmap->N);
1279   TV_add_row("Typename", TV_ascii_string_type, ((PetscObject)mat)->type_name);
1280   return TV_format_OK;
1281 }
1282 #endif
1283 
1284 /*@
1285   MatLoad - Loads a matrix that has been stored in binary/HDF5 format
1286   with `MatView()`.  The matrix format is determined from the options database.
1287   Generates a parallel MPI matrix if the communicator has more than one
1288   processor.  The default matrix type is `MATAIJ`.
1289 
1290   Collective
1291 
1292   Input Parameters:
1293 + mat    - the newly loaded matrix, this needs to have been created with `MatCreate()`
1294             or some related function before a call to `MatLoad()`
1295 - viewer - `PETSCVIEWERBINARY`/`PETSCVIEWERHDF5` file viewer
1296 
1297   Options Database Key:
1298 . -matload_block_size <bs> - set block size
1299 
1300   Level: beginner
1301 
1302   Notes:
1303   If the `Mat` type has not yet been given then `MATAIJ` is used, call `MatSetFromOptions()` on the
1304   `Mat` before calling this routine if you wish to set it from the options database.
1305 
1306   `MatLoad()` automatically loads into the options database any options
1307   given in the file filename.info where filename is the name of the file
1308   that was passed to the `PetscViewerBinaryOpen()`. The options in the info
1309   file will be ignored if you use the -viewer_binary_skip_info option.
1310 
1311   If the type or size of mat is not set before a call to `MatLoad()`, PETSc
1312   sets the default matrix type AIJ and sets the local and global sizes.
1313   If type and/or size is already set, then the same are used.
1314 
1315   In parallel, each processor can load a subset of rows (or the
1316   entire matrix).  This routine is especially useful when a large
1317   matrix is stored on disk and only part of it is desired on each
1318   processor.  For example, a parallel solver may access only some of
1319   the rows from each processor.  The algorithm used here reads
1320   relatively small blocks of data rather than reading the entire
1321   matrix and then subsetting it.
1322 
1323   Viewer's `PetscViewerType` must be either `PETSCVIEWERBINARY` or `PETSCVIEWERHDF5`.
1324   Such viewer can be created using `PetscViewerBinaryOpen()` or `PetscViewerHDF5Open()`,
1325   or the sequence like
1326 .vb
1327     `PetscViewer` v;
1328     `PetscViewerCreate`(`PETSC_COMM_WORLD`,&v);
1329     `PetscViewerSetType`(v,`PETSCVIEWERBINARY`);
1330     `PetscViewerSetFromOptions`(v);
1331     `PetscViewerFileSetMode`(v,`FILE_MODE_READ`);
1332     `PetscViewerFileSetName`(v,"datafile");
1333 .ve
1334   The optional `PetscViewerSetFromOptions()` call allows overriding `PetscViewerSetType()` using the option
1335 $ -viewer_type {binary, hdf5}
1336 
1337   See the example src/ksp/ksp/tutorials/ex27.c with the first approach,
1338   and src/mat/tutorials/ex10.c with the second approach.
1339 
1340   In case of `PETSCVIEWERBINARY`, a native PETSc binary format is used. Each of the blocks
1341   is read onto MPI rank 0 and then shipped to its destination MPI rank, one after another.
1342   Multiple objects, both matrices and vectors, can be stored within the same file.
1343   Their `PetscObject` name is ignored; they are loaded in the order of their storage.
1344 
1345   Most users should not need to know the details of the binary storage
1346   format, since `MatLoad()` and `MatView()` completely hide these details.
1347   But for anyone who is interested, the standard binary matrix storage
1348   format is
1349 
1350 .vb
1351     PetscInt    MAT_FILE_CLASSID
1352     PetscInt    number of rows
1353     PetscInt    number of columns
1354     PetscInt    total number of nonzeros
1355     PetscInt    *number nonzeros in each row
1356     PetscInt    *column indices of all nonzeros (starting index is zero)
1357     PetscScalar *values of all nonzeros
1358 .ve
1359   If PETSc was not configured with `--with-64-bit-indices` then only `MATMPIAIJ` matrices with more than `PETSC_INT_MAX` non-zeros can be
1360   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
1361   case will not fit in a (32-bit) `PetscInt` the value `PETSC_INT_MAX` is used for the header entry `total number of nonzeros`.
1362 
1363   PETSc automatically does the byte swapping for
1364   machines that store the bytes reversed. Thus if you write your own binary
1365   read/write routines you have to swap the bytes; see `PetscBinaryRead()`
1366   and `PetscBinaryWrite()` to see how this may be done.
1367 
1368   In case of `PETSCVIEWERHDF5`, a parallel HDF5 reader is used.
1369   Each processor's chunk is loaded independently by its owning MPI process.
1370   Multiple objects, both matrices and vectors, can be stored within the same file.
1371   They are looked up by their PetscObject name.
1372 
1373   As the MATLAB MAT-File Version 7.3 format is also a HDF5 flavor, we decided to use
1374   by default the same structure and naming of the AIJ arrays and column count
1375   within the HDF5 file. This means that a MAT file saved with -v7.3 flag, e.g.
1376 $    save example.mat A b -v7.3
1377   can be directly read by this routine (see Reference 1 for details).
1378 
1379   Depending on your MATLAB version, this format might be a default,
1380   otherwise you can set it as default in Preferences.
1381 
1382   Unless -nocompression flag is used to save the file in MATLAB,
1383   PETSc must be configured with ZLIB package.
1384 
1385   See also examples src/mat/tutorials/ex10.c and src/ksp/ksp/tutorials/ex27.c
1386 
1387   This reader currently supports only real `MATSEQAIJ`, `MATMPIAIJ`, `MATSEQDENSE` and `MATMPIDENSE` matrices for `PETSCVIEWERHDF5`
1388 
1389   Corresponding `MatView()` is not yet implemented.
1390 
1391   The loaded matrix is actually a transpose of the original one in MATLAB,
1392   unless you push `PETSC_VIEWER_HDF5_MAT` format (see examples above).
1393   With this format, matrix is automatically transposed by PETSc,
1394   unless the matrix is marked as SPD or symmetric
1395   (see `MatSetOption()`, `MAT_SPD`, `MAT_SYMMETRIC`).
1396 
1397   See MATLAB Documentation on `save()`, <https://www.mathworks.com/help/matlab/ref/save.html#btox10b-1-version>
1398 
1399 .seealso: [](ch_matrices), `Mat`, `PetscViewerBinaryOpen()`, `PetscViewerSetType()`, `MatView()`, `VecLoad()`
1400  @*/
1401 PetscErrorCode MatLoad(Mat mat, PetscViewer viewer)
1402 {
1403   PetscBool flg;
1404 
1405   PetscFunctionBegin;
1406   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1407   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1408 
1409   if (!((PetscObject)mat)->type_name) PetscCall(MatSetType(mat, MATAIJ));
1410 
1411   flg = PETSC_FALSE;
1412   PetscCall(PetscOptionsGetBool(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matload_symmetric", &flg, NULL));
1413   if (flg) {
1414     PetscCall(MatSetOption(mat, MAT_SYMMETRIC, PETSC_TRUE));
1415     PetscCall(MatSetOption(mat, MAT_SYMMETRY_ETERNAL, PETSC_TRUE));
1416   }
1417   flg = PETSC_FALSE;
1418   PetscCall(PetscOptionsGetBool(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matload_spd", &flg, NULL));
1419   if (flg) PetscCall(MatSetOption(mat, MAT_SPD, PETSC_TRUE));
1420 
1421   PetscCall(PetscLogEventBegin(MAT_Load, mat, viewer, 0, 0));
1422   PetscUseTypeMethod(mat, load, viewer);
1423   PetscCall(PetscLogEventEnd(MAT_Load, mat, viewer, 0, 0));
1424   PetscFunctionReturn(PETSC_SUCCESS);
1425 }
1426 
1427 static PetscErrorCode MatDestroy_Redundant(Mat_Redundant **redundant)
1428 {
1429   Mat_Redundant *redund = *redundant;
1430 
1431   PetscFunctionBegin;
1432   if (redund) {
1433     if (redund->matseq) { /* via MatCreateSubMatrices()  */
1434       PetscCall(ISDestroy(&redund->isrow));
1435       PetscCall(ISDestroy(&redund->iscol));
1436       PetscCall(MatDestroySubMatrices(1, &redund->matseq));
1437     } else {
1438       PetscCall(PetscFree2(redund->send_rank, redund->recv_rank));
1439       PetscCall(PetscFree(redund->sbuf_j));
1440       PetscCall(PetscFree(redund->sbuf_a));
1441       for (PetscInt i = 0; i < redund->nrecvs; i++) {
1442         PetscCall(PetscFree(redund->rbuf_j[i]));
1443         PetscCall(PetscFree(redund->rbuf_a[i]));
1444       }
1445       PetscCall(PetscFree4(redund->sbuf_nz, redund->rbuf_nz, redund->rbuf_j, redund->rbuf_a));
1446     }
1447 
1448     if (redund->subcomm) PetscCall(PetscCommDestroy(&redund->subcomm));
1449     PetscCall(PetscFree(redund));
1450   }
1451   PetscFunctionReturn(PETSC_SUCCESS);
1452 }
1453 
1454 /*@
1455   MatDestroy - Frees space taken by a matrix.
1456 
1457   Collective
1458 
1459   Input Parameter:
1460 . A - the matrix
1461 
1462   Level: beginner
1463 
1464   Developer Note:
1465   Some special arrays of matrices are not destroyed in this routine but instead by the routines called by
1466   `MatDestroySubMatrices()`. Thus one must be sure that any changes here must also be made in those routines.
1467   `MatHeaderMerge()` and `MatHeaderReplace()` also manipulate the data in the `Mat` object and likely need changes
1468   if changes are needed here.
1469 
1470 .seealso: [](ch_matrices), `Mat`, `MatCreate()`
1471 @*/
1472 PetscErrorCode MatDestroy(Mat *A)
1473 {
1474   PetscFunctionBegin;
1475   if (!*A) PetscFunctionReturn(PETSC_SUCCESS);
1476   PetscValidHeaderSpecific(*A, MAT_CLASSID, 1);
1477   if (--((PetscObject)*A)->refct > 0) {
1478     *A = NULL;
1479     PetscFunctionReturn(PETSC_SUCCESS);
1480   }
1481 
1482   /* if memory was published with SAWs then destroy it */
1483   PetscCall(PetscObjectSAWsViewOff((PetscObject)*A));
1484   PetscTryTypeMethod(*A, destroy);
1485 
1486   PetscCall(PetscFree((*A)->factorprefix));
1487   PetscCall(PetscFree((*A)->defaultvectype));
1488   PetscCall(PetscFree((*A)->defaultrandtype));
1489   PetscCall(PetscFree((*A)->bsizes));
1490   PetscCall(PetscFree((*A)->solvertype));
1491   for (PetscInt i = 0; i < MAT_FACTOR_NUM_TYPES; i++) PetscCall(PetscFree((*A)->preferredordering[i]));
1492   if ((*A)->redundant && (*A)->redundant->matseq[0] == *A) (*A)->redundant->matseq[0] = NULL;
1493   PetscCall(MatDestroy_Redundant(&(*A)->redundant));
1494   PetscCall(MatProductClear(*A));
1495   PetscCall(MatNullSpaceDestroy(&(*A)->nullsp));
1496   PetscCall(MatNullSpaceDestroy(&(*A)->transnullsp));
1497   PetscCall(MatNullSpaceDestroy(&(*A)->nearnullsp));
1498   PetscCall(MatDestroy(&(*A)->schur));
1499   PetscCall(PetscLayoutDestroy(&(*A)->rmap));
1500   PetscCall(PetscLayoutDestroy(&(*A)->cmap));
1501   PetscCall(PetscHeaderDestroy(A));
1502   PetscFunctionReturn(PETSC_SUCCESS);
1503 }
1504 
1505 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1506 /*@
1507   MatSetValues - Inserts or adds a block of values into a matrix.
1508   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
1509   MUST be called after all calls to `MatSetValues()` have been completed.
1510 
1511   Not Collective
1512 
1513   Input Parameters:
1514 + mat  - the matrix
1515 . v    - a logically two-dimensional array of values
1516 . m    - the number of rows
1517 . idxm - the global indices of the rows
1518 . n    - the number of columns
1519 . idxn - the global indices of the columns
1520 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
1521 
1522   Level: beginner
1523 
1524   Notes:
1525   By default the values, `v`, are stored row-oriented. See `MatSetOption()` for other options.
1526 
1527   Calls to `MatSetValues()` with the `INSERT_VALUES` and `ADD_VALUES`
1528   options cannot be mixed without intervening calls to the assembly
1529   routines.
1530 
1531   `MatSetValues()` uses 0-based row and column numbers in Fortran
1532   as well as in C.
1533 
1534   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
1535   simply ignored. This allows easily inserting element stiffness matrices
1536   with homogeneous Dirichlet boundary conditions that you don't want represented
1537   in the matrix.
1538 
1539   Efficiency Alert:
1540   The routine `MatSetValuesBlocked()` may offer much better efficiency
1541   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1542 
1543   Fortran Notes:
1544   If any of `idxm`, `idxn`, and `v` are scalars pass them using, for example,
1545 .vb
1546   call MatSetValues(mat, one, [idxm], one, [idxn], [v], INSERT_VALUES, ierr)
1547 .ve
1548 
1549   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
1550 
1551   Developer Note:
1552   This is labeled with C so does not automatically generate Fortran stubs and interfaces
1553   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
1554 
1555 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1556           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1557 @*/
1558 PetscErrorCode MatSetValues(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar v[], InsertMode addv)
1559 {
1560   PetscFunctionBeginHot;
1561   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1562   PetscValidType(mat, 1);
1563   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1564   PetscAssertPointer(idxm, 3);
1565   PetscAssertPointer(idxn, 5);
1566   MatCheckPreallocated(mat, 1);
1567 
1568   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
1569   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
1570 
1571   if (PetscDefined(USE_DEBUG)) {
1572     PetscInt i, j;
1573 
1574     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1575     if (v) {
1576       for (i = 0; i < m; i++) {
1577         for (j = 0; j < n; j++) {
1578           if (mat->erroriffailure && PetscIsInfOrNanScalar(v[i * n + j]))
1579 #if defined(PETSC_USE_COMPLEX)
1580             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]);
1581 #else
1582             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]);
1583 #endif
1584         }
1585       }
1586     }
1587     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);
1588     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);
1589   }
1590 
1591   if (mat->assembled) {
1592     mat->was_assembled = PETSC_TRUE;
1593     mat->assembled     = PETSC_FALSE;
1594   }
1595   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
1596   PetscUseTypeMethod(mat, setvalues, m, idxm, n, idxn, v, addv);
1597   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
1598   PetscFunctionReturn(PETSC_SUCCESS);
1599 }
1600 
1601 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1602 /*@
1603   MatSetValuesIS - Inserts or adds a block of values into a matrix using an `IS` to indicate the rows and columns
1604   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
1605   MUST be called after all calls to `MatSetValues()` have been completed.
1606 
1607   Not Collective
1608 
1609   Input Parameters:
1610 + mat  - the matrix
1611 . v    - a logically two-dimensional array of values
1612 . ism  - the rows to provide
1613 . isn  - the columns to provide
1614 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
1615 
1616   Level: beginner
1617 
1618   Notes:
1619   By default the values, `v`, are stored row-oriented. See `MatSetOption()` for other options.
1620 
1621   Calls to `MatSetValues()` with the `INSERT_VALUES` and `ADD_VALUES`
1622   options cannot be mixed without intervening calls to the assembly
1623   routines.
1624 
1625   `MatSetValues()` uses 0-based row and column numbers in Fortran
1626   as well as in C.
1627 
1628   Negative indices may be passed in `ism` and `isn`, these rows and columns are
1629   simply ignored. This allows easily inserting element stiffness matrices
1630   with homogeneous Dirichlet boundary conditions that you don't want represented
1631   in the matrix.
1632 
1633   Efficiency Alert:
1634   The routine `MatSetValuesBlocked()` may offer much better efficiency
1635   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1636 
1637   This is currently not optimized for any particular `ISType`
1638 
1639   Developer Note:
1640   This is labeled with C so does not automatically generate Fortran stubs and interfaces
1641   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
1642 
1643 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatSetValues()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1644           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1645 @*/
1646 PetscErrorCode MatSetValuesIS(Mat mat, IS ism, IS isn, const PetscScalar v[], InsertMode addv)
1647 {
1648   PetscInt        m, n;
1649   const PetscInt *rows, *cols;
1650 
1651   PetscFunctionBeginHot;
1652   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1653   PetscCall(ISGetIndices(ism, &rows));
1654   PetscCall(ISGetIndices(isn, &cols));
1655   PetscCall(ISGetLocalSize(ism, &m));
1656   PetscCall(ISGetLocalSize(isn, &n));
1657   PetscCall(MatSetValues(mat, m, rows, n, cols, v, addv));
1658   PetscCall(ISRestoreIndices(ism, &rows));
1659   PetscCall(ISRestoreIndices(isn, &cols));
1660   PetscFunctionReturn(PETSC_SUCCESS);
1661 }
1662 
1663 /*@
1664   MatSetValuesRowLocal - Inserts a row (block row for `MATBAIJ` matrices) of nonzero
1665   values into a matrix
1666 
1667   Not Collective
1668 
1669   Input Parameters:
1670 + mat - the matrix
1671 . row - the (block) row to set
1672 - v   - a logically two-dimensional array of values
1673 
1674   Level: intermediate
1675 
1676   Notes:
1677   The values, `v`, are column-oriented (for the block version) and sorted
1678 
1679   All the nonzero values in `row` must be provided
1680 
1681   The matrix must have previously had its column indices set, likely by having been assembled.
1682 
1683   `row` must belong to this MPI process
1684 
1685 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1686           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`, `MatSetValues()`, `MatSetValuesRow()`, `MatSetLocalToGlobalMapping()`
1687 @*/
1688 PetscErrorCode MatSetValuesRowLocal(Mat mat, PetscInt row, const PetscScalar v[])
1689 {
1690   PetscInt globalrow;
1691 
1692   PetscFunctionBegin;
1693   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1694   PetscValidType(mat, 1);
1695   PetscAssertPointer(v, 3);
1696   PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, 1, &row, &globalrow));
1697   PetscCall(MatSetValuesRow(mat, globalrow, v));
1698   PetscFunctionReturn(PETSC_SUCCESS);
1699 }
1700 
1701 /*@
1702   MatSetValuesRow - Inserts a row (block row for `MATBAIJ` matrices) of nonzero
1703   values into a matrix
1704 
1705   Not Collective
1706 
1707   Input Parameters:
1708 + mat - the matrix
1709 . row - the (block) row to set
1710 - 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
1711 
1712   Level: advanced
1713 
1714   Notes:
1715   The values, `v`, are column-oriented for the block version.
1716 
1717   All the nonzeros in `row` must be provided
1718 
1719   THE MATRIX MUST HAVE PREVIOUSLY HAD ITS COLUMN INDICES SET. IT IS RARE THAT THIS ROUTINE IS USED, usually `MatSetValues()` is used.
1720 
1721   `row` must belong to this process
1722 
1723 .seealso: [](ch_matrices), `Mat`, `MatSetValues()`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1724           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1725 @*/
1726 PetscErrorCode MatSetValuesRow(Mat mat, PetscInt row, const PetscScalar v[])
1727 {
1728   PetscFunctionBeginHot;
1729   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1730   PetscValidType(mat, 1);
1731   MatCheckPreallocated(mat, 1);
1732   PetscAssertPointer(v, 3);
1733   PetscCheck(mat->insertmode != ADD_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add and insert values");
1734   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1735   mat->insertmode = INSERT_VALUES;
1736 
1737   if (mat->assembled) {
1738     mat->was_assembled = PETSC_TRUE;
1739     mat->assembled     = PETSC_FALSE;
1740   }
1741   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
1742   PetscUseTypeMethod(mat, setvaluesrow, row, v);
1743   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
1744   PetscFunctionReturn(PETSC_SUCCESS);
1745 }
1746 
1747 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1748 /*@
1749   MatSetValuesStencil - Inserts or adds a block of values into a matrix.
1750   Using structured grid indexing
1751 
1752   Not Collective
1753 
1754   Input Parameters:
1755 + mat  - the matrix
1756 . m    - number of rows being entered
1757 . idxm - grid coordinates (and component number when dof > 1) for matrix rows being entered
1758 . n    - number of columns being entered
1759 . idxn - grid coordinates (and component number when dof > 1) for matrix columns being entered
1760 . v    - a logically two-dimensional array of values
1761 - addv - either `ADD_VALUES` to add to existing entries at that location or `INSERT_VALUES` to replace existing entries with new values
1762 
1763   Level: beginner
1764 
1765   Notes:
1766   By default the values, `v`, are row-oriented.  See `MatSetOption()` for other options.
1767 
1768   Calls to `MatSetValuesStencil()` with the `INSERT_VALUES` and `ADD_VALUES`
1769   options cannot be mixed without intervening calls to the assembly
1770   routines.
1771 
1772   The grid coordinates are across the entire grid, not just the local portion
1773 
1774   `MatSetValuesStencil()` uses 0-based row and column numbers in Fortran
1775   as well as in C.
1776 
1777   For setting/accessing vector values via array coordinates you can use the `DMDAVecGetArray()` routine
1778 
1779   In order to use this routine you must either obtain the matrix with `DMCreateMatrix()`
1780   or call `MatSetLocalToGlobalMapping()` and `MatSetStencil()` first.
1781 
1782   The columns and rows in the stencil passed in MUST be contained within the
1783   ghost region of the given process as set with DMDACreateXXX() or `MatSetStencil()`. For example,
1784   if you create a `DMDA` with an overlap of one grid level and on a particular process its first
1785   local nonghost x logical coordinate is 6 (so its first ghost x logical coordinate is 5) the
1786   first i index you can use in your column and row indices in `MatSetStencil()` is 5.
1787 
1788   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
1789   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
1790   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
1791   `DM_BOUNDARY_PERIODIC` boundary type.
1792 
1793   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
1794   a single value per point) you can skip filling those indices.
1795 
1796   Inspired by the structured grid interface to the HYPRE package
1797   (https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods)
1798 
1799   Efficiency Alert:
1800   The routine `MatSetValuesBlockedStencil()` may offer much better efficiency
1801   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1802 
1803 .seealso: [](ch_matrices), `Mat`, `DMDA`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1804           `MatSetValues()`, `MatSetValuesBlockedStencil()`, `MatSetStencil()`, `DMCreateMatrix()`, `DMDAVecGetArray()`, `MatStencil`
1805 @*/
1806 PetscErrorCode MatSetValuesStencil(Mat mat, PetscInt m, const MatStencil idxm[], PetscInt n, const MatStencil idxn[], const PetscScalar v[], InsertMode addv)
1807 {
1808   PetscInt  buf[8192], *bufm = NULL, *bufn = NULL, *jdxm, *jdxn;
1809   PetscInt  j, i, dim = mat->stencil.dim, *dims = mat->stencil.dims + 1, tmp;
1810   PetscInt *starts = mat->stencil.starts, *dxm = (PetscInt *)idxm, *dxn = (PetscInt *)idxn, sdim = dim - (1 - (PetscInt)mat->stencil.noc);
1811 
1812   PetscFunctionBegin;
1813   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1814   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1815   PetscValidType(mat, 1);
1816   PetscAssertPointer(idxm, 3);
1817   PetscAssertPointer(idxn, 5);
1818 
1819   if ((m + n) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
1820     jdxm = buf;
1821     jdxn = buf + m;
1822   } else {
1823     PetscCall(PetscMalloc2(m, &bufm, n, &bufn));
1824     jdxm = bufm;
1825     jdxn = bufn;
1826   }
1827   for (i = 0; i < m; i++) {
1828     for (j = 0; j < 3 - sdim; j++) dxm++;
1829     tmp = *dxm++ - starts[0];
1830     for (j = 0; j < dim - 1; j++) {
1831       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1832       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
1833     }
1834     if (mat->stencil.noc) dxm++;
1835     jdxm[i] = tmp;
1836   }
1837   for (i = 0; i < n; i++) {
1838     for (j = 0; j < 3 - sdim; j++) dxn++;
1839     tmp = *dxn++ - starts[0];
1840     for (j = 0; j < dim - 1; j++) {
1841       if ((*dxn++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1842       else tmp = tmp * dims[j] + *(dxn - 1) - starts[j + 1];
1843     }
1844     if (mat->stencil.noc) dxn++;
1845     jdxn[i] = tmp;
1846   }
1847   PetscCall(MatSetValuesLocal(mat, m, jdxm, n, jdxn, v, addv));
1848   PetscCall(PetscFree2(bufm, bufn));
1849   PetscFunctionReturn(PETSC_SUCCESS);
1850 }
1851 
1852 /*@
1853   MatSetValuesBlockedStencil - Inserts or adds a block of values into a matrix.
1854   Using structured grid indexing
1855 
1856   Not Collective
1857 
1858   Input Parameters:
1859 + mat  - the matrix
1860 . m    - number of rows being entered
1861 . idxm - grid coordinates for matrix rows being entered
1862 . n    - number of columns being entered
1863 . idxn - grid coordinates for matrix columns being entered
1864 . v    - a logically two-dimensional array of values
1865 - addv - either `ADD_VALUES` to add to existing entries or `INSERT_VALUES` to replace existing entries with new values
1866 
1867   Level: beginner
1868 
1869   Notes:
1870   By default the values, `v`, are row-oriented and unsorted.
1871   See `MatSetOption()` for other options.
1872 
1873   Calls to `MatSetValuesBlockedStencil()` with the `INSERT_VALUES` and `ADD_VALUES`
1874   options cannot be mixed without intervening calls to the assembly
1875   routines.
1876 
1877   The grid coordinates are across the entire grid, not just the local portion
1878 
1879   `MatSetValuesBlockedStencil()` uses 0-based row and column numbers in Fortran
1880   as well as in C.
1881 
1882   For setting/accessing vector values via array coordinates you can use the `DMDAVecGetArray()` routine
1883 
1884   In order to use this routine you must either obtain the matrix with `DMCreateMatrix()`
1885   or call `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()` and `MatSetStencil()` first.
1886 
1887   The columns and rows in the stencil passed in MUST be contained within the
1888   ghost region of the given process as set with DMDACreateXXX() or `MatSetStencil()`. For example,
1889   if you create a `DMDA` with an overlap of one grid level and on a particular process its first
1890   local nonghost x logical coordinate is 6 (so its first ghost x logical coordinate is 5) the
1891   first i index you can use in your column and row indices in `MatSetStencil()` is 5.
1892 
1893   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
1894   simply ignored. This allows easily inserting element stiffness matrices
1895   with homogeneous Dirichlet boundary conditions that you don't want represented
1896   in the matrix.
1897 
1898   Inspired by the structured grid interface to the HYPRE package
1899   (https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods)
1900 
1901   Fortran Note:
1902   `idxm` and `idxn` should be declared as
1903 .vb
1904     MatStencil idxm(4,m),idxn(4,n)
1905 .ve
1906   and the values inserted using
1907 .vb
1908     idxm(MatStencil_i,1) = i
1909     idxm(MatStencil_j,1) = j
1910     idxm(MatStencil_k,1) = k
1911    etc
1912 .ve
1913 
1914 .seealso: [](ch_matrices), `Mat`, `DMDA`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1915           `MatSetValues()`, `MatSetValuesStencil()`, `MatSetStencil()`, `DMCreateMatrix()`, `DMDAVecGetArray()`, `MatStencil`,
1916           `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()`
1917 @*/
1918 PetscErrorCode MatSetValuesBlockedStencil(Mat mat, PetscInt m, const MatStencil idxm[], PetscInt n, const MatStencil idxn[], const PetscScalar v[], InsertMode addv)
1919 {
1920   PetscInt  buf[8192], *bufm = NULL, *bufn = NULL, *jdxm, *jdxn;
1921   PetscInt  j, i, dim = mat->stencil.dim, *dims = mat->stencil.dims + 1, tmp;
1922   PetscInt *starts = mat->stencil.starts, *dxm = (PetscInt *)idxm, *dxn = (PetscInt *)idxn, sdim = dim - (1 - (PetscInt)mat->stencil.noc);
1923 
1924   PetscFunctionBegin;
1925   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1926   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1927   PetscValidType(mat, 1);
1928   PetscAssertPointer(idxm, 3);
1929   PetscAssertPointer(idxn, 5);
1930   PetscAssertPointer(v, 6);
1931 
1932   if ((m + n) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
1933     jdxm = buf;
1934     jdxn = buf + m;
1935   } else {
1936     PetscCall(PetscMalloc2(m, &bufm, n, &bufn));
1937     jdxm = bufm;
1938     jdxn = bufn;
1939   }
1940   for (i = 0; i < m; i++) {
1941     for (j = 0; j < 3 - sdim; j++) dxm++;
1942     tmp = *dxm++ - starts[0];
1943     for (j = 0; j < sdim - 1; j++) {
1944       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1945       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
1946     }
1947     dxm++;
1948     jdxm[i] = tmp;
1949   }
1950   for (i = 0; i < n; i++) {
1951     for (j = 0; j < 3 - sdim; j++) dxn++;
1952     tmp = *dxn++ - starts[0];
1953     for (j = 0; j < sdim - 1; j++) {
1954       if ((*dxn++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1955       else tmp = tmp * dims[j] + *(dxn - 1) - starts[j + 1];
1956     }
1957     dxn++;
1958     jdxn[i] = tmp;
1959   }
1960   PetscCall(MatSetValuesBlockedLocal(mat, m, jdxm, n, jdxn, v, addv));
1961   PetscCall(PetscFree2(bufm, bufn));
1962   PetscFunctionReturn(PETSC_SUCCESS);
1963 }
1964 
1965 /*@
1966   MatSetStencil - Sets the grid information for setting values into a matrix via
1967   `MatSetValuesStencil()`
1968 
1969   Not Collective
1970 
1971   Input Parameters:
1972 + mat    - the matrix
1973 . dim    - dimension of the grid 1, 2, or 3
1974 . dims   - number of grid points in x, y, and z direction, including ghost points on your processor
1975 . starts - starting point of ghost nodes on your processor in x, y, and z direction
1976 - dof    - number of degrees of freedom per node
1977 
1978   Level: beginner
1979 
1980   Notes:
1981   Inspired by the structured grid interface to the HYPRE package
1982   (www.llnl.gov/CASC/hyper)
1983 
1984   For matrices generated with `DMCreateMatrix()` this routine is automatically called and so not needed by the
1985   user.
1986 
1987 .seealso: [](ch_matrices), `Mat`, `MatStencil`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1988           `MatSetValues()`, `MatSetValuesBlockedStencil()`, `MatSetValuesStencil()`
1989 @*/
1990 PetscErrorCode MatSetStencil(Mat mat, PetscInt dim, const PetscInt dims[], const PetscInt starts[], PetscInt dof)
1991 {
1992   PetscFunctionBegin;
1993   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1994   PetscAssertPointer(dims, 3);
1995   PetscAssertPointer(starts, 4);
1996 
1997   mat->stencil.dim = dim + (dof > 1);
1998   for (PetscInt i = 0; i < dim; i++) {
1999     mat->stencil.dims[i]   = dims[dim - i - 1]; /* copy the values in backwards */
2000     mat->stencil.starts[i] = starts[dim - i - 1];
2001   }
2002   mat->stencil.dims[dim]   = dof;
2003   mat->stencil.starts[dim] = 0;
2004   mat->stencil.noc         = (PetscBool)(dof == 1);
2005   PetscFunctionReturn(PETSC_SUCCESS);
2006 }
2007 
2008 /*@
2009   MatSetValuesBlocked - Inserts or adds a block of values into a matrix.
2010 
2011   Not Collective
2012 
2013   Input Parameters:
2014 + mat  - the matrix
2015 . v    - a logically two-dimensional array of values
2016 . m    - the number of block rows
2017 . idxm - the global block indices
2018 . n    - the number of block columns
2019 . idxn - the global block indices
2020 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` replaces existing entries with new values
2021 
2022   Level: intermediate
2023 
2024   Notes:
2025   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call
2026   MatXXXXSetPreallocation() or `MatSetUp()` before using this routine.
2027 
2028   The `m` and `n` count the NUMBER of blocks in the row direction and column direction,
2029   NOT the total number of rows/columns; for example, if the block size is 2 and
2030   you are passing in values for rows 2,3,4,5  then `m` would be 2 (not 4).
2031   The values in `idxm` would be 1 2; that is the first index for each block divided by
2032   the block size.
2033 
2034   You must call `MatSetBlockSize()` when constructing this matrix (before
2035   preallocating it).
2036 
2037   By default the values, `v`, are row-oriented, so the layout of
2038   `v` is the same as for `MatSetValues()`. See `MatSetOption()` for other options.
2039 
2040   Calls to `MatSetValuesBlocked()` with the `INSERT_VALUES` and `ADD_VALUES`
2041   options cannot be mixed without intervening calls to the assembly
2042   routines.
2043 
2044   `MatSetValuesBlocked()` uses 0-based row and column numbers in Fortran
2045   as well as in C.
2046 
2047   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
2048   simply ignored. This allows easily inserting element stiffness matrices
2049   with homogeneous Dirichlet boundary conditions that you don't want represented
2050   in the matrix.
2051 
2052   Each time an entry is set within a sparse matrix via `MatSetValues()`,
2053   internal searching must be done to determine where to place the
2054   data in the matrix storage space.  By instead inserting blocks of
2055   entries via `MatSetValuesBlocked()`, the overhead of matrix assembly is
2056   reduced.
2057 
2058   Example:
2059 .vb
2060    Suppose m=n=2 and block size(bs) = 2 The array is
2061 
2062    1  2  | 3  4
2063    5  6  | 7  8
2064    - - - | - - -
2065    9  10 | 11 12
2066    13 14 | 15 16
2067 
2068    v[] should be passed in like
2069    v[] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
2070 
2071   If you are not using row-oriented storage of v (that is you called MatSetOption(mat,MAT_ROW_ORIENTED,PETSC_FALSE)) then
2072    v[] = [1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16]
2073 .ve
2074 
2075   Fortran Notes:
2076   If any of `idmx`, `idxn`, and `v` are scalars pass them using, for example,
2077 .vb
2078   call MatSetValuesBlocked(mat, one, [idxm], one, [idxn], [v], INSERT_VALUES, ierr)
2079 .ve
2080 
2081   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2082 
2083 .seealso: [](ch_matrices), `Mat`, `MatSetBlockSize()`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetValuesBlockedLocal()`
2084 @*/
2085 PetscErrorCode MatSetValuesBlocked(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar v[], InsertMode addv)
2086 {
2087   PetscFunctionBeginHot;
2088   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2089   PetscValidType(mat, 1);
2090   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2091   PetscAssertPointer(idxm, 3);
2092   PetscAssertPointer(idxn, 5);
2093   MatCheckPreallocated(mat, 1);
2094   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2095   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2096   if (PetscDefined(USE_DEBUG)) {
2097     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2098     PetscCheck(mat->ops->setvaluesblocked || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2099   }
2100   if (PetscDefined(USE_DEBUG)) {
2101     PetscInt rbs, cbs, M, N, i;
2102     PetscCall(MatGetBlockSizes(mat, &rbs, &cbs));
2103     PetscCall(MatGetSize(mat, &M, &N));
2104     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);
2105     for (i = 0; i < n; i++)
2106       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);
2107   }
2108   if (mat->assembled) {
2109     mat->was_assembled = PETSC_TRUE;
2110     mat->assembled     = PETSC_FALSE;
2111   }
2112   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2113   if (mat->ops->setvaluesblocked) {
2114     PetscUseTypeMethod(mat, setvaluesblocked, m, idxm, n, idxn, v, addv);
2115   } else {
2116     PetscInt buf[8192], *bufr = NULL, *bufc = NULL, *iidxm, *iidxn;
2117     PetscInt i, j, bs, cbs;
2118 
2119     PetscCall(MatGetBlockSizes(mat, &bs, &cbs));
2120     if ((m * bs + n * cbs) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2121       iidxm = buf;
2122       iidxn = buf + m * bs;
2123     } else {
2124       PetscCall(PetscMalloc2(m * bs, &bufr, n * cbs, &bufc));
2125       iidxm = bufr;
2126       iidxn = bufc;
2127     }
2128     for (i = 0; i < m; i++) {
2129       for (j = 0; j < bs; j++) iidxm[i * bs + j] = bs * idxm[i] + j;
2130     }
2131     if (m != n || bs != cbs || idxm != idxn) {
2132       for (i = 0; i < n; i++) {
2133         for (j = 0; j < cbs; j++) iidxn[i * cbs + j] = cbs * idxn[i] + j;
2134       }
2135     } else iidxn = iidxm;
2136     PetscCall(MatSetValues(mat, m * bs, iidxm, n * cbs, iidxn, v, addv));
2137     PetscCall(PetscFree2(bufr, bufc));
2138   }
2139   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2140   PetscFunctionReturn(PETSC_SUCCESS);
2141 }
2142 
2143 /*@
2144   MatGetValues - Gets a block of local values from a matrix.
2145 
2146   Not Collective; can only return values that are owned by the give process
2147 
2148   Input Parameters:
2149 + mat  - the matrix
2150 . v    - a logically two-dimensional array for storing the values
2151 . m    - the number of rows
2152 . idxm - the  global indices of the rows
2153 . n    - the number of columns
2154 - idxn - the global indices of the columns
2155 
2156   Level: advanced
2157 
2158   Notes:
2159   The user must allocate space (m*n `PetscScalar`s) for the values, `v`.
2160   The values, `v`, are then returned in a row-oriented format,
2161   analogous to that used by default in `MatSetValues()`.
2162 
2163   `MatGetValues()` uses 0-based row and column numbers in
2164   Fortran as well as in C.
2165 
2166   `MatGetValues()` requires that the matrix has been assembled
2167   with `MatAssemblyBegin()`/`MatAssemblyEnd()`.  Thus, calls to
2168   `MatSetValues()` and `MatGetValues()` CANNOT be made in succession
2169   without intermediate matrix assembly.
2170 
2171   Negative row or column indices will be ignored and those locations in `v` will be
2172   left unchanged.
2173 
2174   For the standard row-based matrix formats, `idxm` can only contain rows owned by the requesting MPI process.
2175   That is, rows with global index greater than or equal to rstart and less than rend where rstart and rend are obtainable
2176   from `MatGetOwnershipRange`(mat,&rstart,&rend).
2177 
2178 .seealso: [](ch_matrices), `Mat`, `MatGetRow()`, `MatCreateSubMatrices()`, `MatSetValues()`, `MatGetOwnershipRange()`, `MatGetValuesLocal()`, `MatGetValue()`
2179 @*/
2180 PetscErrorCode MatGetValues(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], PetscScalar v[])
2181 {
2182   PetscFunctionBegin;
2183   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2184   PetscValidType(mat, 1);
2185   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS);
2186   PetscAssertPointer(idxm, 3);
2187   PetscAssertPointer(idxn, 5);
2188   PetscAssertPointer(v, 6);
2189   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2190   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2191   MatCheckPreallocated(mat, 1);
2192 
2193   PetscCall(PetscLogEventBegin(MAT_GetValues, mat, 0, 0, 0));
2194   PetscUseTypeMethod(mat, getvalues, m, idxm, n, idxn, v);
2195   PetscCall(PetscLogEventEnd(MAT_GetValues, mat, 0, 0, 0));
2196   PetscFunctionReturn(PETSC_SUCCESS);
2197 }
2198 
2199 /*@
2200   MatGetValuesLocal - retrieves values from certain locations in a matrix using the local numbering of the indices
2201   defined previously by `MatSetLocalToGlobalMapping()`
2202 
2203   Not Collective
2204 
2205   Input Parameters:
2206 + mat  - the matrix
2207 . nrow - number of rows
2208 . irow - the row local indices
2209 . ncol - number of columns
2210 - icol - the column local indices
2211 
2212   Output Parameter:
2213 . y - a logically two-dimensional array of values
2214 
2215   Level: advanced
2216 
2217   Notes:
2218   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetLocalToGlobalMapping()` before using this routine.
2219 
2220   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,
2221   are greater than or equal to rstart and less than rend where rstart and rend are obtainable from `MatGetOwnershipRange`(mat,&rstart,&rend). One can
2222   determine if the resulting global row associated with the local row r is owned by the requesting MPI process by applying the `ISLocalToGlobalMapping` set
2223   with `MatSetLocalToGlobalMapping()`.
2224 
2225   Developer Note:
2226   This is labelled with C so does not automatically generate Fortran stubs and interfaces
2227   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
2228 
2229 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetLocalToGlobalMapping()`,
2230           `MatSetValuesLocal()`, `MatGetValues()`
2231 @*/
2232 PetscErrorCode MatGetValuesLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], PetscScalar y[])
2233 {
2234   PetscFunctionBeginHot;
2235   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2236   PetscValidType(mat, 1);
2237   MatCheckPreallocated(mat, 1);
2238   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to retrieve */
2239   PetscAssertPointer(irow, 3);
2240   PetscAssertPointer(icol, 5);
2241   if (PetscDefined(USE_DEBUG)) {
2242     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2243     PetscCheck(mat->ops->getvalueslocal || mat->ops->getvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2244   }
2245   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2246   PetscCall(PetscLogEventBegin(MAT_GetValues, mat, 0, 0, 0));
2247   if (mat->ops->getvalueslocal) PetscUseTypeMethod(mat, getvalueslocal, nrow, irow, ncol, icol, y);
2248   else {
2249     PetscInt buf[8192], *bufr = NULL, *bufc = NULL, *irowm, *icolm;
2250     if ((nrow + ncol) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2251       irowm = buf;
2252       icolm = buf + nrow;
2253     } else {
2254       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2255       irowm = bufr;
2256       icolm = bufc;
2257     }
2258     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MatGetValuesLocal() cannot proceed without local-to-global row mapping (See MatSetLocalToGlobalMapping()).");
2259     PetscCheck(mat->cmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MatGetValuesLocal() cannot proceed without local-to-global column mapping (See MatSetLocalToGlobalMapping()).");
2260     PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, nrow, irow, irowm));
2261     PetscCall(ISLocalToGlobalMappingApply(mat->cmap->mapping, ncol, icol, icolm));
2262     PetscCall(MatGetValues(mat, nrow, irowm, ncol, icolm, y));
2263     PetscCall(PetscFree2(bufr, bufc));
2264   }
2265   PetscCall(PetscLogEventEnd(MAT_GetValues, mat, 0, 0, 0));
2266   PetscFunctionReturn(PETSC_SUCCESS);
2267 }
2268 
2269 /*@
2270   MatSetValuesBatch - Adds (`ADD_VALUES`) many blocks of values into a matrix at once. The blocks must all be square and
2271   the same size. Currently, this can only be called once and creates the given matrix.
2272 
2273   Not Collective
2274 
2275   Input Parameters:
2276 + mat  - the matrix
2277 . nb   - the number of blocks
2278 . bs   - the number of rows (and columns) in each block
2279 . rows - a concatenation of the rows for each block
2280 - v    - a concatenation of logically two-dimensional arrays of values
2281 
2282   Level: advanced
2283 
2284   Notes:
2285   `MatSetPreallocationCOO()` and `MatSetValuesCOO()` may be a better way to provide the values
2286 
2287   In the future, we will extend this routine to handle rectangular blocks, and to allow multiple calls for a given matrix.
2288 
2289 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
2290           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`, `MatSetValues()`, `MatSetPreallocationCOO()`, `MatSetValuesCOO()`
2291 @*/
2292 PetscErrorCode MatSetValuesBatch(Mat mat, PetscInt nb, PetscInt bs, PetscInt rows[], const PetscScalar v[])
2293 {
2294   PetscFunctionBegin;
2295   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2296   PetscValidType(mat, 1);
2297   PetscAssertPointer(rows, 4);
2298   PetscAssertPointer(v, 5);
2299   PetscAssert(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2300 
2301   PetscCall(PetscLogEventBegin(MAT_SetValuesBatch, mat, 0, 0, 0));
2302   if (mat->ops->setvaluesbatch) PetscUseTypeMethod(mat, setvaluesbatch, nb, bs, rows, v);
2303   else {
2304     for (PetscInt b = 0; b < nb; ++b) PetscCall(MatSetValues(mat, bs, &rows[b * bs], bs, &rows[b * bs], &v[b * bs * bs], ADD_VALUES));
2305   }
2306   PetscCall(PetscLogEventEnd(MAT_SetValuesBatch, mat, 0, 0, 0));
2307   PetscFunctionReturn(PETSC_SUCCESS);
2308 }
2309 
2310 /*@
2311   MatSetLocalToGlobalMapping - Sets a local-to-global numbering for use by
2312   the routine `MatSetValuesLocal()` to allow users to insert matrix entries
2313   using a local (per-processor) numbering.
2314 
2315   Not Collective
2316 
2317   Input Parameters:
2318 + x        - the matrix
2319 . rmapping - row mapping created with `ISLocalToGlobalMappingCreate()` or `ISLocalToGlobalMappingCreateIS()`
2320 - cmapping - column mapping
2321 
2322   Level: intermediate
2323 
2324   Note:
2325   If the matrix is obtained with `DMCreateMatrix()` then this may already have been called on the matrix
2326 
2327 .seealso: [](ch_matrices), `Mat`, `DM`, `DMCreateMatrix()`, `MatGetLocalToGlobalMapping()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetValuesLocal()`, `MatGetValuesLocal()`
2328 @*/
2329 PetscErrorCode MatSetLocalToGlobalMapping(Mat x, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2330 {
2331   PetscFunctionBegin;
2332   PetscValidHeaderSpecific(x, MAT_CLASSID, 1);
2333   PetscValidType(x, 1);
2334   if (rmapping) PetscValidHeaderSpecific(rmapping, IS_LTOGM_CLASSID, 2);
2335   if (cmapping) PetscValidHeaderSpecific(cmapping, IS_LTOGM_CLASSID, 3);
2336   if (x->ops->setlocaltoglobalmapping) PetscUseTypeMethod(x, setlocaltoglobalmapping, rmapping, cmapping);
2337   else {
2338     PetscCall(PetscLayoutSetISLocalToGlobalMapping(x->rmap, rmapping));
2339     PetscCall(PetscLayoutSetISLocalToGlobalMapping(x->cmap, cmapping));
2340   }
2341   PetscFunctionReturn(PETSC_SUCCESS);
2342 }
2343 
2344 /*@
2345   MatGetLocalToGlobalMapping - Gets the local-to-global numbering set by `MatSetLocalToGlobalMapping()`
2346 
2347   Not Collective
2348 
2349   Input Parameter:
2350 . A - the matrix
2351 
2352   Output Parameters:
2353 + rmapping - row mapping
2354 - cmapping - column mapping
2355 
2356   Level: advanced
2357 
2358 .seealso: [](ch_matrices), `Mat`, `MatSetLocalToGlobalMapping()`, `MatSetValuesLocal()`
2359 @*/
2360 PetscErrorCode MatGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
2361 {
2362   PetscFunctionBegin;
2363   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2364   PetscValidType(A, 1);
2365   if (rmapping) {
2366     PetscAssertPointer(rmapping, 2);
2367     *rmapping = A->rmap->mapping;
2368   }
2369   if (cmapping) {
2370     PetscAssertPointer(cmapping, 3);
2371     *cmapping = A->cmap->mapping;
2372   }
2373   PetscFunctionReturn(PETSC_SUCCESS);
2374 }
2375 
2376 /*@
2377   MatSetLayouts - Sets the `PetscLayout` objects for rows and columns of a matrix
2378 
2379   Logically Collective
2380 
2381   Input Parameters:
2382 + A    - the matrix
2383 . rmap - row layout
2384 - cmap - column layout
2385 
2386   Level: advanced
2387 
2388   Note:
2389   The `PetscLayout` objects are usually created automatically for the matrix so this routine rarely needs to be called.
2390 
2391 .seealso: [](ch_matrices), `Mat`, `PetscLayout`, `MatCreateVecs()`, `MatGetLocalToGlobalMapping()`, `MatGetLayouts()`
2392 @*/
2393 PetscErrorCode MatSetLayouts(Mat A, PetscLayout rmap, PetscLayout cmap)
2394 {
2395   PetscFunctionBegin;
2396   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2397   PetscCall(PetscLayoutReference(rmap, &A->rmap));
2398   PetscCall(PetscLayoutReference(cmap, &A->cmap));
2399   PetscFunctionReturn(PETSC_SUCCESS);
2400 }
2401 
2402 /*@
2403   MatGetLayouts - Gets the `PetscLayout` objects for rows and columns
2404 
2405   Not Collective
2406 
2407   Input Parameter:
2408 . A - the matrix
2409 
2410   Output Parameters:
2411 + rmap - row layout
2412 - cmap - column layout
2413 
2414   Level: advanced
2415 
2416 .seealso: [](ch_matrices), `Mat`, [Matrix Layouts](sec_matlayout), `PetscLayout`, `MatCreateVecs()`, `MatGetLocalToGlobalMapping()`, `MatSetLayouts()`
2417 @*/
2418 PetscErrorCode MatGetLayouts(Mat A, PetscLayout *rmap, PetscLayout *cmap)
2419 {
2420   PetscFunctionBegin;
2421   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2422   PetscValidType(A, 1);
2423   if (rmap) {
2424     PetscAssertPointer(rmap, 2);
2425     *rmap = A->rmap;
2426   }
2427   if (cmap) {
2428     PetscAssertPointer(cmap, 3);
2429     *cmap = A->cmap;
2430   }
2431   PetscFunctionReturn(PETSC_SUCCESS);
2432 }
2433 
2434 /*@
2435   MatSetValuesLocal - Inserts or adds values into certain locations of a matrix,
2436   using a local numbering of the rows and columns.
2437 
2438   Not Collective
2439 
2440   Input Parameters:
2441 + mat  - the matrix
2442 . nrow - number of rows
2443 . irow - the row local indices
2444 . ncol - number of columns
2445 . icol - the column local indices
2446 . y    - a logically two-dimensional array of values
2447 - addv - either `INSERT_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
2448 
2449   Level: intermediate
2450 
2451   Notes:
2452   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetLocalToGlobalMapping()` before using this routine
2453 
2454   Calls to `MatSetValuesLocal()` with the `INSERT_VALUES` and `ADD_VALUES`
2455   options cannot be mixed without intervening calls to the assembly
2456   routines.
2457 
2458   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
2459   MUST be called after all calls to `MatSetValuesLocal()` have been completed.
2460 
2461   Fortran Notes:
2462   If any of `irow`, `icol`, and `y` are scalars pass them using, for example,
2463 .vb
2464   call MatSetValuesLocal(mat, one, [irow], one, [icol], [y], INSERT_VALUES, ierr)
2465 .ve
2466 
2467   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2468 
2469 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetLocalToGlobalMapping()`,
2470           `MatGetValuesLocal()`
2471 @*/
2472 PetscErrorCode MatSetValuesLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv)
2473 {
2474   PetscFunctionBeginHot;
2475   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2476   PetscValidType(mat, 1);
2477   MatCheckPreallocated(mat, 1);
2478   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2479   PetscAssertPointer(irow, 3);
2480   PetscAssertPointer(icol, 5);
2481   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2482   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2483   if (PetscDefined(USE_DEBUG)) {
2484     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2485     PetscCheck(mat->ops->setvalueslocal || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2486   }
2487 
2488   if (mat->assembled) {
2489     mat->was_assembled = PETSC_TRUE;
2490     mat->assembled     = PETSC_FALSE;
2491   }
2492   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2493   if (mat->ops->setvalueslocal) PetscUseTypeMethod(mat, setvalueslocal, nrow, irow, ncol, icol, y, addv);
2494   else {
2495     PetscInt        buf[8192], *bufr = NULL, *bufc = NULL;
2496     const PetscInt *irowm, *icolm;
2497 
2498     if ((!mat->rmap->mapping && !mat->cmap->mapping) || (nrow + ncol) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2499       bufr  = buf;
2500       bufc  = buf + nrow;
2501       irowm = bufr;
2502       icolm = bufc;
2503     } else {
2504       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2505       irowm = bufr;
2506       icolm = bufc;
2507     }
2508     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, nrow, irow, bufr));
2509     else irowm = irow;
2510     if (mat->cmap->mapping) {
2511       if (mat->cmap->mapping != mat->rmap->mapping || ncol != nrow || icol != irow) {
2512         PetscCall(ISLocalToGlobalMappingApply(mat->cmap->mapping, ncol, icol, bufc));
2513       } else icolm = irowm;
2514     } else icolm = icol;
2515     PetscCall(MatSetValues(mat, nrow, irowm, ncol, icolm, y, addv));
2516     if (bufr != buf) PetscCall(PetscFree2(bufr, bufc));
2517   }
2518   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2519   PetscFunctionReturn(PETSC_SUCCESS);
2520 }
2521 
2522 /*@
2523   MatSetValuesBlockedLocal - Inserts or adds values into certain locations of a matrix,
2524   using a local ordering of the nodes a block at a time.
2525 
2526   Not Collective
2527 
2528   Input Parameters:
2529 + mat  - the matrix
2530 . nrow - number of rows
2531 . irow - the row local indices
2532 . ncol - number of columns
2533 . icol - the column local indices
2534 . y    - a logically two-dimensional array of values
2535 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
2536 
2537   Level: intermediate
2538 
2539   Notes:
2540   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetBlockSize()` and `MatSetLocalToGlobalMapping()`
2541   before using this routineBefore calling `MatSetValuesLocal()`, the user must first set the
2542 
2543   Calls to `MatSetValuesBlockedLocal()` with the `INSERT_VALUES` and `ADD_VALUES`
2544   options cannot be mixed without intervening calls to the assembly
2545   routines.
2546 
2547   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
2548   MUST be called after all calls to `MatSetValuesBlockedLocal()` have been completed.
2549 
2550   Fortran Notes:
2551   If any of `irow`, `icol`, and `y` are scalars pass them using, for example,
2552 .vb
2553   call MatSetValuesBlockedLocal(mat, one, [irow], one, [icol], [y], INSERT_VALUES, ierr)
2554 .ve
2555 
2556   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2557 
2558 .seealso: [](ch_matrices), `Mat`, `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`,
2559           `MatSetValuesLocal()`, `MatSetValuesBlocked()`
2560 @*/
2561 PetscErrorCode MatSetValuesBlockedLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv)
2562 {
2563   PetscFunctionBeginHot;
2564   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2565   PetscValidType(mat, 1);
2566   MatCheckPreallocated(mat, 1);
2567   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2568   PetscAssertPointer(irow, 3);
2569   PetscAssertPointer(icol, 5);
2570   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2571   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2572   if (PetscDefined(USE_DEBUG)) {
2573     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2574     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);
2575   }
2576 
2577   if (mat->assembled) {
2578     mat->was_assembled = PETSC_TRUE;
2579     mat->assembled     = PETSC_FALSE;
2580   }
2581   if (PetscUnlikelyDebug(mat->rmap->mapping)) { /* Condition on the mapping existing, because MatSetValuesBlockedLocal_IS does not require it to be set. */
2582     PetscInt irbs, rbs;
2583     PetscCall(MatGetBlockSizes(mat, &rbs, NULL));
2584     PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &irbs));
2585     PetscCheck(rbs == irbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Different row block sizes! mat %" PetscInt_FMT ", row l2g map %" PetscInt_FMT, rbs, irbs);
2586   }
2587   if (PetscUnlikelyDebug(mat->cmap->mapping)) {
2588     PetscInt icbs, cbs;
2589     PetscCall(MatGetBlockSizes(mat, NULL, &cbs));
2590     PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &icbs));
2591     PetscCheck(cbs == icbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Different col block sizes! mat %" PetscInt_FMT ", col l2g map %" PetscInt_FMT, cbs, icbs);
2592   }
2593   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2594   if (mat->ops->setvaluesblockedlocal) PetscUseTypeMethod(mat, setvaluesblockedlocal, nrow, irow, ncol, icol, y, addv);
2595   else {
2596     PetscInt        buf[8192], *bufr = NULL, *bufc = NULL;
2597     const PetscInt *irowm, *icolm;
2598 
2599     if ((!mat->rmap->mapping && !mat->cmap->mapping) || (nrow + ncol) <= ((PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf))) {
2600       bufr  = buf;
2601       bufc  = buf + nrow;
2602       irowm = bufr;
2603       icolm = bufc;
2604     } else {
2605       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2606       irowm = bufr;
2607       icolm = bufc;
2608     }
2609     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingApplyBlock(mat->rmap->mapping, nrow, irow, bufr));
2610     else irowm = irow;
2611     if (mat->cmap->mapping) {
2612       if (mat->cmap->mapping != mat->rmap->mapping || ncol != nrow || icol != irow) {
2613         PetscCall(ISLocalToGlobalMappingApplyBlock(mat->cmap->mapping, ncol, icol, bufc));
2614       } else icolm = irowm;
2615     } else icolm = icol;
2616     PetscCall(MatSetValuesBlocked(mat, nrow, irowm, ncol, icolm, y, addv));
2617     if (bufr != buf) PetscCall(PetscFree2(bufr, bufc));
2618   }
2619   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2620   PetscFunctionReturn(PETSC_SUCCESS);
2621 }
2622 
2623 /*@
2624   MatMultDiagonalBlock - Computes the matrix-vector product, $y = Dx$. Where `D` is defined by the inode or block structure of the diagonal
2625 
2626   Collective
2627 
2628   Input Parameters:
2629 + mat - the matrix
2630 - x   - the vector to be multiplied
2631 
2632   Output Parameter:
2633 . y - the result
2634 
2635   Level: developer
2636 
2637   Note:
2638   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2639   call `MatMultDiagonalBlock`(A,y,y).
2640 
2641 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
2642 @*/
2643 PetscErrorCode MatMultDiagonalBlock(Mat mat, Vec x, Vec y)
2644 {
2645   PetscFunctionBegin;
2646   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2647   PetscValidType(mat, 1);
2648   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2649   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2650 
2651   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2652   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2653   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2654   MatCheckPreallocated(mat, 1);
2655 
2656   PetscUseTypeMethod(mat, multdiagonalblock, x, y);
2657   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2658   PetscFunctionReturn(PETSC_SUCCESS);
2659 }
2660 
2661 /*@
2662   MatMult - Computes the matrix-vector product, $y = Ax$.
2663 
2664   Neighbor-wise Collective
2665 
2666   Input Parameters:
2667 + mat - the matrix
2668 - x   - the vector to be multiplied
2669 
2670   Output Parameter:
2671 . y - the result
2672 
2673   Level: beginner
2674 
2675   Note:
2676   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2677   call `MatMult`(A,y,y).
2678 
2679 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
2680 @*/
2681 PetscErrorCode MatMult(Mat mat, Vec x, Vec y)
2682 {
2683   PetscFunctionBegin;
2684   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2685   PetscValidType(mat, 1);
2686   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2687   VecCheckAssembled(x);
2688   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2689   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2690   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2691   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2692   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);
2693   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);
2694   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);
2695   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);
2696   PetscCall(VecSetErrorIfLocked(y, 3));
2697   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2698   MatCheckPreallocated(mat, 1);
2699 
2700   PetscCall(VecLockReadPush(x));
2701   PetscCall(PetscLogEventBegin(MAT_Mult, mat, x, y, 0));
2702   PetscUseTypeMethod(mat, mult, x, y);
2703   PetscCall(PetscLogEventEnd(MAT_Mult, mat, x, y, 0));
2704   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(y, 3, PETSC_FALSE));
2705   PetscCall(VecLockReadPop(x));
2706   PetscFunctionReturn(PETSC_SUCCESS);
2707 }
2708 
2709 /*@
2710   MatMultTranspose - Computes matrix transpose times a vector $y = A^T * x$.
2711 
2712   Neighbor-wise Collective
2713 
2714   Input Parameters:
2715 + mat - the matrix
2716 - x   - the vector to be multiplied
2717 
2718   Output Parameter:
2719 . y - the result
2720 
2721   Level: beginner
2722 
2723   Notes:
2724   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2725   call `MatMultTranspose`(A,y,y).
2726 
2727   For complex numbers this does NOT compute the Hermitian (complex conjugate) transpose multiple,
2728   use `MatMultHermitianTranspose()`
2729 
2730 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatMultHermitianTranspose()`, `MatTranspose()`
2731 @*/
2732 PetscErrorCode MatMultTranspose(Mat mat, Vec x, Vec y)
2733 {
2734   PetscErrorCode (*op)(Mat, Vec, Vec) = NULL;
2735 
2736   PetscFunctionBegin;
2737   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2738   PetscValidType(mat, 1);
2739   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2740   VecCheckAssembled(x);
2741   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2742 
2743   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2744   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2745   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2746   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);
2747   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);
2748   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);
2749   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);
2750   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2751   MatCheckPreallocated(mat, 1);
2752 
2753   if (!mat->ops->multtranspose) {
2754     if (mat->symmetric == PETSC_BOOL3_TRUE && mat->ops->mult) op = mat->ops->mult;
2755     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);
2756   } else op = mat->ops->multtranspose;
2757   PetscCall(PetscLogEventBegin(MAT_MultTranspose, mat, x, y, 0));
2758   PetscCall(VecLockReadPush(x));
2759   PetscCall((*op)(mat, x, y));
2760   PetscCall(VecLockReadPop(x));
2761   PetscCall(PetscLogEventEnd(MAT_MultTranspose, mat, x, y, 0));
2762   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2763   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(y, 3, PETSC_FALSE));
2764   PetscFunctionReturn(PETSC_SUCCESS);
2765 }
2766 
2767 /*@
2768   MatMultHermitianTranspose - Computes matrix Hermitian-transpose times a vector $y = A^H * x$.
2769 
2770   Neighbor-wise Collective
2771 
2772   Input Parameters:
2773 + mat - the matrix
2774 - x   - the vector to be multiplied
2775 
2776   Output Parameter:
2777 . y - the result
2778 
2779   Level: beginner
2780 
2781   Notes:
2782   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2783   call `MatMultHermitianTranspose`(A,y,y).
2784 
2785   Also called the conjugate transpose, complex conjugate transpose, or adjoint.
2786 
2787   For real numbers `MatMultTranspose()` and `MatMultHermitianTranspose()` are identical.
2788 
2789 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `MatMultHermitianTransposeAdd()`, `MatMultTranspose()`
2790 @*/
2791 PetscErrorCode MatMultHermitianTranspose(Mat mat, Vec x, Vec y)
2792 {
2793   PetscFunctionBegin;
2794   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2795   PetscValidType(mat, 1);
2796   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2797   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2798 
2799   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2800   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2801   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2802   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);
2803   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);
2804   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);
2805   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);
2806   MatCheckPreallocated(mat, 1);
2807 
2808   PetscCall(PetscLogEventBegin(MAT_MultHermitianTranspose, mat, x, y, 0));
2809 #if defined(PETSC_USE_COMPLEX)
2810   if (mat->ops->multhermitiantranspose || (mat->hermitian == PETSC_BOOL3_TRUE && mat->ops->mult)) {
2811     PetscCall(VecLockReadPush(x));
2812     if (mat->ops->multhermitiantranspose) PetscUseTypeMethod(mat, multhermitiantranspose, x, y);
2813     else PetscUseTypeMethod(mat, mult, x, y);
2814     PetscCall(VecLockReadPop(x));
2815   } else {
2816     Vec w;
2817     PetscCall(VecDuplicate(x, &w));
2818     PetscCall(VecCopy(x, w));
2819     PetscCall(VecConjugate(w));
2820     PetscCall(MatMultTranspose(mat, w, y));
2821     PetscCall(VecDestroy(&w));
2822     PetscCall(VecConjugate(y));
2823   }
2824   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2825 #else
2826   PetscCall(MatMultTranspose(mat, x, y));
2827 #endif
2828   PetscCall(PetscLogEventEnd(MAT_MultHermitianTranspose, mat, x, y, 0));
2829   PetscFunctionReturn(PETSC_SUCCESS);
2830 }
2831 
2832 /*@
2833   MatMultAdd -  Computes $v3 = v2 + A * v1$.
2834 
2835   Neighbor-wise Collective
2836 
2837   Input Parameters:
2838 + mat - the matrix
2839 . v1  - the vector to be multiplied by `mat`
2840 - v2  - the vector to be added to the result
2841 
2842   Output Parameter:
2843 . v3 - the result
2844 
2845   Level: beginner
2846 
2847   Note:
2848   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2849   call `MatMultAdd`(A,v1,v2,v1).
2850 
2851 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMult()`, `MatMultTransposeAdd()`
2852 @*/
2853 PetscErrorCode MatMultAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2854 {
2855   PetscFunctionBegin;
2856   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2857   PetscValidType(mat, 1);
2858   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2859   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2860   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2861 
2862   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2863   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2864   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);
2865   /* 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);
2866      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); */
2867   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);
2868   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);
2869   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2870   MatCheckPreallocated(mat, 1);
2871 
2872   PetscCall(PetscLogEventBegin(MAT_MultAdd, mat, v1, v2, v3));
2873   PetscCall(VecLockReadPush(v1));
2874   PetscUseTypeMethod(mat, multadd, v1, v2, v3);
2875   PetscCall(VecLockReadPop(v1));
2876   PetscCall(PetscLogEventEnd(MAT_MultAdd, mat, v1, v2, v3));
2877   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2878   PetscFunctionReturn(PETSC_SUCCESS);
2879 }
2880 
2881 /*@
2882   MatMultTransposeAdd - Computes $v3 = v2 + A^T * v1$.
2883 
2884   Neighbor-wise Collective
2885 
2886   Input Parameters:
2887 + mat - the matrix
2888 . v1  - the vector to be multiplied by the transpose of the matrix
2889 - v2  - the vector to be added to the result
2890 
2891   Output Parameter:
2892 . v3 - the result
2893 
2894   Level: beginner
2895 
2896   Note:
2897   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2898   call `MatMultTransposeAdd`(A,v1,v2,v1).
2899 
2900 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMult()`
2901 @*/
2902 PetscErrorCode MatMultTransposeAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2903 {
2904   PetscErrorCode (*op)(Mat, Vec, Vec, Vec) = (!mat->ops->multtransposeadd && mat->symmetric) ? mat->ops->multadd : mat->ops->multtransposeadd;
2905 
2906   PetscFunctionBegin;
2907   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2908   PetscValidType(mat, 1);
2909   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2910   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2911   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2912 
2913   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2914   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2915   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);
2916   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);
2917   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);
2918   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2919   PetscCheck(op, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2920   MatCheckPreallocated(mat, 1);
2921 
2922   PetscCall(PetscLogEventBegin(MAT_MultTransposeAdd, mat, v1, v2, v3));
2923   PetscCall(VecLockReadPush(v1));
2924   PetscCall((*op)(mat, v1, v2, v3));
2925   PetscCall(VecLockReadPop(v1));
2926   PetscCall(PetscLogEventEnd(MAT_MultTransposeAdd, mat, v1, v2, v3));
2927   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2928   PetscFunctionReturn(PETSC_SUCCESS);
2929 }
2930 
2931 /*@
2932   MatMultHermitianTransposeAdd - Computes $v3 = v2 + A^H * v1$.
2933 
2934   Neighbor-wise Collective
2935 
2936   Input Parameters:
2937 + mat - the matrix
2938 . v1  - the vector to be multiplied by the Hermitian transpose
2939 - v2  - the vector to be added to the result
2940 
2941   Output Parameter:
2942 . v3 - the result
2943 
2944   Level: beginner
2945 
2946   Note:
2947   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2948   call `MatMultHermitianTransposeAdd`(A,v1,v2,v1).
2949 
2950 .seealso: [](ch_matrices), `Mat`, `MatMultHermitianTranspose()`, `MatMultTranspose()`, `MatMultAdd()`, `MatMult()`
2951 @*/
2952 PetscErrorCode MatMultHermitianTransposeAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2953 {
2954   PetscFunctionBegin;
2955   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2956   PetscValidType(mat, 1);
2957   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2958   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2959   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2960 
2961   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2962   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2963   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2964   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);
2965   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);
2966   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);
2967   MatCheckPreallocated(mat, 1);
2968 
2969   PetscCall(PetscLogEventBegin(MAT_MultHermitianTransposeAdd, mat, v1, v2, v3));
2970   PetscCall(VecLockReadPush(v1));
2971   if (mat->ops->multhermitiantransposeadd) PetscUseTypeMethod(mat, multhermitiantransposeadd, v1, v2, v3);
2972   else {
2973     Vec w, z;
2974     PetscCall(VecDuplicate(v1, &w));
2975     PetscCall(VecCopy(v1, w));
2976     PetscCall(VecConjugate(w));
2977     PetscCall(VecDuplicate(v3, &z));
2978     PetscCall(MatMultTranspose(mat, w, z));
2979     PetscCall(VecDestroy(&w));
2980     PetscCall(VecConjugate(z));
2981     if (v2 != v3) {
2982       PetscCall(VecWAXPY(v3, 1.0, v2, z));
2983     } else {
2984       PetscCall(VecAXPY(v3, 1.0, z));
2985     }
2986     PetscCall(VecDestroy(&z));
2987   }
2988   PetscCall(VecLockReadPop(v1));
2989   PetscCall(PetscLogEventEnd(MAT_MultHermitianTransposeAdd, mat, v1, v2, v3));
2990   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2991   PetscFunctionReturn(PETSC_SUCCESS);
2992 }
2993 
2994 /*@
2995   MatGetFactorType - gets the type of factorization a matrix is
2996 
2997   Not Collective
2998 
2999   Input Parameter:
3000 . mat - the matrix
3001 
3002   Output Parameter:
3003 . 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`
3004 
3005   Level: intermediate
3006 
3007 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatGetFactor()`, `MatSetFactorType()`, `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`,
3008           `MAT_FACTOR_ICC`,`MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3009 @*/
3010 PetscErrorCode MatGetFactorType(Mat mat, MatFactorType *t)
3011 {
3012   PetscFunctionBegin;
3013   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3014   PetscValidType(mat, 1);
3015   PetscAssertPointer(t, 2);
3016   *t = mat->factortype;
3017   PetscFunctionReturn(PETSC_SUCCESS);
3018 }
3019 
3020 /*@
3021   MatSetFactorType - sets the type of factorization a matrix is
3022 
3023   Logically Collective
3024 
3025   Input Parameters:
3026 + mat - the matrix
3027 - 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`
3028 
3029   Level: intermediate
3030 
3031 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatGetFactor()`, `MatGetFactorType()`, `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`,
3032           `MAT_FACTOR_ICC`,`MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3033 @*/
3034 PetscErrorCode MatSetFactorType(Mat mat, MatFactorType t)
3035 {
3036   PetscFunctionBegin;
3037   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3038   PetscValidType(mat, 1);
3039   mat->factortype = t;
3040   PetscFunctionReturn(PETSC_SUCCESS);
3041 }
3042 
3043 /*@
3044   MatGetInfo - Returns information about matrix storage (number of
3045   nonzeros, memory, etc.).
3046 
3047   Collective if `MAT_GLOBAL_MAX` or `MAT_GLOBAL_SUM` is used as the flag
3048 
3049   Input Parameters:
3050 + mat  - the matrix
3051 - 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)
3052 
3053   Output Parameter:
3054 . info - matrix information context
3055 
3056   Options Database Key:
3057 . -mat_view ::ascii_info - print matrix info to `PETSC_STDOUT`
3058 
3059   Level: intermediate
3060 
3061   Notes:
3062   The `MatInfo` context contains a variety of matrix data, including
3063   number of nonzeros allocated and used, number of mallocs during
3064   matrix assembly, etc.  Additional information for factored matrices
3065   is provided (such as the fill ratio, number of mallocs during
3066   factorization, etc.).
3067 
3068   Example:
3069   See the file ${PETSC_DIR}/include/petscmat.h for a complete list of
3070   data within the `MatInfo` context.  For example,
3071 .vb
3072       MatInfo info;
3073       Mat     A;
3074       double  mal, nz_a, nz_u;
3075 
3076       MatGetInfo(A, MAT_LOCAL, &info);
3077       mal  = info.mallocs;
3078       nz_a = info.nz_allocated;
3079 .ve
3080 
3081 .seealso: [](ch_matrices), `Mat`, `MatInfo`, `MatStashGetInfo()`
3082 @*/
3083 PetscErrorCode MatGetInfo(Mat mat, MatInfoType flag, MatInfo *info)
3084 {
3085   PetscFunctionBegin;
3086   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3087   PetscValidType(mat, 1);
3088   PetscAssertPointer(info, 3);
3089   MatCheckPreallocated(mat, 1);
3090   PetscUseTypeMethod(mat, getinfo, flag, info);
3091   PetscFunctionReturn(PETSC_SUCCESS);
3092 }
3093 
3094 /*
3095    This is used by external packages where it is not easy to get the info from the actual
3096    matrix factorization.
3097 */
3098 PetscErrorCode MatGetInfo_External(Mat A, MatInfoType flag, MatInfo *info)
3099 {
3100   PetscFunctionBegin;
3101   PetscCall(PetscMemzero(info, sizeof(MatInfo)));
3102   PetscFunctionReturn(PETSC_SUCCESS);
3103 }
3104 
3105 /*@
3106   MatLUFactor - Performs in-place LU factorization of matrix.
3107 
3108   Collective
3109 
3110   Input Parameters:
3111 + mat  - the matrix
3112 . row  - row permutation
3113 . col  - column permutation
3114 - info - options for factorization, includes
3115 .vb
3116           fill - expected fill as ratio of original fill.
3117           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3118                    Run with the option -info to determine an optimal value to use
3119 .ve
3120 
3121   Level: developer
3122 
3123   Notes:
3124   Most users should employ the `KSP` interface for linear solvers
3125   instead of working directly with matrix algebra routines such as this.
3126   See, e.g., `KSPCreate()`.
3127 
3128   This changes the state of the matrix to a factored matrix; it cannot be used
3129   for example with `MatSetValues()` unless one first calls `MatSetUnfactored()`.
3130 
3131   This is really in-place only for dense matrices, the preferred approach is to use `MatGetFactor()`, `MatLUFactorSymbolic()`, and `MatLUFactorNumeric()`
3132   when not using `KSP`.
3133 
3134   Developer Note:
3135   The Fortran interface is not autogenerated as the
3136   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3137 
3138 .seealso: [](ch_matrices), [Matrix Factorization](sec_matfactor), `Mat`, `MatFactorType`, `MatLUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`,
3139           `MatGetOrdering()`, `MatSetUnfactored()`, `MatFactorInfo`, `MatGetFactor()`
3140 @*/
3141 PetscErrorCode MatLUFactor(Mat mat, IS row, IS col, const MatFactorInfo *info)
3142 {
3143   MatFactorInfo tinfo;
3144 
3145   PetscFunctionBegin;
3146   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3147   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
3148   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3149   if (info) PetscAssertPointer(info, 4);
3150   PetscValidType(mat, 1);
3151   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3152   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3153   MatCheckPreallocated(mat, 1);
3154   if (!info) {
3155     PetscCall(MatFactorInfoInitialize(&tinfo));
3156     info = &tinfo;
3157   }
3158 
3159   PetscCall(PetscLogEventBegin(MAT_LUFactor, mat, row, col, 0));
3160   PetscUseTypeMethod(mat, lufactor, row, col, info);
3161   PetscCall(PetscLogEventEnd(MAT_LUFactor, mat, row, col, 0));
3162   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3163   PetscFunctionReturn(PETSC_SUCCESS);
3164 }
3165 
3166 /*@
3167   MatILUFactor - Performs in-place ILU factorization of matrix.
3168 
3169   Collective
3170 
3171   Input Parameters:
3172 + mat  - the matrix
3173 . row  - row permutation
3174 . col  - column permutation
3175 - info - structure containing
3176 .vb
3177       levels - number of levels of fill.
3178       expected fill - as ratio of original fill.
3179       1 or 0 - indicating force fill on diagonal (improves robustness for matrices
3180                 missing diagonal entries)
3181 .ve
3182 
3183   Level: developer
3184 
3185   Notes:
3186   Most users should employ the `KSP` interface for linear solvers
3187   instead of working directly with matrix algebra routines such as this.
3188   See, e.g., `KSPCreate()`.
3189 
3190   Probably really in-place only when level of fill is zero, otherwise allocates
3191   new space to store factored matrix and deletes previous memory. The preferred approach is to use `MatGetFactor()`, `MatILUFactorSymbolic()`, and `MatILUFactorNumeric()`
3192   when not using `KSP`.
3193 
3194   Developer Note:
3195   The Fortran interface is not autogenerated as the
3196   interface definition cannot be generated correctly [due to MatFactorInfo]
3197 
3198 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatILUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`
3199 @*/
3200 PetscErrorCode MatILUFactor(Mat mat, IS row, IS col, const MatFactorInfo *info)
3201 {
3202   PetscFunctionBegin;
3203   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3204   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
3205   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3206   PetscAssertPointer(info, 4);
3207   PetscValidType(mat, 1);
3208   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
3209   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3210   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3211   MatCheckPreallocated(mat, 1);
3212 
3213   PetscCall(PetscLogEventBegin(MAT_ILUFactor, mat, row, col, 0));
3214   PetscUseTypeMethod(mat, ilufactor, row, col, info);
3215   PetscCall(PetscLogEventEnd(MAT_ILUFactor, mat, row, col, 0));
3216   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3217   PetscFunctionReturn(PETSC_SUCCESS);
3218 }
3219 
3220 /*@
3221   MatLUFactorSymbolic - Performs symbolic LU factorization of matrix.
3222   Call this routine before calling `MatLUFactorNumeric()` and after `MatGetFactor()`.
3223 
3224   Collective
3225 
3226   Input Parameters:
3227 + fact - the factor matrix obtained with `MatGetFactor()`
3228 . mat  - the matrix
3229 . row  - the row permutation
3230 . col  - the column permutation
3231 - info - options for factorization, includes
3232 .vb
3233           fill - expected fill as ratio of original fill. Run with the option -info to determine an optimal value to use
3234           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3235 .ve
3236 
3237   Level: developer
3238 
3239   Notes:
3240   See [Matrix Factorization](sec_matfactor) for additional information about factorizations
3241 
3242   Most users should employ the simplified `KSP` interface for linear solvers
3243   instead of working directly with matrix algebra routines such as this.
3244   See, e.g., `KSPCreate()`.
3245 
3246   Developer Note:
3247   The Fortran interface is not autogenerated as the
3248   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3249 
3250 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactor()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`, `MatFactorInfoInitialize()`
3251 @*/
3252 PetscErrorCode MatLUFactorSymbolic(Mat fact, Mat mat, IS row, IS col, const MatFactorInfo *info)
3253 {
3254   MatFactorInfo tinfo;
3255 
3256   PetscFunctionBegin;
3257   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3258   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3259   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 3);
3260   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 4);
3261   if (info) PetscAssertPointer(info, 5);
3262   PetscValidType(fact, 1);
3263   PetscValidType(mat, 2);
3264   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3265   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3266   MatCheckPreallocated(mat, 2);
3267   if (!info) {
3268     PetscCall(MatFactorInfoInitialize(&tinfo));
3269     info = &tinfo;
3270   }
3271 
3272   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_LUFactorSymbolic, mat, row, col, 0));
3273   PetscUseTypeMethod(fact, lufactorsymbolic, mat, row, col, info);
3274   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_LUFactorSymbolic, mat, row, col, 0));
3275   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3276   PetscFunctionReturn(PETSC_SUCCESS);
3277 }
3278 
3279 /*@
3280   MatLUFactorNumeric - Performs numeric LU factorization of a matrix.
3281   Call this routine after first calling `MatLUFactorSymbolic()` and `MatGetFactor()`.
3282 
3283   Collective
3284 
3285   Input Parameters:
3286 + fact - the factor matrix obtained with `MatGetFactor()`
3287 . mat  - the matrix
3288 - info - options for factorization
3289 
3290   Level: developer
3291 
3292   Notes:
3293   See `MatLUFactor()` for in-place factorization.  See
3294   `MatCholeskyFactorNumeric()` for the symmetric, positive definite case.
3295 
3296   Most users should employ the `KSP` interface for linear solvers
3297   instead of working directly with matrix algebra routines such as this.
3298   See, e.g., `KSPCreate()`.
3299 
3300   Developer Note:
3301   The Fortran interface is not autogenerated as the
3302   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3303 
3304 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatLUFactorSymbolic()`, `MatLUFactor()`, `MatCholeskyFactor()`
3305 @*/
3306 PetscErrorCode MatLUFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3307 {
3308   MatFactorInfo tinfo;
3309 
3310   PetscFunctionBegin;
3311   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3312   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3313   PetscValidType(fact, 1);
3314   PetscValidType(mat, 2);
3315   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3316   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,
3317              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3318 
3319   MatCheckPreallocated(mat, 2);
3320   if (!info) {
3321     PetscCall(MatFactorInfoInitialize(&tinfo));
3322     info = &tinfo;
3323   }
3324 
3325   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_LUFactorNumeric, mat, fact, 0, 0));
3326   else PetscCall(PetscLogEventBegin(MAT_LUFactor, mat, fact, 0, 0));
3327   PetscUseTypeMethod(fact, lufactornumeric, mat, info);
3328   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_LUFactorNumeric, mat, fact, 0, 0));
3329   else PetscCall(PetscLogEventEnd(MAT_LUFactor, mat, fact, 0, 0));
3330   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3331   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3332   PetscFunctionReturn(PETSC_SUCCESS);
3333 }
3334 
3335 /*@
3336   MatCholeskyFactor - Performs in-place Cholesky factorization of a
3337   symmetric matrix.
3338 
3339   Collective
3340 
3341   Input Parameters:
3342 + mat  - the matrix
3343 . perm - row and column permutations
3344 - info - expected fill as ratio of original fill
3345 
3346   Level: developer
3347 
3348   Notes:
3349   See `MatLUFactor()` for the nonsymmetric case.  See also `MatGetFactor()`,
3350   `MatCholeskyFactorSymbolic()`, and `MatCholeskyFactorNumeric()`.
3351 
3352   Most users should employ the `KSP` interface for linear solvers
3353   instead of working directly with matrix algebra routines such as this.
3354   See, e.g., `KSPCreate()`.
3355 
3356   Developer Note:
3357   The Fortran interface is not autogenerated as the
3358   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3359 
3360 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatLUFactor()`, `MatCholeskyFactorSymbolic()`, `MatCholeskyFactorNumeric()`
3361           `MatGetOrdering()`
3362 @*/
3363 PetscErrorCode MatCholeskyFactor(Mat mat, IS perm, const MatFactorInfo *info)
3364 {
3365   MatFactorInfo tinfo;
3366 
3367   PetscFunctionBegin;
3368   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3369   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 2);
3370   if (info) PetscAssertPointer(info, 3);
3371   PetscValidType(mat, 1);
3372   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Matrix must be square");
3373   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3374   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3375   MatCheckPreallocated(mat, 1);
3376   if (!info) {
3377     PetscCall(MatFactorInfoInitialize(&tinfo));
3378     info = &tinfo;
3379   }
3380 
3381   PetscCall(PetscLogEventBegin(MAT_CholeskyFactor, mat, perm, 0, 0));
3382   PetscUseTypeMethod(mat, choleskyfactor, perm, info);
3383   PetscCall(PetscLogEventEnd(MAT_CholeskyFactor, mat, perm, 0, 0));
3384   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3385   PetscFunctionReturn(PETSC_SUCCESS);
3386 }
3387 
3388 /*@
3389   MatCholeskyFactorSymbolic - Performs symbolic Cholesky factorization
3390   of a symmetric matrix.
3391 
3392   Collective
3393 
3394   Input Parameters:
3395 + fact - the factor matrix obtained with `MatGetFactor()`
3396 . mat  - the matrix
3397 . perm - row and column permutations
3398 - info - options for factorization, includes
3399 .vb
3400           fill - expected fill as ratio of original fill.
3401           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3402                    Run with the option -info to determine an optimal value to use
3403 .ve
3404 
3405   Level: developer
3406 
3407   Notes:
3408   See `MatLUFactorSymbolic()` for the nonsymmetric case.  See also
3409   `MatCholeskyFactor()` and `MatCholeskyFactorNumeric()`.
3410 
3411   Most users should employ the `KSP` interface for linear solvers
3412   instead of working directly with matrix algebra routines such as this.
3413   See, e.g., `KSPCreate()`.
3414 
3415   Developer Note:
3416   The Fortran interface is not autogenerated as the
3417   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3418 
3419 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactor()`, `MatCholeskyFactorNumeric()`
3420           `MatGetOrdering()`
3421 @*/
3422 PetscErrorCode MatCholeskyFactorSymbolic(Mat fact, Mat mat, IS perm, const MatFactorInfo *info)
3423 {
3424   MatFactorInfo tinfo;
3425 
3426   PetscFunctionBegin;
3427   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3428   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3429   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 3);
3430   if (info) PetscAssertPointer(info, 4);
3431   PetscValidType(fact, 1);
3432   PetscValidType(mat, 2);
3433   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Matrix must be square");
3434   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3435   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3436   MatCheckPreallocated(mat, 2);
3437   if (!info) {
3438     PetscCall(MatFactorInfoInitialize(&tinfo));
3439     info = &tinfo;
3440   }
3441 
3442   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_CholeskyFactorSymbolic, mat, perm, 0, 0));
3443   PetscUseTypeMethod(fact, choleskyfactorsymbolic, mat, perm, info);
3444   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_CholeskyFactorSymbolic, mat, perm, 0, 0));
3445   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3446   PetscFunctionReturn(PETSC_SUCCESS);
3447 }
3448 
3449 /*@
3450   MatCholeskyFactorNumeric - Performs numeric Cholesky factorization
3451   of a symmetric matrix. Call this routine after first calling `MatGetFactor()` and
3452   `MatCholeskyFactorSymbolic()`.
3453 
3454   Collective
3455 
3456   Input Parameters:
3457 + fact - the factor matrix obtained with `MatGetFactor()`, where the factored values are stored
3458 . mat  - the initial matrix that is to be factored
3459 - info - options for factorization
3460 
3461   Level: developer
3462 
3463   Note:
3464   Most users should employ the `KSP` interface for linear solvers
3465   instead of working directly with matrix algebra routines such as this.
3466   See, e.g., `KSPCreate()`.
3467 
3468   Developer Note:
3469   The Fortran interface is not autogenerated as the
3470   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3471 
3472 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatCholeskyFactorSymbolic()`, `MatCholeskyFactor()`, `MatLUFactorNumeric()`
3473 @*/
3474 PetscErrorCode MatCholeskyFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3475 {
3476   MatFactorInfo tinfo;
3477 
3478   PetscFunctionBegin;
3479   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3480   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3481   PetscValidType(fact, 1);
3482   PetscValidType(mat, 2);
3483   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3484   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,
3485              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3486   MatCheckPreallocated(mat, 2);
3487   if (!info) {
3488     PetscCall(MatFactorInfoInitialize(&tinfo));
3489     info = &tinfo;
3490   }
3491 
3492   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_CholeskyFactorNumeric, mat, fact, 0, 0));
3493   else PetscCall(PetscLogEventBegin(MAT_CholeskyFactor, mat, fact, 0, 0));
3494   PetscUseTypeMethod(fact, choleskyfactornumeric, mat, info);
3495   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_CholeskyFactorNumeric, mat, fact, 0, 0));
3496   else PetscCall(PetscLogEventEnd(MAT_CholeskyFactor, mat, fact, 0, 0));
3497   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3498   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3499   PetscFunctionReturn(PETSC_SUCCESS);
3500 }
3501 
3502 /*@
3503   MatQRFactor - Performs in-place QR factorization of matrix.
3504 
3505   Collective
3506 
3507   Input Parameters:
3508 + mat  - the matrix
3509 . col  - column permutation
3510 - info - options for factorization, includes
3511 .vb
3512           fill - expected fill as ratio of original fill.
3513           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3514                    Run with the option -info to determine an optimal value to use
3515 .ve
3516 
3517   Level: developer
3518 
3519   Notes:
3520   Most users should employ the `KSP` interface for linear solvers
3521   instead of working directly with matrix algebra routines such as this.
3522   See, e.g., `KSPCreate()`.
3523 
3524   This changes the state of the matrix to a factored matrix; it cannot be used
3525   for example with `MatSetValues()` unless one first calls `MatSetUnfactored()`.
3526 
3527   Developer Note:
3528   The Fortran interface is not autogenerated as the
3529   interface definition cannot be generated correctly [due to MatFactorInfo]
3530 
3531 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatQRFactorSymbolic()`, `MatQRFactorNumeric()`, `MatLUFactor()`,
3532           `MatSetUnfactored()`
3533 @*/
3534 PetscErrorCode MatQRFactor(Mat mat, IS col, const MatFactorInfo *info)
3535 {
3536   PetscFunctionBegin;
3537   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3538   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 2);
3539   if (info) PetscAssertPointer(info, 3);
3540   PetscValidType(mat, 1);
3541   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3542   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3543   MatCheckPreallocated(mat, 1);
3544   PetscCall(PetscLogEventBegin(MAT_QRFactor, mat, col, 0, 0));
3545   PetscUseMethod(mat, "MatQRFactor_C", (Mat, IS, const MatFactorInfo *), (mat, col, info));
3546   PetscCall(PetscLogEventEnd(MAT_QRFactor, mat, col, 0, 0));
3547   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3548   PetscFunctionReturn(PETSC_SUCCESS);
3549 }
3550 
3551 /*@
3552   MatQRFactorSymbolic - Performs symbolic QR factorization of matrix.
3553   Call this routine after `MatGetFactor()` but before calling `MatQRFactorNumeric()`.
3554 
3555   Collective
3556 
3557   Input Parameters:
3558 + fact - the factor matrix obtained with `MatGetFactor()`
3559 . mat  - the matrix
3560 . col  - column permutation
3561 - info - options for factorization, includes
3562 .vb
3563           fill - expected fill as ratio of original fill.
3564           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3565                    Run with the option -info to determine an optimal value to use
3566 .ve
3567 
3568   Level: developer
3569 
3570   Note:
3571   Most users should employ the `KSP` interface for linear solvers
3572   instead of working directly with matrix algebra routines such as this.
3573   See, e.g., `KSPCreate()`.
3574 
3575   Developer Note:
3576   The Fortran interface is not autogenerated as the
3577   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3578 
3579 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatQRFactor()`, `MatQRFactorNumeric()`, `MatLUFactor()`, `MatFactorInfoInitialize()`
3580 @*/
3581 PetscErrorCode MatQRFactorSymbolic(Mat fact, Mat mat, IS col, const MatFactorInfo *info)
3582 {
3583   MatFactorInfo tinfo;
3584 
3585   PetscFunctionBegin;
3586   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3587   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3588   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3589   if (info) PetscAssertPointer(info, 4);
3590   PetscValidType(fact, 1);
3591   PetscValidType(mat, 2);
3592   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3593   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3594   MatCheckPreallocated(mat, 2);
3595   if (!info) {
3596     PetscCall(MatFactorInfoInitialize(&tinfo));
3597     info = &tinfo;
3598   }
3599 
3600   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_QRFactorSymbolic, fact, mat, col, 0));
3601   PetscUseMethod(fact, "MatQRFactorSymbolic_C", (Mat, Mat, IS, const MatFactorInfo *), (fact, mat, col, info));
3602   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_QRFactorSymbolic, fact, mat, col, 0));
3603   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3604   PetscFunctionReturn(PETSC_SUCCESS);
3605 }
3606 
3607 /*@
3608   MatQRFactorNumeric - Performs numeric QR factorization of a matrix.
3609   Call this routine after first calling `MatGetFactor()`, and `MatQRFactorSymbolic()`.
3610 
3611   Collective
3612 
3613   Input Parameters:
3614 + fact - the factor matrix obtained with `MatGetFactor()`
3615 . mat  - the matrix
3616 - info - options for factorization
3617 
3618   Level: developer
3619 
3620   Notes:
3621   See `MatQRFactor()` for in-place factorization.
3622 
3623   Most users should employ the `KSP` interface for linear solvers
3624   instead of working directly with matrix algebra routines such as this.
3625   See, e.g., `KSPCreate()`.
3626 
3627   Developer Note:
3628   The Fortran interface is not autogenerated as the
3629   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3630 
3631 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatQRFactor()`, `MatQRFactorSymbolic()`, `MatLUFactor()`
3632 @*/
3633 PetscErrorCode MatQRFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3634 {
3635   MatFactorInfo tinfo;
3636 
3637   PetscFunctionBegin;
3638   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3639   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3640   PetscValidType(fact, 1);
3641   PetscValidType(mat, 2);
3642   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3643   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,
3644              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3645 
3646   MatCheckPreallocated(mat, 2);
3647   if (!info) {
3648     PetscCall(MatFactorInfoInitialize(&tinfo));
3649     info = &tinfo;
3650   }
3651 
3652   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_QRFactorNumeric, mat, fact, 0, 0));
3653   else PetscCall(PetscLogEventBegin(MAT_QRFactor, mat, fact, 0, 0));
3654   PetscUseMethod(fact, "MatQRFactorNumeric_C", (Mat, Mat, const MatFactorInfo *), (fact, mat, info));
3655   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_QRFactorNumeric, mat, fact, 0, 0));
3656   else PetscCall(PetscLogEventEnd(MAT_QRFactor, mat, fact, 0, 0));
3657   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3658   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3659   PetscFunctionReturn(PETSC_SUCCESS);
3660 }
3661 
3662 /*@
3663   MatSolve - Solves $A x = b$, given a factored matrix.
3664 
3665   Neighbor-wise Collective
3666 
3667   Input Parameters:
3668 + mat - the factored matrix
3669 - b   - the right-hand-side vector
3670 
3671   Output Parameter:
3672 . x - the result vector
3673 
3674   Level: developer
3675 
3676   Notes:
3677   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3678   call `MatSolve`(A,x,x).
3679 
3680   Most users should employ the `KSP` interface for linear solvers
3681   instead of working directly with matrix algebra routines such as this.
3682   See, e.g., `KSPCreate()`.
3683 
3684 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactor()`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`
3685 @*/
3686 PetscErrorCode MatSolve(Mat mat, Vec b, Vec x)
3687 {
3688   PetscFunctionBegin;
3689   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3690   PetscValidType(mat, 1);
3691   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3692   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3693   PetscCheckSameComm(mat, 1, b, 2);
3694   PetscCheckSameComm(mat, 1, x, 3);
3695   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3696   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);
3697   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);
3698   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);
3699   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3700   MatCheckPreallocated(mat, 1);
3701 
3702   PetscCall(PetscLogEventBegin(MAT_Solve, mat, b, x, 0));
3703   PetscCall(VecFlag(x, mat->factorerrortype));
3704   if (mat->factorerrortype) {
3705     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
3706   } else PetscUseTypeMethod(mat, solve, b, x);
3707   PetscCall(PetscLogEventEnd(MAT_Solve, mat, b, x, 0));
3708   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3709   PetscFunctionReturn(PETSC_SUCCESS);
3710 }
3711 
3712 static PetscErrorCode MatMatSolve_Basic(Mat A, Mat B, Mat X, PetscBool trans)
3713 {
3714   Vec      b, x;
3715   PetscInt N, i;
3716   PetscErrorCode (*f)(Mat, Vec, Vec);
3717   PetscBool Abound, Bneedconv = PETSC_FALSE, Xneedconv = PETSC_FALSE;
3718 
3719   PetscFunctionBegin;
3720   if (A->factorerrortype) {
3721     PetscCall(PetscInfo(A, "MatFactorError %d\n", A->factorerrortype));
3722     PetscCall(MatSetInf(X));
3723     PetscFunctionReturn(PETSC_SUCCESS);
3724   }
3725   f = (!trans || (!A->ops->solvetranspose && A->symmetric)) ? A->ops->solve : A->ops->solvetranspose;
3726   PetscCheck(f, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Mat type %s", ((PetscObject)A)->type_name);
3727   PetscCall(MatBoundToCPU(A, &Abound));
3728   if (!Abound) {
3729     PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &Bneedconv, MATSEQDENSE, MATMPIDENSE, ""));
3730     PetscCall(PetscObjectTypeCompareAny((PetscObject)X, &Xneedconv, MATSEQDENSE, MATMPIDENSE, ""));
3731   }
3732 #if PetscDefined(HAVE_CUDA)
3733   if (Bneedconv) PetscCall(MatConvert(B, MATDENSECUDA, MAT_INPLACE_MATRIX, &B));
3734   if (Xneedconv) PetscCall(MatConvert(X, MATDENSECUDA, MAT_INPLACE_MATRIX, &X));
3735 #elif PetscDefined(HAVE_HIP)
3736   if (Bneedconv) PetscCall(MatConvert(B, MATDENSEHIP, MAT_INPLACE_MATRIX, &B));
3737   if (Xneedconv) PetscCall(MatConvert(X, MATDENSEHIP, MAT_INPLACE_MATRIX, &X));
3738 #endif
3739   PetscCall(MatGetSize(B, NULL, &N));
3740   for (i = 0; i < N; i++) {
3741     PetscCall(MatDenseGetColumnVecRead(B, i, &b));
3742     PetscCall(MatDenseGetColumnVecWrite(X, i, &x));
3743     PetscCall((*f)(A, b, x));
3744     PetscCall(MatDenseRestoreColumnVecWrite(X, i, &x));
3745     PetscCall(MatDenseRestoreColumnVecRead(B, i, &b));
3746   }
3747   if (Bneedconv) PetscCall(MatConvert(B, MATDENSE, MAT_INPLACE_MATRIX, &B));
3748   if (Xneedconv) PetscCall(MatConvert(X, MATDENSE, MAT_INPLACE_MATRIX, &X));
3749   PetscFunctionReturn(PETSC_SUCCESS);
3750 }
3751 
3752 /*@
3753   MatMatSolve - Solves $A X = B$, given a factored matrix.
3754 
3755   Neighbor-wise Collective
3756 
3757   Input Parameters:
3758 + A - the factored matrix
3759 - B - the right-hand-side matrix `MATDENSE` (or sparse `MATAIJ`-- when using MUMPS)
3760 
3761   Output Parameter:
3762 . X - the result matrix (dense matrix)
3763 
3764   Level: developer
3765 
3766   Note:
3767   If `B` is a `MATDENSE` matrix then one can call `MatMatSolve`(A,B,B) except with `MATSOLVERMKL_CPARDISO`;
3768   otherwise, `B` and `X` cannot be the same.
3769 
3770 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolve()`, `MatMatSolveTranspose()`, `MatLUFactor()`, `MatCholeskyFactor()`
3771 @*/
3772 PetscErrorCode MatMatSolve(Mat A, Mat B, Mat X)
3773 {
3774   PetscFunctionBegin;
3775   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3776   PetscValidType(A, 1);
3777   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
3778   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3779   PetscCheckSameComm(A, 1, B, 2);
3780   PetscCheckSameComm(A, 1, X, 3);
3781   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);
3782   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);
3783   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");
3784   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3785   MatCheckPreallocated(A, 1);
3786 
3787   PetscCall(PetscLogEventBegin(MAT_MatSolve, A, B, X, 0));
3788   if (!A->ops->matsolve) {
3789     PetscCall(PetscInfo(A, "Mat type %s using basic MatMatSolve\n", ((PetscObject)A)->type_name));
3790     PetscCall(MatMatSolve_Basic(A, B, X, PETSC_FALSE));
3791   } else PetscUseTypeMethod(A, matsolve, B, X);
3792   PetscCall(PetscLogEventEnd(MAT_MatSolve, A, B, X, 0));
3793   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3794   PetscFunctionReturn(PETSC_SUCCESS);
3795 }
3796 
3797 /*@
3798   MatMatSolveTranspose - Solves $A^T X = B $, given a factored matrix.
3799 
3800   Neighbor-wise Collective
3801 
3802   Input Parameters:
3803 + A - the factored matrix
3804 - B - the right-hand-side matrix  (`MATDENSE` matrix)
3805 
3806   Output Parameter:
3807 . X - the result matrix (dense matrix)
3808 
3809   Level: developer
3810 
3811   Note:
3812   The matrices `B` and `X` cannot be the same.  I.e., one cannot
3813   call `MatMatSolveTranspose`(A,X,X).
3814 
3815 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolveTranspose()`, `MatMatSolve()`, `MatLUFactor()`, `MatCholeskyFactor()`
3816 @*/
3817 PetscErrorCode MatMatSolveTranspose(Mat A, Mat B, Mat X)
3818 {
3819   PetscFunctionBegin;
3820   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3821   PetscValidType(A, 1);
3822   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
3823   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3824   PetscCheckSameComm(A, 1, B, 2);
3825   PetscCheckSameComm(A, 1, X, 3);
3826   PetscCheck(X != B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_IDN, "X and B must be different matrices");
3827   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);
3828   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);
3829   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);
3830   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");
3831   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3832   MatCheckPreallocated(A, 1);
3833 
3834   PetscCall(PetscLogEventBegin(MAT_MatSolve, A, B, X, 0));
3835   if (!A->ops->matsolvetranspose) {
3836     PetscCall(PetscInfo(A, "Mat type %s using basic MatMatSolveTranspose\n", ((PetscObject)A)->type_name));
3837     PetscCall(MatMatSolve_Basic(A, B, X, PETSC_TRUE));
3838   } else PetscUseTypeMethod(A, matsolvetranspose, B, X);
3839   PetscCall(PetscLogEventEnd(MAT_MatSolve, A, B, X, 0));
3840   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3841   PetscFunctionReturn(PETSC_SUCCESS);
3842 }
3843 
3844 /*@
3845   MatMatTransposeSolve - Solves $A X = B^T$, given a factored matrix.
3846 
3847   Neighbor-wise Collective
3848 
3849   Input Parameters:
3850 + A  - the factored matrix
3851 - Bt - the transpose of right-hand-side matrix as a `MATDENSE`
3852 
3853   Output Parameter:
3854 . X - the result matrix (dense matrix)
3855 
3856   Level: developer
3857 
3858   Note:
3859   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
3860   format on the host processor and call `MatMatTransposeSolve()` to implement MUMPS' `MatMatSolve()`.
3861 
3862 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatMatSolve()`, `MatMatSolveTranspose()`, `MatLUFactor()`, `MatCholeskyFactor()`
3863 @*/
3864 PetscErrorCode MatMatTransposeSolve(Mat A, Mat Bt, Mat X)
3865 {
3866   PetscFunctionBegin;
3867   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3868   PetscValidType(A, 1);
3869   PetscValidHeaderSpecific(Bt, MAT_CLASSID, 2);
3870   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3871   PetscCheckSameComm(A, 1, Bt, 2);
3872   PetscCheckSameComm(A, 1, X, 3);
3873 
3874   PetscCheck(X != Bt, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_IDN, "X and B must be different matrices");
3875   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);
3876   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);
3877   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");
3878   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3879   PetscCheck(A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
3880   MatCheckPreallocated(A, 1);
3881 
3882   PetscCall(PetscLogEventBegin(MAT_MatTrSolve, A, Bt, X, 0));
3883   PetscUseTypeMethod(A, mattransposesolve, Bt, X);
3884   PetscCall(PetscLogEventEnd(MAT_MatTrSolve, A, Bt, X, 0));
3885   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3886   PetscFunctionReturn(PETSC_SUCCESS);
3887 }
3888 
3889 /*@
3890   MatForwardSolve - Solves $ L x = b $, given a factored matrix, $A = LU $, or
3891   $U^T*D^(1/2) x = b$, given a factored symmetric matrix, $A = U^T*D*U$,
3892 
3893   Neighbor-wise Collective
3894 
3895   Input Parameters:
3896 + mat - the factored matrix
3897 - b   - the right-hand-side vector
3898 
3899   Output Parameter:
3900 . x - the result vector
3901 
3902   Level: developer
3903 
3904   Notes:
3905   `MatSolve()` should be used for most applications, as it performs
3906   a forward solve followed by a backward solve.
3907 
3908   The vectors `b` and `x` cannot be the same,  i.e., one cannot
3909   call `MatForwardSolve`(A,x,x).
3910 
3911   For matrix in `MATSEQBAIJ` format with block size larger than 1,
3912   the diagonal blocks are not implemented as $D = D^(1/2) * D^(1/2)$ yet.
3913   `MatForwardSolve()` solves $U^T*D y = b$, and
3914   `MatBackwardSolve()` solves $U x = y$.
3915   Thus they do not provide a symmetric preconditioner.
3916 
3917 .seealso: [](ch_matrices), `Mat`, `MatBackwardSolve()`, `MatGetFactor()`, `MatSolve()`
3918 @*/
3919 PetscErrorCode MatForwardSolve(Mat mat, Vec b, Vec x)
3920 {
3921   PetscFunctionBegin;
3922   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3923   PetscValidType(mat, 1);
3924   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3925   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3926   PetscCheckSameComm(mat, 1, b, 2);
3927   PetscCheckSameComm(mat, 1, x, 3);
3928   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3929   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);
3930   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);
3931   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);
3932   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3933   MatCheckPreallocated(mat, 1);
3934 
3935   PetscCall(PetscLogEventBegin(MAT_ForwardSolve, mat, b, x, 0));
3936   PetscUseTypeMethod(mat, forwardsolve, b, x);
3937   PetscCall(PetscLogEventEnd(MAT_ForwardSolve, mat, b, x, 0));
3938   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3939   PetscFunctionReturn(PETSC_SUCCESS);
3940 }
3941 
3942 /*@
3943   MatBackwardSolve - Solves $U x = b$, given a factored matrix, $A = LU$.
3944   $D^(1/2) U x = b$, given a factored symmetric matrix, $A = U^T*D*U$,
3945 
3946   Neighbor-wise Collective
3947 
3948   Input Parameters:
3949 + mat - the factored matrix
3950 - b   - the right-hand-side vector
3951 
3952   Output Parameter:
3953 . x - the result vector
3954 
3955   Level: developer
3956 
3957   Notes:
3958   `MatSolve()` should be used for most applications, as it performs
3959   a forward solve followed by a backward solve.
3960 
3961   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3962   call `MatBackwardSolve`(A,x,x).
3963 
3964   For matrix in `MATSEQBAIJ` format with block size larger than 1,
3965   the diagonal blocks are not implemented as $D = D^(1/2) * D^(1/2)$ yet.
3966   `MatForwardSolve()` solves $U^T*D y = b$, and
3967   `MatBackwardSolve()` solves $U x = y$.
3968   Thus they do not provide a symmetric preconditioner.
3969 
3970 .seealso: [](ch_matrices), `Mat`, `MatForwardSolve()`, `MatGetFactor()`, `MatSolve()`
3971 @*/
3972 PetscErrorCode MatBackwardSolve(Mat mat, Vec b, Vec x)
3973 {
3974   PetscFunctionBegin;
3975   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3976   PetscValidType(mat, 1);
3977   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3978   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3979   PetscCheckSameComm(mat, 1, b, 2);
3980   PetscCheckSameComm(mat, 1, x, 3);
3981   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3982   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);
3983   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);
3984   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);
3985   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3986   MatCheckPreallocated(mat, 1);
3987 
3988   PetscCall(PetscLogEventBegin(MAT_BackwardSolve, mat, b, x, 0));
3989   PetscUseTypeMethod(mat, backwardsolve, b, x);
3990   PetscCall(PetscLogEventEnd(MAT_BackwardSolve, mat, b, x, 0));
3991   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3992   PetscFunctionReturn(PETSC_SUCCESS);
3993 }
3994 
3995 /*@
3996   MatSolveAdd - Computes $x = y + A^{-1}*b$, given a factored matrix.
3997 
3998   Neighbor-wise Collective
3999 
4000   Input Parameters:
4001 + mat - the factored matrix
4002 . b   - the right-hand-side vector
4003 - y   - the vector to be added to
4004 
4005   Output Parameter:
4006 . x - the result vector
4007 
4008   Level: developer
4009 
4010   Note:
4011   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4012   call `MatSolveAdd`(A,x,y,x).
4013 
4014 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatSolve()`, `MatGetFactor()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`
4015 @*/
4016 PetscErrorCode MatSolveAdd(Mat mat, Vec b, Vec y, Vec x)
4017 {
4018   PetscScalar one = 1.0;
4019   Vec         tmp;
4020 
4021   PetscFunctionBegin;
4022   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4023   PetscValidType(mat, 1);
4024   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
4025   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4026   PetscValidHeaderSpecific(x, VEC_CLASSID, 4);
4027   PetscCheckSameComm(mat, 1, b, 2);
4028   PetscCheckSameComm(mat, 1, y, 3);
4029   PetscCheckSameComm(mat, 1, x, 4);
4030   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4031   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);
4032   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);
4033   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);
4034   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);
4035   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);
4036   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4037   MatCheckPreallocated(mat, 1);
4038 
4039   PetscCall(PetscLogEventBegin(MAT_SolveAdd, mat, b, x, y));
4040   PetscCall(VecFlag(x, mat->factorerrortype));
4041   if (mat->factorerrortype) {
4042     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4043   } else if (mat->ops->solveadd) {
4044     PetscUseTypeMethod(mat, solveadd, b, y, x);
4045   } else {
4046     /* do the solve then the add manually */
4047     if (x != y) {
4048       PetscCall(MatSolve(mat, b, x));
4049       PetscCall(VecAXPY(x, one, y));
4050     } else {
4051       PetscCall(VecDuplicate(x, &tmp));
4052       PetscCall(VecCopy(x, tmp));
4053       PetscCall(MatSolve(mat, b, x));
4054       PetscCall(VecAXPY(x, one, tmp));
4055       PetscCall(VecDestroy(&tmp));
4056     }
4057   }
4058   PetscCall(PetscLogEventEnd(MAT_SolveAdd, mat, b, x, y));
4059   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4060   PetscFunctionReturn(PETSC_SUCCESS);
4061 }
4062 
4063 /*@
4064   MatSolveTranspose - Solves $A^T x = b$, given a factored matrix.
4065 
4066   Neighbor-wise Collective
4067 
4068   Input Parameters:
4069 + mat - the factored matrix
4070 - b   - the right-hand-side vector
4071 
4072   Output Parameter:
4073 . x - the result vector
4074 
4075   Level: developer
4076 
4077   Notes:
4078   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4079   call `MatSolveTranspose`(A,x,x).
4080 
4081   Most users should employ the `KSP` interface for linear solvers
4082   instead of working directly with matrix algebra routines such as this.
4083   See, e.g., `KSPCreate()`.
4084 
4085 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `KSP`, `MatSolve()`, `MatSolveAdd()`, `MatSolveTransposeAdd()`
4086 @*/
4087 PetscErrorCode MatSolveTranspose(Mat mat, Vec b, Vec x)
4088 {
4089   PetscErrorCode (*f)(Mat, Vec, Vec) = (!mat->ops->solvetranspose && mat->symmetric) ? mat->ops->solve : mat->ops->solvetranspose;
4090 
4091   PetscFunctionBegin;
4092   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4093   PetscValidType(mat, 1);
4094   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4095   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
4096   PetscCheckSameComm(mat, 1, b, 2);
4097   PetscCheckSameComm(mat, 1, x, 3);
4098   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4099   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);
4100   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);
4101   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4102   MatCheckPreallocated(mat, 1);
4103   PetscCall(PetscLogEventBegin(MAT_SolveTranspose, mat, b, x, 0));
4104   PetscCall(VecFlag(x, mat->factorerrortype));
4105   if (mat->factorerrortype) {
4106     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4107   } else {
4108     PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Matrix type %s", ((PetscObject)mat)->type_name);
4109     PetscCall((*f)(mat, b, x));
4110   }
4111   PetscCall(PetscLogEventEnd(MAT_SolveTranspose, mat, b, x, 0));
4112   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4113   PetscFunctionReturn(PETSC_SUCCESS);
4114 }
4115 
4116 /*@
4117   MatSolveTransposeAdd - Computes $x = y + A^{-T} b$
4118   factored matrix.
4119 
4120   Neighbor-wise Collective
4121 
4122   Input Parameters:
4123 + mat - the factored matrix
4124 . b   - the right-hand-side vector
4125 - y   - the vector to be added to
4126 
4127   Output Parameter:
4128 . x - the result vector
4129 
4130   Level: developer
4131 
4132   Note:
4133   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4134   call `MatSolveTransposeAdd`(A,x,y,x).
4135 
4136 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatSolve()`, `MatSolveAdd()`, `MatSolveTranspose()`
4137 @*/
4138 PetscErrorCode MatSolveTransposeAdd(Mat mat, Vec b, Vec y, Vec x)
4139 {
4140   PetscScalar one = 1.0;
4141   Vec         tmp;
4142   PetscErrorCode (*f)(Mat, Vec, Vec, Vec) = (!mat->ops->solvetransposeadd && mat->symmetric) ? mat->ops->solveadd : mat->ops->solvetransposeadd;
4143 
4144   PetscFunctionBegin;
4145   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4146   PetscValidType(mat, 1);
4147   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
4148   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4149   PetscValidHeaderSpecific(x, VEC_CLASSID, 4);
4150   PetscCheckSameComm(mat, 1, b, 2);
4151   PetscCheckSameComm(mat, 1, y, 3);
4152   PetscCheckSameComm(mat, 1, x, 4);
4153   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4154   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);
4155   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);
4156   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);
4157   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);
4158   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4159   MatCheckPreallocated(mat, 1);
4160 
4161   PetscCall(PetscLogEventBegin(MAT_SolveTransposeAdd, mat, b, x, y));
4162   PetscCall(VecFlag(x, mat->factorerrortype));
4163   if (mat->factorerrortype) {
4164     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4165   } else if (f) {
4166     PetscCall((*f)(mat, b, y, x));
4167   } else {
4168     /* do the solve then the add manually */
4169     if (x != y) {
4170       PetscCall(MatSolveTranspose(mat, b, x));
4171       PetscCall(VecAXPY(x, one, y));
4172     } else {
4173       PetscCall(VecDuplicate(x, &tmp));
4174       PetscCall(VecCopy(x, tmp));
4175       PetscCall(MatSolveTranspose(mat, b, x));
4176       PetscCall(VecAXPY(x, one, tmp));
4177       PetscCall(VecDestroy(&tmp));
4178     }
4179   }
4180   PetscCall(PetscLogEventEnd(MAT_SolveTransposeAdd, mat, b, x, y));
4181   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4182   PetscFunctionReturn(PETSC_SUCCESS);
4183 }
4184 
4185 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
4186 /*@
4187   MatSOR - Computes relaxation (SOR, Gauss-Seidel) sweeps.
4188 
4189   Neighbor-wise Collective
4190 
4191   Input Parameters:
4192 + mat   - the matrix
4193 . b     - the right-hand side
4194 . omega - the relaxation factor
4195 . flag  - flag indicating the type of SOR (see below)
4196 . shift - diagonal shift
4197 . its   - the number of iterations
4198 - lits  - the number of local iterations
4199 
4200   Output Parameter:
4201 . x - the solution (can contain an initial guess, use option `SOR_ZERO_INITIAL_GUESS` to indicate no guess)
4202 
4203   SOR Flags:
4204 +     `SOR_FORWARD_SWEEP` - forward SOR
4205 .     `SOR_BACKWARD_SWEEP` - backward SOR
4206 .     `SOR_SYMMETRIC_SWEEP` - SSOR (symmetric SOR)
4207 .     `SOR_LOCAL_FORWARD_SWEEP` - local forward SOR
4208 .     `SOR_LOCAL_BACKWARD_SWEEP` - local forward SOR
4209 .     `SOR_LOCAL_SYMMETRIC_SWEEP` - local SSOR
4210 .     `SOR_EISENSTAT` - SOR with Eisenstat trick
4211 .     `SOR_APPLY_UPPER`, `SOR_APPLY_LOWER` - applies
4212   upper/lower triangular part of matrix to
4213   vector (with omega)
4214 -     `SOR_ZERO_INITIAL_GUESS` - zero initial guess
4215 
4216   Level: developer
4217 
4218   Notes:
4219   `SOR_LOCAL_FORWARD_SWEEP`, `SOR_LOCAL_BACKWARD_SWEEP`, and
4220   `SOR_LOCAL_SYMMETRIC_SWEEP` perform separate independent smoothings
4221   on each processor.
4222 
4223   Application programmers will not generally use `MatSOR()` directly,
4224   but instead will employ the `KSP`/`PC` interface.
4225 
4226   For `MATBAIJ`, `MATSBAIJ`, and `MATAIJ` matrices with Inodes this does a block SOR smoothing, otherwise it does a pointwise smoothing
4227 
4228   Most users should employ the `KSP` interface for linear solvers
4229   instead of working directly with matrix algebra routines such as this.
4230   See, e.g., `KSPCreate()`.
4231 
4232   Vectors `x` and `b` CANNOT be the same
4233 
4234   The flags are implemented as bitwise inclusive or operations.
4235   For example, use (`SOR_ZERO_INITIAL_GUESS` | `SOR_SYMMETRIC_SWEEP`)
4236   to specify a zero initial guess for SSOR.
4237 
4238   Developer Note:
4239   We should add block SOR support for `MATAIJ` matrices with block size set to great than one and no inodes
4240 
4241 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `KSP`, `PC`, `MatGetFactor()`
4242 @*/
4243 PetscErrorCode MatSOR(Mat mat, Vec b, PetscReal omega, MatSORType flag, PetscReal shift, PetscInt its, PetscInt lits, Vec x)
4244 {
4245   PetscFunctionBegin;
4246   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4247   PetscValidType(mat, 1);
4248   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4249   PetscValidHeaderSpecific(x, VEC_CLASSID, 8);
4250   PetscCheckSameComm(mat, 1, b, 2);
4251   PetscCheckSameComm(mat, 1, x, 8);
4252   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4253   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4254   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);
4255   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);
4256   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);
4257   PetscCheck(its > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires global its %" PetscInt_FMT " positive", its);
4258   PetscCheck(lits > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires local its %" PetscInt_FMT " positive", lits);
4259   PetscCheck(b != x, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "b and x vector cannot be the same");
4260 
4261   MatCheckPreallocated(mat, 1);
4262   PetscCall(PetscLogEventBegin(MAT_SOR, mat, b, x, 0));
4263   PetscUseTypeMethod(mat, sor, b, omega, flag, shift, its, lits, x);
4264   PetscCall(PetscLogEventEnd(MAT_SOR, mat, b, x, 0));
4265   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4266   PetscFunctionReturn(PETSC_SUCCESS);
4267 }
4268 
4269 /*
4270       Default matrix copy routine.
4271 */
4272 PetscErrorCode MatCopy_Basic(Mat A, Mat B, MatStructure str)
4273 {
4274   PetscInt           i, rstart = 0, rend = 0, nz;
4275   const PetscInt    *cwork;
4276   const PetscScalar *vwork;
4277 
4278   PetscFunctionBegin;
4279   if (B->assembled) PetscCall(MatZeroEntries(B));
4280   if (str == SAME_NONZERO_PATTERN) {
4281     PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
4282     for (i = rstart; i < rend; i++) {
4283       PetscCall(MatGetRow(A, i, &nz, &cwork, &vwork));
4284       PetscCall(MatSetValues(B, 1, &i, nz, cwork, vwork, INSERT_VALUES));
4285       PetscCall(MatRestoreRow(A, i, &nz, &cwork, &vwork));
4286     }
4287   } else {
4288     PetscCall(MatAYPX(B, 0.0, A, str));
4289   }
4290   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
4291   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
4292   PetscFunctionReturn(PETSC_SUCCESS);
4293 }
4294 
4295 /*@
4296   MatCopy - Copies a matrix to another matrix.
4297 
4298   Collective
4299 
4300   Input Parameters:
4301 + A   - the matrix
4302 - str - `SAME_NONZERO_PATTERN` or `DIFFERENT_NONZERO_PATTERN`
4303 
4304   Output Parameter:
4305 . B - where the copy is put
4306 
4307   Level: intermediate
4308 
4309   Notes:
4310   If you use `SAME_NONZERO_PATTERN`, then the two matrices must have the same nonzero pattern or the routine will crash.
4311 
4312   `MatCopy()` copies the matrix entries of a matrix to another existing
4313   matrix (after first zeroing the second matrix).  A related routine is
4314   `MatConvert()`, which first creates a new matrix and then copies the data.
4315 
4316 .seealso: [](ch_matrices), `Mat`, `MatConvert()`, `MatDuplicate()`
4317 @*/
4318 PetscErrorCode MatCopy(Mat A, Mat B, MatStructure str)
4319 {
4320   PetscInt i;
4321 
4322   PetscFunctionBegin;
4323   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
4324   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
4325   PetscValidType(A, 1);
4326   PetscValidType(B, 2);
4327   PetscCheckSameComm(A, 1, B, 2);
4328   MatCheckPreallocated(B, 2);
4329   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4330   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4331   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,
4332              A->cmap->N, B->cmap->N);
4333   MatCheckPreallocated(A, 1);
4334   if (A == B) PetscFunctionReturn(PETSC_SUCCESS);
4335 
4336   PetscCall(PetscLogEventBegin(MAT_Copy, A, B, 0, 0));
4337   if (A->ops->copy) PetscUseTypeMethod(A, copy, B, str);
4338   else PetscCall(MatCopy_Basic(A, B, str));
4339 
4340   B->stencil.dim = A->stencil.dim;
4341   B->stencil.noc = A->stencil.noc;
4342   for (i = 0; i <= A->stencil.dim + (A->stencil.noc ? 0 : -1); i++) {
4343     B->stencil.dims[i]   = A->stencil.dims[i];
4344     B->stencil.starts[i] = A->stencil.starts[i];
4345   }
4346 
4347   PetscCall(PetscLogEventEnd(MAT_Copy, A, B, 0, 0));
4348   PetscCall(PetscObjectStateIncrease((PetscObject)B));
4349   PetscFunctionReturn(PETSC_SUCCESS);
4350 }
4351 
4352 /*@
4353   MatConvert - Converts a matrix to another matrix, either of the same
4354   or different type.
4355 
4356   Collective
4357 
4358   Input Parameters:
4359 + mat     - the matrix
4360 . newtype - new matrix type.  Use `MATSAME` to create a new matrix of the
4361             same type as the original matrix.
4362 - reuse   - denotes if the destination matrix is to be created or reused.
4363             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
4364             `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).
4365 
4366   Output Parameter:
4367 . M - pointer to place new matrix
4368 
4369   Level: intermediate
4370 
4371   Notes:
4372   `MatConvert()` first creates a new matrix and then copies the data from
4373   the first matrix.  A related routine is `MatCopy()`, which copies the matrix
4374   entries of one matrix to another already existing matrix context.
4375 
4376   Cannot be used to convert a sequential matrix to parallel or parallel to sequential,
4377   the MPI communicator of the generated matrix is always the same as the communicator
4378   of the input matrix.
4379 
4380 .seealso: [](ch_matrices), `Mat`, `MatCopy()`, `MatDuplicate()`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
4381 @*/
4382 PetscErrorCode MatConvert(Mat mat, MatType newtype, MatReuse reuse, Mat *M)
4383 {
4384   PetscBool  sametype, issame, flg;
4385   PetscBool3 issymmetric, ishermitian;
4386   char       convname[256], mtype[256];
4387   Mat        B;
4388 
4389   PetscFunctionBegin;
4390   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4391   PetscValidType(mat, 1);
4392   PetscAssertPointer(M, 4);
4393   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4394   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4395   MatCheckPreallocated(mat, 1);
4396 
4397   PetscCall(PetscOptionsGetString(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matconvert_type", mtype, sizeof(mtype), &flg));
4398   if (flg) newtype = mtype;
4399 
4400   PetscCall(PetscObjectTypeCompare((PetscObject)mat, newtype, &sametype));
4401   PetscCall(PetscStrcmp(newtype, "same", &issame));
4402   PetscCheck(!(reuse == MAT_INPLACE_MATRIX) || !(mat != *M), PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX requires same input and output matrix");
4403   if (reuse == MAT_REUSE_MATRIX) {
4404     PetscValidHeaderSpecific(*M, MAT_CLASSID, 4);
4405     PetscCheck(mat != *M, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_REUSE_MATRIX means reuse matrix in final argument, perhaps you mean MAT_INPLACE_MATRIX");
4406   }
4407 
4408   if ((reuse == MAT_INPLACE_MATRIX) && (issame || sametype)) {
4409     PetscCall(PetscInfo(mat, "Early return for inplace %s %d %d\n", ((PetscObject)mat)->type_name, sametype, issame));
4410     PetscFunctionReturn(PETSC_SUCCESS);
4411   }
4412 
4413   /* Cache Mat options because some converters use MatHeaderReplace  */
4414   issymmetric = mat->symmetric;
4415   ishermitian = mat->hermitian;
4416 
4417   if ((sametype || issame) && (reuse == MAT_INITIAL_MATRIX) && mat->ops->duplicate) {
4418     PetscCall(PetscInfo(mat, "Calling duplicate for initial matrix %s %d %d\n", ((PetscObject)mat)->type_name, sametype, issame));
4419     PetscUseTypeMethod(mat, duplicate, MAT_COPY_VALUES, M);
4420   } else {
4421     PetscErrorCode (*conv)(Mat, MatType, MatReuse, Mat *) = NULL;
4422     const char *prefix[3]                                 = {"seq", "mpi", ""};
4423     PetscInt    i;
4424     /*
4425        Order of precedence:
4426        0) See if newtype is a superclass of the current matrix.
4427        1) See if a specialized converter is known to the current matrix.
4428        2) See if a specialized converter is known to the desired matrix class.
4429        3) See if a good general converter is registered for the desired class
4430           (as of 6/27/03 only MATMPIADJ falls into this category).
4431        4) See if a good general converter is known for the current matrix.
4432        5) Use a really basic converter.
4433     */
4434 
4435     /* 0) See if newtype is a superclass of the current matrix.
4436           i.e mat is mpiaij and newtype is aij */
4437     for (i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(prefix); i++) {
4438       PetscCall(PetscStrncpy(convname, prefix[i], sizeof(convname)));
4439       PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4440       PetscCall(PetscStrcmp(convname, ((PetscObject)mat)->type_name, &flg));
4441       PetscCall(PetscInfo(mat, "Check superclass %s %s -> %d\n", convname, ((PetscObject)mat)->type_name, flg));
4442       if (flg) {
4443         if (reuse == MAT_INPLACE_MATRIX) {
4444           PetscCall(PetscInfo(mat, "Early return\n"));
4445           PetscFunctionReturn(PETSC_SUCCESS);
4446         } else if (reuse == MAT_INITIAL_MATRIX && mat->ops->duplicate) {
4447           PetscCall(PetscInfo(mat, "Calling MatDuplicate\n"));
4448           PetscUseTypeMethod(mat, duplicate, MAT_COPY_VALUES, M);
4449           PetscFunctionReturn(PETSC_SUCCESS);
4450         } else if (reuse == MAT_REUSE_MATRIX && mat->ops->copy) {
4451           PetscCall(PetscInfo(mat, "Calling MatCopy\n"));
4452           PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
4453           PetscFunctionReturn(PETSC_SUCCESS);
4454         }
4455       }
4456     }
4457     /* 1) See if a specialized converter is known to the current matrix and the desired class */
4458     for (i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(prefix); i++) {
4459       PetscCall(PetscStrncpy(convname, "MatConvert_", sizeof(convname)));
4460       PetscCall(PetscStrlcat(convname, ((PetscObject)mat)->type_name, sizeof(convname)));
4461       PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4462       PetscCall(PetscStrlcat(convname, prefix[i], sizeof(convname)));
4463       PetscCall(PetscStrlcat(convname, issame ? ((PetscObject)mat)->type_name : newtype, sizeof(convname)));
4464       PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4465       PetscCall(PetscObjectQueryFunction((PetscObject)mat, convname, &conv));
4466       PetscCall(PetscInfo(mat, "Check specialized (1) %s (%s) -> %d\n", convname, ((PetscObject)mat)->type_name, !!conv));
4467       if (conv) goto foundconv;
4468     }
4469 
4470     /* 2)  See if a specialized converter is known to the desired matrix class. */
4471     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
4472     PetscCall(MatSetSizes(B, mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N));
4473     PetscCall(MatSetType(B, newtype));
4474     for (i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(prefix); i++) {
4475       PetscCall(PetscStrncpy(convname, "MatConvert_", sizeof(convname)));
4476       PetscCall(PetscStrlcat(convname, ((PetscObject)mat)->type_name, sizeof(convname)));
4477       PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4478       PetscCall(PetscStrlcat(convname, prefix[i], sizeof(convname)));
4479       PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4480       PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4481       PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4482       PetscCall(PetscInfo(mat, "Check specialized (2) %s (%s) -> %d\n", convname, ((PetscObject)B)->type_name, !!conv));
4483       if (conv) {
4484         PetscCall(MatDestroy(&B));
4485         goto foundconv;
4486       }
4487     }
4488 
4489     /* 3) See if a good general converter is registered for the desired class */
4490     conv = B->ops->convertfrom;
4491     PetscCall(PetscInfo(mat, "Check convertfrom (%s) -> %d\n", ((PetscObject)B)->type_name, !!conv));
4492     PetscCall(MatDestroy(&B));
4493     if (conv) goto foundconv;
4494 
4495     /* 4) See if a good general converter is known for the current matrix */
4496     if (mat->ops->convert) conv = mat->ops->convert;
4497     PetscCall(PetscInfo(mat, "Check general convert (%s) -> %d\n", ((PetscObject)mat)->type_name, !!conv));
4498     if (conv) goto foundconv;
4499 
4500     /* 5) Use a really basic converter. */
4501     PetscCall(PetscInfo(mat, "Using MatConvert_Basic\n"));
4502     conv = MatConvert_Basic;
4503 
4504   foundconv:
4505     PetscCall(PetscLogEventBegin(MAT_Convert, mat, 0, 0, 0));
4506     PetscCall((*conv)(mat, newtype, reuse, M));
4507     if (mat->rmap->mapping && mat->cmap->mapping && !(*M)->rmap->mapping && !(*M)->cmap->mapping) {
4508       /* the block sizes must be same if the mappings are copied over */
4509       (*M)->rmap->bs = mat->rmap->bs;
4510       (*M)->cmap->bs = mat->cmap->bs;
4511       PetscCall(PetscObjectReference((PetscObject)mat->rmap->mapping));
4512       PetscCall(PetscObjectReference((PetscObject)mat->cmap->mapping));
4513       (*M)->rmap->mapping = mat->rmap->mapping;
4514       (*M)->cmap->mapping = mat->cmap->mapping;
4515     }
4516     (*M)->stencil.dim = mat->stencil.dim;
4517     (*M)->stencil.noc = mat->stencil.noc;
4518     for (i = 0; i <= mat->stencil.dim + (mat->stencil.noc ? 0 : -1); i++) {
4519       (*M)->stencil.dims[i]   = mat->stencil.dims[i];
4520       (*M)->stencil.starts[i] = mat->stencil.starts[i];
4521     }
4522     PetscCall(PetscLogEventEnd(MAT_Convert, mat, 0, 0, 0));
4523   }
4524   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4525 
4526   /* Copy Mat options */
4527   if (issymmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*M, MAT_SYMMETRIC, PETSC_TRUE));
4528   else if (issymmetric == PETSC_BOOL3_FALSE) PetscCall(MatSetOption(*M, MAT_SYMMETRIC, PETSC_FALSE));
4529   if (ishermitian == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*M, MAT_HERMITIAN, PETSC_TRUE));
4530   else if (ishermitian == PETSC_BOOL3_FALSE) PetscCall(MatSetOption(*M, MAT_HERMITIAN, PETSC_FALSE));
4531   PetscFunctionReturn(PETSC_SUCCESS);
4532 }
4533 
4534 /*@
4535   MatFactorGetSolverType - Returns name of the package providing the factorization routines
4536 
4537   Not Collective
4538 
4539   Input Parameter:
4540 . mat - the matrix, must be a factored matrix
4541 
4542   Output Parameter:
4543 . type - the string name of the package (do not free this string)
4544 
4545   Level: intermediate
4546 
4547 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolverType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`
4548 @*/
4549 PetscErrorCode MatFactorGetSolverType(Mat mat, MatSolverType *type)
4550 {
4551   PetscErrorCode (*conv)(Mat, MatSolverType *);
4552 
4553   PetscFunctionBegin;
4554   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4555   PetscValidType(mat, 1);
4556   PetscAssertPointer(type, 2);
4557   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
4558   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorGetSolverType_C", &conv));
4559   if (conv) PetscCall((*conv)(mat, type));
4560   else *type = MATSOLVERPETSC;
4561   PetscFunctionReturn(PETSC_SUCCESS);
4562 }
4563 
4564 typedef struct _MatSolverTypeForSpecifcType *MatSolverTypeForSpecifcType;
4565 struct _MatSolverTypeForSpecifcType {
4566   MatType mtype;
4567   /* no entry for MAT_FACTOR_NONE */
4568   PetscErrorCode (*createfactor[MAT_FACTOR_NUM_TYPES - 1])(Mat, MatFactorType, Mat *);
4569   MatSolverTypeForSpecifcType next;
4570 };
4571 
4572 typedef struct _MatSolverTypeHolder *MatSolverTypeHolder;
4573 struct _MatSolverTypeHolder {
4574   char                       *name;
4575   MatSolverTypeForSpecifcType handlers;
4576   MatSolverTypeHolder         next;
4577 };
4578 
4579 static MatSolverTypeHolder MatSolverTypeHolders = NULL;
4580 
4581 /*@C
4582   MatSolverTypeRegister - Registers a `MatSolverType` that works for a particular matrix type
4583 
4584   Logically Collective, No Fortran Support
4585 
4586   Input Parameters:
4587 + package      - name of the package, for example `petsc` or `superlu`
4588 . mtype        - the matrix type that works with this package
4589 . ftype        - the type of factorization supported by the package
4590 - createfactor - routine that will create the factored matrix ready to be used
4591 
4592   Level: developer
4593 
4594 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorGetSolverType()`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`,
4595   `MatGetFactor()`
4596 @*/
4597 PetscErrorCode MatSolverTypeRegister(MatSolverType package, MatType mtype, MatFactorType ftype, PetscErrorCode (*createfactor)(Mat, MatFactorType, Mat *))
4598 {
4599   MatSolverTypeHolder         next = MatSolverTypeHolders, prev = NULL;
4600   PetscBool                   flg;
4601   MatSolverTypeForSpecifcType inext, iprev = NULL;
4602 
4603   PetscFunctionBegin;
4604   PetscCall(MatInitializePackage());
4605   if (!next) {
4606     PetscCall(PetscNew(&MatSolverTypeHolders));
4607     PetscCall(PetscStrallocpy(package, &MatSolverTypeHolders->name));
4608     PetscCall(PetscNew(&MatSolverTypeHolders->handlers));
4609     PetscCall(PetscStrallocpy(mtype, (char **)&MatSolverTypeHolders->handlers->mtype));
4610     MatSolverTypeHolders->handlers->createfactor[(int)ftype - 1] = createfactor;
4611     PetscFunctionReturn(PETSC_SUCCESS);
4612   }
4613   while (next) {
4614     PetscCall(PetscStrcasecmp(package, next->name, &flg));
4615     if (flg) {
4616       PetscCheck(next->handlers, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatSolverTypeHolder is missing handlers");
4617       inext = next->handlers;
4618       while (inext) {
4619         PetscCall(PetscStrcasecmp(mtype, inext->mtype, &flg));
4620         if (flg) {
4621           inext->createfactor[(int)ftype - 1] = createfactor;
4622           PetscFunctionReturn(PETSC_SUCCESS);
4623         }
4624         iprev = inext;
4625         inext = inext->next;
4626       }
4627       PetscCall(PetscNew(&iprev->next));
4628       PetscCall(PetscStrallocpy(mtype, (char **)&iprev->next->mtype));
4629       iprev->next->createfactor[(int)ftype - 1] = createfactor;
4630       PetscFunctionReturn(PETSC_SUCCESS);
4631     }
4632     prev = next;
4633     next = next->next;
4634   }
4635   PetscCall(PetscNew(&prev->next));
4636   PetscCall(PetscStrallocpy(package, &prev->next->name));
4637   PetscCall(PetscNew(&prev->next->handlers));
4638   PetscCall(PetscStrallocpy(mtype, (char **)&prev->next->handlers->mtype));
4639   prev->next->handlers->createfactor[(int)ftype - 1] = createfactor;
4640   PetscFunctionReturn(PETSC_SUCCESS);
4641 }
4642 
4643 /*@C
4644   MatSolverTypeGet - Gets the function that creates the factor matrix if it exist
4645 
4646   Input Parameters:
4647 + 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
4648 . ftype - the type of factorization supported by the type
4649 - mtype - the matrix type that works with this type
4650 
4651   Output Parameters:
4652 + foundtype    - `PETSC_TRUE` if the type was registered
4653 . foundmtype   - `PETSC_TRUE` if the type supports the requested mtype
4654 - createfactor - routine that will create the factored matrix ready to be used or `NULL` if not found
4655 
4656   Calling sequence of `createfactor`:
4657 + A     - the matrix providing the factor matrix
4658 . ftype - the `MatFactorType` of the factor requested
4659 - B     - the new factor matrix that responds to MatXXFactorSymbolic,Numeric() functions, such as `MatLUFactorSymbolic()`
4660 
4661   Level: developer
4662 
4663   Note:
4664   When `type` is `NULL` the available functions are searched for based on the order of the calls to `MatSolverTypeRegister()` in `MatInitializePackage()`.
4665   Since different PETSc configurations may have different external solvers, seemingly identical runs with different PETSc configurations may use a different solver.
4666   For example if one configuration had `--download-mumps` while a different one had `--download-superlu_dist`.
4667 
4668 .seealso: [](ch_matrices), `Mat`, `MatFactorType`, `MatType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatSolverTypeRegister()`, `MatGetFactor()`,
4669           `MatInitializePackage()`
4670 @*/
4671 PetscErrorCode MatSolverTypeGet(MatSolverType type, MatType mtype, MatFactorType ftype, PetscBool *foundtype, PetscBool *foundmtype, PetscErrorCode (**createfactor)(Mat A, MatFactorType ftype, Mat *B))
4672 {
4673   MatSolverTypeHolder         next = MatSolverTypeHolders;
4674   PetscBool                   flg;
4675   MatSolverTypeForSpecifcType inext;
4676 
4677   PetscFunctionBegin;
4678   if (foundtype) *foundtype = PETSC_FALSE;
4679   if (foundmtype) *foundmtype = PETSC_FALSE;
4680   if (createfactor) *createfactor = NULL;
4681 
4682   if (type) {
4683     while (next) {
4684       PetscCall(PetscStrcasecmp(type, next->name, &flg));
4685       if (flg) {
4686         if (foundtype) *foundtype = PETSC_TRUE;
4687         inext = next->handlers;
4688         while (inext) {
4689           PetscCall(PetscStrbeginswith(mtype, inext->mtype, &flg));
4690           if (flg) {
4691             if (foundmtype) *foundmtype = PETSC_TRUE;
4692             if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4693             PetscFunctionReturn(PETSC_SUCCESS);
4694           }
4695           inext = inext->next;
4696         }
4697       }
4698       next = next->next;
4699     }
4700   } else {
4701     while (next) {
4702       inext = next->handlers;
4703       while (inext) {
4704         PetscCall(PetscStrcmp(mtype, inext->mtype, &flg));
4705         if (flg && inext->createfactor[(int)ftype - 1]) {
4706           if (foundtype) *foundtype = PETSC_TRUE;
4707           if (foundmtype) *foundmtype = PETSC_TRUE;
4708           if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4709           PetscFunctionReturn(PETSC_SUCCESS);
4710         }
4711         inext = inext->next;
4712       }
4713       next = next->next;
4714     }
4715     /* try with base classes inext->mtype */
4716     next = MatSolverTypeHolders;
4717     while (next) {
4718       inext = next->handlers;
4719       while (inext) {
4720         PetscCall(PetscStrbeginswith(mtype, inext->mtype, &flg));
4721         if (flg && inext->createfactor[(int)ftype - 1]) {
4722           if (foundtype) *foundtype = PETSC_TRUE;
4723           if (foundmtype) *foundmtype = PETSC_TRUE;
4724           if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4725           PetscFunctionReturn(PETSC_SUCCESS);
4726         }
4727         inext = inext->next;
4728       }
4729       next = next->next;
4730     }
4731   }
4732   PetscFunctionReturn(PETSC_SUCCESS);
4733 }
4734 
4735 PetscErrorCode MatSolverTypeDestroy(void)
4736 {
4737   MatSolverTypeHolder         next = MatSolverTypeHolders, prev;
4738   MatSolverTypeForSpecifcType inext, iprev;
4739 
4740   PetscFunctionBegin;
4741   while (next) {
4742     PetscCall(PetscFree(next->name));
4743     inext = next->handlers;
4744     while (inext) {
4745       PetscCall(PetscFree(inext->mtype));
4746       iprev = inext;
4747       inext = inext->next;
4748       PetscCall(PetscFree(iprev));
4749     }
4750     prev = next;
4751     next = next->next;
4752     PetscCall(PetscFree(prev));
4753   }
4754   MatSolverTypeHolders = NULL;
4755   PetscFunctionReturn(PETSC_SUCCESS);
4756 }
4757 
4758 /*@
4759   MatFactorGetCanUseOrdering - Indicates if the factorization can use the ordering provided in `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4760 
4761   Logically Collective
4762 
4763   Input Parameter:
4764 . mat - the matrix
4765 
4766   Output Parameter:
4767 . flg - `PETSC_TRUE` if uses the ordering
4768 
4769   Level: developer
4770 
4771   Note:
4772   Most internal PETSc factorizations use the ordering passed to the factorization routine but external
4773   packages do not, thus we want to skip generating the ordering when it is not needed or used.
4774 
4775 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4776 @*/
4777 PetscErrorCode MatFactorGetCanUseOrdering(Mat mat, PetscBool *flg)
4778 {
4779   PetscFunctionBegin;
4780   *flg = mat->canuseordering;
4781   PetscFunctionReturn(PETSC_SUCCESS);
4782 }
4783 
4784 /*@
4785   MatFactorGetPreferredOrdering - The preferred ordering for a particular matrix factor object
4786 
4787   Logically Collective
4788 
4789   Input Parameters:
4790 + mat   - the matrix obtained with `MatGetFactor()`
4791 - ftype - the factorization type to be used
4792 
4793   Output Parameter:
4794 . otype - the preferred ordering type
4795 
4796   Level: developer
4797 
4798 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatOrderingType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4799 @*/
4800 PetscErrorCode MatFactorGetPreferredOrdering(Mat mat, MatFactorType ftype, MatOrderingType *otype)
4801 {
4802   PetscFunctionBegin;
4803   *otype = mat->preferredordering[ftype];
4804   PetscCheck(*otype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatFactor did not have a preferred ordering");
4805   PetscFunctionReturn(PETSC_SUCCESS);
4806 }
4807 
4808 /*@
4809   MatGetFactor - Returns a matrix suitable to calls to MatXXFactorSymbolic,Numeric()
4810 
4811   Collective
4812 
4813   Input Parameters:
4814 + mat   - the matrix
4815 . 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
4816           the other criteria is returned
4817 - ftype - factor type, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`
4818 
4819   Output Parameter:
4820 . f - the factor matrix used with MatXXFactorSymbolic,Numeric() calls. Can be `NULL` in some cases, see notes below.
4821 
4822   Options Database Keys:
4823 + -pc_factor_mat_solver_type <type>    - choose the type at run time. When using `KSP` solvers
4824 . -pc_factor_mat_factor_on_host <bool> - do mat factorization on host (with device matrices). Default is doing it on device
4825 - -pc_factor_mat_solve_on_host <bool>  - do mat solve on host (with device matrices). Default is doing it on device
4826 
4827   Level: intermediate
4828 
4829   Notes:
4830   The return matrix can be `NULL` if the requested factorization is not available, since some combinations of matrix types and factorization
4831   types registered with `MatSolverTypeRegister()` cannot be fully tested if not at runtime.
4832 
4833   Users usually access the factorization solvers via `KSP`
4834 
4835   Some PETSc matrix formats have alternative solvers available that are contained in alternative packages
4836   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
4837 
4838   When `type` is `NULL` the available results are searched for based on the order of the calls to `MatSolverTypeRegister()` in `MatInitializePackage()`.
4839   Since different PETSc configurations may have different external solvers, seemingly identical runs with different PETSc configurations may use a different solver.
4840   For example if one configuration had --download-mumps while a different one had --download-superlu_dist.
4841 
4842   Some of the packages have options for controlling the factorization, these are in the form -prefix_mat_packagename_packageoption
4843   where prefix is normally obtained from the calling `KSP`/`PC`. If `MatGetFactor()` is called directly one can set
4844   call `MatSetOptionsPrefixFactor()` on the originating matrix or  `MatSetOptionsPrefix()` on the resulting factor matrix.
4845 
4846   Developer Note:
4847   This should actually be called `MatCreateFactor()` since it creates a new factor object
4848 
4849 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `KSP`, `MatSolverType`, `MatFactorType`, `MatCopy()`, `MatDuplicate()`,
4850           `MatGetFactorAvailable()`, `MatFactorGetCanUseOrdering()`, `MatSolverTypeRegister()`, `MatSolverTypeGet()`
4851           `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`, `MatInitializePackage()`
4852 @*/
4853 PetscErrorCode MatGetFactor(Mat mat, MatSolverType type, MatFactorType ftype, Mat *f)
4854 {
4855   PetscBool foundtype, foundmtype, shell, hasop = PETSC_FALSE;
4856   PetscErrorCode (*conv)(Mat, MatFactorType, Mat *);
4857 
4858   PetscFunctionBegin;
4859   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4860   PetscValidType(mat, 1);
4861 
4862   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4863   MatCheckPreallocated(mat, 1);
4864 
4865   PetscCall(MatIsShell(mat, &shell));
4866   if (shell) PetscCall(MatHasOperation(mat, MATOP_GET_FACTOR, &hasop));
4867   if (hasop) {
4868     PetscUseTypeMethod(mat, getfactor, type, ftype, f);
4869     PetscFunctionReturn(PETSC_SUCCESS);
4870   }
4871 
4872   PetscCall(MatSolverTypeGet(type, ((PetscObject)mat)->type_name, ftype, &foundtype, &foundmtype, &conv));
4873   if (!foundtype) {
4874     if (type) {
4875       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],
4876               ((PetscObject)mat)->type_name, type);
4877     } else {
4878       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);
4879     }
4880   }
4881   PetscCheck(foundmtype, PetscObjectComm((PetscObject)mat), PETSC_ERR_MISSING_FACTOR, "MatSolverType %s does not support matrix type %s", type, ((PetscObject)mat)->type_name);
4882   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);
4883 
4884   PetscCall((*conv)(mat, ftype, f));
4885   if (mat->factorprefix) PetscCall(MatSetOptionsPrefix(*f, mat->factorprefix));
4886   PetscFunctionReturn(PETSC_SUCCESS);
4887 }
4888 
4889 /*@
4890   MatGetFactorAvailable - Returns a flag if matrix supports particular type and factor type
4891 
4892   Not Collective
4893 
4894   Input Parameters:
4895 + mat   - the matrix
4896 . type  - name of solver type, for example, `superlu`, `petsc` (to use PETSc's default)
4897 - ftype - factor type, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`
4898 
4899   Output Parameter:
4900 . flg - PETSC_TRUE if the factorization is available
4901 
4902   Level: intermediate
4903 
4904   Notes:
4905   Some PETSc matrix formats have alternative solvers available that are contained in alternative packages
4906   such as pastix, superlu, mumps etc.
4907 
4908   PETSc must have been ./configure to use the external solver, using the option --download-package
4909 
4910   Developer Note:
4911   This should actually be called `MatCreateFactorAvailable()` since `MatGetFactor()` creates a new factor object
4912 
4913 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatSolverType`, `MatFactorType`, `MatGetFactor()`, `MatCopy()`, `MatDuplicate()`, `MatSolverTypeRegister()`,
4914           `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`, `MatSolverTypeGet()`
4915 @*/
4916 PetscErrorCode MatGetFactorAvailable(Mat mat, MatSolverType type, MatFactorType ftype, PetscBool *flg)
4917 {
4918   PetscErrorCode (*gconv)(Mat, MatFactorType, Mat *);
4919 
4920   PetscFunctionBegin;
4921   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4922   PetscAssertPointer(flg, 4);
4923 
4924   *flg = PETSC_FALSE;
4925   if (!((PetscObject)mat)->type_name) PetscFunctionReturn(PETSC_SUCCESS);
4926 
4927   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4928   MatCheckPreallocated(mat, 1);
4929 
4930   PetscCall(MatSolverTypeGet(type, ((PetscObject)mat)->type_name, ftype, NULL, NULL, &gconv));
4931   *flg = gconv ? PETSC_TRUE : PETSC_FALSE;
4932   PetscFunctionReturn(PETSC_SUCCESS);
4933 }
4934 
4935 /*@
4936   MatDuplicate - Duplicates a matrix including the non-zero structure.
4937 
4938   Collective
4939 
4940   Input Parameters:
4941 + mat - the matrix
4942 - op  - One of `MAT_DO_NOT_COPY_VALUES`, `MAT_COPY_VALUES`, or `MAT_SHARE_NONZERO_PATTERN`.
4943         See the manual page for `MatDuplicateOption()` for an explanation of these options.
4944 
4945   Output Parameter:
4946 . M - pointer to place new matrix
4947 
4948   Level: intermediate
4949 
4950   Notes:
4951   You cannot change the nonzero pattern for the parent or child matrix later if you use `MAT_SHARE_NONZERO_PATTERN`.
4952 
4953   If `op` is not `MAT_COPY_VALUES` the numerical values in the new matrix are zeroed.
4954 
4955   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.
4956 
4957   When original mat is a product of matrix operation, e.g., an output of `MatMatMult()` or `MatCreateSubMatrix()`, only the matrix data structure of `mat`
4958   is duplicated and the internal data structures created for the reuse of previous matrix operations are not duplicated.
4959   User should not use `MatDuplicate()` to create new matrix `M` if `M` is intended to be reused as the product of matrix operation.
4960 
4961 .seealso: [](ch_matrices), `Mat`, `MatCopy()`, `MatConvert()`, `MatDuplicateOption`
4962 @*/
4963 PetscErrorCode MatDuplicate(Mat mat, MatDuplicateOption op, Mat *M)
4964 {
4965   Mat         B;
4966   VecType     vtype;
4967   PetscInt    i;
4968   PetscObject dm, container_h, container_d;
4969   void (*viewf)(void);
4970 
4971   PetscFunctionBegin;
4972   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4973   PetscValidType(mat, 1);
4974   PetscAssertPointer(M, 3);
4975   PetscCheck(op != MAT_COPY_VALUES || mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MAT_COPY_VALUES not allowed for unassembled matrix");
4976   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4977   MatCheckPreallocated(mat, 1);
4978 
4979   PetscCall(PetscLogEventBegin(MAT_Convert, mat, 0, 0, 0));
4980   PetscUseTypeMethod(mat, duplicate, op, M);
4981   PetscCall(PetscLogEventEnd(MAT_Convert, mat, 0, 0, 0));
4982   B = *M;
4983 
4984   PetscCall(MatGetOperation(mat, MATOP_VIEW, &viewf));
4985   if (viewf) PetscCall(MatSetOperation(B, MATOP_VIEW, viewf));
4986   PetscCall(MatGetVecType(mat, &vtype));
4987   PetscCall(MatSetVecType(B, vtype));
4988 
4989   B->stencil.dim = mat->stencil.dim;
4990   B->stencil.noc = mat->stencil.noc;
4991   for (i = 0; i <= mat->stencil.dim + (mat->stencil.noc ? 0 : -1); i++) {
4992     B->stencil.dims[i]   = mat->stencil.dims[i];
4993     B->stencil.starts[i] = mat->stencil.starts[i];
4994   }
4995 
4996   B->nooffproczerorows = mat->nooffproczerorows;
4997   B->nooffprocentries  = mat->nooffprocentries;
4998 
4999   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_dm", &dm));
5000   if (dm) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_dm", dm));
5001   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_MatCOOStruct_Host", &container_h));
5002   if (container_h) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_MatCOOStruct_Host", container_h));
5003   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_MatCOOStruct_Device", &container_d));
5004   if (container_d) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_MatCOOStruct_Device", container_d));
5005   if (op == MAT_COPY_VALUES) PetscCall(MatPropagateSymmetryOptions(mat, B));
5006   PetscCall(PetscObjectStateIncrease((PetscObject)B));
5007   PetscFunctionReturn(PETSC_SUCCESS);
5008 }
5009 
5010 /*@
5011   MatGetDiagonal - Gets the diagonal of a matrix as a `Vec`
5012 
5013   Logically Collective
5014 
5015   Input Parameter:
5016 . mat - the matrix
5017 
5018   Output Parameter:
5019 . v - the diagonal of the matrix
5020 
5021   Level: intermediate
5022 
5023   Note:
5024   If `mat` has local sizes `n` x `m`, this routine fills the first `ndiag = min(n, m)` entries
5025   of `v` with the diagonal values. Thus `v` must have local size of at least `ndiag`. If `v`
5026   is larger than `ndiag`, the values of the remaining entries are unspecified.
5027 
5028   Currently only correct in parallel for square matrices.
5029 
5030 .seealso: [](ch_matrices), `Mat`, `Vec`, `MatGetRow()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`
5031 @*/
5032 PetscErrorCode MatGetDiagonal(Mat mat, Vec v)
5033 {
5034   PetscFunctionBegin;
5035   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5036   PetscValidType(mat, 1);
5037   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5038   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5039   MatCheckPreallocated(mat, 1);
5040   if (PetscDefined(USE_DEBUG)) {
5041     PetscInt nv, row, col, ndiag;
5042 
5043     PetscCall(VecGetLocalSize(v, &nv));
5044     PetscCall(MatGetLocalSize(mat, &row, &col));
5045     ndiag = PetscMin(row, col);
5046     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);
5047   }
5048 
5049   PetscUseTypeMethod(mat, getdiagonal, v);
5050   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5051   PetscFunctionReturn(PETSC_SUCCESS);
5052 }
5053 
5054 /*@
5055   MatGetRowMin - Gets the minimum value (of the real part) of each
5056   row of the matrix
5057 
5058   Logically Collective
5059 
5060   Input Parameter:
5061 . mat - the matrix
5062 
5063   Output Parameters:
5064 + v   - the vector for storing the maximums
5065 - idx - the indices of the column found for each row (optional, pass `NULL` if not needed)
5066 
5067   Level: intermediate
5068 
5069   Note:
5070   The result of this call are the same as if one converted the matrix to dense format
5071   and found the minimum value in each row (i.e. the implicit zeros are counted as zeros).
5072 
5073   This code is only implemented for a couple of matrix formats.
5074 
5075 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`, `MatGetRowMinAbs()`,
5076           `MatGetRowMax()`
5077 @*/
5078 PetscErrorCode MatGetRowMin(Mat mat, Vec v, PetscInt idx[])
5079 {
5080   PetscFunctionBegin;
5081   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5082   PetscValidType(mat, 1);
5083   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5084   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5085 
5086   if (!mat->cmap->N) {
5087     PetscCall(VecSet(v, PETSC_MAX_REAL));
5088     if (idx) {
5089       PetscInt i, m = mat->rmap->n;
5090       for (i = 0; i < m; i++) idx[i] = -1;
5091     }
5092   } else {
5093     MatCheckPreallocated(mat, 1);
5094   }
5095   PetscUseTypeMethod(mat, getrowmin, v, idx);
5096   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5097   PetscFunctionReturn(PETSC_SUCCESS);
5098 }
5099 
5100 /*@
5101   MatGetRowMinAbs - Gets the minimum value (in absolute value) of each
5102   row of the matrix
5103 
5104   Logically Collective
5105 
5106   Input Parameter:
5107 . mat - the matrix
5108 
5109   Output Parameters:
5110 + v   - the vector for storing the minimums
5111 - idx - the indices of the column found for each row (or `NULL` if not needed)
5112 
5113   Level: intermediate
5114 
5115   Notes:
5116   if a row is completely empty or has only 0.0 values, then the `idx` value for that
5117   row is 0 (the first column).
5118 
5119   This code is only implemented for a couple of matrix formats.
5120 
5121 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMaxAbs()`, `MatGetRowMin()`
5122 @*/
5123 PetscErrorCode MatGetRowMinAbs(Mat mat, Vec v, PetscInt idx[])
5124 {
5125   PetscFunctionBegin;
5126   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5127   PetscValidType(mat, 1);
5128   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5129   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5130   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5131 
5132   if (!mat->cmap->N) {
5133     PetscCall(VecSet(v, 0.0));
5134     if (idx) {
5135       PetscInt i, m = mat->rmap->n;
5136       for (i = 0; i < m; i++) idx[i] = -1;
5137     }
5138   } else {
5139     MatCheckPreallocated(mat, 1);
5140     if (idx) PetscCall(PetscArrayzero(idx, mat->rmap->n));
5141     PetscUseTypeMethod(mat, getrowminabs, v, idx);
5142   }
5143   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5144   PetscFunctionReturn(PETSC_SUCCESS);
5145 }
5146 
5147 /*@
5148   MatGetRowMax - Gets the maximum value (of the real part) of each
5149   row of the matrix
5150 
5151   Logically Collective
5152 
5153   Input Parameter:
5154 . mat - the matrix
5155 
5156   Output Parameters:
5157 + v   - the vector for storing the maximums
5158 - idx - the indices of the column found for each row (optional, otherwise pass `NULL`)
5159 
5160   Level: intermediate
5161 
5162   Notes:
5163   The result of this call are the same as if one converted the matrix to dense format
5164   and found the minimum value in each row (i.e. the implicit zeros are counted as zeros).
5165 
5166   This code is only implemented for a couple of matrix formats.
5167 
5168 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5169 @*/
5170 PetscErrorCode MatGetRowMax(Mat mat, Vec v, PetscInt idx[])
5171 {
5172   PetscFunctionBegin;
5173   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5174   PetscValidType(mat, 1);
5175   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5176   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5177 
5178   if (!mat->cmap->N) {
5179     PetscCall(VecSet(v, PETSC_MIN_REAL));
5180     if (idx) {
5181       PetscInt i, m = mat->rmap->n;
5182       for (i = 0; i < m; i++) idx[i] = -1;
5183     }
5184   } else {
5185     MatCheckPreallocated(mat, 1);
5186     PetscUseTypeMethod(mat, getrowmax, v, idx);
5187   }
5188   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5189   PetscFunctionReturn(PETSC_SUCCESS);
5190 }
5191 
5192 /*@
5193   MatGetRowMaxAbs - Gets the maximum value (in absolute value) of each
5194   row of the matrix
5195 
5196   Logically Collective
5197 
5198   Input Parameter:
5199 . mat - the matrix
5200 
5201   Output Parameters:
5202 + v   - the vector for storing the maximums
5203 - idx - the indices of the column found for each row (or `NULL` if not needed)
5204 
5205   Level: intermediate
5206 
5207   Notes:
5208   if a row is completely empty or has only 0.0 values, then the `idx` value for that
5209   row is 0 (the first column).
5210 
5211   This code is only implemented for a couple of matrix formats.
5212 
5213 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowSum()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5214 @*/
5215 PetscErrorCode MatGetRowMaxAbs(Mat mat, Vec v, PetscInt idx[])
5216 {
5217   PetscFunctionBegin;
5218   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5219   PetscValidType(mat, 1);
5220   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5221   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5222 
5223   if (!mat->cmap->N) {
5224     PetscCall(VecSet(v, 0.0));
5225     if (idx) {
5226       PetscInt i, m = mat->rmap->n;
5227       for (i = 0; i < m; i++) idx[i] = -1;
5228     }
5229   } else {
5230     MatCheckPreallocated(mat, 1);
5231     if (idx) PetscCall(PetscArrayzero(idx, mat->rmap->n));
5232     PetscUseTypeMethod(mat, getrowmaxabs, v, idx);
5233   }
5234   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5235   PetscFunctionReturn(PETSC_SUCCESS);
5236 }
5237 
5238 /*@
5239   MatGetRowSumAbs - Gets the sum value (in absolute value) of each row of the matrix
5240 
5241   Logically Collective
5242 
5243   Input Parameter:
5244 . mat - the matrix
5245 
5246   Output Parameter:
5247 . v - the vector for storing the sum
5248 
5249   Level: intermediate
5250 
5251   This code is only implemented for a couple of matrix formats.
5252 
5253 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5254 @*/
5255 PetscErrorCode MatGetRowSumAbs(Mat mat, Vec v)
5256 {
5257   PetscFunctionBegin;
5258   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5259   PetscValidType(mat, 1);
5260   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5261   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5262 
5263   if (!mat->cmap->N) {
5264     PetscCall(VecSet(v, 0.0));
5265   } else {
5266     MatCheckPreallocated(mat, 1);
5267     PetscUseTypeMethod(mat, getrowsumabs, v);
5268   }
5269   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5270   PetscFunctionReturn(PETSC_SUCCESS);
5271 }
5272 
5273 /*@
5274   MatGetRowSum - Gets the sum of each row of the matrix
5275 
5276   Logically or Neighborhood Collective
5277 
5278   Input Parameter:
5279 . mat - the matrix
5280 
5281   Output Parameter:
5282 . v - the vector for storing the sum of rows
5283 
5284   Level: intermediate
5285 
5286   Note:
5287   This code is slow since it is not currently specialized for different formats
5288 
5289 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMin()`, `MatGetRowMaxAbs()`, `MatGetRowMinAbs()`, `MatGetRowSumAbs()`
5290 @*/
5291 PetscErrorCode MatGetRowSum(Mat mat, Vec v)
5292 {
5293   Vec ones;
5294 
5295   PetscFunctionBegin;
5296   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5297   PetscValidType(mat, 1);
5298   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5299   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5300   MatCheckPreallocated(mat, 1);
5301   PetscCall(MatCreateVecs(mat, &ones, NULL));
5302   PetscCall(VecSet(ones, 1.));
5303   PetscCall(MatMult(mat, ones, v));
5304   PetscCall(VecDestroy(&ones));
5305   PetscFunctionReturn(PETSC_SUCCESS);
5306 }
5307 
5308 /*@
5309   MatTransposeSetPrecursor - Set the matrix from which the second matrix will receive numerical transpose data with a call to `MatTranspose`(A,`MAT_REUSE_MATRIX`,&B)
5310   when B was not obtained with `MatTranspose`(A,`MAT_INITIAL_MATRIX`,&B)
5311 
5312   Collective
5313 
5314   Input Parameter:
5315 . mat - the matrix to provide the transpose
5316 
5317   Output Parameter:
5318 . 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
5319 
5320   Level: advanced
5321 
5322   Note:
5323   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
5324   routine allows bypassing that call.
5325 
5326 .seealso: [](ch_matrices), `Mat`, `MatTransposeSymbolic()`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
5327 @*/
5328 PetscErrorCode MatTransposeSetPrecursor(Mat mat, Mat B)
5329 {
5330   MatParentState *rb = NULL;
5331 
5332   PetscFunctionBegin;
5333   PetscCall(PetscNew(&rb));
5334   rb->id    = ((PetscObject)mat)->id;
5335   rb->state = 0;
5336   PetscCall(MatGetNonzeroState(mat, &rb->nonzerostate));
5337   PetscCall(PetscObjectContainerCompose((PetscObject)B, "MatTransposeParent", rb, PetscCtxDestroyDefault));
5338   PetscFunctionReturn(PETSC_SUCCESS);
5339 }
5340 
5341 /*@
5342   MatTranspose - Computes the transpose of a matrix, either in-place or out-of-place.
5343 
5344   Collective
5345 
5346   Input Parameters:
5347 + mat   - the matrix to transpose
5348 - reuse - either `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, or `MAT_INPLACE_MATRIX`
5349 
5350   Output Parameter:
5351 . B - the transpose of the matrix
5352 
5353   Level: intermediate
5354 
5355   Notes:
5356   If you use `MAT_INPLACE_MATRIX` then you must pass in `&mat` for `B`
5357 
5358   `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
5359   transpose, call `MatTransposeSetPrecursor(mat, B)` before calling this routine.
5360 
5361   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.
5362 
5363   Consider using `MatCreateTranspose()` instead if you only need a matrix that behaves like the transpose but don't need the storage to be changed.
5364   For example, the result of `MatCreateTranspose()` will compute the transpose of the given matrix times a vector for matrix-vector products computed with `MatMult()`.
5365 
5366   If `mat` is unchanged from the last call this function returns immediately without recomputing the result
5367 
5368   If you only need the symbolic transpose of a matrix, and not the numerical values, use `MatTransposeSymbolic()`
5369 
5370 .seealso: [](ch_matrices), `Mat`, `MatTransposeSetPrecursor()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`,
5371           `MatTransposeSymbolic()`, `MatCreateTranspose()`
5372 @*/
5373 PetscErrorCode MatTranspose(Mat mat, MatReuse reuse, Mat *B)
5374 {
5375   PetscContainer  rB = NULL;
5376   MatParentState *rb = NULL;
5377 
5378   PetscFunctionBegin;
5379   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5380   PetscValidType(mat, 1);
5381   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5382   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5383   PetscCheck(reuse != MAT_INPLACE_MATRIX || mat == *B, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX requires last matrix to match first");
5384   PetscCheck(reuse != MAT_REUSE_MATRIX || mat != *B, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Perhaps you mean MAT_INPLACE_MATRIX");
5385   MatCheckPreallocated(mat, 1);
5386   if (reuse == MAT_REUSE_MATRIX) {
5387     PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
5388     PetscCheck(rB, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose(). Suggest MatTransposeSetPrecursor().");
5389     PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5390     PetscCheck(rb->id == ((PetscObject)mat)->id, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from input matrix");
5391     if (rb->state == ((PetscObject)mat)->state) PetscFunctionReturn(PETSC_SUCCESS);
5392   }
5393 
5394   PetscCall(PetscLogEventBegin(MAT_Transpose, mat, 0, 0, 0));
5395   if (reuse != MAT_INPLACE_MATRIX || mat->symmetric != PETSC_BOOL3_TRUE) {
5396     PetscUseTypeMethod(mat, transpose, reuse, B);
5397     PetscCall(PetscObjectStateIncrease((PetscObject)*B));
5398   }
5399   PetscCall(PetscLogEventEnd(MAT_Transpose, mat, 0, 0, 0));
5400 
5401   if (reuse == MAT_INITIAL_MATRIX) PetscCall(MatTransposeSetPrecursor(mat, *B));
5402   if (reuse != MAT_INPLACE_MATRIX) {
5403     PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
5404     PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5405     rb->state        = ((PetscObject)mat)->state;
5406     rb->nonzerostate = mat->nonzerostate;
5407   }
5408   PetscFunctionReturn(PETSC_SUCCESS);
5409 }
5410 
5411 /*@
5412   MatTransposeSymbolic - Computes the symbolic part of the transpose of a matrix.
5413 
5414   Collective
5415 
5416   Input Parameter:
5417 . A - the matrix to transpose
5418 
5419   Output Parameter:
5420 . 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
5421       numerical portion.
5422 
5423   Level: intermediate
5424 
5425   Note:
5426   This is not supported for many matrix types, use `MatTranspose()` in those cases
5427 
5428 .seealso: [](ch_matrices), `Mat`, `MatTransposeSetPrecursor()`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
5429 @*/
5430 PetscErrorCode MatTransposeSymbolic(Mat A, Mat *B)
5431 {
5432   PetscFunctionBegin;
5433   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5434   PetscValidType(A, 1);
5435   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5436   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5437   PetscCall(PetscLogEventBegin(MAT_Transpose, A, 0, 0, 0));
5438   PetscUseTypeMethod(A, transposesymbolic, B);
5439   PetscCall(PetscLogEventEnd(MAT_Transpose, A, 0, 0, 0));
5440 
5441   PetscCall(MatTransposeSetPrecursor(A, *B));
5442   PetscFunctionReturn(PETSC_SUCCESS);
5443 }
5444 
5445 PetscErrorCode MatTransposeCheckNonzeroState_Private(Mat A, Mat B)
5446 {
5447   PetscContainer  rB;
5448   MatParentState *rb;
5449 
5450   PetscFunctionBegin;
5451   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5452   PetscValidType(A, 1);
5453   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5454   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5455   PetscCall(PetscObjectQuery((PetscObject)B, "MatTransposeParent", (PetscObject *)&rB));
5456   PetscCheck(rB, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose()");
5457   PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5458   PetscCheck(rb->id == ((PetscObject)A)->id, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from input matrix");
5459   PetscCheck(rb->nonzerostate == A->nonzerostate, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Reuse matrix has changed nonzero structure");
5460   PetscFunctionReturn(PETSC_SUCCESS);
5461 }
5462 
5463 /*@
5464   MatIsTranspose - Test whether a matrix is another one's transpose,
5465   or its own, in which case it tests symmetry.
5466 
5467   Collective
5468 
5469   Input Parameters:
5470 + A   - the matrix to test
5471 . B   - the matrix to test against, this can equal the first parameter
5472 - tol - tolerance, differences between entries smaller than this are counted as zero
5473 
5474   Output Parameter:
5475 . flg - the result
5476 
5477   Level: intermediate
5478 
5479   Notes:
5480   The sequential algorithm has a running time of the order of the number of nonzeros; the parallel
5481   test involves parallel copies of the block off-diagonal parts of the matrix.
5482 
5483 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsSymmetric()`, `MatIsHermitian()`
5484 @*/
5485 PetscErrorCode MatIsTranspose(Mat A, Mat B, PetscReal tol, PetscBool *flg)
5486 {
5487   PetscErrorCode (*f)(Mat, Mat, PetscReal, PetscBool *), (*g)(Mat, Mat, PetscReal, PetscBool *);
5488 
5489   PetscFunctionBegin;
5490   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5491   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5492   PetscAssertPointer(flg, 4);
5493   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatIsTranspose_C", &f));
5494   PetscCall(PetscObjectQueryFunction((PetscObject)B, "MatIsTranspose_C", &g));
5495   *flg = PETSC_FALSE;
5496   if (f && g) {
5497     PetscCheck(f == g, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_NOTSAMETYPE, "Matrices do not have the same comparator for symmetry test");
5498     PetscCall((*f)(A, B, tol, flg));
5499   } else {
5500     MatType mattype;
5501 
5502     PetscCall(MatGetType(f ? B : A, &mattype));
5503     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Matrix of type %s does not support checking for transpose", mattype);
5504   }
5505   PetscFunctionReturn(PETSC_SUCCESS);
5506 }
5507 
5508 /*@
5509   MatHermitianTranspose - Computes an in-place or out-of-place Hermitian transpose of a matrix in complex conjugate.
5510 
5511   Collective
5512 
5513   Input Parameters:
5514 + mat   - the matrix to transpose and complex conjugate
5515 - reuse - either `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, or `MAT_INPLACE_MATRIX`
5516 
5517   Output Parameter:
5518 . B - the Hermitian transpose
5519 
5520   Level: intermediate
5521 
5522 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`
5523 @*/
5524 PetscErrorCode MatHermitianTranspose(Mat mat, MatReuse reuse, Mat *B)
5525 {
5526   PetscFunctionBegin;
5527   PetscCall(MatTranspose(mat, reuse, B));
5528 #if defined(PETSC_USE_COMPLEX)
5529   PetscCall(MatConjugate(*B));
5530 #endif
5531   PetscFunctionReturn(PETSC_SUCCESS);
5532 }
5533 
5534 /*@
5535   MatIsHermitianTranspose - Test whether a matrix is another one's Hermitian transpose,
5536 
5537   Collective
5538 
5539   Input Parameters:
5540 + A   - the matrix to test
5541 . B   - the matrix to test against, this can equal the first parameter
5542 - tol - tolerance, differences between entries smaller than this are counted as zero
5543 
5544   Output Parameter:
5545 . flg - the result
5546 
5547   Level: intermediate
5548 
5549   Notes:
5550   Only available for `MATAIJ` matrices.
5551 
5552   The sequential algorithm
5553   has a running time of the order of the number of nonzeros; the parallel
5554   test involves parallel copies of the block off-diagonal parts of the matrix.
5555 
5556 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsTranspose()`
5557 @*/
5558 PetscErrorCode MatIsHermitianTranspose(Mat A, Mat B, PetscReal tol, PetscBool *flg)
5559 {
5560   PetscErrorCode (*f)(Mat, Mat, PetscReal, PetscBool *), (*g)(Mat, Mat, PetscReal, PetscBool *);
5561 
5562   PetscFunctionBegin;
5563   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5564   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5565   PetscAssertPointer(flg, 4);
5566   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatIsHermitianTranspose_C", &f));
5567   PetscCall(PetscObjectQueryFunction((PetscObject)B, "MatIsHermitianTranspose_C", &g));
5568   if (f && g) {
5569     PetscCheck(f != g, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_NOTSAMETYPE, "Matrices do not have the same comparator for Hermitian test");
5570     PetscCall((*f)(A, B, tol, flg));
5571   }
5572   PetscFunctionReturn(PETSC_SUCCESS);
5573 }
5574 
5575 /*@
5576   MatPermute - Creates a new matrix with rows and columns permuted from the
5577   original.
5578 
5579   Collective
5580 
5581   Input Parameters:
5582 + mat - the matrix to permute
5583 . row - row permutation, each processor supplies only the permutation for its rows
5584 - col - column permutation, each processor supplies only the permutation for its columns
5585 
5586   Output Parameter:
5587 . B - the permuted matrix
5588 
5589   Level: advanced
5590 
5591   Note:
5592   The index sets map from row/col of permuted matrix to row/col of original matrix.
5593   The index sets should be on the same communicator as mat and have the same local sizes.
5594 
5595   Developer Note:
5596   If you want to implement `MatPermute()` for a matrix type, and your approach doesn't
5597   exploit the fact that row and col are permutations, consider implementing the
5598   more general `MatCreateSubMatrix()` instead.
5599 
5600 .seealso: [](ch_matrices), `Mat`, `MatGetOrdering()`, `ISAllGather()`, `MatCreateSubMatrix()`
5601 @*/
5602 PetscErrorCode MatPermute(Mat mat, IS row, IS col, Mat *B)
5603 {
5604   PetscFunctionBegin;
5605   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5606   PetscValidType(mat, 1);
5607   PetscValidHeaderSpecific(row, IS_CLASSID, 2);
5608   PetscValidHeaderSpecific(col, IS_CLASSID, 3);
5609   PetscAssertPointer(B, 4);
5610   PetscCheckSameComm(mat, 1, row, 2);
5611   if (row != col) PetscCheckSameComm(row, 2, col, 3);
5612   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5613   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5614   PetscCheck(mat->ops->permute || mat->ops->createsubmatrix, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatPermute not available for Mat type %s", ((PetscObject)mat)->type_name);
5615   MatCheckPreallocated(mat, 1);
5616 
5617   if (mat->ops->permute) {
5618     PetscUseTypeMethod(mat, permute, row, col, B);
5619     PetscCall(PetscObjectStateIncrease((PetscObject)*B));
5620   } else {
5621     PetscCall(MatCreateSubMatrix(mat, row, col, MAT_INITIAL_MATRIX, B));
5622   }
5623   PetscFunctionReturn(PETSC_SUCCESS);
5624 }
5625 
5626 /*@
5627   MatEqual - Compares two matrices.
5628 
5629   Collective
5630 
5631   Input Parameters:
5632 + A - the first matrix
5633 - B - the second matrix
5634 
5635   Output Parameter:
5636 . flg - `PETSC_TRUE` if the matrices are equal; `PETSC_FALSE` otherwise.
5637 
5638   Level: intermediate
5639 
5640   Note:
5641   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
5642   using several randomly created vectors, see `MatMultEqual()`.
5643 
5644 .seealso: [](ch_matrices), `Mat`, `MatMultEqual()`
5645 @*/
5646 PetscErrorCode MatEqual(Mat A, Mat B, PetscBool *flg)
5647 {
5648   PetscFunctionBegin;
5649   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5650   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5651   PetscValidType(A, 1);
5652   PetscValidType(B, 2);
5653   PetscAssertPointer(flg, 3);
5654   PetscCheckSameComm(A, 1, B, 2);
5655   MatCheckPreallocated(A, 1);
5656   MatCheckPreallocated(B, 2);
5657   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5658   PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5659   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,
5660              B->cmap->N);
5661   if (A->ops->equal && A->ops->equal == B->ops->equal) {
5662     PetscUseTypeMethod(A, equal, B, flg);
5663   } else {
5664     PetscCall(MatMultEqual(A, B, 10, flg));
5665   }
5666   PetscFunctionReturn(PETSC_SUCCESS);
5667 }
5668 
5669 /*@
5670   MatDiagonalScale - Scales a matrix on the left and right by diagonal
5671   matrices that are stored as vectors.  Either of the two scaling
5672   matrices can be `NULL`.
5673 
5674   Collective
5675 
5676   Input Parameters:
5677 + mat - the matrix to be scaled
5678 . l   - the left scaling vector (or `NULL`)
5679 - r   - the right scaling vector (or `NULL`)
5680 
5681   Level: intermediate
5682 
5683   Note:
5684   `MatDiagonalScale()` computes $A = LAR$, where
5685   L = a diagonal matrix (stored as a vector), R = a diagonal matrix (stored as a vector)
5686   The L scales the rows of the matrix, the R scales the columns of the matrix.
5687 
5688 .seealso: [](ch_matrices), `Mat`, `MatScale()`, `MatShift()`, `MatDiagonalSet()`
5689 @*/
5690 PetscErrorCode MatDiagonalScale(Mat mat, Vec l, Vec r)
5691 {
5692   PetscFunctionBegin;
5693   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5694   PetscValidType(mat, 1);
5695   if (l) {
5696     PetscValidHeaderSpecific(l, VEC_CLASSID, 2);
5697     PetscCheckSameComm(mat, 1, l, 2);
5698   }
5699   if (r) {
5700     PetscValidHeaderSpecific(r, VEC_CLASSID, 3);
5701     PetscCheckSameComm(mat, 1, r, 3);
5702   }
5703   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5704   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5705   MatCheckPreallocated(mat, 1);
5706   if (!l && !r) PetscFunctionReturn(PETSC_SUCCESS);
5707 
5708   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
5709   PetscUseTypeMethod(mat, diagonalscale, l, r);
5710   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
5711   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5712   if (l != r) mat->symmetric = PETSC_BOOL3_FALSE;
5713   PetscFunctionReturn(PETSC_SUCCESS);
5714 }
5715 
5716 /*@
5717   MatScale - Scales all elements of a matrix by a given number.
5718 
5719   Logically Collective
5720 
5721   Input Parameters:
5722 + mat - the matrix to be scaled
5723 - a   - the scaling value
5724 
5725   Level: intermediate
5726 
5727 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
5728 @*/
5729 PetscErrorCode MatScale(Mat mat, PetscScalar a)
5730 {
5731   PetscFunctionBegin;
5732   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5733   PetscValidType(mat, 1);
5734   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5735   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5736   PetscValidLogicalCollectiveScalar(mat, a, 2);
5737   MatCheckPreallocated(mat, 1);
5738 
5739   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
5740   if (a != (PetscScalar)1.0) {
5741     PetscUseTypeMethod(mat, scale, a);
5742     PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5743   }
5744   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
5745   PetscFunctionReturn(PETSC_SUCCESS);
5746 }
5747 
5748 /*@
5749   MatNorm - Calculates various norms of a matrix.
5750 
5751   Collective
5752 
5753   Input Parameters:
5754 + mat  - the matrix
5755 - type - the type of norm, `NORM_1`, `NORM_FROBENIUS`, `NORM_INFINITY`
5756 
5757   Output Parameter:
5758 . nrm - the resulting norm
5759 
5760   Level: intermediate
5761 
5762 .seealso: [](ch_matrices), `Mat`
5763 @*/
5764 PetscErrorCode MatNorm(Mat mat, NormType type, PetscReal *nrm)
5765 {
5766   PetscFunctionBegin;
5767   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5768   PetscValidType(mat, 1);
5769   PetscAssertPointer(nrm, 3);
5770 
5771   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5772   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5773   MatCheckPreallocated(mat, 1);
5774 
5775   PetscUseTypeMethod(mat, norm, type, nrm);
5776   PetscFunctionReturn(PETSC_SUCCESS);
5777 }
5778 
5779 /*
5780      This variable is used to prevent counting of MatAssemblyBegin() that
5781    are called from within a MatAssemblyEnd().
5782 */
5783 static PetscInt MatAssemblyEnd_InUse = 0;
5784 /*@
5785   MatAssemblyBegin - Begins assembling the matrix.  This routine should
5786   be called after completing all calls to `MatSetValues()`.
5787 
5788   Collective
5789 
5790   Input Parameters:
5791 + mat  - the matrix
5792 - type - type of assembly, either `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY`
5793 
5794   Level: beginner
5795 
5796   Notes:
5797   `MatSetValues()` generally caches the values that belong to other MPI processes.  The matrix is ready to
5798   use only after `MatAssemblyBegin()` and `MatAssemblyEnd()` have been called.
5799 
5800   Use `MAT_FLUSH_ASSEMBLY` when switching between `ADD_VALUES` and `INSERT_VALUES`
5801   in `MatSetValues()`; use `MAT_FINAL_ASSEMBLY` for the final assembly before
5802   using the matrix.
5803 
5804   ALL processes that share a matrix MUST call `MatAssemblyBegin()` and `MatAssemblyEnd()` the SAME NUMBER of times, and each time with the
5805   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
5806   a global collective operation requiring all processes that share the matrix.
5807 
5808   Space for preallocated nonzeros that is not filled by a call to `MatSetValues()` or a related routine are compressed
5809   out by assembly. If you intend to use that extra space on a subsequent assembly, be sure to insert explicit zeros
5810   before `MAT_FINAL_ASSEMBLY` so the space is not compressed out.
5811 
5812 .seealso: [](ch_matrices), `Mat`, `MatAssemblyEnd()`, `MatSetValues()`, `MatAssembled()`
5813 @*/
5814 PetscErrorCode MatAssemblyBegin(Mat mat, MatAssemblyType type)
5815 {
5816   PetscFunctionBegin;
5817   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5818   PetscValidType(mat, 1);
5819   MatCheckPreallocated(mat, 1);
5820   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix. Did you forget to call MatSetUnfactored()?");
5821   if (mat->assembled) {
5822     mat->was_assembled = PETSC_TRUE;
5823     mat->assembled     = PETSC_FALSE;
5824   }
5825 
5826   if (!MatAssemblyEnd_InUse) {
5827     PetscCall(PetscLogEventBegin(MAT_AssemblyBegin, mat, 0, 0, 0));
5828     PetscTryTypeMethod(mat, assemblybegin, type);
5829     PetscCall(PetscLogEventEnd(MAT_AssemblyBegin, mat, 0, 0, 0));
5830   } else PetscTryTypeMethod(mat, assemblybegin, type);
5831   PetscFunctionReturn(PETSC_SUCCESS);
5832 }
5833 
5834 /*@
5835   MatAssembled - Indicates if a matrix has been assembled and is ready for
5836   use; for example, in matrix-vector product.
5837 
5838   Not Collective
5839 
5840   Input Parameter:
5841 . mat - the matrix
5842 
5843   Output Parameter:
5844 . assembled - `PETSC_TRUE` or `PETSC_FALSE`
5845 
5846   Level: advanced
5847 
5848 .seealso: [](ch_matrices), `Mat`, `MatAssemblyEnd()`, `MatSetValues()`, `MatAssemblyBegin()`
5849 @*/
5850 PetscErrorCode MatAssembled(Mat mat, PetscBool *assembled)
5851 {
5852   PetscFunctionBegin;
5853   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5854   PetscAssertPointer(assembled, 2);
5855   *assembled = mat->assembled;
5856   PetscFunctionReturn(PETSC_SUCCESS);
5857 }
5858 
5859 /*@
5860   MatAssemblyEnd - Completes assembling the matrix.  This routine should
5861   be called after `MatAssemblyBegin()`.
5862 
5863   Collective
5864 
5865   Input Parameters:
5866 + mat  - the matrix
5867 - type - type of assembly, either `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY`
5868 
5869   Options Database Keys:
5870 + -mat_view ::ascii_info             - Prints info on matrix at conclusion of `MatAssemblyEnd()`
5871 . -mat_view ::ascii_info_detail      - Prints more detailed info
5872 . -mat_view                          - Prints matrix in ASCII format
5873 . -mat_view ::ascii_matlab           - Prints matrix in MATLAB format
5874 . -mat_view draw                     - draws nonzero structure of matrix, using `MatView()` and `PetscDrawOpenX()`.
5875 . -display <name>                    - Sets display name (default is host)
5876 . -draw_pause <sec>                  - Sets number of seconds to pause after display
5877 . -mat_view socket                   - Sends matrix to socket, can be accessed from MATLAB (See [Using MATLAB with PETSc](ch_matlab))
5878 . -viewer_socket_machine <machine>   - Machine to use for socket
5879 . -viewer_socket_port <port>         - Port number to use for socket
5880 - -mat_view binary:filename[:append] - Save matrix to file in binary format
5881 
5882   Level: beginner
5883 
5884 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatSetValues()`, `PetscDrawOpenX()`, `PetscDrawCreate()`, `MatView()`, `MatAssembled()`, `PetscViewerSocketOpen()`
5885 @*/
5886 PetscErrorCode MatAssemblyEnd(Mat mat, MatAssemblyType type)
5887 {
5888   static PetscInt inassm = 0;
5889   PetscBool       flg    = PETSC_FALSE;
5890 
5891   PetscFunctionBegin;
5892   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5893   PetscValidType(mat, 1);
5894 
5895   inassm++;
5896   MatAssemblyEnd_InUse++;
5897   if (MatAssemblyEnd_InUse == 1) { /* Do the logging only the first time through */
5898     PetscCall(PetscLogEventBegin(MAT_AssemblyEnd, mat, 0, 0, 0));
5899     PetscTryTypeMethod(mat, assemblyend, type);
5900     PetscCall(PetscLogEventEnd(MAT_AssemblyEnd, mat, 0, 0, 0));
5901   } else PetscTryTypeMethod(mat, assemblyend, type);
5902 
5903   /* Flush assembly is not a true assembly */
5904   if (type != MAT_FLUSH_ASSEMBLY) {
5905     if (mat->num_ass) {
5906       if (!mat->symmetry_eternal) {
5907         mat->symmetric = PETSC_BOOL3_UNKNOWN;
5908         mat->hermitian = PETSC_BOOL3_UNKNOWN;
5909       }
5910       if (!mat->structural_symmetry_eternal && mat->ass_nonzerostate != mat->nonzerostate) mat->structurally_symmetric = PETSC_BOOL3_UNKNOWN;
5911       if (!mat->spd_eternal) mat->spd = PETSC_BOOL3_UNKNOWN;
5912     }
5913     mat->num_ass++;
5914     mat->assembled        = PETSC_TRUE;
5915     mat->ass_nonzerostate = mat->nonzerostate;
5916   }
5917 
5918   mat->insertmode = NOT_SET_VALUES;
5919   MatAssemblyEnd_InUse--;
5920   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5921   if (inassm == 1 && type != MAT_FLUSH_ASSEMBLY) {
5922     PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
5923 
5924     if (mat->checksymmetryonassembly) {
5925       PetscCall(MatIsSymmetric(mat, mat->checksymmetrytol, &flg));
5926       if (flg) {
5927         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "Matrix is symmetric (tolerance %g)\n", (double)mat->checksymmetrytol));
5928       } else {
5929         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "Matrix is not symmetric (tolerance %g)\n", (double)mat->checksymmetrytol));
5930       }
5931     }
5932     if (mat->nullsp && mat->checknullspaceonassembly) PetscCall(MatNullSpaceTest(mat->nullsp, mat, NULL));
5933   }
5934   inassm--;
5935   PetscFunctionReturn(PETSC_SUCCESS);
5936 }
5937 
5938 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
5939 /*@
5940   MatSetOption - Sets a parameter option for a matrix. Some options
5941   may be specific to certain storage formats.  Some options
5942   determine how values will be inserted (or added). Sorted,
5943   row-oriented input will generally assemble the fastest. The default
5944   is row-oriented.
5945 
5946   Logically Collective for certain operations, such as `MAT_SPD`, not collective for `MAT_ROW_ORIENTED`, see `MatOption`
5947 
5948   Input Parameters:
5949 + mat - the matrix
5950 . op  - the option, one of those listed below (and possibly others),
5951 - flg - turn the option on (`PETSC_TRUE`) or off (`PETSC_FALSE`)
5952 
5953   Options Describing Matrix Structure:
5954 + `MAT_SPD`                         - symmetric positive definite
5955 . `MAT_SYMMETRIC`                   - symmetric in terms of both structure and value
5956 . `MAT_HERMITIAN`                   - transpose is the complex conjugation
5957 . `MAT_STRUCTURALLY_SYMMETRIC`      - symmetric nonzero structure
5958 . `MAT_SYMMETRY_ETERNAL`            - indicates the symmetry (or Hermitian structure) or its absence will persist through any changes to the matrix
5959 . `MAT_STRUCTURAL_SYMMETRY_ETERNAL` - indicates the structural symmetry or its absence will persist through any changes to the matrix
5960 . `MAT_SPD_ETERNAL`                 - indicates the value of `MAT_SPD` (true or false) will persist through any changes to the matrix
5961 
5962    These are not really options of the matrix, they are knowledge about the structure of the matrix that users may provide so that they
5963    do not need to be computed (usually at a high cost)
5964 
5965    Options For Use with `MatSetValues()`:
5966    Insert a logically dense subblock, which can be
5967 . `MAT_ROW_ORIENTED`                - row-oriented (default)
5968 
5969    These options reflect the data you pass in with `MatSetValues()`; it has
5970    nothing to do with how the data is stored internally in the matrix
5971    data structure.
5972 
5973    When (re)assembling a matrix, we can restrict the input for
5974    efficiency/debugging purposes.  These options include
5975 . `MAT_NEW_NONZERO_LOCATIONS`       - additional insertions will be allowed if they generate a new nonzero (slow)
5976 . `MAT_FORCE_DIAGONAL_ENTRIES`      - forces diagonal entries to be allocated
5977 . `MAT_IGNORE_OFF_PROC_ENTRIES`     - drops off-processor entries
5978 . `MAT_NEW_NONZERO_LOCATION_ERR`    - generates an error for new matrix entry
5979 . `MAT_USE_HASH_TABLE`              - uses a hash table to speed up matrix assembly
5980 . `MAT_NO_OFF_PROC_ENTRIES`         - you know each process will only set values for its own rows, will generate an error if
5981         any process sets values for another process. This avoids all reductions in the MatAssembly routines and thus improves
5982         performance for very large process counts.
5983 - `MAT_SUBSET_OFF_PROC_ENTRIES`     - you know that the first assembly after setting this flag will set a superset
5984         of the off-process entries required for all subsequent assemblies. This avoids a rendezvous step in the MatAssembly
5985         functions, instead sending only neighbor messages.
5986 
5987   Level: intermediate
5988 
5989   Notes:
5990   Except for `MAT_UNUSED_NONZERO_LOCATION_ERR` and  `MAT_ROW_ORIENTED` all processes that share the matrix must pass the same value in flg!
5991 
5992   Some options are relevant only for particular matrix types and
5993   are thus ignored by others.  Other options are not supported by
5994   certain matrix types and will generate an error message if set.
5995 
5996   If using Fortran to compute a matrix, one may need to
5997   use the column-oriented option (or convert to the row-oriented
5998   format).
5999 
6000   `MAT_NEW_NONZERO_LOCATIONS` set to `PETSC_FALSE` indicates that any add or insertion
6001   that would generate a new entry in the nonzero structure is instead
6002   ignored.  Thus, if memory has not already been allocated for this particular
6003   data, then the insertion is ignored. For dense matrices, in which
6004   the entire array is allocated, no entries are ever ignored.
6005   Set after the first `MatAssemblyEnd()`. If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
6006 
6007   `MAT_NEW_NONZERO_LOCATION_ERR` set to PETSC_TRUE indicates that any add or insertion
6008   that would generate a new entry in the nonzero structure instead produces
6009   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
6010 
6011   `MAT_NEW_NONZERO_ALLOCATION_ERR` set to `PETSC_TRUE` indicates that any add or insertion
6012   that would generate a new entry that has not been preallocated will
6013   instead produce an error. (Currently supported for `MATAIJ` and `MATBAIJ` formats
6014   only.) This is a useful flag when debugging matrix memory preallocation.
6015   If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
6016 
6017   `MAT_IGNORE_OFF_PROC_ENTRIES` set to `PETSC_TRUE` indicates entries destined for
6018   other processors should be dropped, rather than stashed.
6019   This is useful if you know that the "owning" processor is also
6020   always generating the correct matrix entries, so that PETSc need
6021   not transfer duplicate entries generated on another processor.
6022 
6023   `MAT_USE_HASH_TABLE` indicates that a hash table be used to improve the
6024   searches during matrix assembly. When this flag is set, the hash table
6025   is created during the first matrix assembly. This hash table is
6026   used the next time through, during `MatSetValues()`/`MatSetValuesBlocked()`
6027   to improve the searching of indices. `MAT_NEW_NONZERO_LOCATIONS` flag
6028   should be used with `MAT_USE_HASH_TABLE` flag. This option is currently
6029   supported by `MATMPIBAIJ` format only.
6030 
6031   `MAT_KEEP_NONZERO_PATTERN` indicates when `MatZeroRows()` is called the zeroed entries
6032   are kept in the nonzero structure. This flag is not used for `MatZeroRowsColumns()`
6033 
6034   `MAT_IGNORE_ZERO_ENTRIES` - for `MATAIJ` and `MATIS` matrices this will stop zero values from creating
6035   a zero location in the matrix
6036 
6037   `MAT_USE_INODES` - indicates using inode version of the code - works with `MATAIJ` matrix types
6038 
6039   `MAT_NO_OFF_PROC_ZERO_ROWS` - you know each process will only zero its own rows. This avoids all reductions in the
6040   zero row routines and thus improves performance for very large process counts.
6041 
6042   `MAT_IGNORE_LOWER_TRIANGULAR` - For `MATSBAIJ` matrices will ignore any insertions you make in the lower triangular
6043   part of the matrix (since they should match the upper triangular part).
6044 
6045   `MAT_SORTED_FULL` - each process provides exactly its local rows; all column indices for a given row are passed in a
6046   single call to `MatSetValues()`, preallocation is perfect, row-oriented, `INSERT_VALUES` is used. Common
6047   with finite difference schemes with non-periodic boundary conditions.
6048 
6049   Developer Note:
6050   `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, and `MAT_SPD_ETERNAL` are used by `MatAssemblyEnd()` and in other
6051   places where otherwise the value of `MAT_SYMMETRIC`, `MAT_STRUCTURALLY_SYMMETRIC` or `MAT_SPD` would need to be changed back
6052   to `PETSC_BOOL3_UNKNOWN` because the matrix values had changed so the code cannot be certain that the related property had
6053   not changed.
6054 
6055 .seealso: [](ch_matrices), `MatOption`, `Mat`, `MatGetOption()`
6056 @*/
6057 PetscErrorCode MatSetOption(Mat mat, MatOption op, PetscBool flg)
6058 {
6059   PetscFunctionBegin;
6060   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6061   if (op > 0) {
6062     PetscValidLogicalCollectiveEnum(mat, op, 2);
6063     PetscValidLogicalCollectiveBool(mat, flg, 3);
6064   }
6065 
6066   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);
6067 
6068   switch (op) {
6069   case MAT_FORCE_DIAGONAL_ENTRIES:
6070     mat->force_diagonals = flg;
6071     PetscFunctionReturn(PETSC_SUCCESS);
6072   case MAT_NO_OFF_PROC_ENTRIES:
6073     mat->nooffprocentries = flg;
6074     PetscFunctionReturn(PETSC_SUCCESS);
6075   case MAT_SUBSET_OFF_PROC_ENTRIES:
6076     mat->assembly_subset = flg;
6077     if (!mat->assembly_subset) { /* See the same logic in VecAssembly wrt VEC_SUBSET_OFF_PROC_ENTRIES */
6078 #if !defined(PETSC_HAVE_MPIUNI)
6079       PetscCall(MatStashScatterDestroy_BTS(&mat->stash));
6080 #endif
6081       mat->stash.first_assembly_done = PETSC_FALSE;
6082     }
6083     PetscFunctionReturn(PETSC_SUCCESS);
6084   case MAT_NO_OFF_PROC_ZERO_ROWS:
6085     mat->nooffproczerorows = flg;
6086     PetscFunctionReturn(PETSC_SUCCESS);
6087   case MAT_SPD:
6088     if (flg) {
6089       mat->spd                    = PETSC_BOOL3_TRUE;
6090       mat->symmetric              = PETSC_BOOL3_TRUE;
6091       mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6092     } else {
6093       mat->spd = PETSC_BOOL3_FALSE;
6094     }
6095     break;
6096   case MAT_SYMMETRIC:
6097     mat->symmetric = PetscBoolToBool3(flg);
6098     if (flg) mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6099 #if !defined(PETSC_USE_COMPLEX)
6100     mat->hermitian = PetscBoolToBool3(flg);
6101 #endif
6102     break;
6103   case MAT_HERMITIAN:
6104     mat->hermitian = PetscBoolToBool3(flg);
6105     if (flg) mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6106 #if !defined(PETSC_USE_COMPLEX)
6107     mat->symmetric = PetscBoolToBool3(flg);
6108 #endif
6109     break;
6110   case MAT_STRUCTURALLY_SYMMETRIC:
6111     mat->structurally_symmetric = PetscBoolToBool3(flg);
6112     break;
6113   case MAT_SYMMETRY_ETERNAL:
6114     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");
6115     mat->symmetry_eternal = flg;
6116     if (flg) mat->structural_symmetry_eternal = PETSC_TRUE;
6117     break;
6118   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
6119     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");
6120     mat->structural_symmetry_eternal = flg;
6121     break;
6122   case MAT_SPD_ETERNAL:
6123     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");
6124     mat->spd_eternal = flg;
6125     if (flg) {
6126       mat->structural_symmetry_eternal = PETSC_TRUE;
6127       mat->symmetry_eternal            = PETSC_TRUE;
6128     }
6129     break;
6130   case MAT_STRUCTURE_ONLY:
6131     mat->structure_only = flg;
6132     break;
6133   case MAT_SORTED_FULL:
6134     mat->sortedfull = flg;
6135     break;
6136   default:
6137     break;
6138   }
6139   PetscTryTypeMethod(mat, setoption, op, flg);
6140   PetscFunctionReturn(PETSC_SUCCESS);
6141 }
6142 
6143 /*@
6144   MatGetOption - Gets a parameter option that has been set for a matrix.
6145 
6146   Logically Collective
6147 
6148   Input Parameters:
6149 + mat - the matrix
6150 - op  - the option, this only responds to certain options, check the code for which ones
6151 
6152   Output Parameter:
6153 . flg - turn the option on (`PETSC_TRUE`) or off (`PETSC_FALSE`)
6154 
6155   Level: intermediate
6156 
6157   Notes:
6158   Can only be called after `MatSetSizes()` and `MatSetType()` have been set.
6159 
6160   Certain option values may be unknown, for those use the routines `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, or
6161   `MatIsSymmetricKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
6162 
6163 .seealso: [](ch_matrices), `Mat`, `MatOption`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`,
6164     `MatIsSymmetricKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
6165 @*/
6166 PetscErrorCode MatGetOption(Mat mat, MatOption op, PetscBool *flg)
6167 {
6168   PetscFunctionBegin;
6169   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6170   PetscValidType(mat, 1);
6171 
6172   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);
6173   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()");
6174 
6175   switch (op) {
6176   case MAT_NO_OFF_PROC_ENTRIES:
6177     *flg = mat->nooffprocentries;
6178     break;
6179   case MAT_NO_OFF_PROC_ZERO_ROWS:
6180     *flg = mat->nooffproczerorows;
6181     break;
6182   case MAT_SYMMETRIC:
6183     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsSymmetric() or MatIsSymmetricKnown()");
6184     break;
6185   case MAT_HERMITIAN:
6186     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsHermitian() or MatIsHermitianKnown()");
6187     break;
6188   case MAT_STRUCTURALLY_SYMMETRIC:
6189     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsStructurallySymmetric() or MatIsStructurallySymmetricKnown()");
6190     break;
6191   case MAT_SPD:
6192     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsSPDKnown()");
6193     break;
6194   case MAT_SYMMETRY_ETERNAL:
6195     *flg = mat->symmetry_eternal;
6196     break;
6197   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
6198     *flg = mat->symmetry_eternal;
6199     break;
6200   default:
6201     break;
6202   }
6203   PetscFunctionReturn(PETSC_SUCCESS);
6204 }
6205 
6206 /*@
6207   MatZeroEntries - Zeros all entries of a matrix.  For sparse matrices
6208   this routine retains the old nonzero structure.
6209 
6210   Logically Collective
6211 
6212   Input Parameter:
6213 . mat - the matrix
6214 
6215   Level: intermediate
6216 
6217   Note:
6218   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.
6219   See the Performance chapter of the users manual for information on preallocating matrices.
6220 
6221 .seealso: [](ch_matrices), `Mat`, `MatZeroRows()`, `MatZeroRowsColumns()`
6222 @*/
6223 PetscErrorCode MatZeroEntries(Mat mat)
6224 {
6225   PetscFunctionBegin;
6226   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6227   PetscValidType(mat, 1);
6228   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6229   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");
6230   MatCheckPreallocated(mat, 1);
6231 
6232   PetscCall(PetscLogEventBegin(MAT_ZeroEntries, mat, 0, 0, 0));
6233   PetscUseTypeMethod(mat, zeroentries);
6234   PetscCall(PetscLogEventEnd(MAT_ZeroEntries, mat, 0, 0, 0));
6235   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6236   PetscFunctionReturn(PETSC_SUCCESS);
6237 }
6238 
6239 /*@
6240   MatZeroRowsColumns - Zeros all entries (except possibly the main diagonal)
6241   of a set of rows and columns of a matrix.
6242 
6243   Collective
6244 
6245   Input Parameters:
6246 + mat     - the matrix
6247 . numRows - the number of rows/columns to zero
6248 . rows    - the global row indices
6249 . diag    - value put in the diagonal of the eliminated rows
6250 . x       - optional vector of the solution for zeroed rows (other entries in vector are not used), these must be set before this call
6251 - b       - optional vector of the right-hand side, that will be adjusted by provided solution entries
6252 
6253   Level: intermediate
6254 
6255   Notes:
6256   This routine, along with `MatZeroRows()`, is typically used to eliminate known Dirichlet boundary conditions from a linear system.
6257 
6258   For each zeroed row, the value of the corresponding `b` is set to diag times the value of the corresponding `x`.
6259   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
6260 
6261   If the resulting linear system is to be solved with `KSP` then one can (but does not have to) call `KSPSetInitialGuessNonzero()` to allow the
6262   Krylov method to take advantage of the known solution on the zeroed rows.
6263 
6264   For the parallel case, all processes that share the matrix (i.e.,
6265   those in the communicator used for matrix creation) MUST call this
6266   routine, regardless of whether any rows being zeroed are owned by
6267   them.
6268 
6269   Unlike `MatZeroRows()`, this ignores the `MAT_KEEP_NONZERO_PATTERN` option value set with `MatSetOption()`, it merely zeros those entries in the matrix, but never
6270   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
6271   missing.
6272 
6273   Each processor can indicate any rows in the entire matrix to be zeroed (i.e. each process does NOT have to
6274   list only rows local to itself).
6275 
6276   The option `MAT_NO_OFF_PROC_ZERO_ROWS` does not apply to this routine.
6277 
6278 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRows()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6279           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6280 @*/
6281 PetscErrorCode MatZeroRowsColumns(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6282 {
6283   PetscFunctionBegin;
6284   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6285   PetscValidType(mat, 1);
6286   if (numRows) PetscAssertPointer(rows, 3);
6287   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6288   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6289   MatCheckPreallocated(mat, 1);
6290 
6291   PetscUseTypeMethod(mat, zerorowscolumns, numRows, rows, diag, x, b);
6292   PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
6293   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6294   PetscFunctionReturn(PETSC_SUCCESS);
6295 }
6296 
6297 /*@
6298   MatZeroRowsColumnsIS - Zeros all entries (except possibly the main diagonal)
6299   of a set of rows and columns of a matrix.
6300 
6301   Collective
6302 
6303   Input Parameters:
6304 + mat  - the matrix
6305 . is   - the rows to zero
6306 . diag - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6307 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6308 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6309 
6310   Level: intermediate
6311 
6312   Note:
6313   See `MatZeroRowsColumns()` for details on how this routine operates.
6314 
6315 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6316           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRows()`, `MatZeroRowsColumnsStencil()`
6317 @*/
6318 PetscErrorCode MatZeroRowsColumnsIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6319 {
6320   PetscInt        numRows;
6321   const PetscInt *rows;
6322 
6323   PetscFunctionBegin;
6324   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6325   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6326   PetscValidType(mat, 1);
6327   PetscValidType(is, 2);
6328   PetscCall(ISGetLocalSize(is, &numRows));
6329   PetscCall(ISGetIndices(is, &rows));
6330   PetscCall(MatZeroRowsColumns(mat, numRows, rows, diag, x, b));
6331   PetscCall(ISRestoreIndices(is, &rows));
6332   PetscFunctionReturn(PETSC_SUCCESS);
6333 }
6334 
6335 /*@
6336   MatZeroRows - Zeros all entries (except possibly the main diagonal)
6337   of a set of rows of a matrix.
6338 
6339   Collective
6340 
6341   Input Parameters:
6342 + mat     - the matrix
6343 . numRows - the number of rows to zero
6344 . rows    - the global row indices
6345 . diag    - value put in the diagonal of the zeroed rows
6346 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used), these must be set before this call
6347 - b       - optional vector of right-hand side, that will be adjusted by provided solution entries
6348 
6349   Level: intermediate
6350 
6351   Notes:
6352   This routine, along with `MatZeroRowsColumns()`, is typically used to eliminate known Dirichlet boundary conditions from a linear system.
6353 
6354   For each zeroed row, the value of the corresponding `b` is set to `diag` times the value of the corresponding `x`.
6355 
6356   If the resulting linear system is to be solved with `KSP` then one can (but does not have to) call `KSPSetInitialGuessNonzero()` to allow the
6357   Krylov method to take advantage of the known solution on the zeroed rows.
6358 
6359   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)
6360   from the matrix.
6361 
6362   Unlike `MatZeroRowsColumns()` for the `MATAIJ` and `MATBAIJ` matrix formats this removes the old nonzero structure, from the eliminated rows of the matrix
6363   but does not release memory.  Because of this removal matrix-vector products with the adjusted matrix will be a bit faster. For the dense
6364   formats this does not alter the nonzero structure.
6365 
6366   If the option `MatSetOption`(mat,`MAT_KEEP_NONZERO_PATTERN`,`PETSC_TRUE`) the nonzero structure
6367   of the matrix is not changed the values are
6368   merely zeroed.
6369 
6370   The user can set a value in the diagonal entry (or for the `MATAIJ` format
6371   formats can optionally remove the main diagonal entry from the
6372   nonzero structure as well, by passing 0.0 as the final argument).
6373 
6374   For the parallel case, all processes that share the matrix (i.e.,
6375   those in the communicator used for matrix creation) MUST call this
6376   routine, regardless of whether any rows being zeroed are owned by
6377   them.
6378 
6379   Each processor can indicate any rows in the entire matrix to be zeroed (i.e. each process does NOT have to
6380   list only rows local to itself).
6381 
6382   You can call `MatSetOption`(mat,`MAT_NO_OFF_PROC_ZERO_ROWS`,`PETSC_TRUE`) if each process indicates only rows it
6383   owns that are to be zeroed. This saves a global synchronization in the implementation.
6384 
6385 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6386           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`, `PCREDISTRIBUTE`, `MAT_KEEP_NONZERO_PATTERN`
6387 @*/
6388 PetscErrorCode MatZeroRows(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6389 {
6390   PetscFunctionBegin;
6391   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6392   PetscValidType(mat, 1);
6393   if (numRows) PetscAssertPointer(rows, 3);
6394   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6395   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6396   MatCheckPreallocated(mat, 1);
6397 
6398   PetscUseTypeMethod(mat, zerorows, numRows, rows, diag, x, b);
6399   PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
6400   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6401   PetscFunctionReturn(PETSC_SUCCESS);
6402 }
6403 
6404 /*@
6405   MatZeroRowsIS - Zeros all entries (except possibly the main diagonal)
6406   of a set of rows of a matrix indicated by an `IS`
6407 
6408   Collective
6409 
6410   Input Parameters:
6411 + mat  - the matrix
6412 . is   - index set, `IS`, of rows to remove (if `NULL` then no row is removed)
6413 . diag - value put in all diagonals of eliminated rows
6414 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6415 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6416 
6417   Level: intermediate
6418 
6419   Note:
6420   See `MatZeroRows()` for details on how this routine operates.
6421 
6422 .seealso: [](ch_matrices), `Mat`, `MatZeroRows()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6423           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`, `IS`
6424 @*/
6425 PetscErrorCode MatZeroRowsIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6426 {
6427   PetscInt        numRows = 0;
6428   const PetscInt *rows    = NULL;
6429 
6430   PetscFunctionBegin;
6431   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6432   PetscValidType(mat, 1);
6433   if (is) {
6434     PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6435     PetscCall(ISGetLocalSize(is, &numRows));
6436     PetscCall(ISGetIndices(is, &rows));
6437   }
6438   PetscCall(MatZeroRows(mat, numRows, rows, diag, x, b));
6439   if (is) PetscCall(ISRestoreIndices(is, &rows));
6440   PetscFunctionReturn(PETSC_SUCCESS);
6441 }
6442 
6443 /*@
6444   MatZeroRowsStencil - Zeros all entries (except possibly the main diagonal)
6445   of a set of rows of a matrix indicated by a `MatStencil`. These rows must be local to the process.
6446 
6447   Collective
6448 
6449   Input Parameters:
6450 + mat     - the matrix
6451 . numRows - the number of rows to remove
6452 . rows    - the grid coordinates (and component number when dof > 1) for matrix rows indicated by an array of `MatStencil`
6453 . diag    - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6454 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6455 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6456 
6457   Level: intermediate
6458 
6459   Notes:
6460   See `MatZeroRows()` for details on how this routine operates.
6461 
6462   The grid coordinates are across the entire grid, not just the local portion
6463 
6464   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
6465   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
6466   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
6467   `DM_BOUNDARY_PERIODIC` boundary type.
6468 
6469   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
6470   a single value per point) you can skip filling those indices.
6471 
6472   Fortran Note:
6473   `idxm` and `idxn` should be declared as
6474 .vb
6475     MatStencil idxm(4, m)
6476 .ve
6477   and the values inserted using
6478 .vb
6479     idxm(MatStencil_i, 1) = i
6480     idxm(MatStencil_j, 1) = j
6481     idxm(MatStencil_k, 1) = k
6482     idxm(MatStencil_c, 1) = c
6483    etc
6484 .ve
6485 
6486 .seealso: [](ch_matrices), `Mat`, `MatStencil`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRows()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6487           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6488 @*/
6489 PetscErrorCode MatZeroRowsStencil(Mat mat, PetscInt numRows, const MatStencil rows[], PetscScalar diag, Vec x, Vec b)
6490 {
6491   PetscInt  dim    = mat->stencil.dim;
6492   PetscInt  sdim   = dim - (1 - (PetscInt)mat->stencil.noc);
6493   PetscInt *dims   = mat->stencil.dims + 1;
6494   PetscInt *starts = mat->stencil.starts;
6495   PetscInt *dxm    = (PetscInt *)rows;
6496   PetscInt *jdxm, i, j, tmp, numNewRows = 0;
6497 
6498   PetscFunctionBegin;
6499   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6500   PetscValidType(mat, 1);
6501   if (numRows) PetscAssertPointer(rows, 3);
6502 
6503   PetscCall(PetscMalloc1(numRows, &jdxm));
6504   for (i = 0; i < numRows; ++i) {
6505     /* Skip unused dimensions (they are ordered k, j, i, c) */
6506     for (j = 0; j < 3 - sdim; ++j) dxm++;
6507     /* Local index in X dir */
6508     tmp = *dxm++ - starts[0];
6509     /* Loop over remaining dimensions */
6510     for (j = 0; j < dim - 1; ++j) {
6511       /* If nonlocal, set index to be negative */
6512       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = PETSC_INT_MIN;
6513       /* Update local index */
6514       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
6515     }
6516     /* Skip component slot if necessary */
6517     if (mat->stencil.noc) dxm++;
6518     /* Local row number */
6519     if (tmp >= 0) jdxm[numNewRows++] = tmp;
6520   }
6521   PetscCall(MatZeroRowsLocal(mat, numNewRows, jdxm, diag, x, b));
6522   PetscCall(PetscFree(jdxm));
6523   PetscFunctionReturn(PETSC_SUCCESS);
6524 }
6525 
6526 /*@
6527   MatZeroRowsColumnsStencil - Zeros all row and column entries (except possibly the main diagonal)
6528   of a set of rows and columns of a matrix.
6529 
6530   Collective
6531 
6532   Input Parameters:
6533 + mat     - the matrix
6534 . numRows - the number of rows/columns to remove
6535 . rows    - the grid coordinates (and component number when dof > 1) for matrix rows
6536 . diag    - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6537 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6538 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6539 
6540   Level: intermediate
6541 
6542   Notes:
6543   See `MatZeroRowsColumns()` for details on how this routine operates.
6544 
6545   The grid coordinates are across the entire grid, not just the local portion
6546 
6547   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
6548   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
6549   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
6550   `DM_BOUNDARY_PERIODIC` boundary type.
6551 
6552   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
6553   a single value per point) you can skip filling those indices.
6554 
6555   Fortran Note:
6556   `idxm` and `idxn` should be declared as
6557 .vb
6558     MatStencil idxm(4, m)
6559 .ve
6560   and the values inserted using
6561 .vb
6562     idxm(MatStencil_i, 1) = i
6563     idxm(MatStencil_j, 1) = j
6564     idxm(MatStencil_k, 1) = k
6565     idxm(MatStencil_c, 1) = c
6566     etc
6567 .ve
6568 
6569 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6570           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRows()`
6571 @*/
6572 PetscErrorCode MatZeroRowsColumnsStencil(Mat mat, PetscInt numRows, const MatStencil rows[], PetscScalar diag, Vec x, Vec b)
6573 {
6574   PetscInt  dim    = mat->stencil.dim;
6575   PetscInt  sdim   = dim - (1 - (PetscInt)mat->stencil.noc);
6576   PetscInt *dims   = mat->stencil.dims + 1;
6577   PetscInt *starts = mat->stencil.starts;
6578   PetscInt *dxm    = (PetscInt *)rows;
6579   PetscInt *jdxm, i, j, tmp, numNewRows = 0;
6580 
6581   PetscFunctionBegin;
6582   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6583   PetscValidType(mat, 1);
6584   if (numRows) PetscAssertPointer(rows, 3);
6585 
6586   PetscCall(PetscMalloc1(numRows, &jdxm));
6587   for (i = 0; i < numRows; ++i) {
6588     /* Skip unused dimensions (they are ordered k, j, i, c) */
6589     for (j = 0; j < 3 - sdim; ++j) dxm++;
6590     /* Local index in X dir */
6591     tmp = *dxm++ - starts[0];
6592     /* Loop over remaining dimensions */
6593     for (j = 0; j < dim - 1; ++j) {
6594       /* If nonlocal, set index to be negative */
6595       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = PETSC_INT_MIN;
6596       /* Update local index */
6597       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
6598     }
6599     /* Skip component slot if necessary */
6600     if (mat->stencil.noc) dxm++;
6601     /* Local row number */
6602     if (tmp >= 0) jdxm[numNewRows++] = tmp;
6603   }
6604   PetscCall(MatZeroRowsColumnsLocal(mat, numNewRows, jdxm, diag, x, b));
6605   PetscCall(PetscFree(jdxm));
6606   PetscFunctionReturn(PETSC_SUCCESS);
6607 }
6608 
6609 /*@
6610   MatZeroRowsLocal - Zeros all entries (except possibly the main diagonal)
6611   of a set of rows of a matrix; using local numbering of rows.
6612 
6613   Collective
6614 
6615   Input Parameters:
6616 + mat     - the matrix
6617 . numRows - the number of rows to remove
6618 . rows    - the local row indices
6619 . diag    - value put in all diagonals of eliminated rows
6620 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6621 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6622 
6623   Level: intermediate
6624 
6625   Notes:
6626   Before calling `MatZeroRowsLocal()`, the user must first set the
6627   local-to-global mapping by calling MatSetLocalToGlobalMapping(), this is often already set for matrices obtained with `DMCreateMatrix()`.
6628 
6629   See `MatZeroRows()` for details on how this routine operates.
6630 
6631 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRows()`, `MatSetOption()`,
6632           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6633 @*/
6634 PetscErrorCode MatZeroRowsLocal(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6635 {
6636   PetscFunctionBegin;
6637   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6638   PetscValidType(mat, 1);
6639   if (numRows) PetscAssertPointer(rows, 3);
6640   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6641   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6642   MatCheckPreallocated(mat, 1);
6643 
6644   if (mat->ops->zerorowslocal) {
6645     PetscUseTypeMethod(mat, zerorowslocal, numRows, rows, diag, x, b);
6646   } else {
6647     IS              is, newis;
6648     const PetscInt *newRows;
6649 
6650     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Need to provide local to global mapping to matrix first");
6651     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numRows, rows, PETSC_COPY_VALUES, &is));
6652     PetscCall(ISLocalToGlobalMappingApplyIS(mat->rmap->mapping, is, &newis));
6653     PetscCall(ISGetIndices(newis, &newRows));
6654     PetscUseTypeMethod(mat, zerorows, numRows, newRows, diag, x, b);
6655     PetscCall(ISRestoreIndices(newis, &newRows));
6656     PetscCall(ISDestroy(&newis));
6657     PetscCall(ISDestroy(&is));
6658   }
6659   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6660   PetscFunctionReturn(PETSC_SUCCESS);
6661 }
6662 
6663 /*@
6664   MatZeroRowsLocalIS - Zeros all entries (except possibly the main diagonal)
6665   of a set of rows of a matrix; using local numbering of rows.
6666 
6667   Collective
6668 
6669   Input Parameters:
6670 + mat  - the matrix
6671 . is   - index set of rows to remove
6672 . diag - value put in all diagonals of eliminated rows
6673 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6674 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6675 
6676   Level: intermediate
6677 
6678   Notes:
6679   Before calling `MatZeroRowsLocalIS()`, the user must first set the
6680   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6681 
6682   See `MatZeroRows()` for details on how this routine operates.
6683 
6684 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRows()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6685           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6686 @*/
6687 PetscErrorCode MatZeroRowsLocalIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6688 {
6689   PetscInt        numRows;
6690   const PetscInt *rows;
6691 
6692   PetscFunctionBegin;
6693   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6694   PetscValidType(mat, 1);
6695   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6696   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6697   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6698   MatCheckPreallocated(mat, 1);
6699 
6700   PetscCall(ISGetLocalSize(is, &numRows));
6701   PetscCall(ISGetIndices(is, &rows));
6702   PetscCall(MatZeroRowsLocal(mat, numRows, rows, diag, x, b));
6703   PetscCall(ISRestoreIndices(is, &rows));
6704   PetscFunctionReturn(PETSC_SUCCESS);
6705 }
6706 
6707 /*@
6708   MatZeroRowsColumnsLocal - Zeros all entries (except possibly the main diagonal)
6709   of a set of rows and columns of a matrix; using local numbering of rows.
6710 
6711   Collective
6712 
6713   Input Parameters:
6714 + mat     - the matrix
6715 . numRows - the number of rows to remove
6716 . rows    - the global row indices
6717 . diag    - value put in all diagonals of eliminated rows
6718 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6719 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6720 
6721   Level: intermediate
6722 
6723   Notes:
6724   Before calling `MatZeroRowsColumnsLocal()`, the user must first set the
6725   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6726 
6727   See `MatZeroRowsColumns()` for details on how this routine operates.
6728 
6729 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6730           `MatZeroRows()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6731 @*/
6732 PetscErrorCode MatZeroRowsColumnsLocal(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6733 {
6734   IS              is, newis;
6735   const PetscInt *newRows;
6736 
6737   PetscFunctionBegin;
6738   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6739   PetscValidType(mat, 1);
6740   if (numRows) PetscAssertPointer(rows, 3);
6741   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6742   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6743   MatCheckPreallocated(mat, 1);
6744 
6745   PetscCheck(mat->cmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Need to provide local to global mapping to matrix first");
6746   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numRows, rows, PETSC_COPY_VALUES, &is));
6747   PetscCall(ISLocalToGlobalMappingApplyIS(mat->cmap->mapping, is, &newis));
6748   PetscCall(ISGetIndices(newis, &newRows));
6749   PetscUseTypeMethod(mat, zerorowscolumns, numRows, newRows, diag, x, b);
6750   PetscCall(ISRestoreIndices(newis, &newRows));
6751   PetscCall(ISDestroy(&newis));
6752   PetscCall(ISDestroy(&is));
6753   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6754   PetscFunctionReturn(PETSC_SUCCESS);
6755 }
6756 
6757 /*@
6758   MatZeroRowsColumnsLocalIS - Zeros all entries (except possibly the main diagonal)
6759   of a set of rows and columns of a matrix; using local numbering of rows.
6760 
6761   Collective
6762 
6763   Input Parameters:
6764 + mat  - the matrix
6765 . is   - index set of rows to remove
6766 . diag - value put in all diagonals of eliminated rows
6767 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6768 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6769 
6770   Level: intermediate
6771 
6772   Notes:
6773   Before calling `MatZeroRowsColumnsLocalIS()`, the user must first set the
6774   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6775 
6776   See `MatZeroRowsColumns()` for details on how this routine operates.
6777 
6778 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6779           `MatZeroRowsColumnsLocal()`, `MatZeroRows()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6780 @*/
6781 PetscErrorCode MatZeroRowsColumnsLocalIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6782 {
6783   PetscInt        numRows;
6784   const PetscInt *rows;
6785 
6786   PetscFunctionBegin;
6787   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6788   PetscValidType(mat, 1);
6789   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6790   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6791   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6792   MatCheckPreallocated(mat, 1);
6793 
6794   PetscCall(ISGetLocalSize(is, &numRows));
6795   PetscCall(ISGetIndices(is, &rows));
6796   PetscCall(MatZeroRowsColumnsLocal(mat, numRows, rows, diag, x, b));
6797   PetscCall(ISRestoreIndices(is, &rows));
6798   PetscFunctionReturn(PETSC_SUCCESS);
6799 }
6800 
6801 /*@
6802   MatGetSize - Returns the numbers of rows and columns in a matrix.
6803 
6804   Not Collective
6805 
6806   Input Parameter:
6807 . mat - the matrix
6808 
6809   Output Parameters:
6810 + m - the number of global rows
6811 - n - the number of global columns
6812 
6813   Level: beginner
6814 
6815   Note:
6816   Both output parameters can be `NULL` on input.
6817 
6818 .seealso: [](ch_matrices), `Mat`, `MatSetSizes()`, `MatGetLocalSize()`
6819 @*/
6820 PetscErrorCode MatGetSize(Mat mat, PetscInt *m, PetscInt *n)
6821 {
6822   PetscFunctionBegin;
6823   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6824   if (m) *m = mat->rmap->N;
6825   if (n) *n = mat->cmap->N;
6826   PetscFunctionReturn(PETSC_SUCCESS);
6827 }
6828 
6829 /*@
6830   MatGetLocalSize - For most matrix formats, excluding `MATELEMENTAL` and `MATSCALAPACK`, Returns the number of local rows and local columns
6831   of a matrix. For all matrices this is the local size of the left and right vectors as returned by `MatCreateVecs()`.
6832 
6833   Not Collective
6834 
6835   Input Parameter:
6836 . mat - the matrix
6837 
6838   Output Parameters:
6839 + m - the number of local rows, use `NULL` to not obtain this value
6840 - n - the number of local columns, use `NULL` to not obtain this value
6841 
6842   Level: beginner
6843 
6844 .seealso: [](ch_matrices), `Mat`, `MatSetSizes()`, `MatGetSize()`
6845 @*/
6846 PetscErrorCode MatGetLocalSize(Mat mat, PetscInt *m, PetscInt *n)
6847 {
6848   PetscFunctionBegin;
6849   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6850   if (m) PetscAssertPointer(m, 2);
6851   if (n) PetscAssertPointer(n, 3);
6852   if (m) *m = mat->rmap->n;
6853   if (n) *n = mat->cmap->n;
6854   PetscFunctionReturn(PETSC_SUCCESS);
6855 }
6856 
6857 /*@
6858   MatGetOwnershipRangeColumn - Returns the range of matrix columns associated with rows of a
6859   vector one multiplies this matrix by that are owned by this processor.
6860 
6861   Not Collective, unless matrix has not been allocated, then collective
6862 
6863   Input Parameter:
6864 . mat - the matrix
6865 
6866   Output Parameters:
6867 + m - the global index of the first local column, use `NULL` to not obtain this value
6868 - n - one more than the global index of the last local column, use `NULL` to not obtain this value
6869 
6870   Level: developer
6871 
6872   Notes:
6873   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6874 
6875   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6876   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6877 
6878   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6879   the local values in the matrix.
6880 
6881   Returns the columns of the "diagonal block" for most sparse matrix formats. See [Matrix
6882   Layouts](sec_matlayout) for details on matrix layouts.
6883 
6884 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`,
6885           `MatSetSizes()`, `MatCreateAIJ()`, `DMDAGetGhostCorners()`, `DM`
6886 @*/
6887 PetscErrorCode MatGetOwnershipRangeColumn(Mat mat, PetscInt *m, PetscInt *n)
6888 {
6889   PetscFunctionBegin;
6890   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6891   PetscValidType(mat, 1);
6892   if (m) PetscAssertPointer(m, 2);
6893   if (n) PetscAssertPointer(n, 3);
6894   MatCheckPreallocated(mat, 1);
6895   if (m) *m = mat->cmap->rstart;
6896   if (n) *n = mat->cmap->rend;
6897   PetscFunctionReturn(PETSC_SUCCESS);
6898 }
6899 
6900 /*@
6901   MatGetOwnershipRange - For matrices that own values by row, excludes `MATELEMENTAL` and `MATSCALAPACK`, returns the range of matrix rows owned by
6902   this MPI process.
6903 
6904   Not Collective
6905 
6906   Input Parameter:
6907 . mat - the matrix
6908 
6909   Output Parameters:
6910 + m - the global index of the first local row, use `NULL` to not obtain this value
6911 - n - one more than the global index of the last local row, use `NULL` to not obtain this value
6912 
6913   Level: beginner
6914 
6915   Notes:
6916   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6917 
6918   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6919   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6920 
6921   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6922   the local values in the matrix.
6923 
6924   The high argument is one more than the last element stored locally.
6925 
6926   For all matrices  it returns the range of matrix rows associated with rows of a vector that
6927   would contain the result of a matrix vector product with this matrix. See [Matrix
6928   Layouts](sec_matlayout) for details on matrix layouts.
6929 
6930 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscSplitOwnership()`,
6931           `PetscSplitOwnershipBlock()`, `PetscLayout`, `MatSetSizes()`, `MatCreateAIJ()`, `DMDAGetGhostCorners()`, `DM`
6932 @*/
6933 PetscErrorCode MatGetOwnershipRange(Mat mat, PetscInt *m, PetscInt *n)
6934 {
6935   PetscFunctionBegin;
6936   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6937   PetscValidType(mat, 1);
6938   if (m) PetscAssertPointer(m, 2);
6939   if (n) PetscAssertPointer(n, 3);
6940   MatCheckPreallocated(mat, 1);
6941   if (m) *m = mat->rmap->rstart;
6942   if (n) *n = mat->rmap->rend;
6943   PetscFunctionReturn(PETSC_SUCCESS);
6944 }
6945 
6946 /*@C
6947   MatGetOwnershipRanges - For matrices that own values by row, excludes `MATELEMENTAL` and
6948   `MATSCALAPACK`, returns the range of matrix rows owned by each process.
6949 
6950   Not Collective, unless matrix has not been allocated
6951 
6952   Input Parameter:
6953 . mat - the matrix
6954 
6955   Output Parameter:
6956 . ranges - start of each processors portion plus one more than the total length at the end, of length `size` + 1
6957            where `size` is the number of MPI processes used by `mat`
6958 
6959   Level: beginner
6960 
6961   Notes:
6962   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6963 
6964   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6965   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6966 
6967   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6968   the local values in the matrix.
6969 
6970   For all matrices  it returns the ranges of matrix rows associated with rows of a vector that
6971   would contain the result of a matrix vector product with this matrix. See [Matrix
6972   Layouts](sec_matlayout) for details on matrix layouts.
6973 
6974 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`,
6975           `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`, `MatSetSizes()`, `MatCreateAIJ()`,
6976           `DMDAGetGhostCorners()`, `DM`
6977 @*/
6978 PetscErrorCode MatGetOwnershipRanges(Mat mat, const PetscInt *ranges[])
6979 {
6980   PetscFunctionBegin;
6981   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6982   PetscValidType(mat, 1);
6983   MatCheckPreallocated(mat, 1);
6984   PetscCall(PetscLayoutGetRanges(mat->rmap, ranges));
6985   PetscFunctionReturn(PETSC_SUCCESS);
6986 }
6987 
6988 /*@C
6989   MatGetOwnershipRangesColumn - Returns the ranges of matrix columns associated with rows of a
6990   vector one multiplies this vector by that are owned by each processor.
6991 
6992   Not Collective, unless matrix has not been allocated
6993 
6994   Input Parameter:
6995 . mat - the matrix
6996 
6997   Output Parameter:
6998 . ranges - start of each processors portion plus one more than the total length at the end
6999 
7000   Level: beginner
7001 
7002   Notes:
7003   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
7004 
7005   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
7006   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
7007 
7008   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
7009   the local values in the matrix.
7010 
7011   Returns the columns of the "diagonal blocks", for most sparse matrix formats. See [Matrix
7012   Layouts](sec_matlayout) for details on matrix layouts.
7013 
7014 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRanges()`,
7015           `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`, `PetscLayout`, `MatSetSizes()`, `MatCreateAIJ()`,
7016           `DMDAGetGhostCorners()`, `DM`
7017 @*/
7018 PetscErrorCode MatGetOwnershipRangesColumn(Mat mat, const PetscInt *ranges[])
7019 {
7020   PetscFunctionBegin;
7021   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7022   PetscValidType(mat, 1);
7023   MatCheckPreallocated(mat, 1);
7024   PetscCall(PetscLayoutGetRanges(mat->cmap, ranges));
7025   PetscFunctionReturn(PETSC_SUCCESS);
7026 }
7027 
7028 /*@
7029   MatGetOwnershipIS - Get row and column ownership of a matrices' values as index sets.
7030 
7031   Not Collective
7032 
7033   Input Parameter:
7034 . A - matrix
7035 
7036   Output Parameters:
7037 + rows - rows in which this process owns elements, , use `NULL` to not obtain this value
7038 - cols - columns in which this process owns elements, use `NULL` to not obtain this value
7039 
7040   Level: intermediate
7041 
7042   Note:
7043   You should call `ISDestroy()` on the returned `IS`
7044 
7045   For most matrices, excluding `MATELEMENTAL` and `MATSCALAPACK`, this corresponds to values
7046   returned by `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`. For `MATELEMENTAL` and
7047   `MATSCALAPACK` the ownership is more complicated. See [Matrix Layouts](sec_matlayout) for
7048   details on matrix layouts.
7049 
7050 .seealso: [](ch_matrices), `IS`, `Mat`, `MatGetOwnershipRanges()`, `MatSetValues()`, `MATELEMENTAL`, `MATSCALAPACK`
7051 @*/
7052 PetscErrorCode MatGetOwnershipIS(Mat A, IS *rows, IS *cols)
7053 {
7054   PetscErrorCode (*f)(Mat, IS *, IS *);
7055 
7056   PetscFunctionBegin;
7057   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
7058   PetscValidType(A, 1);
7059   MatCheckPreallocated(A, 1);
7060   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatGetOwnershipIS_C", &f));
7061   if (f) {
7062     PetscCall((*f)(A, rows, cols));
7063   } else { /* Create a standard row-based partition, each process is responsible for ALL columns in their row block */
7064     if (rows) PetscCall(ISCreateStride(PETSC_COMM_SELF, A->rmap->n, A->rmap->rstart, 1, rows));
7065     if (cols) PetscCall(ISCreateStride(PETSC_COMM_SELF, A->cmap->N, 0, 1, cols));
7066   }
7067   PetscFunctionReturn(PETSC_SUCCESS);
7068 }
7069 
7070 /*@
7071   MatILUFactorSymbolic - Performs symbolic ILU factorization of a matrix obtained with `MatGetFactor()`
7072   Uses levels of fill only, not drop tolerance. Use `MatLUFactorNumeric()`
7073   to complete the factorization.
7074 
7075   Collective
7076 
7077   Input Parameters:
7078 + fact - the factorized matrix obtained with `MatGetFactor()`
7079 . mat  - the matrix
7080 . row  - row permutation
7081 . col  - column permutation
7082 - info - structure containing
7083 .vb
7084       levels - number of levels of fill.
7085       expected fill - as ratio of original fill.
7086       1 or 0 - indicating force fill on diagonal (improves robustness for matrices
7087                 missing diagonal entries)
7088 .ve
7089 
7090   Level: developer
7091 
7092   Notes:
7093   See [Matrix Factorization](sec_matfactor) for additional information.
7094 
7095   Most users should employ the `KSP` interface for linear solvers
7096   instead of working directly with matrix algebra routines such as this.
7097   See, e.g., `KSPCreate()`.
7098 
7099   Uses the definition of level of fill as in Y. Saad, {cite}`saad2003`
7100 
7101   Developer Note:
7102   The Fortran interface is not autogenerated as the
7103   interface definition cannot be generated correctly [due to `MatFactorInfo`]
7104 
7105 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
7106           `MatGetOrdering()`, `MatFactorInfo`
7107 @*/
7108 PetscErrorCode MatILUFactorSymbolic(Mat fact, Mat mat, IS row, IS col, const MatFactorInfo *info)
7109 {
7110   PetscFunctionBegin;
7111   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
7112   PetscValidType(mat, 2);
7113   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 3);
7114   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 4);
7115   PetscAssertPointer(info, 5);
7116   PetscAssertPointer(fact, 1);
7117   PetscCheck(info->levels >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Levels of fill negative %" PetscInt_FMT, (PetscInt)info->levels);
7118   PetscCheck(info->fill >= 1.0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Expected fill less than 1.0 %g", (double)info->fill);
7119   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7120   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7121   MatCheckPreallocated(mat, 2);
7122 
7123   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_ILUFactorSymbolic, mat, row, col, 0));
7124   PetscUseTypeMethod(fact, ilufactorsymbolic, mat, row, col, info);
7125   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_ILUFactorSymbolic, mat, row, col, 0));
7126   PetscFunctionReturn(PETSC_SUCCESS);
7127 }
7128 
7129 /*@
7130   MatICCFactorSymbolic - Performs symbolic incomplete
7131   Cholesky factorization for a symmetric matrix.  Use
7132   `MatCholeskyFactorNumeric()` to complete the factorization.
7133 
7134   Collective
7135 
7136   Input Parameters:
7137 + fact - the factorized matrix obtained with `MatGetFactor()`
7138 . mat  - the matrix to be factored
7139 . perm - row and column permutation
7140 - info - structure containing
7141 .vb
7142       levels - number of levels of fill.
7143       expected fill - as ratio of original fill.
7144 .ve
7145 
7146   Level: developer
7147 
7148   Notes:
7149   Most users should employ the `KSP` interface for linear solvers
7150   instead of working directly with matrix algebra routines such as this.
7151   See, e.g., `KSPCreate()`.
7152 
7153   This uses the definition of level of fill as in Y. Saad {cite}`saad2003`
7154 
7155   Developer Note:
7156   The Fortran interface is not autogenerated as the
7157   interface definition cannot be generated correctly [due to `MatFactorInfo`]
7158 
7159 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`
7160 @*/
7161 PetscErrorCode MatICCFactorSymbolic(Mat fact, Mat mat, IS perm, const MatFactorInfo *info)
7162 {
7163   PetscFunctionBegin;
7164   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
7165   PetscValidType(mat, 2);
7166   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 3);
7167   PetscAssertPointer(info, 4);
7168   PetscAssertPointer(fact, 1);
7169   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7170   PetscCheck(info->levels >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Levels negative %" PetscInt_FMT, (PetscInt)info->levels);
7171   PetscCheck(info->fill >= 1.0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Expected fill less than 1.0 %g", (double)info->fill);
7172   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7173   MatCheckPreallocated(mat, 2);
7174 
7175   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_ICCFactorSymbolic, mat, perm, 0, 0));
7176   PetscUseTypeMethod(fact, iccfactorsymbolic, mat, perm, info);
7177   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_ICCFactorSymbolic, mat, perm, 0, 0));
7178   PetscFunctionReturn(PETSC_SUCCESS);
7179 }
7180 
7181 /*@C
7182   MatCreateSubMatrices - Extracts several submatrices from a matrix. If submat
7183   points to an array of valid matrices, they may be reused to store the new
7184   submatrices.
7185 
7186   Collective
7187 
7188   Input Parameters:
7189 + mat   - the matrix
7190 . n     - the number of submatrixes to be extracted (on this processor, may be zero)
7191 . irow  - index set of rows to extract
7192 . icol  - index set of columns to extract
7193 - scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
7194 
7195   Output Parameter:
7196 . submat - the array of submatrices
7197 
7198   Level: advanced
7199 
7200   Notes:
7201   `MatCreateSubMatrices()` can extract ONLY sequential submatrices
7202   (from both sequential and parallel matrices). Use `MatCreateSubMatrix()`
7203   to extract a parallel submatrix.
7204 
7205   Some matrix types place restrictions on the row and column
7206   indices, such as that they be sorted or that they be equal to each other.
7207 
7208   The index sets may not have duplicate entries.
7209 
7210   When extracting submatrices from a parallel matrix, each processor can
7211   form a different submatrix by setting the rows and columns of its
7212   individual index sets according to the local submatrix desired.
7213 
7214   When finished using the submatrices, the user should destroy
7215   them with `MatDestroySubMatrices()`.
7216 
7217   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
7218   original matrix has not changed from that last call to `MatCreateSubMatrices()`.
7219 
7220   This routine creates the matrices in submat; you should NOT create them before
7221   calling it. It also allocates the array of matrix pointers submat.
7222 
7223   For `MATBAIJ` matrices the index sets must respect the block structure, that is if they
7224   request one row/column in a block, they must request all rows/columns that are in
7225   that block. For example, if the block size is 2 you cannot request just row 0 and
7226   column 0.
7227 
7228   Fortran Note:
7229 .vb
7230   Mat, pointer :: submat(:)
7231 .ve
7232 
7233 .seealso: [](ch_matrices), `Mat`, `MatDestroySubMatrices()`, `MatCreateSubMatrix()`, `MatGetRow()`, `MatGetDiagonal()`, `MatReuse`
7234 @*/
7235 PetscErrorCode MatCreateSubMatrices(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
7236 {
7237   PetscInt  i;
7238   PetscBool eq;
7239 
7240   PetscFunctionBegin;
7241   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7242   PetscValidType(mat, 1);
7243   if (n) {
7244     PetscAssertPointer(irow, 3);
7245     for (i = 0; i < n; i++) PetscValidHeaderSpecific(irow[i], IS_CLASSID, 3);
7246     PetscAssertPointer(icol, 4);
7247     for (i = 0; i < n; i++) PetscValidHeaderSpecific(icol[i], IS_CLASSID, 4);
7248   }
7249   PetscAssertPointer(submat, 6);
7250   if (n && scall == MAT_REUSE_MATRIX) {
7251     PetscAssertPointer(*submat, 6);
7252     for (i = 0; i < n; i++) PetscValidHeaderSpecific((*submat)[i], MAT_CLASSID, 6);
7253   }
7254   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7255   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7256   MatCheckPreallocated(mat, 1);
7257   PetscCall(PetscLogEventBegin(MAT_CreateSubMats, mat, 0, 0, 0));
7258   PetscUseTypeMethod(mat, createsubmatrices, n, irow, icol, scall, submat);
7259   PetscCall(PetscLogEventEnd(MAT_CreateSubMats, mat, 0, 0, 0));
7260   for (i = 0; i < n; i++) {
7261     (*submat)[i]->factortype = MAT_FACTOR_NONE; /* in case in place factorization was previously done on submatrix */
7262     PetscCall(ISEqualUnsorted(irow[i], icol[i], &eq));
7263     if (eq) PetscCall(MatPropagateSymmetryOptions(mat, (*submat)[i]));
7264 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
7265     if (mat->boundtocpu && mat->bindingpropagates) {
7266       PetscCall(MatBindToCPU((*submat)[i], PETSC_TRUE));
7267       PetscCall(MatSetBindingPropagates((*submat)[i], PETSC_TRUE));
7268     }
7269 #endif
7270   }
7271   PetscFunctionReturn(PETSC_SUCCESS);
7272 }
7273 
7274 /*@C
7275   MatCreateSubMatricesMPI - Extracts MPI submatrices across a sub communicator of `mat` (by pairs of `IS` that may live on subcomms).
7276 
7277   Collective
7278 
7279   Input Parameters:
7280 + mat   - the matrix
7281 . n     - the number of submatrixes to be extracted
7282 . irow  - index set of rows to extract
7283 . icol  - index set of columns to extract
7284 - scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
7285 
7286   Output Parameter:
7287 . submat - the array of submatrices
7288 
7289   Level: advanced
7290 
7291   Note:
7292   This is used by `PCGASM`
7293 
7294 .seealso: [](ch_matrices), `Mat`, `PCGASM`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRow()`, `MatGetDiagonal()`, `MatReuse`
7295 @*/
7296 PetscErrorCode MatCreateSubMatricesMPI(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
7297 {
7298   PetscInt  i;
7299   PetscBool eq;
7300 
7301   PetscFunctionBegin;
7302   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7303   PetscValidType(mat, 1);
7304   if (n) {
7305     PetscAssertPointer(irow, 3);
7306     PetscValidHeaderSpecific(*irow, IS_CLASSID, 3);
7307     PetscAssertPointer(icol, 4);
7308     PetscValidHeaderSpecific(*icol, IS_CLASSID, 4);
7309   }
7310   PetscAssertPointer(submat, 6);
7311   if (n && scall == MAT_REUSE_MATRIX) {
7312     PetscAssertPointer(*submat, 6);
7313     PetscValidHeaderSpecific(**submat, MAT_CLASSID, 6);
7314   }
7315   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7316   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7317   MatCheckPreallocated(mat, 1);
7318 
7319   PetscCall(PetscLogEventBegin(MAT_CreateSubMats, mat, 0, 0, 0));
7320   PetscUseTypeMethod(mat, createsubmatricesmpi, n, irow, icol, scall, submat);
7321   PetscCall(PetscLogEventEnd(MAT_CreateSubMats, mat, 0, 0, 0));
7322   for (i = 0; i < n; i++) {
7323     PetscCall(ISEqualUnsorted(irow[i], icol[i], &eq));
7324     if (eq) PetscCall(MatPropagateSymmetryOptions(mat, (*submat)[i]));
7325   }
7326   PetscFunctionReturn(PETSC_SUCCESS);
7327 }
7328 
7329 /*@C
7330   MatDestroyMatrices - Destroys an array of matrices
7331 
7332   Collective
7333 
7334   Input Parameters:
7335 + n   - the number of local matrices
7336 - mat - the matrices (this is a pointer to the array of matrices)
7337 
7338   Level: advanced
7339 
7340   Notes:
7341   Frees not only the matrices, but also the array that contains the matrices
7342 
7343   For matrices obtained with  `MatCreateSubMatrices()` use `MatDestroySubMatrices()`
7344 
7345 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatDestroySubMatrices()`
7346 @*/
7347 PetscErrorCode MatDestroyMatrices(PetscInt n, Mat *mat[])
7348 {
7349   PetscInt i;
7350 
7351   PetscFunctionBegin;
7352   if (!*mat) PetscFunctionReturn(PETSC_SUCCESS);
7353   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy negative number of matrices %" PetscInt_FMT, n);
7354   PetscAssertPointer(mat, 2);
7355 
7356   for (i = 0; i < n; i++) PetscCall(MatDestroy(&(*mat)[i]));
7357 
7358   /* memory is allocated even if n = 0 */
7359   PetscCall(PetscFree(*mat));
7360   PetscFunctionReturn(PETSC_SUCCESS);
7361 }
7362 
7363 /*@C
7364   MatDestroySubMatrices - Destroys a set of matrices obtained with `MatCreateSubMatrices()`.
7365 
7366   Collective
7367 
7368   Input Parameters:
7369 + n   - the number of local matrices
7370 - mat - the matrices (this is a pointer to the array of matrices, to match the calling sequence of `MatCreateSubMatrices()`)
7371 
7372   Level: advanced
7373 
7374   Note:
7375   Frees not only the matrices, but also the array that contains the matrices
7376 
7377 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatDestroyMatrices()`
7378 @*/
7379 PetscErrorCode MatDestroySubMatrices(PetscInt n, Mat *mat[])
7380 {
7381   Mat mat0;
7382 
7383   PetscFunctionBegin;
7384   if (!*mat) PetscFunctionReturn(PETSC_SUCCESS);
7385   /* mat[] is an array of length n+1, see MatCreateSubMatrices_xxx() */
7386   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy negative number of matrices %" PetscInt_FMT, n);
7387   PetscAssertPointer(mat, 2);
7388 
7389   mat0 = (*mat)[0];
7390   if (mat0 && mat0->ops->destroysubmatrices) {
7391     PetscCall((*mat0->ops->destroysubmatrices)(n, mat));
7392   } else {
7393     PetscCall(MatDestroyMatrices(n, mat));
7394   }
7395   PetscFunctionReturn(PETSC_SUCCESS);
7396 }
7397 
7398 /*@
7399   MatGetSeqNonzeroStructure - Extracts the nonzero structure from a matrix and stores it, in its entirety, on each process
7400 
7401   Collective
7402 
7403   Input Parameter:
7404 . mat - the matrix
7405 
7406   Output Parameter:
7407 . matstruct - the sequential matrix with the nonzero structure of `mat`
7408 
7409   Level: developer
7410 
7411 .seealso: [](ch_matrices), `Mat`, `MatDestroySeqNonzeroStructure()`, `MatCreateSubMatrices()`, `MatDestroyMatrices()`
7412 @*/
7413 PetscErrorCode MatGetSeqNonzeroStructure(Mat mat, Mat *matstruct)
7414 {
7415   PetscFunctionBegin;
7416   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7417   PetscAssertPointer(matstruct, 2);
7418 
7419   PetscValidType(mat, 1);
7420   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7421   MatCheckPreallocated(mat, 1);
7422 
7423   PetscCall(PetscLogEventBegin(MAT_GetSeqNonzeroStructure, mat, 0, 0, 0));
7424   PetscUseTypeMethod(mat, getseqnonzerostructure, matstruct);
7425   PetscCall(PetscLogEventEnd(MAT_GetSeqNonzeroStructure, mat, 0, 0, 0));
7426   PetscFunctionReturn(PETSC_SUCCESS);
7427 }
7428 
7429 /*@C
7430   MatDestroySeqNonzeroStructure - Destroys matrix obtained with `MatGetSeqNonzeroStructure()`.
7431 
7432   Collective
7433 
7434   Input Parameter:
7435 . mat - the matrix
7436 
7437   Level: advanced
7438 
7439   Note:
7440   This is not needed, one can just call `MatDestroy()`
7441 
7442 .seealso: [](ch_matrices), `Mat`, `MatGetSeqNonzeroStructure()`
7443 @*/
7444 PetscErrorCode MatDestroySeqNonzeroStructure(Mat *mat)
7445 {
7446   PetscFunctionBegin;
7447   PetscAssertPointer(mat, 1);
7448   PetscCall(MatDestroy(mat));
7449   PetscFunctionReturn(PETSC_SUCCESS);
7450 }
7451 
7452 /*@
7453   MatIncreaseOverlap - Given a set of submatrices indicated by index sets,
7454   replaces the index sets by larger ones that represent submatrices with
7455   additional overlap.
7456 
7457   Collective
7458 
7459   Input Parameters:
7460 + mat - the matrix
7461 . n   - the number of index sets
7462 . is  - the array of index sets (these index sets will changed during the call)
7463 - ov  - the additional overlap requested
7464 
7465   Options Database Key:
7466 . -mat_increase_overlap_scalable - use a scalable algorithm to compute the overlap (supported by MPIAIJ matrix)
7467 
7468   Level: developer
7469 
7470   Note:
7471   The computed overlap preserves the matrix block sizes when the blocks are square.
7472   That is: if a matrix nonzero for a given block would increase the overlap all columns associated with
7473   that block are included in the overlap regardless of whether each specific column would increase the overlap.
7474 
7475 .seealso: [](ch_matrices), `Mat`, `PCASM`, `MatSetBlockSize()`, `MatIncreaseOverlapSplit()`, `MatCreateSubMatrices()`
7476 @*/
7477 PetscErrorCode MatIncreaseOverlap(Mat mat, PetscInt n, IS is[], PetscInt ov)
7478 {
7479   PetscInt i, bs, cbs;
7480 
7481   PetscFunctionBegin;
7482   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7483   PetscValidType(mat, 1);
7484   PetscValidLogicalCollectiveInt(mat, n, 2);
7485   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have one or more domains, you have %" PetscInt_FMT, n);
7486   if (n) {
7487     PetscAssertPointer(is, 3);
7488     for (i = 0; i < n; i++) PetscValidHeaderSpecific(is[i], IS_CLASSID, 3);
7489   }
7490   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7491   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7492   MatCheckPreallocated(mat, 1);
7493 
7494   if (!ov || !n) PetscFunctionReturn(PETSC_SUCCESS);
7495   PetscCall(PetscLogEventBegin(MAT_IncreaseOverlap, mat, 0, 0, 0));
7496   PetscUseTypeMethod(mat, increaseoverlap, n, is, ov);
7497   PetscCall(PetscLogEventEnd(MAT_IncreaseOverlap, mat, 0, 0, 0));
7498   PetscCall(MatGetBlockSizes(mat, &bs, &cbs));
7499   if (bs == cbs) {
7500     for (i = 0; i < n; i++) PetscCall(ISSetBlockSize(is[i], bs));
7501   }
7502   PetscFunctionReturn(PETSC_SUCCESS);
7503 }
7504 
7505 PetscErrorCode MatIncreaseOverlapSplit_Single(Mat, IS *, PetscInt);
7506 
7507 /*@
7508   MatIncreaseOverlapSplit - Given a set of submatrices indicated by index sets across
7509   a sub communicator, replaces the index sets by larger ones that represent submatrices with
7510   additional overlap.
7511 
7512   Collective
7513 
7514   Input Parameters:
7515 + mat - the matrix
7516 . n   - the number of index sets
7517 . is  - the array of index sets (these index sets will changed during the call)
7518 - ov  - the additional overlap requested
7519 
7520   `   Options Database Key:
7521 . -mat_increase_overlap_scalable - use a scalable algorithm to compute the overlap (supported by MPIAIJ matrix)
7522 
7523   Level: developer
7524 
7525 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatIncreaseOverlap()`
7526 @*/
7527 PetscErrorCode MatIncreaseOverlapSplit(Mat mat, PetscInt n, IS is[], PetscInt ov)
7528 {
7529   PetscInt i;
7530 
7531   PetscFunctionBegin;
7532   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7533   PetscValidType(mat, 1);
7534   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have one or more domains, you have %" PetscInt_FMT, n);
7535   if (n) {
7536     PetscAssertPointer(is, 3);
7537     PetscValidHeaderSpecific(*is, IS_CLASSID, 3);
7538   }
7539   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7540   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7541   MatCheckPreallocated(mat, 1);
7542   if (!ov) PetscFunctionReturn(PETSC_SUCCESS);
7543   PetscCall(PetscLogEventBegin(MAT_IncreaseOverlap, mat, 0, 0, 0));
7544   for (i = 0; i < n; i++) PetscCall(MatIncreaseOverlapSplit_Single(mat, &is[i], ov));
7545   PetscCall(PetscLogEventEnd(MAT_IncreaseOverlap, mat, 0, 0, 0));
7546   PetscFunctionReturn(PETSC_SUCCESS);
7547 }
7548 
7549 /*@
7550   MatGetBlockSize - Returns the matrix block size.
7551 
7552   Not Collective
7553 
7554   Input Parameter:
7555 . mat - the matrix
7556 
7557   Output Parameter:
7558 . bs - block size
7559 
7560   Level: intermediate
7561 
7562   Notes:
7563   Block row formats are `MATBAIJ` and `MATSBAIJ` ALWAYS have square block storage in the matrix.
7564 
7565   If the block size has not been set yet this routine returns 1.
7566 
7567 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSizes()`
7568 @*/
7569 PetscErrorCode MatGetBlockSize(Mat mat, PetscInt *bs)
7570 {
7571   PetscFunctionBegin;
7572   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7573   PetscAssertPointer(bs, 2);
7574   *bs = mat->rmap->bs;
7575   PetscFunctionReturn(PETSC_SUCCESS);
7576 }
7577 
7578 /*@
7579   MatGetBlockSizes - Returns the matrix block row and column sizes.
7580 
7581   Not Collective
7582 
7583   Input Parameter:
7584 . mat - the matrix
7585 
7586   Output Parameters:
7587 + rbs - row block size
7588 - cbs - column block size
7589 
7590   Level: intermediate
7591 
7592   Notes:
7593   Block row formats are `MATBAIJ` and `MATSBAIJ` ALWAYS have square block storage in the matrix.
7594   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
7595 
7596   If a block size has not been set yet this routine returns 1.
7597 
7598 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatSetBlockSizes()`
7599 @*/
7600 PetscErrorCode MatGetBlockSizes(Mat mat, PetscInt *rbs, PetscInt *cbs)
7601 {
7602   PetscFunctionBegin;
7603   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7604   if (rbs) PetscAssertPointer(rbs, 2);
7605   if (cbs) PetscAssertPointer(cbs, 3);
7606   if (rbs) *rbs = mat->rmap->bs;
7607   if (cbs) *cbs = mat->cmap->bs;
7608   PetscFunctionReturn(PETSC_SUCCESS);
7609 }
7610 
7611 /*@
7612   MatSetBlockSize - Sets the matrix block size.
7613 
7614   Logically Collective
7615 
7616   Input Parameters:
7617 + mat - the matrix
7618 - bs  - block size
7619 
7620   Level: intermediate
7621 
7622   Notes:
7623   Block row formats are `MATBAIJ` and `MATSBAIJ` formats ALWAYS have square block storage in the matrix.
7624   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
7625 
7626   For `MATAIJ` matrix format, this function can be called at a later stage, provided that the specified block size
7627   is compatible with the matrix local sizes.
7628 
7629 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MATAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`
7630 @*/
7631 PetscErrorCode MatSetBlockSize(Mat mat, PetscInt bs)
7632 {
7633   PetscFunctionBegin;
7634   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7635   PetscValidLogicalCollectiveInt(mat, bs, 2);
7636   PetscCall(MatSetBlockSizes(mat, bs, bs));
7637   PetscFunctionReturn(PETSC_SUCCESS);
7638 }
7639 
7640 typedef struct {
7641   PetscInt         n;
7642   IS              *is;
7643   Mat             *mat;
7644   PetscObjectState nonzerostate;
7645   Mat              C;
7646 } EnvelopeData;
7647 
7648 static PetscErrorCode EnvelopeDataDestroy(void **ptr)
7649 {
7650   EnvelopeData *edata = (EnvelopeData *)*ptr;
7651 
7652   PetscFunctionBegin;
7653   for (PetscInt i = 0; i < edata->n; i++) PetscCall(ISDestroy(&edata->is[i]));
7654   PetscCall(PetscFree(edata->is));
7655   PetscCall(PetscFree(edata));
7656   PetscFunctionReturn(PETSC_SUCCESS);
7657 }
7658 
7659 /*@
7660   MatComputeVariableBlockEnvelope - Given a matrix whose nonzeros are in blocks along the diagonal this computes and stores
7661   the sizes of these blocks in the matrix. An individual block may lie over several processes.
7662 
7663   Collective
7664 
7665   Input Parameter:
7666 . mat - the matrix
7667 
7668   Level: intermediate
7669 
7670   Notes:
7671   There can be zeros within the blocks
7672 
7673   The blocks can overlap between processes, including laying on more than two processes
7674 
7675 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatSetVariableBlockSizes()`
7676 @*/
7677 PetscErrorCode MatComputeVariableBlockEnvelope(Mat mat)
7678 {
7679   PetscInt           n, *sizes, *starts, i = 0, env = 0, tbs = 0, lblocks = 0, rstart, II, ln = 0, cnt = 0, cstart, cend;
7680   PetscInt          *diag, *odiag, sc;
7681   VecScatter         scatter;
7682   PetscScalar       *seqv;
7683   const PetscScalar *parv;
7684   const PetscInt    *ia, *ja;
7685   PetscBool          set, flag, done;
7686   Mat                AA = mat, A;
7687   MPI_Comm           comm;
7688   PetscMPIInt        rank, size, tag;
7689   MPI_Status         status;
7690   PetscContainer     container;
7691   EnvelopeData      *edata;
7692   Vec                seq, par;
7693   IS                 isglobal;
7694 
7695   PetscFunctionBegin;
7696   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7697   PetscCall(MatIsSymmetricKnown(mat, &set, &flag));
7698   if (!set || !flag) {
7699     /* TODO: only needs nonzero structure of transpose */
7700     PetscCall(MatTranspose(mat, MAT_INITIAL_MATRIX, &AA));
7701     PetscCall(MatAXPY(AA, 1.0, mat, DIFFERENT_NONZERO_PATTERN));
7702   }
7703   PetscCall(MatAIJGetLocalMat(AA, &A));
7704   PetscCall(MatGetRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ia, &ja, &done));
7705   PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Unable to get IJ structure from matrix");
7706 
7707   PetscCall(MatGetLocalSize(mat, &n, NULL));
7708   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag));
7709   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
7710   PetscCallMPI(MPI_Comm_size(comm, &size));
7711   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7712 
7713   PetscCall(PetscMalloc2(n, &sizes, n, &starts));
7714 
7715   if (rank > 0) {
7716     PetscCallMPI(MPI_Recv(&env, 1, MPIU_INT, rank - 1, tag, comm, &status));
7717     PetscCallMPI(MPI_Recv(&tbs, 1, MPIU_INT, rank - 1, tag, comm, &status));
7718   }
7719   PetscCall(MatGetOwnershipRange(mat, &rstart, NULL));
7720   for (i = 0; i < n; i++) {
7721     env = PetscMax(env, ja[ia[i + 1] - 1]);
7722     II  = rstart + i;
7723     if (env == II) {
7724       starts[lblocks]  = tbs;
7725       sizes[lblocks++] = 1 + II - tbs;
7726       tbs              = 1 + II;
7727     }
7728   }
7729   if (rank < size - 1) {
7730     PetscCallMPI(MPI_Send(&env, 1, MPIU_INT, rank + 1, tag, comm));
7731     PetscCallMPI(MPI_Send(&tbs, 1, MPIU_INT, rank + 1, tag, comm));
7732   }
7733 
7734   PetscCall(MatRestoreRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ia, &ja, &done));
7735   if (!set || !flag) PetscCall(MatDestroy(&AA));
7736   PetscCall(MatDestroy(&A));
7737 
7738   PetscCall(PetscNew(&edata));
7739   PetscCall(MatGetNonzeroState(mat, &edata->nonzerostate));
7740   edata->n = lblocks;
7741   /* create IS needed for extracting blocks from the original matrix */
7742   PetscCall(PetscMalloc1(lblocks, &edata->is));
7743   for (PetscInt i = 0; i < lblocks; i++) PetscCall(ISCreateStride(PETSC_COMM_SELF, sizes[i], starts[i], 1, &edata->is[i]));
7744 
7745   /* Create the resulting inverse matrix nonzero structure with preallocation information */
7746   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &edata->C));
7747   PetscCall(MatSetSizes(edata->C, mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N));
7748   PetscCall(MatSetBlockSizesFromMats(edata->C, mat, mat));
7749   PetscCall(MatSetType(edata->C, MATAIJ));
7750 
7751   /* Communicate the start and end of each row, from each block to the correct rank */
7752   /* TODO: Use PetscSF instead of VecScatter */
7753   for (PetscInt i = 0; i < lblocks; i++) ln += sizes[i];
7754   PetscCall(VecCreateSeq(PETSC_COMM_SELF, 2 * ln, &seq));
7755   PetscCall(VecGetArrayWrite(seq, &seqv));
7756   for (PetscInt i = 0; i < lblocks; i++) {
7757     for (PetscInt j = 0; j < sizes[i]; j++) {
7758       seqv[cnt]     = starts[i];
7759       seqv[cnt + 1] = starts[i] + sizes[i];
7760       cnt += 2;
7761     }
7762   }
7763   PetscCall(VecRestoreArrayWrite(seq, &seqv));
7764   PetscCallMPI(MPI_Scan(&cnt, &sc, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
7765   sc -= cnt;
7766   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)mat), 2 * mat->rmap->n, 2 * mat->rmap->N, &par));
7767   PetscCall(ISCreateStride(PETSC_COMM_SELF, cnt, sc, 1, &isglobal));
7768   PetscCall(VecScatterCreate(seq, NULL, par, isglobal, &scatter));
7769   PetscCall(ISDestroy(&isglobal));
7770   PetscCall(VecScatterBegin(scatter, seq, par, INSERT_VALUES, SCATTER_FORWARD));
7771   PetscCall(VecScatterEnd(scatter, seq, par, INSERT_VALUES, SCATTER_FORWARD));
7772   PetscCall(VecScatterDestroy(&scatter));
7773   PetscCall(VecDestroy(&seq));
7774   PetscCall(MatGetOwnershipRangeColumn(mat, &cstart, &cend));
7775   PetscCall(PetscMalloc2(mat->rmap->n, &diag, mat->rmap->n, &odiag));
7776   PetscCall(VecGetArrayRead(par, &parv));
7777   cnt = 0;
7778   PetscCall(MatGetSize(mat, NULL, &n));
7779   for (PetscInt i = 0; i < mat->rmap->n; i++) {
7780     PetscInt start, end, d = 0, od = 0;
7781 
7782     start = (PetscInt)PetscRealPart(parv[cnt]);
7783     end   = (PetscInt)PetscRealPart(parv[cnt + 1]);
7784     cnt += 2;
7785 
7786     if (start < cstart) {
7787       od += cstart - start + n - cend;
7788       d += cend - cstart;
7789     } else if (start < cend) {
7790       od += n - cend;
7791       d += cend - start;
7792     } else od += n - start;
7793     if (end <= cstart) {
7794       od -= cstart - end + n - cend;
7795       d -= cend - cstart;
7796     } else if (end < cend) {
7797       od -= n - cend;
7798       d -= cend - end;
7799     } else od -= n - end;
7800 
7801     odiag[i] = od;
7802     diag[i]  = d;
7803   }
7804   PetscCall(VecRestoreArrayRead(par, &parv));
7805   PetscCall(VecDestroy(&par));
7806   PetscCall(MatXAIJSetPreallocation(edata->C, mat->rmap->bs, diag, odiag, NULL, NULL));
7807   PetscCall(PetscFree2(diag, odiag));
7808   PetscCall(PetscFree2(sizes, starts));
7809 
7810   PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container));
7811   PetscCall(PetscContainerSetPointer(container, edata));
7812   PetscCall(PetscContainerSetCtxDestroy(container, EnvelopeDataDestroy));
7813   PetscCall(PetscObjectCompose((PetscObject)mat, "EnvelopeData", (PetscObject)container));
7814   PetscCall(PetscObjectDereference((PetscObject)container));
7815   PetscFunctionReturn(PETSC_SUCCESS);
7816 }
7817 
7818 /*@
7819   MatInvertVariableBlockEnvelope - set matrix C to be the inverted block diagonal of matrix A
7820 
7821   Collective
7822 
7823   Input Parameters:
7824 + A     - the matrix
7825 - reuse - indicates if the `C` matrix was obtained from a previous call to this routine
7826 
7827   Output Parameter:
7828 . C - matrix with inverted block diagonal of `A`
7829 
7830   Level: advanced
7831 
7832   Note:
7833   For efficiency the matrix `A` should have all the nonzero entries clustered in smallish blocks along the diagonal.
7834 
7835 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatComputeBlockDiagonal()`
7836 @*/
7837 PetscErrorCode MatInvertVariableBlockEnvelope(Mat A, MatReuse reuse, Mat *C)
7838 {
7839   PetscContainer   container;
7840   EnvelopeData    *edata;
7841   PetscObjectState nonzerostate;
7842 
7843   PetscFunctionBegin;
7844   PetscCall(PetscObjectQuery((PetscObject)A, "EnvelopeData", (PetscObject *)&container));
7845   if (!container) {
7846     PetscCall(MatComputeVariableBlockEnvelope(A));
7847     PetscCall(PetscObjectQuery((PetscObject)A, "EnvelopeData", (PetscObject *)&container));
7848   }
7849   PetscCall(PetscContainerGetPointer(container, (void **)&edata));
7850   PetscCall(MatGetNonzeroState(A, &nonzerostate));
7851   PetscCheck(nonzerostate <= edata->nonzerostate, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot handle changes to matrix nonzero structure");
7852   PetscCheck(reuse != MAT_REUSE_MATRIX || *C == edata->C, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "C matrix must be the same as previously output");
7853 
7854   PetscCall(MatCreateSubMatrices(A, edata->n, edata->is, edata->is, MAT_INITIAL_MATRIX, &edata->mat));
7855   *C = edata->C;
7856 
7857   for (PetscInt i = 0; i < edata->n; i++) {
7858     Mat          D;
7859     PetscScalar *dvalues;
7860 
7861     PetscCall(MatConvert(edata->mat[i], MATSEQDENSE, MAT_INITIAL_MATRIX, &D));
7862     PetscCall(MatSetOption(*C, MAT_ROW_ORIENTED, PETSC_FALSE));
7863     PetscCall(MatSeqDenseInvert(D));
7864     PetscCall(MatDenseGetArray(D, &dvalues));
7865     PetscCall(MatSetValuesIS(*C, edata->is[i], edata->is[i], dvalues, INSERT_VALUES));
7866     PetscCall(MatDestroy(&D));
7867   }
7868   PetscCall(MatDestroySubMatrices(edata->n, &edata->mat));
7869   PetscCall(MatAssemblyBegin(*C, MAT_FINAL_ASSEMBLY));
7870   PetscCall(MatAssemblyEnd(*C, MAT_FINAL_ASSEMBLY));
7871   PetscFunctionReturn(PETSC_SUCCESS);
7872 }
7873 
7874 /*@
7875   MatSetVariableBlockSizes - Sets diagonal point-blocks of the matrix that need not be of the same size
7876 
7877   Not Collective
7878 
7879   Input Parameters:
7880 + mat     - the matrix
7881 . nblocks - the number of blocks on this process, each block can only exist on a single process
7882 - bsizes  - the block sizes
7883 
7884   Level: intermediate
7885 
7886   Notes:
7887   Currently used by `PCVPBJACOBI` for `MATAIJ` matrices
7888 
7889   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.
7890 
7891 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`, `MatGetVariableBlockSizes()`,
7892           `MatComputeVariableBlockEnvelope()`, `PCVPBJACOBI`
7893 @*/
7894 PetscErrorCode MatSetVariableBlockSizes(Mat mat, PetscInt nblocks, const PetscInt bsizes[])
7895 {
7896   PetscInt ncnt = 0, nlocal;
7897 
7898   PetscFunctionBegin;
7899   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7900   PetscCall(MatGetLocalSize(mat, &nlocal, NULL));
7901   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);
7902   for (PetscInt i = 0; i < nblocks; i++) ncnt += bsizes[i];
7903   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);
7904   PetscCall(PetscFree(mat->bsizes));
7905   mat->nblocks = nblocks;
7906   PetscCall(PetscMalloc1(nblocks, &mat->bsizes));
7907   PetscCall(PetscArraycpy(mat->bsizes, bsizes, nblocks));
7908   PetscFunctionReturn(PETSC_SUCCESS);
7909 }
7910 
7911 /*@C
7912   MatGetVariableBlockSizes - Gets a diagonal blocks of the matrix that need not be of the same size
7913 
7914   Not Collective; No Fortran Support
7915 
7916   Input Parameter:
7917 . mat - the matrix
7918 
7919   Output Parameters:
7920 + nblocks - the number of blocks on this process
7921 - bsizes  - the block sizes
7922 
7923   Level: intermediate
7924 
7925 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`, `MatSetVariableBlockSizes()`, `MatComputeVariableBlockEnvelope()`
7926 @*/
7927 PetscErrorCode MatGetVariableBlockSizes(Mat mat, PetscInt *nblocks, const PetscInt *bsizes[])
7928 {
7929   PetscFunctionBegin;
7930   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7931   if (nblocks) *nblocks = mat->nblocks;
7932   if (bsizes) *bsizes = mat->bsizes;
7933   PetscFunctionReturn(PETSC_SUCCESS);
7934 }
7935 
7936 /*@
7937   MatSetBlockSizes - Sets the matrix block row and column sizes.
7938 
7939   Logically Collective
7940 
7941   Input Parameters:
7942 + mat - the matrix
7943 . rbs - row block size
7944 - cbs - column block size
7945 
7946   Level: intermediate
7947 
7948   Notes:
7949   Block row formats are `MATBAIJ` and  `MATSBAIJ`. These formats ALWAYS have square block storage in the matrix.
7950   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
7951   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
7952 
7953   For `MATAIJ` matrix this function can be called at a later stage, provided that the specified block sizes
7954   are compatible with the matrix local sizes.
7955 
7956   The row and column block size determine the blocksize of the "row" and "column" vectors returned by `MatCreateVecs()`.
7957 
7958 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatGetBlockSizes()`
7959 @*/
7960 PetscErrorCode MatSetBlockSizes(Mat mat, PetscInt rbs, PetscInt cbs)
7961 {
7962   PetscFunctionBegin;
7963   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7964   PetscValidLogicalCollectiveInt(mat, rbs, 2);
7965   PetscValidLogicalCollectiveInt(mat, cbs, 3);
7966   PetscTryTypeMethod(mat, setblocksizes, rbs, cbs);
7967   if (mat->rmap->refcnt) {
7968     ISLocalToGlobalMapping l2g  = NULL;
7969     PetscLayout            nmap = NULL;
7970 
7971     PetscCall(PetscLayoutDuplicate(mat->rmap, &nmap));
7972     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->rmap->mapping, &l2g));
7973     PetscCall(PetscLayoutDestroy(&mat->rmap));
7974     mat->rmap          = nmap;
7975     mat->rmap->mapping = l2g;
7976   }
7977   if (mat->cmap->refcnt) {
7978     ISLocalToGlobalMapping l2g  = NULL;
7979     PetscLayout            nmap = NULL;
7980 
7981     PetscCall(PetscLayoutDuplicate(mat->cmap, &nmap));
7982     if (mat->cmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->cmap->mapping, &l2g));
7983     PetscCall(PetscLayoutDestroy(&mat->cmap));
7984     mat->cmap          = nmap;
7985     mat->cmap->mapping = l2g;
7986   }
7987   PetscCall(PetscLayoutSetBlockSize(mat->rmap, rbs));
7988   PetscCall(PetscLayoutSetBlockSize(mat->cmap, cbs));
7989   PetscFunctionReturn(PETSC_SUCCESS);
7990 }
7991 
7992 /*@
7993   MatSetBlockSizesFromMats - Sets the matrix block row and column sizes to match a pair of matrices
7994 
7995   Logically Collective
7996 
7997   Input Parameters:
7998 + mat     - the matrix
7999 . fromRow - matrix from which to copy row block size
8000 - fromCol - matrix from which to copy column block size (can be same as fromRow)
8001 
8002   Level: developer
8003 
8004 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`
8005 @*/
8006 PetscErrorCode MatSetBlockSizesFromMats(Mat mat, Mat fromRow, Mat fromCol)
8007 {
8008   PetscFunctionBegin;
8009   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8010   PetscValidHeaderSpecific(fromRow, MAT_CLASSID, 2);
8011   PetscValidHeaderSpecific(fromCol, MAT_CLASSID, 3);
8012   PetscCall(PetscLayoutSetBlockSize(mat->rmap, fromRow->rmap->bs));
8013   PetscCall(PetscLayoutSetBlockSize(mat->cmap, fromCol->cmap->bs));
8014   PetscFunctionReturn(PETSC_SUCCESS);
8015 }
8016 
8017 /*@
8018   MatResidual - Default routine to calculate the residual r = b - Ax
8019 
8020   Collective
8021 
8022   Input Parameters:
8023 + mat - the matrix
8024 . b   - the right-hand-side
8025 - x   - the approximate solution
8026 
8027   Output Parameter:
8028 . r - location to store the residual
8029 
8030   Level: developer
8031 
8032 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `PCMGSetResidual()`
8033 @*/
8034 PetscErrorCode MatResidual(Mat mat, Vec b, Vec x, Vec r)
8035 {
8036   PetscFunctionBegin;
8037   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8038   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
8039   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
8040   PetscValidHeaderSpecific(r, VEC_CLASSID, 4);
8041   PetscValidType(mat, 1);
8042   MatCheckPreallocated(mat, 1);
8043   PetscCall(PetscLogEventBegin(MAT_Residual, mat, 0, 0, 0));
8044   if (!mat->ops->residual) {
8045     PetscCall(MatMult(mat, x, r));
8046     PetscCall(VecAYPX(r, -1.0, b));
8047   } else {
8048     PetscUseTypeMethod(mat, residual, b, x, r);
8049   }
8050   PetscCall(PetscLogEventEnd(MAT_Residual, mat, 0, 0, 0));
8051   PetscFunctionReturn(PETSC_SUCCESS);
8052 }
8053 
8054 /*@C
8055   MatGetRowIJ - Returns the compressed row storage i and j indices for the local rows of a sparse matrix
8056 
8057   Collective
8058 
8059   Input Parameters:
8060 + mat             - the matrix
8061 . shift           - 0 or 1 indicating we want the indices starting at 0 or 1
8062 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8063 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE`  indicating if the nonzero structure of the
8064                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8065                  always used.
8066 
8067   Output Parameters:
8068 + n    - number of local rows in the (possibly compressed) matrix, use `NULL` if not needed
8069 . 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
8070 . ja   - the column indices, use `NULL` if not needed
8071 - done - indicates if the routine actually worked and returned appropriate ia[] and ja[] arrays; callers
8072            are responsible for handling the case when done == `PETSC_FALSE` and ia and ja are not set
8073 
8074   Level: developer
8075 
8076   Notes:
8077   You CANNOT change any of the ia[] or ja[] values.
8078 
8079   Use `MatRestoreRowIJ()` when you are finished accessing the ia[] and ja[] values.
8080 
8081   Fortran Notes:
8082   Use
8083 .vb
8084     PetscInt, pointer :: ia(:),ja(:)
8085     call MatGetRowIJ(mat,shift,symmetric,inodecompressed,n,ia,ja,done,ierr)
8086     ! Access the ith and jth entries via ia(i) and ja(j)
8087 .ve
8088 
8089 .seealso: [](ch_matrices), `Mat`, `MATAIJ`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`, `MatSeqAIJGetArray()`
8090 @*/
8091 PetscErrorCode MatGetRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8092 {
8093   PetscFunctionBegin;
8094   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8095   PetscValidType(mat, 1);
8096   if (n) PetscAssertPointer(n, 5);
8097   if (ia) PetscAssertPointer(ia, 6);
8098   if (ja) PetscAssertPointer(ja, 7);
8099   if (done) PetscAssertPointer(done, 8);
8100   MatCheckPreallocated(mat, 1);
8101   if (!mat->ops->getrowij && done) *done = PETSC_FALSE;
8102   else {
8103     if (done) *done = PETSC_TRUE;
8104     PetscCall(PetscLogEventBegin(MAT_GetRowIJ, mat, 0, 0, 0));
8105     PetscUseTypeMethod(mat, getrowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8106     PetscCall(PetscLogEventEnd(MAT_GetRowIJ, mat, 0, 0, 0));
8107   }
8108   PetscFunctionReturn(PETSC_SUCCESS);
8109 }
8110 
8111 /*@C
8112   MatGetColumnIJ - Returns the compressed column storage i and j indices for sequential matrices.
8113 
8114   Collective
8115 
8116   Input Parameters:
8117 + mat             - the matrix
8118 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8119 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be
8120                 symmetrized
8121 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8122                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8123                  always used.
8124 . n               - number of columns in the (possibly compressed) matrix
8125 . ia              - the column pointers; that is ia[0] = 0, ia[col] = i[col-1] + number of elements in that col of the matrix
8126 - ja              - the row indices
8127 
8128   Output Parameter:
8129 . done - `PETSC_TRUE` or `PETSC_FALSE`, indicating whether the values have been returned
8130 
8131   Level: developer
8132 
8133 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8134 @*/
8135 PetscErrorCode MatGetColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8136 {
8137   PetscFunctionBegin;
8138   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8139   PetscValidType(mat, 1);
8140   PetscAssertPointer(n, 5);
8141   if (ia) PetscAssertPointer(ia, 6);
8142   if (ja) PetscAssertPointer(ja, 7);
8143   PetscAssertPointer(done, 8);
8144   MatCheckPreallocated(mat, 1);
8145   if (!mat->ops->getcolumnij) *done = PETSC_FALSE;
8146   else {
8147     *done = PETSC_TRUE;
8148     PetscUseTypeMethod(mat, getcolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8149   }
8150   PetscFunctionReturn(PETSC_SUCCESS);
8151 }
8152 
8153 /*@C
8154   MatRestoreRowIJ - Call after you are completed with the ia,ja indices obtained with `MatGetRowIJ()`.
8155 
8156   Collective
8157 
8158   Input Parameters:
8159 + mat             - the matrix
8160 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8161 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8162 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8163                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8164                     always used.
8165 . n               - size of (possibly compressed) matrix
8166 . ia              - the row pointers
8167 - ja              - the column indices
8168 
8169   Output Parameter:
8170 . done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8171 
8172   Level: developer
8173 
8174   Note:
8175   This routine zeros out `n`, `ia`, and `ja`. This is to prevent accidental
8176   us of the array after it has been restored. If you pass `NULL`, it will
8177   not zero the pointers.  Use of ia or ja after `MatRestoreRowIJ()` is invalid.
8178 
8179 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8180 @*/
8181 PetscErrorCode MatRestoreRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8182 {
8183   PetscFunctionBegin;
8184   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8185   PetscValidType(mat, 1);
8186   if (ia) PetscAssertPointer(ia, 6);
8187   if (ja) PetscAssertPointer(ja, 7);
8188   if (done) PetscAssertPointer(done, 8);
8189   MatCheckPreallocated(mat, 1);
8190 
8191   if (!mat->ops->restorerowij && done) *done = PETSC_FALSE;
8192   else {
8193     if (done) *done = PETSC_TRUE;
8194     PetscUseTypeMethod(mat, restorerowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8195     if (n) *n = 0;
8196     if (ia) *ia = NULL;
8197     if (ja) *ja = NULL;
8198   }
8199   PetscFunctionReturn(PETSC_SUCCESS);
8200 }
8201 
8202 /*@C
8203   MatRestoreColumnIJ - Call after you are completed with the ia,ja indices obtained with `MatGetColumnIJ()`.
8204 
8205   Collective
8206 
8207   Input Parameters:
8208 + mat             - the matrix
8209 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8210 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8211 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8212                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8213                     always used.
8214 
8215   Output Parameters:
8216 + n    - size of (possibly compressed) matrix
8217 . ia   - the column pointers
8218 . ja   - the row indices
8219 - done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8220 
8221   Level: developer
8222 
8223 .seealso: [](ch_matrices), `Mat`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`
8224 @*/
8225 PetscErrorCode MatRestoreColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8226 {
8227   PetscFunctionBegin;
8228   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8229   PetscValidType(mat, 1);
8230   if (ia) PetscAssertPointer(ia, 6);
8231   if (ja) PetscAssertPointer(ja, 7);
8232   PetscAssertPointer(done, 8);
8233   MatCheckPreallocated(mat, 1);
8234 
8235   if (!mat->ops->restorecolumnij) *done = PETSC_FALSE;
8236   else {
8237     *done = PETSC_TRUE;
8238     PetscUseTypeMethod(mat, restorecolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8239     if (n) *n = 0;
8240     if (ia) *ia = NULL;
8241     if (ja) *ja = NULL;
8242   }
8243   PetscFunctionReturn(PETSC_SUCCESS);
8244 }
8245 
8246 /*@
8247   MatColoringPatch - Used inside matrix coloring routines that use `MatGetRowIJ()` and/or
8248   `MatGetColumnIJ()`.
8249 
8250   Collective
8251 
8252   Input Parameters:
8253 + mat        - the matrix
8254 . ncolors    - maximum color value
8255 . n          - number of entries in colorarray
8256 - colorarray - array indicating color for each column
8257 
8258   Output Parameter:
8259 . iscoloring - coloring generated using colorarray information
8260 
8261   Level: developer
8262 
8263 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatGetColumnIJ()`
8264 @*/
8265 PetscErrorCode MatColoringPatch(Mat mat, PetscInt ncolors, PetscInt n, ISColoringValue colorarray[], ISColoring *iscoloring)
8266 {
8267   PetscFunctionBegin;
8268   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8269   PetscValidType(mat, 1);
8270   PetscAssertPointer(colorarray, 4);
8271   PetscAssertPointer(iscoloring, 5);
8272   MatCheckPreallocated(mat, 1);
8273 
8274   if (!mat->ops->coloringpatch) {
8275     PetscCall(ISColoringCreate(PetscObjectComm((PetscObject)mat), ncolors, n, colorarray, PETSC_OWN_POINTER, iscoloring));
8276   } else {
8277     PetscUseTypeMethod(mat, coloringpatch, ncolors, n, colorarray, iscoloring);
8278   }
8279   PetscFunctionReturn(PETSC_SUCCESS);
8280 }
8281 
8282 /*@
8283   MatSetUnfactored - Resets a factored matrix to be treated as unfactored.
8284 
8285   Logically Collective
8286 
8287   Input Parameter:
8288 . mat - the factored matrix to be reset
8289 
8290   Level: developer
8291 
8292   Notes:
8293   This routine should be used only with factored matrices formed by in-place
8294   factorization via ILU(0) (or by in-place LU factorization for the `MATSEQDENSE`
8295   format).  This option can save memory, for example, when solving nonlinear
8296   systems with a matrix-free Newton-Krylov method and a matrix-based, in-place
8297   ILU(0) preconditioner.
8298 
8299   One can specify in-place ILU(0) factorization by calling
8300 .vb
8301      PCType(pc,PCILU);
8302      PCFactorSeUseInPlace(pc);
8303 .ve
8304   or by using the options -pc_type ilu -pc_factor_in_place
8305 
8306   In-place factorization ILU(0) can also be used as a local
8307   solver for the blocks within the block Jacobi or additive Schwarz
8308   methods (runtime option: -sub_pc_factor_in_place).  See Users-Manual: ch_pc
8309   for details on setting local solver options.
8310 
8311   Most users should employ the `KSP` interface for linear solvers
8312   instead of working directly with matrix algebra routines such as this.
8313   See, e.g., `KSPCreate()`.
8314 
8315 .seealso: [](ch_matrices), `Mat`, `PCFactorSetUseInPlace()`, `PCFactorGetUseInPlace()`
8316 @*/
8317 PetscErrorCode MatSetUnfactored(Mat mat)
8318 {
8319   PetscFunctionBegin;
8320   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8321   PetscValidType(mat, 1);
8322   MatCheckPreallocated(mat, 1);
8323   mat->factortype = MAT_FACTOR_NONE;
8324   if (!mat->ops->setunfactored) PetscFunctionReturn(PETSC_SUCCESS);
8325   PetscUseTypeMethod(mat, setunfactored);
8326   PetscFunctionReturn(PETSC_SUCCESS);
8327 }
8328 
8329 /*@
8330   MatCreateSubMatrix - Gets a single submatrix on the same number of processors
8331   as the original matrix.
8332 
8333   Collective
8334 
8335   Input Parameters:
8336 + mat   - the original matrix
8337 . isrow - parallel `IS` containing the rows this processor should obtain
8338 . 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.
8339 - cll   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
8340 
8341   Output Parameter:
8342 . newmat - the new submatrix, of the same type as the original matrix
8343 
8344   Level: advanced
8345 
8346   Notes:
8347   The submatrix will be able to be multiplied with vectors using the same layout as `iscol`.
8348 
8349   Some matrix types place restrictions on the row and column indices, such
8350   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;
8351   for example, if the block size is 3 one cannot select the 0 and 2 rows without selecting the 1 row.
8352 
8353   The index sets may not have duplicate entries.
8354 
8355   The first time this is called you should use a cll of `MAT_INITIAL_MATRIX`,
8356   the `MatCreateSubMatrix()` routine will create the newmat for you. Any additional calls
8357   to this routine with a mat of the same nonzero structure and with a call of `MAT_REUSE_MATRIX`
8358   will reuse the matrix generated the first time.  You should call `MatDestroy()` on `newmat` when
8359   you are finished using it.
8360 
8361   The communicator of the newly obtained matrix is ALWAYS the same as the communicator of
8362   the input matrix.
8363 
8364   If `iscol` is `NULL` then all columns are obtained (not supported in Fortran).
8365 
8366   If `isrow` and `iscol` have a nontrivial block-size, then the resulting matrix has this block-size as well. This feature
8367   is used by `PCFIELDSPLIT` to allow easy nesting of its use.
8368 
8369   Example usage:
8370   Consider the following 8x8 matrix with 34 non-zero values, that is
8371   assembled across 3 processors. Let's assume that proc0 owns 3 rows,
8372   proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
8373   as follows
8374 .vb
8375             1  2  0  |  0  3  0  |  0  4
8376     Proc0   0  5  6  |  7  0  0  |  8  0
8377             9  0 10  | 11  0  0  | 12  0
8378     -------------------------------------
8379            13  0 14  | 15 16 17  |  0  0
8380     Proc1   0 18  0  | 19 20 21  |  0  0
8381             0  0  0  | 22 23  0  | 24  0
8382     -------------------------------------
8383     Proc2  25 26 27  |  0  0 28  | 29  0
8384            30  0  0  | 31 32 33  |  0 34
8385 .ve
8386 
8387   Suppose `isrow` = [0 1 | 4 | 6 7] and `iscol` = [1 2 | 3 4 5 | 6].  The resulting submatrix is
8388 
8389 .vb
8390             2  0  |  0  3  0  |  0
8391     Proc0   5  6  |  7  0  0  |  8
8392     -------------------------------
8393     Proc1  18  0  | 19 20 21  |  0
8394     -------------------------------
8395     Proc2  26 27  |  0  0 28  | 29
8396             0  0  | 31 32 33  |  0
8397 .ve
8398 
8399 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatCreateSubMatricesMPI()`, `MatCreateSubMatrixVirtual()`, `MatSubMatrixVirtualUpdate()`
8400 @*/
8401 PetscErrorCode MatCreateSubMatrix(Mat mat, IS isrow, IS iscol, MatReuse cll, Mat *newmat)
8402 {
8403   PetscMPIInt size;
8404   Mat        *local;
8405   IS          iscoltmp;
8406   PetscBool   flg;
8407 
8408   PetscFunctionBegin;
8409   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8410   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
8411   if (iscol) PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
8412   PetscAssertPointer(newmat, 5);
8413   if (cll == MAT_REUSE_MATRIX) PetscValidHeaderSpecific(*newmat, MAT_CLASSID, 5);
8414   PetscValidType(mat, 1);
8415   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
8416   PetscCheck(cll != MAT_IGNORE_MATRIX, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot use MAT_IGNORE_MATRIX");
8417 
8418   MatCheckPreallocated(mat, 1);
8419   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
8420 
8421   if (!iscol || isrow == iscol) {
8422     PetscBool   stride;
8423     PetscMPIInt grabentirematrix = 0, grab;
8424     PetscCall(PetscObjectTypeCompare((PetscObject)isrow, ISSTRIDE, &stride));
8425     if (stride) {
8426       PetscInt first, step, n, rstart, rend;
8427       PetscCall(ISStrideGetInfo(isrow, &first, &step));
8428       if (step == 1) {
8429         PetscCall(MatGetOwnershipRange(mat, &rstart, &rend));
8430         if (rstart == first) {
8431           PetscCall(ISGetLocalSize(isrow, &n));
8432           if (n == rend - rstart) grabentirematrix = 1;
8433         }
8434       }
8435     }
8436     PetscCallMPI(MPIU_Allreduce(&grabentirematrix, &grab, 1, MPI_INT, MPI_MIN, PetscObjectComm((PetscObject)mat)));
8437     if (grab) {
8438       PetscCall(PetscInfo(mat, "Getting entire matrix as submatrix\n"));
8439       if (cll == MAT_INITIAL_MATRIX) {
8440         *newmat = mat;
8441         PetscCall(PetscObjectReference((PetscObject)mat));
8442       }
8443       PetscFunctionReturn(PETSC_SUCCESS);
8444     }
8445   }
8446 
8447   if (!iscol) {
8448     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)mat), mat->cmap->n, mat->cmap->rstart, 1, &iscoltmp));
8449   } else {
8450     iscoltmp = iscol;
8451   }
8452 
8453   /* if original matrix is on just one processor then use submatrix generated */
8454   if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1 && cll == MAT_REUSE_MATRIX) {
8455     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_REUSE_MATRIX, &newmat));
8456     goto setproperties;
8457   } else if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1) {
8458     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_INITIAL_MATRIX, &local));
8459     *newmat = *local;
8460     PetscCall(PetscFree(local));
8461     goto setproperties;
8462   } else if (!mat->ops->createsubmatrix) {
8463     /* Create a new matrix type that implements the operation using the full matrix */
8464     PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8465     switch (cll) {
8466     case MAT_INITIAL_MATRIX:
8467       PetscCall(MatCreateSubMatrixVirtual(mat, isrow, iscoltmp, newmat));
8468       break;
8469     case MAT_REUSE_MATRIX:
8470       PetscCall(MatSubMatrixVirtualUpdate(*newmat, mat, isrow, iscoltmp));
8471       break;
8472     default:
8473       SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Invalid MatReuse, must be either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX");
8474     }
8475     PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8476     goto setproperties;
8477   }
8478 
8479   PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8480   PetscUseTypeMethod(mat, createsubmatrix, isrow, iscoltmp, cll, newmat);
8481   PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8482 
8483 setproperties:
8484   if ((*newmat)->symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->structurally_symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->spd == PETSC_BOOL3_UNKNOWN && (*newmat)->hermitian == PETSC_BOOL3_UNKNOWN) {
8485     PetscCall(ISEqualUnsorted(isrow, iscoltmp, &flg));
8486     if (flg) PetscCall(MatPropagateSymmetryOptions(mat, *newmat));
8487   }
8488   if (!iscol) PetscCall(ISDestroy(&iscoltmp));
8489   if (*newmat && cll == MAT_INITIAL_MATRIX) PetscCall(PetscObjectStateIncrease((PetscObject)*newmat));
8490   PetscFunctionReturn(PETSC_SUCCESS);
8491 }
8492 
8493 /*@
8494   MatPropagateSymmetryOptions - Propagates symmetry options set on a matrix to another matrix
8495 
8496   Not Collective
8497 
8498   Input Parameters:
8499 + A - the matrix we wish to propagate options from
8500 - B - the matrix we wish to propagate options to
8501 
8502   Level: beginner
8503 
8504   Note:
8505   Propagates the options associated to `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_HERMITIAN`, `MAT_SPD`, `MAT_SYMMETRIC`, and `MAT_STRUCTURAL_SYMMETRY_ETERNAL`
8506 
8507 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatIsSymmetricKnown()`, `MatIsSPDKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
8508 @*/
8509 PetscErrorCode MatPropagateSymmetryOptions(Mat A, Mat B)
8510 {
8511   PetscFunctionBegin;
8512   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8513   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
8514   B->symmetry_eternal            = A->symmetry_eternal;
8515   B->structural_symmetry_eternal = A->structural_symmetry_eternal;
8516   B->symmetric                   = A->symmetric;
8517   B->structurally_symmetric      = A->structurally_symmetric;
8518   B->spd                         = A->spd;
8519   B->hermitian                   = A->hermitian;
8520   PetscFunctionReturn(PETSC_SUCCESS);
8521 }
8522 
8523 /*@
8524   MatStashSetInitialSize - sets the sizes of the matrix stash, that is
8525   used during the assembly process to store values that belong to
8526   other processors.
8527 
8528   Not Collective
8529 
8530   Input Parameters:
8531 + mat   - the matrix
8532 . size  - the initial size of the stash.
8533 - bsize - the initial size of the block-stash(if used).
8534 
8535   Options Database Keys:
8536 + -matstash_initial_size <size> or <size0,size1,...sizep-1>            - set initial size
8537 - -matstash_block_initial_size <bsize>  or <bsize0,bsize1,...bsizep-1> - set initial block size
8538 
8539   Level: intermediate
8540 
8541   Notes:
8542   The block-stash is used for values set with `MatSetValuesBlocked()` while
8543   the stash is used for values set with `MatSetValues()`
8544 
8545   Run with the option -info and look for output of the form
8546   MatAssemblyBegin_MPIXXX:Stash has MM entries, uses nn mallocs.
8547   to determine the appropriate value, MM, to use for size and
8548   MatAssemblyBegin_MPIXXX:Block-Stash has BMM entries, uses nn mallocs.
8549   to determine the value, BMM to use for bsize
8550 
8551 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashGetInfo()`
8552 @*/
8553 PetscErrorCode MatStashSetInitialSize(Mat mat, PetscInt size, PetscInt bsize)
8554 {
8555   PetscFunctionBegin;
8556   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8557   PetscValidType(mat, 1);
8558   PetscCall(MatStashSetInitialSize_Private(&mat->stash, size));
8559   PetscCall(MatStashSetInitialSize_Private(&mat->bstash, bsize));
8560   PetscFunctionReturn(PETSC_SUCCESS);
8561 }
8562 
8563 /*@
8564   MatInterpolateAdd - $w = y + A*x$ or $A^T*x$ depending on the shape of
8565   the matrix
8566 
8567   Neighbor-wise Collective
8568 
8569   Input Parameters:
8570 + A - the matrix
8571 . x - the vector to be multiplied by the interpolation operator
8572 - y - the vector to be added to the result
8573 
8574   Output Parameter:
8575 . w - the resulting vector
8576 
8577   Level: intermediate
8578 
8579   Notes:
8580   `w` may be the same vector as `y`.
8581 
8582   This allows one to use either the restriction or interpolation (its transpose)
8583   matrix to do the interpolation
8584 
8585 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8586 @*/
8587 PetscErrorCode MatInterpolateAdd(Mat A, Vec x, Vec y, Vec w)
8588 {
8589   PetscInt M, N, Ny;
8590 
8591   PetscFunctionBegin;
8592   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8593   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8594   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8595   PetscValidHeaderSpecific(w, VEC_CLASSID, 4);
8596   PetscCall(MatGetSize(A, &M, &N));
8597   PetscCall(VecGetSize(y, &Ny));
8598   if (M == Ny) {
8599     PetscCall(MatMultAdd(A, x, y, w));
8600   } else {
8601     PetscCall(MatMultTransposeAdd(A, x, y, w));
8602   }
8603   PetscFunctionReturn(PETSC_SUCCESS);
8604 }
8605 
8606 /*@
8607   MatInterpolate - $y = A*x$ or $A^T*x$ depending on the shape of
8608   the matrix
8609 
8610   Neighbor-wise Collective
8611 
8612   Input Parameters:
8613 + A - the matrix
8614 - x - the vector to be interpolated
8615 
8616   Output Parameter:
8617 . y - the resulting vector
8618 
8619   Level: intermediate
8620 
8621   Note:
8622   This allows one to use either the restriction or interpolation (its transpose)
8623   matrix to do the interpolation
8624 
8625 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8626 @*/
8627 PetscErrorCode MatInterpolate(Mat A, Vec x, Vec y)
8628 {
8629   PetscInt M, N, Ny;
8630 
8631   PetscFunctionBegin;
8632   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8633   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8634   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8635   PetscCall(MatGetSize(A, &M, &N));
8636   PetscCall(VecGetSize(y, &Ny));
8637   if (M == Ny) {
8638     PetscCall(MatMult(A, x, y));
8639   } else {
8640     PetscCall(MatMultTranspose(A, x, y));
8641   }
8642   PetscFunctionReturn(PETSC_SUCCESS);
8643 }
8644 
8645 /*@
8646   MatRestrict - $y = A*x$ or $A^T*x$
8647 
8648   Neighbor-wise Collective
8649 
8650   Input Parameters:
8651 + A - the matrix
8652 - x - the vector to be restricted
8653 
8654   Output Parameter:
8655 . y - the resulting vector
8656 
8657   Level: intermediate
8658 
8659   Note:
8660   This allows one to use either the restriction or interpolation (its transpose)
8661   matrix to do the restriction
8662 
8663 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatInterpolate()`, `PCMG`
8664 @*/
8665 PetscErrorCode MatRestrict(Mat A, Vec x, Vec y)
8666 {
8667   PetscInt M, N, Nx;
8668 
8669   PetscFunctionBegin;
8670   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8671   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8672   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8673   PetscCall(MatGetSize(A, &M, &N));
8674   PetscCall(VecGetSize(x, &Nx));
8675   if (M == Nx) {
8676     PetscCall(MatMultTranspose(A, x, y));
8677   } else {
8678     PetscCall(MatMult(A, x, y));
8679   }
8680   PetscFunctionReturn(PETSC_SUCCESS);
8681 }
8682 
8683 /*@
8684   MatMatInterpolateAdd - $Y = W + A*X$ or $W + A^T*X$ depending on the shape of `A`
8685 
8686   Neighbor-wise Collective
8687 
8688   Input Parameters:
8689 + A - the matrix
8690 . x - the input dense matrix to be multiplied
8691 - w - the input dense matrix to be added to the result
8692 
8693   Output Parameter:
8694 . y - the output dense matrix
8695 
8696   Level: intermediate
8697 
8698   Note:
8699   This allows one to use either the restriction or interpolation (its transpose)
8700   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8701   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8702 
8703 .seealso: [](ch_matrices), `Mat`, `MatInterpolateAdd()`, `MatMatInterpolate()`, `MatMatRestrict()`, `PCMG`
8704 @*/
8705 PetscErrorCode MatMatInterpolateAdd(Mat A, Mat x, Mat w, Mat *y)
8706 {
8707   PetscInt  M, N, Mx, Nx, Mo, My = 0, Ny = 0;
8708   PetscBool trans = PETSC_TRUE;
8709   MatReuse  reuse = MAT_INITIAL_MATRIX;
8710 
8711   PetscFunctionBegin;
8712   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8713   PetscValidHeaderSpecific(x, MAT_CLASSID, 2);
8714   PetscValidType(x, 2);
8715   if (w) PetscValidHeaderSpecific(w, MAT_CLASSID, 3);
8716   if (*y) PetscValidHeaderSpecific(*y, MAT_CLASSID, 4);
8717   PetscCall(MatGetSize(A, &M, &N));
8718   PetscCall(MatGetSize(x, &Mx, &Nx));
8719   if (N == Mx) trans = PETSC_FALSE;
8720   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);
8721   Mo = trans ? N : M;
8722   if (*y) {
8723     PetscCall(MatGetSize(*y, &My, &Ny));
8724     if (Mo == My && Nx == Ny) {
8725       reuse = MAT_REUSE_MATRIX;
8726     } else {
8727       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);
8728       PetscCall(MatDestroy(y));
8729     }
8730   }
8731 
8732   if (w && *y == w) { /* this is to minimize changes in PCMG */
8733     PetscBool flg;
8734 
8735     PetscCall(PetscObjectQuery((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject *)&w));
8736     if (w) {
8737       PetscInt My, Ny, Mw, Nw;
8738 
8739       PetscCall(PetscObjectTypeCompare((PetscObject)*y, ((PetscObject)w)->type_name, &flg));
8740       PetscCall(MatGetSize(*y, &My, &Ny));
8741       PetscCall(MatGetSize(w, &Mw, &Nw));
8742       if (!flg || My != Mw || Ny != Nw) w = NULL;
8743     }
8744     if (!w) {
8745       PetscCall(MatDuplicate(*y, MAT_COPY_VALUES, &w));
8746       PetscCall(PetscObjectCompose((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject)w));
8747       PetscCall(PetscObjectDereference((PetscObject)w));
8748     } else {
8749       PetscCall(MatCopy(*y, w, UNKNOWN_NONZERO_PATTERN));
8750     }
8751   }
8752   if (!trans) {
8753     PetscCall(MatMatMult(A, x, reuse, PETSC_DETERMINE, y));
8754   } else {
8755     PetscCall(MatTransposeMatMult(A, x, reuse, PETSC_DETERMINE, y));
8756   }
8757   if (w) PetscCall(MatAXPY(*y, 1.0, w, UNKNOWN_NONZERO_PATTERN));
8758   PetscFunctionReturn(PETSC_SUCCESS);
8759 }
8760 
8761 /*@
8762   MatMatInterpolate - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8763 
8764   Neighbor-wise Collective
8765 
8766   Input Parameters:
8767 + A - the matrix
8768 - x - the input dense matrix
8769 
8770   Output Parameter:
8771 . y - the output dense matrix
8772 
8773   Level: intermediate
8774 
8775   Note:
8776   This allows one to use either the restriction or interpolation (its transpose)
8777   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8778   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8779 
8780 .seealso: [](ch_matrices), `Mat`, `MatInterpolate()`, `MatRestrict()`, `MatMatRestrict()`, `PCMG`
8781 @*/
8782 PetscErrorCode MatMatInterpolate(Mat A, Mat x, Mat *y)
8783 {
8784   PetscFunctionBegin;
8785   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8786   PetscFunctionReturn(PETSC_SUCCESS);
8787 }
8788 
8789 /*@
8790   MatMatRestrict - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8791 
8792   Neighbor-wise Collective
8793 
8794   Input Parameters:
8795 + A - the matrix
8796 - x - the input dense matrix
8797 
8798   Output Parameter:
8799 . y - the output dense matrix
8800 
8801   Level: intermediate
8802 
8803   Note:
8804   This allows one to use either the restriction or interpolation (its transpose)
8805   matrix to do the restriction. `y` matrix can be reused if already created with the proper sizes,
8806   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8807 
8808 .seealso: [](ch_matrices), `Mat`, `MatRestrict()`, `MatInterpolate()`, `MatMatInterpolate()`, `PCMG`
8809 @*/
8810 PetscErrorCode MatMatRestrict(Mat A, Mat x, Mat *y)
8811 {
8812   PetscFunctionBegin;
8813   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8814   PetscFunctionReturn(PETSC_SUCCESS);
8815 }
8816 
8817 /*@
8818   MatGetNullSpace - retrieves the null space of a matrix.
8819 
8820   Logically Collective
8821 
8822   Input Parameters:
8823 + mat    - the matrix
8824 - nullsp - the null space object
8825 
8826   Level: developer
8827 
8828 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetNullSpace()`, `MatNullSpace`
8829 @*/
8830 PetscErrorCode MatGetNullSpace(Mat mat, MatNullSpace *nullsp)
8831 {
8832   PetscFunctionBegin;
8833   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8834   PetscAssertPointer(nullsp, 2);
8835   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->nullsp) ? mat->transnullsp : mat->nullsp;
8836   PetscFunctionReturn(PETSC_SUCCESS);
8837 }
8838 
8839 /*@C
8840   MatGetNullSpaces - gets the null spaces, transpose null spaces, and near null spaces from an array of matrices
8841 
8842   Logically Collective
8843 
8844   Input Parameters:
8845 + n   - the number of matrices
8846 - mat - the array of matrices
8847 
8848   Output Parameters:
8849 . nullsp - an array of null spaces, `NULL` for each matrix that does not have a null space, length 3 * `n`
8850 
8851   Level: developer
8852 
8853   Note:
8854   Call `MatRestoreNullspaces()` to provide these to another array of matrices
8855 
8856 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
8857           `MatNullSpaceRemove()`, `MatRestoreNullSpaces()`
8858 @*/
8859 PetscErrorCode MatGetNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
8860 {
8861   PetscFunctionBegin;
8862   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
8863   PetscAssertPointer(mat, 2);
8864   PetscAssertPointer(nullsp, 3);
8865 
8866   PetscCall(PetscCalloc1(3 * n, nullsp));
8867   for (PetscInt i = 0; i < n; i++) {
8868     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
8869     (*nullsp)[i] = mat[i]->nullsp;
8870     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[i]));
8871     (*nullsp)[n + i] = mat[i]->nearnullsp;
8872     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[n + i]));
8873     (*nullsp)[2 * n + i] = mat[i]->transnullsp;
8874     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[2 * n + i]));
8875   }
8876   PetscFunctionReturn(PETSC_SUCCESS);
8877 }
8878 
8879 /*@C
8880   MatRestoreNullSpaces - sets the null spaces, transpose null spaces, and near null spaces obtained with `MatGetNullSpaces()` for an array of matrices
8881 
8882   Logically Collective
8883 
8884   Input Parameters:
8885 + n      - the number of matrices
8886 . mat    - the array of matrices
8887 - nullsp - an array of null spaces
8888 
8889   Level: developer
8890 
8891   Note:
8892   Call `MatGetNullSpaces()` to create `nullsp`
8893 
8894 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
8895           `MatNullSpaceRemove()`, `MatGetNullSpaces()`
8896 @*/
8897 PetscErrorCode MatRestoreNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
8898 {
8899   PetscFunctionBegin;
8900   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
8901   PetscAssertPointer(mat, 2);
8902   PetscAssertPointer(nullsp, 3);
8903   PetscAssertPointer(*nullsp, 3);
8904 
8905   for (PetscInt i = 0; i < n; i++) {
8906     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
8907     PetscCall(MatSetNullSpace(mat[i], (*nullsp)[i]));
8908     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[i]));
8909     PetscCall(MatSetNearNullSpace(mat[i], (*nullsp)[n + i]));
8910     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[n + i]));
8911     PetscCall(MatSetTransposeNullSpace(mat[i], (*nullsp)[2 * n + i]));
8912     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[2 * n + i]));
8913   }
8914   PetscCall(PetscFree(*nullsp));
8915   PetscFunctionReturn(PETSC_SUCCESS);
8916 }
8917 
8918 /*@
8919   MatSetNullSpace - attaches a null space to a matrix.
8920 
8921   Logically Collective
8922 
8923   Input Parameters:
8924 + mat    - the matrix
8925 - nullsp - the null space object
8926 
8927   Level: advanced
8928 
8929   Notes:
8930   This null space is used by the `KSP` linear solvers to solve singular systems.
8931 
8932   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`
8933 
8934   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
8935   to zero but the linear system will still be solved in a least squares sense.
8936 
8937   The fundamental theorem of linear algebra (Gilbert Strang, Introduction to Applied Mathematics, page 72) states that
8938   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)$.
8939   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
8940   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
8941   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$).
8942   This  \hat{b} can be obtained by calling `MatNullSpaceRemove()` with the null space of the transpose of the matrix.
8943 
8944   If the matrix is known to be symmetric because it is an `MATSBAIJ` matrix or one as called
8945   `MatSetOption`(mat,`MAT_SYMMETRIC` or possibly `MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`); this
8946   routine also automatically calls `MatSetTransposeNullSpace()`.
8947 
8948   The user should call `MatNullSpaceDestroy()`.
8949 
8950 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`,
8951           `KSPSetPCSide()`
8952 @*/
8953 PetscErrorCode MatSetNullSpace(Mat mat, MatNullSpace nullsp)
8954 {
8955   PetscFunctionBegin;
8956   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8957   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
8958   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
8959   PetscCall(MatNullSpaceDestroy(&mat->nullsp));
8960   mat->nullsp = nullsp;
8961   if (mat->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetTransposeNullSpace(mat, nullsp));
8962   PetscFunctionReturn(PETSC_SUCCESS);
8963 }
8964 
8965 /*@
8966   MatGetTransposeNullSpace - retrieves the null space of the transpose of a matrix.
8967 
8968   Logically Collective
8969 
8970   Input Parameters:
8971 + mat    - the matrix
8972 - nullsp - the null space object
8973 
8974   Level: developer
8975 
8976 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetTransposeNullSpace()`, `MatSetNullSpace()`, `MatGetNullSpace()`
8977 @*/
8978 PetscErrorCode MatGetTransposeNullSpace(Mat mat, MatNullSpace *nullsp)
8979 {
8980   PetscFunctionBegin;
8981   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8982   PetscValidType(mat, 1);
8983   PetscAssertPointer(nullsp, 2);
8984   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->transnullsp) ? mat->nullsp : mat->transnullsp;
8985   PetscFunctionReturn(PETSC_SUCCESS);
8986 }
8987 
8988 /*@
8989   MatSetTransposeNullSpace - attaches the null space of a transpose of a matrix to the matrix
8990 
8991   Logically Collective
8992 
8993   Input Parameters:
8994 + mat    - the matrix
8995 - nullsp - the null space object
8996 
8997   Level: advanced
8998 
8999   Notes:
9000   This allows solving singular linear systems defined by the transpose of the matrix using `KSP` solvers with left preconditioning.
9001 
9002   See `MatSetNullSpace()`
9003 
9004 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`, `KSPSetPCSide()`
9005 @*/
9006 PetscErrorCode MatSetTransposeNullSpace(Mat mat, MatNullSpace nullsp)
9007 {
9008   PetscFunctionBegin;
9009   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9010   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9011   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9012   PetscCall(MatNullSpaceDestroy(&mat->transnullsp));
9013   mat->transnullsp = nullsp;
9014   PetscFunctionReturn(PETSC_SUCCESS);
9015 }
9016 
9017 /*@
9018   MatSetNearNullSpace - attaches a null space to a matrix, which is often the null space (rigid body modes) of the operator without boundary conditions
9019   This null space will be used to provide near null space vectors to a multigrid preconditioner built from this matrix.
9020 
9021   Logically Collective
9022 
9023   Input Parameters:
9024 + mat    - the matrix
9025 - nullsp - the null space object
9026 
9027   Level: advanced
9028 
9029   Notes:
9030   Overwrites any previous near null space that may have been attached
9031 
9032   You can remove the null space by calling this routine with an `nullsp` of `NULL`
9033 
9034 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNullSpace()`, `MatNullSpaceCreateRigidBody()`, `MatGetNearNullSpace()`
9035 @*/
9036 PetscErrorCode MatSetNearNullSpace(Mat mat, MatNullSpace nullsp)
9037 {
9038   PetscFunctionBegin;
9039   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9040   PetscValidType(mat, 1);
9041   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9042   MatCheckPreallocated(mat, 1);
9043   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9044   PetscCall(MatNullSpaceDestroy(&mat->nearnullsp));
9045   mat->nearnullsp = nullsp;
9046   PetscFunctionReturn(PETSC_SUCCESS);
9047 }
9048 
9049 /*@
9050   MatGetNearNullSpace - Get null space attached with `MatSetNearNullSpace()`
9051 
9052   Not Collective
9053 
9054   Input Parameter:
9055 . mat - the matrix
9056 
9057   Output Parameter:
9058 . nullsp - the null space object, `NULL` if not set
9059 
9060   Level: advanced
9061 
9062 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatNullSpaceCreate()`
9063 @*/
9064 PetscErrorCode MatGetNearNullSpace(Mat mat, MatNullSpace *nullsp)
9065 {
9066   PetscFunctionBegin;
9067   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9068   PetscValidType(mat, 1);
9069   PetscAssertPointer(nullsp, 2);
9070   MatCheckPreallocated(mat, 1);
9071   *nullsp = mat->nearnullsp;
9072   PetscFunctionReturn(PETSC_SUCCESS);
9073 }
9074 
9075 /*@
9076   MatICCFactor - Performs in-place incomplete Cholesky factorization of matrix.
9077 
9078   Collective
9079 
9080   Input Parameters:
9081 + mat  - the matrix
9082 . row  - row/column permutation
9083 - info - information on desired factorization process
9084 
9085   Level: developer
9086 
9087   Notes:
9088   Probably really in-place only when level of fill is zero, otherwise allocates
9089   new space to store factored matrix and deletes previous memory.
9090 
9091   Most users should employ the `KSP` interface for linear solvers
9092   instead of working directly with matrix algebra routines such as this.
9093   See, e.g., `KSPCreate()`.
9094 
9095   Developer Note:
9096   The Fortran interface is not autogenerated as the
9097   interface definition cannot be generated correctly [due to `MatFactorInfo`]
9098 
9099 .seealso: [](ch_matrices), `Mat`, `MatFactorInfo`, `MatGetFactor()`, `MatICCFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
9100 @*/
9101 PetscErrorCode MatICCFactor(Mat mat, IS row, const MatFactorInfo *info)
9102 {
9103   PetscFunctionBegin;
9104   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9105   PetscValidType(mat, 1);
9106   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
9107   PetscAssertPointer(info, 3);
9108   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
9109   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
9110   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9111   MatCheckPreallocated(mat, 1);
9112   PetscUseTypeMethod(mat, iccfactor, row, info);
9113   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9114   PetscFunctionReturn(PETSC_SUCCESS);
9115 }
9116 
9117 /*@
9118   MatDiagonalScaleLocal - Scales columns of a matrix given the scaling values including the
9119   ghosted ones.
9120 
9121   Not Collective
9122 
9123   Input Parameters:
9124 + mat  - the matrix
9125 - diag - the diagonal values, including ghost ones
9126 
9127   Level: developer
9128 
9129   Notes:
9130   Works only for `MATMPIAIJ` and `MATMPIBAIJ` matrices
9131 
9132   This allows one to avoid during communication to perform the scaling that must be done with `MatDiagonalScale()`
9133 
9134 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
9135 @*/
9136 PetscErrorCode MatDiagonalScaleLocal(Mat mat, Vec diag)
9137 {
9138   PetscMPIInt size;
9139 
9140   PetscFunctionBegin;
9141   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9142   PetscValidHeaderSpecific(diag, VEC_CLASSID, 2);
9143   PetscValidType(mat, 1);
9144 
9145   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must be already assembled");
9146   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
9147   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
9148   if (size == 1) {
9149     PetscInt n, m;
9150     PetscCall(VecGetSize(diag, &n));
9151     PetscCall(MatGetSize(mat, NULL, &m));
9152     PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supported for sequential matrices when no ghost points/periodic conditions");
9153     PetscCall(MatDiagonalScale(mat, NULL, diag));
9154   } else {
9155     PetscUseMethod(mat, "MatDiagonalScaleLocal_C", (Mat, Vec), (mat, diag));
9156   }
9157   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
9158   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9159   PetscFunctionReturn(PETSC_SUCCESS);
9160 }
9161 
9162 /*@
9163   MatGetInertia - Gets the inertia from a factored matrix
9164 
9165   Collective
9166 
9167   Input Parameter:
9168 . mat - the matrix
9169 
9170   Output Parameters:
9171 + nneg  - number of negative eigenvalues
9172 . nzero - number of zero eigenvalues
9173 - npos  - number of positive eigenvalues
9174 
9175   Level: advanced
9176 
9177   Note:
9178   Matrix must have been factored by `MatCholeskyFactor()`
9179 
9180 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactor()`
9181 @*/
9182 PetscErrorCode MatGetInertia(Mat mat, PetscInt *nneg, PetscInt *nzero, PetscInt *npos)
9183 {
9184   PetscFunctionBegin;
9185   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9186   PetscValidType(mat, 1);
9187   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9188   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Numeric factor mat is not assembled");
9189   PetscUseTypeMethod(mat, getinertia, nneg, nzero, npos);
9190   PetscFunctionReturn(PETSC_SUCCESS);
9191 }
9192 
9193 /*@C
9194   MatSolves - Solves $A x = b$, given a factored matrix, for a collection of vectors
9195 
9196   Neighbor-wise Collective
9197 
9198   Input Parameters:
9199 + mat - the factored matrix obtained with `MatGetFactor()`
9200 - b   - the right-hand-side vectors
9201 
9202   Output Parameter:
9203 . x - the result vectors
9204 
9205   Level: developer
9206 
9207   Note:
9208   The vectors `b` and `x` cannot be the same.  I.e., one cannot
9209   call `MatSolves`(A,x,x).
9210 
9211 .seealso: [](ch_matrices), `Mat`, `Vecs`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`, `MatSolve()`
9212 @*/
9213 PetscErrorCode MatSolves(Mat mat, Vecs b, Vecs x)
9214 {
9215   PetscFunctionBegin;
9216   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9217   PetscValidType(mat, 1);
9218   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
9219   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9220   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
9221 
9222   MatCheckPreallocated(mat, 1);
9223   PetscCall(PetscLogEventBegin(MAT_Solves, mat, 0, 0, 0));
9224   PetscUseTypeMethod(mat, solves, b, x);
9225   PetscCall(PetscLogEventEnd(MAT_Solves, mat, 0, 0, 0));
9226   PetscFunctionReturn(PETSC_SUCCESS);
9227 }
9228 
9229 /*@
9230   MatIsSymmetric - Test whether a matrix is symmetric
9231 
9232   Collective
9233 
9234   Input Parameters:
9235 + A   - the matrix to test
9236 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact transpose)
9237 
9238   Output Parameter:
9239 . flg - the result
9240 
9241   Level: intermediate
9242 
9243   Notes:
9244   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9245 
9246   If the matrix does not yet know if it is symmetric or not this can be an expensive operation, also available `MatIsSymmetricKnown()`
9247 
9248   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9249   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9250 
9251 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetricKnown()`,
9252           `MAT_SYMMETRIC`, `MAT_SYMMETRY_ETERNAL`
9253 @*/
9254 PetscErrorCode MatIsSymmetric(Mat A, PetscReal tol, PetscBool *flg)
9255 {
9256   PetscFunctionBegin;
9257   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9258   PetscAssertPointer(flg, 3);
9259   if (A->symmetric != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->symmetric);
9260   else {
9261     if (A->ops->issymmetric) PetscUseTypeMethod(A, issymmetric, tol, flg);
9262     else PetscCall(MatIsTranspose(A, A, tol, flg));
9263     if (!tol) PetscCall(MatSetOption(A, MAT_SYMMETRIC, *flg));
9264   }
9265   PetscFunctionReturn(PETSC_SUCCESS);
9266 }
9267 
9268 /*@
9269   MatIsHermitian - Test whether a matrix is Hermitian
9270 
9271   Collective
9272 
9273   Input Parameters:
9274 + A   - the matrix to test
9275 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact Hermitian)
9276 
9277   Output Parameter:
9278 . flg - the result
9279 
9280   Level: intermediate
9281 
9282   Notes:
9283   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9284 
9285   If the matrix does not yet know if it is Hermitian or not this can be an expensive operation, also available `MatIsHermitianKnown()`
9286 
9287   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9288   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMEMTRY_ETERNAL`,`PETSC_TRUE`)
9289 
9290 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetric()`, `MatSetOption()`,
9291           `MatIsSymmetricKnown()`, `MatIsSymmetric()`, `MAT_HERMITIAN`, `MAT_SYMMETRY_ETERNAL`
9292 @*/
9293 PetscErrorCode MatIsHermitian(Mat A, PetscReal tol, PetscBool *flg)
9294 {
9295   PetscFunctionBegin;
9296   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9297   PetscAssertPointer(flg, 3);
9298   if (A->hermitian != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->hermitian);
9299   else {
9300     if (A->ops->ishermitian) PetscUseTypeMethod(A, ishermitian, tol, flg);
9301     else PetscCall(MatIsHermitianTranspose(A, A, tol, flg));
9302     if (!tol) PetscCall(MatSetOption(A, MAT_HERMITIAN, *flg));
9303   }
9304   PetscFunctionReturn(PETSC_SUCCESS);
9305 }
9306 
9307 /*@
9308   MatIsSymmetricKnown - Checks if a matrix knows if it is symmetric or not and its symmetric state
9309 
9310   Not Collective
9311 
9312   Input Parameter:
9313 . A - the matrix to check
9314 
9315   Output Parameters:
9316 + set - `PETSC_TRUE` if the matrix knows its symmetry state (this tells you if the next flag is valid)
9317 - flg - the result (only valid if set is `PETSC_TRUE`)
9318 
9319   Level: advanced
9320 
9321   Notes:
9322   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsSymmetric()`
9323   if you want it explicitly checked
9324 
9325   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9326   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9327 
9328 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9329 @*/
9330 PetscErrorCode MatIsSymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9331 {
9332   PetscFunctionBegin;
9333   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9334   PetscAssertPointer(set, 2);
9335   PetscAssertPointer(flg, 3);
9336   if (A->symmetric != PETSC_BOOL3_UNKNOWN) {
9337     *set = PETSC_TRUE;
9338     *flg = PetscBool3ToBool(A->symmetric);
9339   } else {
9340     *set = PETSC_FALSE;
9341   }
9342   PetscFunctionReturn(PETSC_SUCCESS);
9343 }
9344 
9345 /*@
9346   MatIsSPDKnown - Checks if a matrix knows if it is symmetric positive definite or not and its symmetric positive definite state
9347 
9348   Not Collective
9349 
9350   Input Parameter:
9351 . A - the matrix to check
9352 
9353   Output Parameters:
9354 + set - `PETSC_TRUE` if the matrix knows its symmetric positive definite state (this tells you if the next flag is valid)
9355 - flg - the result (only valid if set is `PETSC_TRUE`)
9356 
9357   Level: advanced
9358 
9359   Notes:
9360   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`).
9361 
9362   One can declare that a matrix is SPD with `MatSetOption`(mat,`MAT_SPD`,`PETSC_TRUE`) and if it is known to remain SPD
9363   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SPD_ETERNAL`,`PETSC_TRUE`)
9364 
9365 .seealso: [](ch_matrices), `Mat`, `MAT_SPD_ETERNAL`, `MAT_SPD`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9366 @*/
9367 PetscErrorCode MatIsSPDKnown(Mat A, PetscBool *set, PetscBool *flg)
9368 {
9369   PetscFunctionBegin;
9370   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9371   PetscAssertPointer(set, 2);
9372   PetscAssertPointer(flg, 3);
9373   if (A->spd != PETSC_BOOL3_UNKNOWN) {
9374     *set = PETSC_TRUE;
9375     *flg = PetscBool3ToBool(A->spd);
9376   } else {
9377     *set = PETSC_FALSE;
9378   }
9379   PetscFunctionReturn(PETSC_SUCCESS);
9380 }
9381 
9382 /*@
9383   MatIsHermitianKnown - Checks if a matrix knows if it is Hermitian or not and its Hermitian state
9384 
9385   Not Collective
9386 
9387   Input Parameter:
9388 . A - the matrix to check
9389 
9390   Output Parameters:
9391 + set - `PETSC_TRUE` if the matrix knows its Hermitian state (this tells you if the next flag is valid)
9392 - flg - the result (only valid if set is `PETSC_TRUE`)
9393 
9394   Level: advanced
9395 
9396   Notes:
9397   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsHermitian()`
9398   if you want it explicitly checked
9399 
9400   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9401   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9402 
9403 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MAT_HERMITIAN`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`
9404 @*/
9405 PetscErrorCode MatIsHermitianKnown(Mat A, PetscBool *set, PetscBool *flg)
9406 {
9407   PetscFunctionBegin;
9408   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9409   PetscAssertPointer(set, 2);
9410   PetscAssertPointer(flg, 3);
9411   if (A->hermitian != PETSC_BOOL3_UNKNOWN) {
9412     *set = PETSC_TRUE;
9413     *flg = PetscBool3ToBool(A->hermitian);
9414   } else {
9415     *set = PETSC_FALSE;
9416   }
9417   PetscFunctionReturn(PETSC_SUCCESS);
9418 }
9419 
9420 /*@
9421   MatIsStructurallySymmetric - Test whether a matrix is structurally symmetric
9422 
9423   Collective
9424 
9425   Input Parameter:
9426 . A - the matrix to test
9427 
9428   Output Parameter:
9429 . flg - the result
9430 
9431   Level: intermediate
9432 
9433   Notes:
9434   If the matrix does yet know it is structurally symmetric this can be an expensive operation, also available `MatIsStructurallySymmetricKnown()`
9435 
9436   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
9437   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9438 
9439 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsSymmetric()`, `MatSetOption()`, `MatIsStructurallySymmetricKnown()`
9440 @*/
9441 PetscErrorCode MatIsStructurallySymmetric(Mat A, PetscBool *flg)
9442 {
9443   PetscFunctionBegin;
9444   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9445   PetscAssertPointer(flg, 2);
9446   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9447     *flg = PetscBool3ToBool(A->structurally_symmetric);
9448   } else {
9449     PetscUseTypeMethod(A, isstructurallysymmetric, flg);
9450     PetscCall(MatSetOption(A, MAT_STRUCTURALLY_SYMMETRIC, *flg));
9451   }
9452   PetscFunctionReturn(PETSC_SUCCESS);
9453 }
9454 
9455 /*@
9456   MatIsStructurallySymmetricKnown - Checks if a matrix knows if it is structurally symmetric or not and its structurally symmetric state
9457 
9458   Not Collective
9459 
9460   Input Parameter:
9461 . A - the matrix to check
9462 
9463   Output Parameters:
9464 + set - PETSC_TRUE if the matrix knows its structurally symmetric state (this tells you if the next flag is valid)
9465 - flg - the result (only valid if set is PETSC_TRUE)
9466 
9467   Level: advanced
9468 
9469   Notes:
9470   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
9471   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9472 
9473   Use `MatIsStructurallySymmetric()` to explicitly check if a matrix is structurally symmetric (this is an expensive operation)
9474 
9475 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9476 @*/
9477 PetscErrorCode MatIsStructurallySymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9478 {
9479   PetscFunctionBegin;
9480   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9481   PetscAssertPointer(set, 2);
9482   PetscAssertPointer(flg, 3);
9483   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9484     *set = PETSC_TRUE;
9485     *flg = PetscBool3ToBool(A->structurally_symmetric);
9486   } else {
9487     *set = PETSC_FALSE;
9488   }
9489   PetscFunctionReturn(PETSC_SUCCESS);
9490 }
9491 
9492 /*@
9493   MatStashGetInfo - Gets how many values are currently in the matrix stash, i.e. need
9494   to be communicated to other processors during the `MatAssemblyBegin()`/`MatAssemblyEnd()` process
9495 
9496   Not Collective
9497 
9498   Input Parameter:
9499 . mat - the matrix
9500 
9501   Output Parameters:
9502 + nstash    - the size of the stash
9503 . reallocs  - the number of additional mallocs incurred.
9504 . bnstash   - the size of the block stash
9505 - breallocs - the number of additional mallocs incurred.in the block stash
9506 
9507   Level: advanced
9508 
9509 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashSetInitialSize()`
9510 @*/
9511 PetscErrorCode MatStashGetInfo(Mat mat, PetscInt *nstash, PetscInt *reallocs, PetscInt *bnstash, PetscInt *breallocs)
9512 {
9513   PetscFunctionBegin;
9514   PetscCall(MatStashGetInfo_Private(&mat->stash, nstash, reallocs));
9515   PetscCall(MatStashGetInfo_Private(&mat->bstash, bnstash, breallocs));
9516   PetscFunctionReturn(PETSC_SUCCESS);
9517 }
9518 
9519 /*@
9520   MatCreateVecs - Get vector(s) compatible with the matrix, i.e. with the same
9521   parallel layout, `PetscLayout` for rows and columns
9522 
9523   Collective
9524 
9525   Input Parameter:
9526 . mat - the matrix
9527 
9528   Output Parameters:
9529 + right - (optional) vector that the matrix can be multiplied against
9530 - left  - (optional) vector that the matrix vector product can be stored in
9531 
9532   Level: advanced
9533 
9534   Notes:
9535   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()`.
9536 
9537   These are new vectors which are not owned by the mat, they should be destroyed in `VecDestroy()` when no longer needed
9538 
9539 .seealso: [](ch_matrices), `Mat`, `Vec`, `VecCreate()`, `VecDestroy()`, `DMCreateGlobalVector()`
9540 @*/
9541 PetscErrorCode MatCreateVecs(Mat mat, Vec *right, Vec *left)
9542 {
9543   PetscFunctionBegin;
9544   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9545   PetscValidType(mat, 1);
9546   if (mat->ops->getvecs) {
9547     PetscUseTypeMethod(mat, getvecs, right, left);
9548   } else {
9549     if (right) {
9550       PetscCheck(mat->cmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for columns not yet setup");
9551       PetscCall(VecCreateWithLayout_Private(mat->cmap, right));
9552       PetscCall(VecSetType(*right, mat->defaultvectype));
9553 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9554       if (mat->boundtocpu && mat->bindingpropagates) {
9555         PetscCall(VecSetBindingPropagates(*right, PETSC_TRUE));
9556         PetscCall(VecBindToCPU(*right, PETSC_TRUE));
9557       }
9558 #endif
9559     }
9560     if (left) {
9561       PetscCheck(mat->rmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for rows not yet setup");
9562       PetscCall(VecCreateWithLayout_Private(mat->rmap, left));
9563       PetscCall(VecSetType(*left, 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(*left, PETSC_TRUE));
9567         PetscCall(VecBindToCPU(*left, PETSC_TRUE));
9568       }
9569 #endif
9570     }
9571   }
9572   PetscFunctionReturn(PETSC_SUCCESS);
9573 }
9574 
9575 /*@
9576   MatFactorInfoInitialize - Initializes a `MatFactorInfo` data structure
9577   with default values.
9578 
9579   Not Collective
9580 
9581   Input Parameter:
9582 . info - the `MatFactorInfo` data structure
9583 
9584   Level: developer
9585 
9586   Notes:
9587   The solvers are generally used through the `KSP` and `PC` objects, for example
9588   `PCLU`, `PCILU`, `PCCHOLESKY`, `PCICC`
9589 
9590   Once the data structure is initialized one may change certain entries as desired for the particular factorization to be performed
9591 
9592 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorInfo`
9593 @*/
9594 PetscErrorCode MatFactorInfoInitialize(MatFactorInfo *info)
9595 {
9596   PetscFunctionBegin;
9597   PetscCall(PetscMemzero(info, sizeof(MatFactorInfo)));
9598   PetscFunctionReturn(PETSC_SUCCESS);
9599 }
9600 
9601 /*@
9602   MatFactorSetSchurIS - Set indices corresponding to the Schur complement you wish to have computed
9603 
9604   Collective
9605 
9606   Input Parameters:
9607 + mat - the factored matrix
9608 - is  - the index set defining the Schur indices (0-based)
9609 
9610   Level: advanced
9611 
9612   Notes:
9613   Call `MatFactorSolveSchurComplement()` or `MatFactorSolveSchurComplementTranspose()` after this call to solve a Schur complement system.
9614 
9615   You can call `MatFactorGetSchurComplement()` or `MatFactorCreateSchurComplement()` after this call.
9616 
9617   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9618 
9619 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorGetSchurComplement()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSolveSchurComplement()`,
9620           `MatFactorSolveSchurComplementTranspose()`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9621 @*/
9622 PetscErrorCode MatFactorSetSchurIS(Mat mat, IS is)
9623 {
9624   PetscErrorCode (*f)(Mat, IS);
9625 
9626   PetscFunctionBegin;
9627   PetscValidType(mat, 1);
9628   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9629   PetscValidType(is, 2);
9630   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
9631   PetscCheckSameComm(mat, 1, is, 2);
9632   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
9633   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorSetSchurIS_C", &f));
9634   PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "The selected MatSolverType does not support Schur complement computation. You should use MATSOLVERMUMPS or MATSOLVERMKL_PARDISO");
9635   PetscCall(MatDestroy(&mat->schur));
9636   PetscCall((*f)(mat, is));
9637   PetscCheck(mat->schur, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Schur complement has not been created");
9638   PetscFunctionReturn(PETSC_SUCCESS);
9639 }
9640 
9641 /*@
9642   MatFactorCreateSchurComplement - Create a Schur complement matrix object using Schur data computed during the factorization step
9643 
9644   Logically Collective
9645 
9646   Input Parameters:
9647 + F      - the factored matrix obtained by calling `MatGetFactor()`
9648 . S      - location where to return the Schur complement, can be `NULL`
9649 - status - the status of the Schur complement matrix, can be `NULL`
9650 
9651   Level: advanced
9652 
9653   Notes:
9654   You must call `MatFactorSetSchurIS()` before calling this routine.
9655 
9656   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9657 
9658   The routine provides a copy of the Schur matrix stored within the solver data structures.
9659   The caller must destroy the object when it is no longer needed.
9660   If `MatFactorInvertSchurComplement()` has been called, the routine gets back the inverse.
9661 
9662   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)
9663 
9664   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9665 
9666   Developer Note:
9667   The reason this routine exists is because the representation of the Schur complement within the factor matrix may be different than a standard PETSc
9668   matrix representation and we normally do not want to use the time or memory to make a copy as a regular PETSc matrix.
9669 
9670 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorSchurStatus`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9671 @*/
9672 PetscErrorCode MatFactorCreateSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9673 {
9674   PetscFunctionBegin;
9675   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9676   if (S) PetscAssertPointer(S, 2);
9677   if (status) PetscAssertPointer(status, 3);
9678   if (S) {
9679     PetscErrorCode (*f)(Mat, Mat *);
9680 
9681     PetscCall(PetscObjectQueryFunction((PetscObject)F, "MatFactorCreateSchurComplement_C", &f));
9682     if (f) {
9683       PetscCall((*f)(F, S));
9684     } else {
9685       PetscCall(MatDuplicate(F->schur, MAT_COPY_VALUES, S));
9686     }
9687   }
9688   if (status) *status = F->schur_status;
9689   PetscFunctionReturn(PETSC_SUCCESS);
9690 }
9691 
9692 /*@
9693   MatFactorGetSchurComplement - Gets access to a Schur complement matrix using the current Schur data within a factored matrix
9694 
9695   Logically Collective
9696 
9697   Input Parameters:
9698 + F      - the factored matrix obtained by calling `MatGetFactor()`
9699 . S      - location where to return the Schur complement, can be `NULL`
9700 - status - the status of the Schur complement matrix, can be `NULL`
9701 
9702   Level: advanced
9703 
9704   Notes:
9705   You must call `MatFactorSetSchurIS()` before calling this routine.
9706 
9707   Schur complement mode is currently implemented for sequential matrices with factor type of `MATSOLVERMUMPS`
9708 
9709   The routine returns a the Schur Complement stored within the data structures of the solver.
9710 
9711   If `MatFactorInvertSchurComplement()` has previously been called, the returned matrix is actually the inverse of the Schur complement.
9712 
9713   The returned matrix should not be destroyed; the caller should call `MatFactorRestoreSchurComplement()` when the object is no longer needed.
9714 
9715   Use `MatFactorCreateSchurComplement()` to create a copy of the Schur complement matrix that is within a factored matrix
9716 
9717   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9718 
9719 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9720 @*/
9721 PetscErrorCode MatFactorGetSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9722 {
9723   PetscFunctionBegin;
9724   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9725   if (S) {
9726     PetscAssertPointer(S, 2);
9727     *S = F->schur;
9728   }
9729   if (status) {
9730     PetscAssertPointer(status, 3);
9731     *status = F->schur_status;
9732   }
9733   PetscFunctionReturn(PETSC_SUCCESS);
9734 }
9735 
9736 static PetscErrorCode MatFactorUpdateSchurStatus_Private(Mat F)
9737 {
9738   Mat S = F->schur;
9739 
9740   PetscFunctionBegin;
9741   switch (F->schur_status) {
9742   case MAT_FACTOR_SCHUR_UNFACTORED: // fall-through
9743   case MAT_FACTOR_SCHUR_INVERTED:
9744     if (S) {
9745       S->ops->solve             = NULL;
9746       S->ops->matsolve          = NULL;
9747       S->ops->solvetranspose    = NULL;
9748       S->ops->matsolvetranspose = NULL;
9749       S->ops->solveadd          = NULL;
9750       S->ops->solvetransposeadd = NULL;
9751       S->factortype             = MAT_FACTOR_NONE;
9752       PetscCall(PetscFree(S->solvertype));
9753     }
9754   case MAT_FACTOR_SCHUR_FACTORED: // fall-through
9755     break;
9756   default:
9757     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9758   }
9759   PetscFunctionReturn(PETSC_SUCCESS);
9760 }
9761 
9762 /*@
9763   MatFactorRestoreSchurComplement - Restore the Schur complement matrix object obtained from a call to `MatFactorGetSchurComplement()`
9764 
9765   Logically Collective
9766 
9767   Input Parameters:
9768 + F      - the factored matrix obtained by calling `MatGetFactor()`
9769 . S      - location where the Schur complement is stored
9770 - status - the status of the Schur complement matrix (see `MatFactorSchurStatus`)
9771 
9772   Level: advanced
9773 
9774 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9775 @*/
9776 PetscErrorCode MatFactorRestoreSchurComplement(Mat F, Mat *S, MatFactorSchurStatus status)
9777 {
9778   PetscFunctionBegin;
9779   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9780   if (S) {
9781     PetscValidHeaderSpecific(*S, MAT_CLASSID, 2);
9782     *S = NULL;
9783   }
9784   F->schur_status = status;
9785   PetscCall(MatFactorUpdateSchurStatus_Private(F));
9786   PetscFunctionReturn(PETSC_SUCCESS);
9787 }
9788 
9789 /*@
9790   MatFactorSolveSchurComplementTranspose - Solve the transpose of the Schur complement system computed during the factorization step
9791 
9792   Logically Collective
9793 
9794   Input Parameters:
9795 + F   - the factored matrix obtained by calling `MatGetFactor()`
9796 . rhs - location where the right-hand side of the Schur complement system is stored
9797 - sol - location where the solution of the Schur complement system has to be returned
9798 
9799   Level: advanced
9800 
9801   Notes:
9802   The sizes of the vectors should match the size of the Schur complement
9803 
9804   Must be called after `MatFactorSetSchurIS()`
9805 
9806 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplement()`
9807 @*/
9808 PetscErrorCode MatFactorSolveSchurComplementTranspose(Mat F, Vec rhs, Vec sol)
9809 {
9810   PetscFunctionBegin;
9811   PetscValidType(F, 1);
9812   PetscValidType(rhs, 2);
9813   PetscValidType(sol, 3);
9814   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9815   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
9816   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
9817   PetscCheckSameComm(F, 1, rhs, 2);
9818   PetscCheckSameComm(F, 1, sol, 3);
9819   PetscCall(MatFactorFactorizeSchurComplement(F));
9820   switch (F->schur_status) {
9821   case MAT_FACTOR_SCHUR_FACTORED:
9822     PetscCall(MatSolveTranspose(F->schur, rhs, sol));
9823     break;
9824   case MAT_FACTOR_SCHUR_INVERTED:
9825     PetscCall(MatMultTranspose(F->schur, rhs, sol));
9826     break;
9827   default:
9828     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9829   }
9830   PetscFunctionReturn(PETSC_SUCCESS);
9831 }
9832 
9833 /*@
9834   MatFactorSolveSchurComplement - Solve the Schur complement system computed during the factorization step
9835 
9836   Logically Collective
9837 
9838   Input Parameters:
9839 + F   - the factored matrix obtained by calling `MatGetFactor()`
9840 . rhs - location where the right-hand side of the Schur complement system is stored
9841 - sol - location where the solution of the Schur complement system has to be returned
9842 
9843   Level: advanced
9844 
9845   Notes:
9846   The sizes of the vectors should match the size of the Schur complement
9847 
9848   Must be called after `MatFactorSetSchurIS()`
9849 
9850 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplementTranspose()`
9851 @*/
9852 PetscErrorCode MatFactorSolveSchurComplement(Mat F, Vec rhs, Vec sol)
9853 {
9854   PetscFunctionBegin;
9855   PetscValidType(F, 1);
9856   PetscValidType(rhs, 2);
9857   PetscValidType(sol, 3);
9858   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9859   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
9860   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
9861   PetscCheckSameComm(F, 1, rhs, 2);
9862   PetscCheckSameComm(F, 1, sol, 3);
9863   PetscCall(MatFactorFactorizeSchurComplement(F));
9864   switch (F->schur_status) {
9865   case MAT_FACTOR_SCHUR_FACTORED:
9866     PetscCall(MatSolve(F->schur, rhs, sol));
9867     break;
9868   case MAT_FACTOR_SCHUR_INVERTED:
9869     PetscCall(MatMult(F->schur, rhs, sol));
9870     break;
9871   default:
9872     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9873   }
9874   PetscFunctionReturn(PETSC_SUCCESS);
9875 }
9876 
9877 PETSC_EXTERN PetscErrorCode MatSeqDenseInvertFactors_Private(Mat);
9878 #if PetscDefined(HAVE_CUDA)
9879 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode MatSeqDenseCUDAInvertFactors_Internal(Mat);
9880 #endif
9881 
9882 /* Schur status updated in the interface */
9883 static PetscErrorCode MatFactorInvertSchurComplement_Private(Mat F)
9884 {
9885   Mat S = F->schur;
9886 
9887   PetscFunctionBegin;
9888   if (S) {
9889     PetscMPIInt size;
9890     PetscBool   isdense, isdensecuda;
9891 
9892     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)S), &size));
9893     PetscCheck(size <= 1, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not yet implemented");
9894     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSE, &isdense));
9895     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSECUDA, &isdensecuda));
9896     PetscCheck(isdense || isdensecuda, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not implemented for type %s", ((PetscObject)S)->type_name);
9897     PetscCall(PetscLogEventBegin(MAT_FactorInvS, F, 0, 0, 0));
9898     if (isdense) {
9899       PetscCall(MatSeqDenseInvertFactors_Private(S));
9900     } else if (isdensecuda) {
9901 #if defined(PETSC_HAVE_CUDA)
9902       PetscCall(MatSeqDenseCUDAInvertFactors_Internal(S));
9903 #endif
9904     }
9905     // HIP??????????????
9906     PetscCall(PetscLogEventEnd(MAT_FactorInvS, F, 0, 0, 0));
9907   }
9908   PetscFunctionReturn(PETSC_SUCCESS);
9909 }
9910 
9911 /*@
9912   MatFactorInvertSchurComplement - Invert the Schur complement matrix computed during the factorization step
9913 
9914   Logically Collective
9915 
9916   Input Parameter:
9917 . F - the factored matrix obtained by calling `MatGetFactor()`
9918 
9919   Level: advanced
9920 
9921   Notes:
9922   Must be called after `MatFactorSetSchurIS()`.
9923 
9924   Call `MatFactorGetSchurComplement()` or  `MatFactorCreateSchurComplement()` AFTER this call to actually compute the inverse and get access to it.
9925 
9926 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorCreateSchurComplement()`
9927 @*/
9928 PetscErrorCode MatFactorInvertSchurComplement(Mat F)
9929 {
9930   PetscFunctionBegin;
9931   PetscValidType(F, 1);
9932   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9933   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED) PetscFunctionReturn(PETSC_SUCCESS);
9934   PetscCall(MatFactorFactorizeSchurComplement(F));
9935   PetscCall(MatFactorInvertSchurComplement_Private(F));
9936   F->schur_status = MAT_FACTOR_SCHUR_INVERTED;
9937   PetscFunctionReturn(PETSC_SUCCESS);
9938 }
9939 
9940 /*@
9941   MatFactorFactorizeSchurComplement - Factorize the Schur complement matrix computed during the factorization step
9942 
9943   Logically Collective
9944 
9945   Input Parameter:
9946 . F - the factored matrix obtained by calling `MatGetFactor()`
9947 
9948   Level: advanced
9949 
9950   Note:
9951   Must be called after `MatFactorSetSchurIS()`
9952 
9953 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorInvertSchurComplement()`
9954 @*/
9955 PetscErrorCode MatFactorFactorizeSchurComplement(Mat F)
9956 {
9957   MatFactorInfo info;
9958 
9959   PetscFunctionBegin;
9960   PetscValidType(F, 1);
9961   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9962   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED || F->schur_status == MAT_FACTOR_SCHUR_FACTORED) PetscFunctionReturn(PETSC_SUCCESS);
9963   PetscCall(PetscLogEventBegin(MAT_FactorFactS, F, 0, 0, 0));
9964   PetscCall(PetscMemzero(&info, sizeof(MatFactorInfo)));
9965   if (F->factortype == MAT_FACTOR_CHOLESKY) { /* LDL^t regarded as Cholesky */
9966     PetscCall(MatCholeskyFactor(F->schur, NULL, &info));
9967   } else {
9968     PetscCall(MatLUFactor(F->schur, NULL, NULL, &info));
9969   }
9970   PetscCall(PetscLogEventEnd(MAT_FactorFactS, F, 0, 0, 0));
9971   F->schur_status = MAT_FACTOR_SCHUR_FACTORED;
9972   PetscFunctionReturn(PETSC_SUCCESS);
9973 }
9974 
9975 /*@
9976   MatPtAP - Creates the matrix product $C = P^T * A * P$
9977 
9978   Neighbor-wise Collective
9979 
9980   Input Parameters:
9981 + A     - the matrix
9982 . P     - the projection matrix
9983 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
9984 - 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
9985           if the result is a dense matrix this is irrelevant
9986 
9987   Output Parameter:
9988 . C - the product matrix
9989 
9990   Level: intermediate
9991 
9992   Notes:
9993   C will be created and must be destroyed by the user with `MatDestroy()`.
9994 
9995   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
9996 
9997   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
9998 
9999   Developer Note:
10000   For matrix types without special implementation the function fallbacks to `MatMatMult()` followed by `MatTransposeMatMult()`.
10001 
10002 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatRARt()`
10003 @*/
10004 PetscErrorCode MatPtAP(Mat A, Mat P, MatReuse scall, PetscReal fill, Mat *C)
10005 {
10006   PetscFunctionBegin;
10007   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10008   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10009 
10010   if (scall == MAT_INITIAL_MATRIX) {
10011     PetscCall(MatProductCreate(A, P, NULL, C));
10012     PetscCall(MatProductSetType(*C, MATPRODUCT_PtAP));
10013     PetscCall(MatProductSetAlgorithm(*C, "default"));
10014     PetscCall(MatProductSetFill(*C, fill));
10015 
10016     (*C)->product->api_user = PETSC_TRUE;
10017     PetscCall(MatProductSetFromOptions(*C));
10018     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);
10019     PetscCall(MatProductSymbolic(*C));
10020   } else { /* scall == MAT_REUSE_MATRIX */
10021     PetscCall(MatProductReplaceMats(A, P, NULL, *C));
10022   }
10023 
10024   PetscCall(MatProductNumeric(*C));
10025   (*C)->symmetric = A->symmetric;
10026   (*C)->spd       = A->spd;
10027   PetscFunctionReturn(PETSC_SUCCESS);
10028 }
10029 
10030 /*@
10031   MatRARt - Creates the matrix product $C = R * A * R^T$
10032 
10033   Neighbor-wise Collective
10034 
10035   Input Parameters:
10036 + A     - the matrix
10037 . R     - the projection matrix
10038 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10039 - fill  - expected fill as ratio of nnz(C)/nnz(A), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10040           if the result is a dense matrix this is irrelevant
10041 
10042   Output Parameter:
10043 . C - the product matrix
10044 
10045   Level: intermediate
10046 
10047   Notes:
10048   `C` will be created and must be destroyed by the user with `MatDestroy()`.
10049 
10050   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
10051 
10052   This routine is currently only implemented for pairs of `MATAIJ` matrices and classes
10053   which inherit from `MATAIJ`. Due to PETSc sparse matrix block row distribution among processes,
10054   the parallel `MatRARt()` is implemented computing the explicit transpose of `R`, which can be very expensive.
10055   We recommend using `MatPtAP()` when possible.
10056 
10057   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10058 
10059 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatPtAP()`
10060 @*/
10061 PetscErrorCode MatRARt(Mat A, Mat R, MatReuse scall, PetscReal fill, Mat *C)
10062 {
10063   PetscFunctionBegin;
10064   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10065   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10066 
10067   if (scall == MAT_INITIAL_MATRIX) {
10068     PetscCall(MatProductCreate(A, R, NULL, C));
10069     PetscCall(MatProductSetType(*C, MATPRODUCT_RARt));
10070     PetscCall(MatProductSetAlgorithm(*C, "default"));
10071     PetscCall(MatProductSetFill(*C, fill));
10072 
10073     (*C)->product->api_user = PETSC_TRUE;
10074     PetscCall(MatProductSetFromOptions(*C));
10075     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);
10076     PetscCall(MatProductSymbolic(*C));
10077   } else { /* scall == MAT_REUSE_MATRIX */
10078     PetscCall(MatProductReplaceMats(A, R, NULL, *C));
10079   }
10080 
10081   PetscCall(MatProductNumeric(*C));
10082   if (A->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10083   PetscFunctionReturn(PETSC_SUCCESS);
10084 }
10085 
10086 static PetscErrorCode MatProduct_Private(Mat A, Mat B, MatReuse scall, PetscReal fill, MatProductType ptype, Mat *C)
10087 {
10088   PetscBool flg = PETSC_TRUE;
10089 
10090   PetscFunctionBegin;
10091   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX product not supported");
10092   if (scall == MAT_INITIAL_MATRIX) {
10093     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_INITIAL_MATRIX and product type %s\n", MatProductTypes[ptype]));
10094     PetscCall(MatProductCreate(A, B, NULL, C));
10095     PetscCall(MatProductSetAlgorithm(*C, MATPRODUCTALGORITHMDEFAULT));
10096     PetscCall(MatProductSetFill(*C, fill));
10097   } else { /* scall == MAT_REUSE_MATRIX */
10098     Mat_Product *product = (*C)->product;
10099 
10100     PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)*C, &flg, MATSEQDENSE, MATMPIDENSE, ""));
10101     if (flg && product && product->type != ptype) {
10102       PetscCall(MatProductClear(*C));
10103       product = NULL;
10104     }
10105     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_REUSE_MATRIX %s product present and product type %s\n", product ? "with" : "without", MatProductTypes[ptype]));
10106     if (!product) { /* user provide the dense matrix *C without calling MatProductCreate() or reusing it from previous calls */
10107       PetscCheck(flg, PetscObjectComm((PetscObject)*C), PETSC_ERR_SUP, "Call MatProductCreate() first");
10108       PetscCall(MatProductCreate_Private(A, B, NULL, *C));
10109       product        = (*C)->product;
10110       product->fill  = fill;
10111       product->clear = PETSC_TRUE;
10112     } else { /* user may change input matrices A or B when MAT_REUSE_MATRIX */
10113       flg = PETSC_FALSE;
10114       PetscCall(MatProductReplaceMats(A, B, NULL, *C));
10115     }
10116   }
10117   if (flg) {
10118     (*C)->product->api_user = PETSC_TRUE;
10119     PetscCall(MatProductSetType(*C, ptype));
10120     PetscCall(MatProductSetFromOptions(*C));
10121     PetscCall(MatProductSymbolic(*C));
10122   }
10123   PetscCall(MatProductNumeric(*C));
10124   PetscFunctionReturn(PETSC_SUCCESS);
10125 }
10126 
10127 /*@
10128   MatMatMult - Performs matrix-matrix multiplication C=A*B.
10129 
10130   Neighbor-wise Collective
10131 
10132   Input Parameters:
10133 + A     - the left matrix
10134 . B     - the right matrix
10135 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10136 - 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
10137           if the result is a dense matrix this is irrelevant
10138 
10139   Output Parameter:
10140 . C - the product matrix
10141 
10142   Notes:
10143   Unless scall is `MAT_REUSE_MATRIX` C will be created.
10144 
10145   `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
10146   call to this function with `MAT_INITIAL_MATRIX`.
10147 
10148   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value actually needed.
10149 
10150   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`,
10151   rather than first having `MatMatMult()` create it for you. You can NEVER do this if the matrix `C` is sparse.
10152 
10153   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10154 
10155   Example of Usage:
10156 .vb
10157      MatProductCreate(A,B,NULL,&C);
10158      MatProductSetType(C,MATPRODUCT_AB);
10159      MatProductSymbolic(C);
10160      MatProductNumeric(C); // compute C=A * B
10161      MatProductReplaceMats(A1,B1,NULL,C); // compute C=A1 * B1
10162      MatProductNumeric(C);
10163      MatProductReplaceMats(A2,NULL,NULL,C); // compute C=A2 * B1
10164      MatProductNumeric(C);
10165 .ve
10166 
10167   Level: intermediate
10168 
10169 .seealso: [](ch_matrices), `Mat`, `MatProductType`, `MATPRODUCT_AB`, `MatTransposeMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`, `MatProductCreate()`, `MatProductSymbolic()`, `MatProductReplaceMats()`, `MatProductNumeric()`
10170 @*/
10171 PetscErrorCode MatMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10172 {
10173   PetscFunctionBegin;
10174   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AB, C));
10175   PetscFunctionReturn(PETSC_SUCCESS);
10176 }
10177 
10178 /*@
10179   MatMatTransposeMult - Performs matrix-matrix multiplication $C = A*B^T$.
10180 
10181   Neighbor-wise Collective
10182 
10183   Input Parameters:
10184 + A     - the left matrix
10185 . B     - the right matrix
10186 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10187 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10188 
10189   Output Parameter:
10190 . C - the product matrix
10191 
10192   Options Database Key:
10193 . -matmattransmult_mpidense_mpidense_via {allgatherv,cyclic} - Choose between algorithms for `MATMPIDENSE` matrices: the
10194               first redundantly copies the transposed `B` matrix on each process and requires O(log P) communication complexity;
10195               the second never stores more than one portion of the `B` matrix at a time but requires O(P) communication complexity.
10196 
10197   Level: intermediate
10198 
10199   Notes:
10200   C will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10201 
10202   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call
10203 
10204   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10205   actually needed.
10206 
10207   This routine is currently only implemented for pairs of `MATSEQAIJ` matrices, for the `MATSEQDENSE` class,
10208   and for pairs of `MATMPIDENSE` matrices.
10209 
10210   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABt`
10211 
10212   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10213 
10214 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABt`, `MatMatMult()`, `MatTransposeMatMult()` `MatPtAP()`, `MatProductAlgorithm`, `MatProductType`
10215 @*/
10216 PetscErrorCode MatMatTransposeMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10217 {
10218   PetscFunctionBegin;
10219   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_ABt, C));
10220   if (A == B) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10221   PetscFunctionReturn(PETSC_SUCCESS);
10222 }
10223 
10224 /*@
10225   MatTransposeMatMult - Performs matrix-matrix multiplication $C = A^T*B$.
10226 
10227   Neighbor-wise Collective
10228 
10229   Input Parameters:
10230 + A     - the left matrix
10231 . B     - the right matrix
10232 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10233 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10234 
10235   Output Parameter:
10236 . C - the product matrix
10237 
10238   Level: intermediate
10239 
10240   Notes:
10241   `C` will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10242 
10243   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call.
10244 
10245   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_AtB`
10246 
10247   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10248   actually needed.
10249 
10250   This routine is currently implemented for pairs of `MATAIJ` matrices and pairs of `MATSEQDENSE` matrices and classes
10251   which inherit from `MATSEQAIJ`.  `C` will be of the same type as the input matrices.
10252 
10253   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10254 
10255 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_AtB`, `MatMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`
10256 @*/
10257 PetscErrorCode MatTransposeMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10258 {
10259   PetscFunctionBegin;
10260   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AtB, C));
10261   PetscFunctionReturn(PETSC_SUCCESS);
10262 }
10263 
10264 /*@
10265   MatMatMatMult - Performs matrix-matrix-matrix multiplication D=A*B*C.
10266 
10267   Neighbor-wise Collective
10268 
10269   Input Parameters:
10270 + A     - the left matrix
10271 . B     - the middle matrix
10272 . C     - the right matrix
10273 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10274 - 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
10275           if the result is a dense matrix this is irrelevant
10276 
10277   Output Parameter:
10278 . D - the product matrix
10279 
10280   Level: intermediate
10281 
10282   Notes:
10283   Unless `scall` is `MAT_REUSE_MATRIX` `D` will be created.
10284 
10285   `MAT_REUSE_MATRIX` can only be used if the matrices `A`, `B`, and `C` have the same nonzero pattern as in the previous call
10286 
10287   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABC`
10288 
10289   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value
10290   actually needed.
10291 
10292   If you have many matrices with the same non-zero structure to multiply, you
10293   should use `MAT_REUSE_MATRIX` in all calls but the first
10294 
10295   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10296 
10297 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABC`, `MatMatMult`, `MatPtAP()`, `MatMatTransposeMult()`, `MatTransposeMatMult()`
10298 @*/
10299 PetscErrorCode MatMatMatMult(Mat A, Mat B, Mat C, MatReuse scall, PetscReal fill, Mat *D)
10300 {
10301   PetscFunctionBegin;
10302   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*D, 6);
10303   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10304 
10305   if (scall == MAT_INITIAL_MATRIX) {
10306     PetscCall(MatProductCreate(A, B, C, D));
10307     PetscCall(MatProductSetType(*D, MATPRODUCT_ABC));
10308     PetscCall(MatProductSetAlgorithm(*D, "default"));
10309     PetscCall(MatProductSetFill(*D, fill));
10310 
10311     (*D)->product->api_user = PETSC_TRUE;
10312     PetscCall(MatProductSetFromOptions(*D));
10313     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,
10314                ((PetscObject)C)->type_name);
10315     PetscCall(MatProductSymbolic(*D));
10316   } else { /* user may change input matrices when REUSE */
10317     PetscCall(MatProductReplaceMats(A, B, C, *D));
10318   }
10319   PetscCall(MatProductNumeric(*D));
10320   PetscFunctionReturn(PETSC_SUCCESS);
10321 }
10322 
10323 /*@
10324   MatCreateRedundantMatrix - Create redundant matrices and put them into processors of subcommunicators.
10325 
10326   Collective
10327 
10328   Input Parameters:
10329 + mat      - the matrix
10330 . nsubcomm - the number of subcommunicators (= number of redundant parallel or sequential matrices)
10331 . subcomm  - MPI communicator split from the communicator where mat resides in (or `MPI_COMM_NULL` if nsubcomm is used)
10332 - reuse    - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10333 
10334   Output Parameter:
10335 . matredundant - redundant matrix
10336 
10337   Level: advanced
10338 
10339   Notes:
10340   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
10341   original matrix has not changed from that last call to `MatCreateRedundantMatrix()`.
10342 
10343   This routine creates the duplicated matrices in the subcommunicators; you should NOT create them before
10344   calling it.
10345 
10346   `PetscSubcommCreate()` can be used to manage the creation of the subcomm but need not be.
10347 
10348 .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `PetscSubcommCreate()`, `PetscSubcomm`
10349 @*/
10350 PetscErrorCode MatCreateRedundantMatrix(Mat mat, PetscInt nsubcomm, MPI_Comm subcomm, MatReuse reuse, Mat *matredundant)
10351 {
10352   MPI_Comm       comm;
10353   PetscMPIInt    size;
10354   PetscInt       mloc_sub, nloc_sub, rstart, rend, M = mat->rmap->N, N = mat->cmap->N, bs = mat->rmap->bs;
10355   Mat_Redundant *redund     = NULL;
10356   PetscSubcomm   psubcomm   = NULL;
10357   MPI_Comm       subcomm_in = subcomm;
10358   Mat           *matseq;
10359   IS             isrow, iscol;
10360   PetscBool      newsubcomm = PETSC_FALSE;
10361 
10362   PetscFunctionBegin;
10363   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10364   if (nsubcomm && reuse == MAT_REUSE_MATRIX) {
10365     PetscAssertPointer(*matredundant, 5);
10366     PetscValidHeaderSpecific(*matredundant, MAT_CLASSID, 5);
10367   }
10368 
10369   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
10370   if (size == 1 || nsubcomm == 1) {
10371     if (reuse == MAT_INITIAL_MATRIX) {
10372       PetscCall(MatDuplicate(mat, MAT_COPY_VALUES, matredundant));
10373     } else {
10374       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");
10375       PetscCall(MatCopy(mat, *matredundant, SAME_NONZERO_PATTERN));
10376     }
10377     PetscFunctionReturn(PETSC_SUCCESS);
10378   }
10379 
10380   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10381   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10382   MatCheckPreallocated(mat, 1);
10383 
10384   PetscCall(PetscLogEventBegin(MAT_RedundantMat, mat, 0, 0, 0));
10385   if (subcomm_in == MPI_COMM_NULL && reuse == MAT_INITIAL_MATRIX) { /* get subcomm if user does not provide subcomm */
10386     /* create psubcomm, then get subcomm */
10387     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10388     PetscCallMPI(MPI_Comm_size(comm, &size));
10389     PetscCheck(nsubcomm >= 1 && nsubcomm <= size, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "nsubcomm must between 1 and %d", size);
10390 
10391     PetscCall(PetscSubcommCreate(comm, &psubcomm));
10392     PetscCall(PetscSubcommSetNumber(psubcomm, nsubcomm));
10393     PetscCall(PetscSubcommSetType(psubcomm, PETSC_SUBCOMM_CONTIGUOUS));
10394     PetscCall(PetscSubcommSetFromOptions(psubcomm));
10395     PetscCall(PetscCommDuplicate(PetscSubcommChild(psubcomm), &subcomm, NULL));
10396     newsubcomm = PETSC_TRUE;
10397     PetscCall(PetscSubcommDestroy(&psubcomm));
10398   }
10399 
10400   /* get isrow, iscol and a local sequential matrix matseq[0] */
10401   if (reuse == MAT_INITIAL_MATRIX) {
10402     mloc_sub = PETSC_DECIDE;
10403     nloc_sub = PETSC_DECIDE;
10404     if (bs < 1) {
10405       PetscCall(PetscSplitOwnership(subcomm, &mloc_sub, &M));
10406       PetscCall(PetscSplitOwnership(subcomm, &nloc_sub, &N));
10407     } else {
10408       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &mloc_sub, &M));
10409       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &nloc_sub, &N));
10410     }
10411     PetscCallMPI(MPI_Scan(&mloc_sub, &rend, 1, MPIU_INT, MPI_SUM, subcomm));
10412     rstart = rend - mloc_sub;
10413     PetscCall(ISCreateStride(PETSC_COMM_SELF, mloc_sub, rstart, 1, &isrow));
10414     PetscCall(ISCreateStride(PETSC_COMM_SELF, N, 0, 1, &iscol));
10415     PetscCall(ISSetIdentity(iscol));
10416   } else { /* reuse == MAT_REUSE_MATRIX */
10417     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");
10418     /* retrieve subcomm */
10419     PetscCall(PetscObjectGetComm((PetscObject)*matredundant, &subcomm));
10420     redund = (*matredundant)->redundant;
10421     isrow  = redund->isrow;
10422     iscol  = redund->iscol;
10423     matseq = redund->matseq;
10424   }
10425   PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscol, reuse, &matseq));
10426 
10427   /* get matredundant over subcomm */
10428   if (reuse == MAT_INITIAL_MATRIX) {
10429     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], nloc_sub, reuse, matredundant));
10430 
10431     /* create a supporting struct and attach it to C for reuse */
10432     PetscCall(PetscNew(&redund));
10433     (*matredundant)->redundant = redund;
10434     redund->isrow              = isrow;
10435     redund->iscol              = iscol;
10436     redund->matseq             = matseq;
10437     if (newsubcomm) {
10438       redund->subcomm = subcomm;
10439     } else {
10440       redund->subcomm = MPI_COMM_NULL;
10441     }
10442   } else {
10443     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], PETSC_DECIDE, reuse, matredundant));
10444   }
10445 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
10446   if (matseq[0]->boundtocpu && matseq[0]->bindingpropagates) {
10447     PetscCall(MatBindToCPU(*matredundant, PETSC_TRUE));
10448     PetscCall(MatSetBindingPropagates(*matredundant, PETSC_TRUE));
10449   }
10450 #endif
10451   PetscCall(PetscLogEventEnd(MAT_RedundantMat, mat, 0, 0, 0));
10452   PetscFunctionReturn(PETSC_SUCCESS);
10453 }
10454 
10455 /*@C
10456   MatGetMultiProcBlock - Create multiple 'parallel submatrices' from
10457   a given `Mat`. Each submatrix can span multiple procs.
10458 
10459   Collective
10460 
10461   Input Parameters:
10462 + mat     - the matrix
10463 . subComm - the sub communicator obtained as if by `MPI_Comm_split(PetscObjectComm((PetscObject)mat))`
10464 - scall   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10465 
10466   Output Parameter:
10467 . subMat - parallel sub-matrices each spanning a given `subcomm`
10468 
10469   Level: advanced
10470 
10471   Notes:
10472   The submatrix partition across processors is dictated by `subComm` a
10473   communicator obtained by `MPI_comm_split()` or via `PetscSubcommCreate()`. The `subComm`
10474   is not restricted to be grouped with consecutive original MPI processes.
10475 
10476   Due the `MPI_Comm_split()` usage, the parallel layout of the submatrices
10477   map directly to the layout of the original matrix [wrt the local
10478   row,col partitioning]. So the original 'DiagonalMat' naturally maps
10479   into the 'DiagonalMat' of the `subMat`, hence it is used directly from
10480   the `subMat`. However the offDiagMat looses some columns - and this is
10481   reconstructed with `MatSetValues()`
10482 
10483   This is used by `PCBJACOBI` when a single block spans multiple MPI processes.
10484 
10485 .seealso: [](ch_matrices), `Mat`, `MatCreateRedundantMatrix()`, `MatCreateSubMatrices()`, `PCBJACOBI`
10486 @*/
10487 PetscErrorCode MatGetMultiProcBlock(Mat mat, MPI_Comm subComm, MatReuse scall, Mat *subMat)
10488 {
10489   PetscMPIInt commsize, subCommSize;
10490 
10491   PetscFunctionBegin;
10492   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &commsize));
10493   PetscCallMPI(MPI_Comm_size(subComm, &subCommSize));
10494   PetscCheck(subCommSize <= commsize, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "CommSize %d < SubCommZize %d", commsize, subCommSize);
10495 
10496   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");
10497   PetscCall(PetscLogEventBegin(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10498   PetscUseTypeMethod(mat, getmultiprocblock, subComm, scall, subMat);
10499   PetscCall(PetscLogEventEnd(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10500   PetscFunctionReturn(PETSC_SUCCESS);
10501 }
10502 
10503 /*@
10504   MatGetLocalSubMatrix - Gets a reference to a submatrix specified in local numbering
10505 
10506   Not Collective
10507 
10508   Input Parameters:
10509 + mat   - matrix to extract local submatrix from
10510 . isrow - local row indices for submatrix
10511 - iscol - local column indices for submatrix
10512 
10513   Output Parameter:
10514 . submat - the submatrix
10515 
10516   Level: intermediate
10517 
10518   Notes:
10519   `submat` should be disposed of with `MatRestoreLocalSubMatrix()`.
10520 
10521   Depending on the format of `mat`, the returned `submat` may not implement `MatMult()`.  Its communicator may be
10522   the same as `mat`, it may be `PETSC_COMM_SELF`, or some other sub-communictor of `mat`'s.
10523 
10524   `submat` always implements `MatSetValuesLocal()`.  If `isrow` and `iscol` have the same block size, then
10525   `MatSetValuesBlockedLocal()` will also be implemented.
10526 
10527   `mat` must have had a `ISLocalToGlobalMapping` provided to it with `MatSetLocalToGlobalMapping()`.
10528   Matrices obtained with `DMCreateMatrix()` generally already have the local to global mapping provided.
10529 
10530 .seealso: [](ch_matrices), `Mat`, `MatRestoreLocalSubMatrix()`, `MatCreateLocalRef()`, `MatSetLocalToGlobalMapping()`
10531 @*/
10532 PetscErrorCode MatGetLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10533 {
10534   PetscFunctionBegin;
10535   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10536   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10537   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10538   PetscCheckSameComm(isrow, 2, iscol, 3);
10539   PetscAssertPointer(submat, 4);
10540   PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must have local to global mapping provided before this call");
10541 
10542   if (mat->ops->getlocalsubmatrix) {
10543     PetscUseTypeMethod(mat, getlocalsubmatrix, isrow, iscol, submat);
10544   } else {
10545     PetscCall(MatCreateLocalRef(mat, isrow, iscol, submat));
10546   }
10547   PetscFunctionReturn(PETSC_SUCCESS);
10548 }
10549 
10550 /*@
10551   MatRestoreLocalSubMatrix - Restores a reference to a submatrix specified in local numbering obtained with `MatGetLocalSubMatrix()`
10552 
10553   Not Collective
10554 
10555   Input Parameters:
10556 + mat    - matrix to extract local submatrix from
10557 . isrow  - local row indices for submatrix
10558 . iscol  - local column indices for submatrix
10559 - submat - the submatrix
10560 
10561   Level: intermediate
10562 
10563 .seealso: [](ch_matrices), `Mat`, `MatGetLocalSubMatrix()`
10564 @*/
10565 PetscErrorCode MatRestoreLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10566 {
10567   PetscFunctionBegin;
10568   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10569   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10570   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10571   PetscCheckSameComm(isrow, 2, iscol, 3);
10572   PetscAssertPointer(submat, 4);
10573   if (*submat) PetscValidHeaderSpecific(*submat, MAT_CLASSID, 4);
10574 
10575   if (mat->ops->restorelocalsubmatrix) {
10576     PetscUseTypeMethod(mat, restorelocalsubmatrix, isrow, iscol, submat);
10577   } else {
10578     PetscCall(MatDestroy(submat));
10579   }
10580   *submat = NULL;
10581   PetscFunctionReturn(PETSC_SUCCESS);
10582 }
10583 
10584 /*@
10585   MatFindZeroDiagonals - Finds all the rows of a matrix that have zero or no diagonal entry in the matrix
10586 
10587   Collective
10588 
10589   Input Parameter:
10590 . mat - the matrix
10591 
10592   Output Parameter:
10593 . is - if any rows have zero diagonals this contains the list of them
10594 
10595   Level: developer
10596 
10597 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10598 @*/
10599 PetscErrorCode MatFindZeroDiagonals(Mat mat, IS *is)
10600 {
10601   PetscFunctionBegin;
10602   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10603   PetscValidType(mat, 1);
10604   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10605   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10606 
10607   if (!mat->ops->findzerodiagonals) {
10608     Vec                diag;
10609     const PetscScalar *a;
10610     PetscInt          *rows;
10611     PetscInt           rStart, rEnd, r, nrow = 0;
10612 
10613     PetscCall(MatCreateVecs(mat, &diag, NULL));
10614     PetscCall(MatGetDiagonal(mat, diag));
10615     PetscCall(MatGetOwnershipRange(mat, &rStart, &rEnd));
10616     PetscCall(VecGetArrayRead(diag, &a));
10617     for (r = 0; r < rEnd - rStart; ++r)
10618       if (a[r] == 0.0) ++nrow;
10619     PetscCall(PetscMalloc1(nrow, &rows));
10620     nrow = 0;
10621     for (r = 0; r < rEnd - rStart; ++r)
10622       if (a[r] == 0.0) rows[nrow++] = r + rStart;
10623     PetscCall(VecRestoreArrayRead(diag, &a));
10624     PetscCall(VecDestroy(&diag));
10625     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nrow, rows, PETSC_OWN_POINTER, is));
10626   } else {
10627     PetscUseTypeMethod(mat, findzerodiagonals, is);
10628   }
10629   PetscFunctionReturn(PETSC_SUCCESS);
10630 }
10631 
10632 /*@
10633   MatFindOffBlockDiagonalEntries - Finds all the rows of a matrix that have entries outside of the main diagonal block (defined by the matrix block size)
10634 
10635   Collective
10636 
10637   Input Parameter:
10638 . mat - the matrix
10639 
10640   Output Parameter:
10641 . is - contains the list of rows with off block diagonal entries
10642 
10643   Level: developer
10644 
10645 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10646 @*/
10647 PetscErrorCode MatFindOffBlockDiagonalEntries(Mat mat, IS *is)
10648 {
10649   PetscFunctionBegin;
10650   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10651   PetscValidType(mat, 1);
10652   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10653   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10654 
10655   PetscUseTypeMethod(mat, findoffblockdiagonalentries, is);
10656   PetscFunctionReturn(PETSC_SUCCESS);
10657 }
10658 
10659 /*@C
10660   MatInvertBlockDiagonal - Inverts the block diagonal entries.
10661 
10662   Collective; No Fortran Support
10663 
10664   Input Parameter:
10665 . mat - the matrix
10666 
10667   Output Parameter:
10668 . values - the block inverses in column major order (FORTRAN-like)
10669 
10670   Level: advanced
10671 
10672   Notes:
10673   The size of the blocks is determined by the block size of the matrix.
10674 
10675   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10676 
10677   The blocks all have the same size, use `MatInvertVariableBlockDiagonal()` for variable block size
10678 
10679 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatInvertBlockDiagonalMat()`
10680 @*/
10681 PetscErrorCode MatInvertBlockDiagonal(Mat mat, const PetscScalar *values[])
10682 {
10683   PetscFunctionBegin;
10684   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10685   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10686   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10687   PetscUseTypeMethod(mat, invertblockdiagonal, values);
10688   PetscFunctionReturn(PETSC_SUCCESS);
10689 }
10690 
10691 /*@
10692   MatInvertVariableBlockDiagonal - Inverts the point block diagonal entries.
10693 
10694   Collective; No Fortran Support
10695 
10696   Input Parameters:
10697 + mat     - the matrix
10698 . nblocks - the number of blocks on the process, set with `MatSetVariableBlockSizes()`
10699 - bsizes  - the size of each block on the process, set with `MatSetVariableBlockSizes()`
10700 
10701   Output Parameter:
10702 . values - the block inverses in column major order (FORTRAN-like)
10703 
10704   Level: advanced
10705 
10706   Notes:
10707   Use `MatInvertBlockDiagonal()` if all blocks have the same size
10708 
10709   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10710 
10711 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatSetVariableBlockSizes()`, `MatInvertVariableBlockEnvelope()`
10712 @*/
10713 PetscErrorCode MatInvertVariableBlockDiagonal(Mat mat, PetscInt nblocks, const PetscInt bsizes[], PetscScalar values[])
10714 {
10715   PetscFunctionBegin;
10716   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10717   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10718   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10719   PetscUseTypeMethod(mat, invertvariableblockdiagonal, nblocks, bsizes, values);
10720   PetscFunctionReturn(PETSC_SUCCESS);
10721 }
10722 
10723 /*@
10724   MatInvertBlockDiagonalMat - set the values of matrix C to be the inverted block diagonal of matrix A
10725 
10726   Collective
10727 
10728   Input Parameters:
10729 + A - the matrix
10730 - C - matrix with inverted block diagonal of `A`.  This matrix should be created and may have its type set.
10731 
10732   Level: advanced
10733 
10734   Note:
10735   The blocksize of the matrix is used to determine the blocks on the diagonal of `C`
10736 
10737 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`
10738 @*/
10739 PetscErrorCode MatInvertBlockDiagonalMat(Mat A, Mat C)
10740 {
10741   const PetscScalar *vals;
10742   PetscInt          *dnnz;
10743   PetscInt           m, rstart, rend, bs, i, j;
10744 
10745   PetscFunctionBegin;
10746   PetscCall(MatInvertBlockDiagonal(A, &vals));
10747   PetscCall(MatGetBlockSize(A, &bs));
10748   PetscCall(MatGetLocalSize(A, &m, NULL));
10749   PetscCall(MatSetLayouts(C, A->rmap, A->cmap));
10750   PetscCall(MatSetBlockSizes(C, A->rmap->bs, A->cmap->bs));
10751   PetscCall(PetscMalloc1(m / bs, &dnnz));
10752   for (j = 0; j < m / bs; j++) dnnz[j] = 1;
10753   PetscCall(MatXAIJSetPreallocation(C, bs, dnnz, NULL, NULL, NULL));
10754   PetscCall(PetscFree(dnnz));
10755   PetscCall(MatGetOwnershipRange(C, &rstart, &rend));
10756   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_FALSE));
10757   for (i = rstart / bs; i < rend / bs; i++) PetscCall(MatSetValuesBlocked(C, 1, &i, 1, &i, &vals[(i - rstart / bs) * bs * bs], INSERT_VALUES));
10758   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
10759   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
10760   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_TRUE));
10761   PetscFunctionReturn(PETSC_SUCCESS);
10762 }
10763 
10764 /*@
10765   MatTransposeColoringDestroy - Destroys a coloring context for matrix product $C = A*B^T$ that was created
10766   via `MatTransposeColoringCreate()`.
10767 
10768   Collective
10769 
10770   Input Parameter:
10771 . c - coloring context
10772 
10773   Level: intermediate
10774 
10775 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`
10776 @*/
10777 PetscErrorCode MatTransposeColoringDestroy(MatTransposeColoring *c)
10778 {
10779   MatTransposeColoring matcolor = *c;
10780 
10781   PetscFunctionBegin;
10782   if (!matcolor) PetscFunctionReturn(PETSC_SUCCESS);
10783   if (--((PetscObject)matcolor)->refct > 0) {
10784     matcolor = NULL;
10785     PetscFunctionReturn(PETSC_SUCCESS);
10786   }
10787 
10788   PetscCall(PetscFree3(matcolor->ncolumns, matcolor->nrows, matcolor->colorforrow));
10789   PetscCall(PetscFree(matcolor->rows));
10790   PetscCall(PetscFree(matcolor->den2sp));
10791   PetscCall(PetscFree(matcolor->colorforcol));
10792   PetscCall(PetscFree(matcolor->columns));
10793   if (matcolor->brows > 0) PetscCall(PetscFree(matcolor->lstart));
10794   PetscCall(PetscHeaderDestroy(c));
10795   PetscFunctionReturn(PETSC_SUCCESS);
10796 }
10797 
10798 /*@
10799   MatTransColoringApplySpToDen - Given a symbolic matrix product $C = A*B^T$ for which
10800   a `MatTransposeColoring` context has been created, computes a dense $B^T$ by applying
10801   `MatTransposeColoring` to sparse `B`.
10802 
10803   Collective
10804 
10805   Input Parameters:
10806 + coloring - coloring context created with `MatTransposeColoringCreate()`
10807 - B        - sparse matrix
10808 
10809   Output Parameter:
10810 . Btdense - dense matrix $B^T$
10811 
10812   Level: developer
10813 
10814   Note:
10815   These are used internally for some implementations of `MatRARt()`
10816 
10817 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplyDenToSp()`
10818 @*/
10819 PetscErrorCode MatTransColoringApplySpToDen(MatTransposeColoring coloring, Mat B, Mat Btdense)
10820 {
10821   PetscFunctionBegin;
10822   PetscValidHeaderSpecific(coloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
10823   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
10824   PetscValidHeaderSpecific(Btdense, MAT_CLASSID, 3);
10825 
10826   PetscCall((*B->ops->transcoloringapplysptoden)(coloring, B, Btdense));
10827   PetscFunctionReturn(PETSC_SUCCESS);
10828 }
10829 
10830 /*@
10831   MatTransColoringApplyDenToSp - Given a symbolic matrix product $C_{sp} = A*B^T$ for which
10832   a `MatTransposeColoring` context has been created and a dense matrix $C_{den} = A*B^T_{dense}$
10833   in which `B^T_{dens}` is obtained from `MatTransColoringApplySpToDen()`, recover sparse matrix
10834   $C_{sp}$ from $C_{den}$.
10835 
10836   Collective
10837 
10838   Input Parameters:
10839 + matcoloring - coloring context created with `MatTransposeColoringCreate()`
10840 - Cden        - matrix product of a sparse matrix and a dense matrix Btdense
10841 
10842   Output Parameter:
10843 . Csp - sparse matrix
10844 
10845   Level: developer
10846 
10847   Note:
10848   These are used internally for some implementations of `MatRARt()`
10849 
10850 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`
10851 @*/
10852 PetscErrorCode MatTransColoringApplyDenToSp(MatTransposeColoring matcoloring, Mat Cden, Mat Csp)
10853 {
10854   PetscFunctionBegin;
10855   PetscValidHeaderSpecific(matcoloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
10856   PetscValidHeaderSpecific(Cden, MAT_CLASSID, 2);
10857   PetscValidHeaderSpecific(Csp, MAT_CLASSID, 3);
10858 
10859   PetscCall((*Csp->ops->transcoloringapplydentosp)(matcoloring, Cden, Csp));
10860   PetscCall(MatAssemblyBegin(Csp, MAT_FINAL_ASSEMBLY));
10861   PetscCall(MatAssemblyEnd(Csp, MAT_FINAL_ASSEMBLY));
10862   PetscFunctionReturn(PETSC_SUCCESS);
10863 }
10864 
10865 /*@
10866   MatTransposeColoringCreate - Creates a matrix coloring context for the matrix product $C = A*B^T$.
10867 
10868   Collective
10869 
10870   Input Parameters:
10871 + mat        - the matrix product C
10872 - iscoloring - the coloring of the matrix; usually obtained with `MatColoringCreate()` or `DMCreateColoring()`
10873 
10874   Output Parameter:
10875 . color - the new coloring context
10876 
10877   Level: intermediate
10878 
10879 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`,
10880           `MatTransColoringApplyDenToSp()`
10881 @*/
10882 PetscErrorCode MatTransposeColoringCreate(Mat mat, ISColoring iscoloring, MatTransposeColoring *color)
10883 {
10884   MatTransposeColoring c;
10885   MPI_Comm             comm;
10886 
10887   PetscFunctionBegin;
10888   PetscAssertPointer(color, 3);
10889 
10890   PetscCall(PetscLogEventBegin(MAT_TransposeColoringCreate, mat, 0, 0, 0));
10891   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10892   PetscCall(PetscHeaderCreate(c, MAT_TRANSPOSECOLORING_CLASSID, "MatTransposeColoring", "Matrix product C=A*B^T via coloring", "Mat", comm, MatTransposeColoringDestroy, NULL));
10893   c->ctype = iscoloring->ctype;
10894   PetscUseTypeMethod(mat, transposecoloringcreate, iscoloring, c);
10895   *color = c;
10896   PetscCall(PetscLogEventEnd(MAT_TransposeColoringCreate, mat, 0, 0, 0));
10897   PetscFunctionReturn(PETSC_SUCCESS);
10898 }
10899 
10900 /*@
10901   MatGetNonzeroState - Returns a 64-bit integer representing the current state of nonzeros in the matrix. If the
10902   matrix has had new nonzero locations added to (or removed from) the matrix since the previous call, the value will be larger.
10903 
10904   Not Collective
10905 
10906   Input Parameter:
10907 . mat - the matrix
10908 
10909   Output Parameter:
10910 . state - the current state
10911 
10912   Level: intermediate
10913 
10914   Notes:
10915   You can only compare states from two different calls to the SAME matrix, you cannot compare calls between
10916   different matrices
10917 
10918   Use `PetscObjectStateGet()` to check for changes to the numerical values in a matrix
10919 
10920   Use the result of `PetscObjectGetId()` to compare if a previously checked matrix is the same as the current matrix, do not compare object pointers.
10921 
10922 .seealso: [](ch_matrices), `Mat`, `PetscObjectStateGet()`, `PetscObjectGetId()`
10923 @*/
10924 PetscErrorCode MatGetNonzeroState(Mat mat, PetscObjectState *state)
10925 {
10926   PetscFunctionBegin;
10927   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10928   *state = mat->nonzerostate;
10929   PetscFunctionReturn(PETSC_SUCCESS);
10930 }
10931 
10932 /*@
10933   MatCreateMPIMatConcatenateSeqMat - Creates a single large PETSc matrix by concatenating sequential
10934   matrices from each processor
10935 
10936   Collective
10937 
10938   Input Parameters:
10939 + comm   - the communicators the parallel matrix will live on
10940 . seqmat - the input sequential matrices
10941 . n      - number of local columns (or `PETSC_DECIDE`)
10942 - reuse  - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10943 
10944   Output Parameter:
10945 . mpimat - the parallel matrix generated
10946 
10947   Level: developer
10948 
10949   Note:
10950   The number of columns of the matrix in EACH processor MUST be the same.
10951 
10952 .seealso: [](ch_matrices), `Mat`
10953 @*/
10954 PetscErrorCode MatCreateMPIMatConcatenateSeqMat(MPI_Comm comm, Mat seqmat, PetscInt n, MatReuse reuse, Mat *mpimat)
10955 {
10956   PetscMPIInt size;
10957 
10958   PetscFunctionBegin;
10959   PetscCallMPI(MPI_Comm_size(comm, &size));
10960   if (size == 1) {
10961     if (reuse == MAT_INITIAL_MATRIX) {
10962       PetscCall(MatDuplicate(seqmat, MAT_COPY_VALUES, mpimat));
10963     } else {
10964       PetscCall(MatCopy(seqmat, *mpimat, SAME_NONZERO_PATTERN));
10965     }
10966     PetscFunctionReturn(PETSC_SUCCESS);
10967   }
10968 
10969   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");
10970 
10971   PetscCall(PetscLogEventBegin(MAT_Merge, seqmat, 0, 0, 0));
10972   PetscCall((*seqmat->ops->creatempimatconcatenateseqmat)(comm, seqmat, n, reuse, mpimat));
10973   PetscCall(PetscLogEventEnd(MAT_Merge, seqmat, 0, 0, 0));
10974   PetscFunctionReturn(PETSC_SUCCESS);
10975 }
10976 
10977 /*@
10978   MatSubdomainsCreateCoalesce - Creates index subdomains by coalescing adjacent MPI processes' ownership ranges.
10979 
10980   Collective
10981 
10982   Input Parameters:
10983 + A - the matrix to create subdomains from
10984 - N - requested number of subdomains
10985 
10986   Output Parameters:
10987 + n   - number of subdomains resulting on this MPI process
10988 - iss - `IS` list with indices of subdomains on this MPI process
10989 
10990   Level: advanced
10991 
10992   Note:
10993   The number of subdomains must be smaller than the communicator size
10994 
10995 .seealso: [](ch_matrices), `Mat`, `IS`
10996 @*/
10997 PetscErrorCode MatSubdomainsCreateCoalesce(Mat A, PetscInt N, PetscInt *n, IS *iss[])
10998 {
10999   MPI_Comm    comm, subcomm;
11000   PetscMPIInt size, rank, color;
11001   PetscInt    rstart, rend, k;
11002 
11003   PetscFunctionBegin;
11004   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
11005   PetscCallMPI(MPI_Comm_size(comm, &size));
11006   PetscCallMPI(MPI_Comm_rank(comm, &rank));
11007   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);
11008   *n    = 1;
11009   k     = size / N + (size % N > 0); /* There are up to k ranks to a color */
11010   color = rank / k;
11011   PetscCallMPI(MPI_Comm_split(comm, color, rank, &subcomm));
11012   PetscCall(PetscMalloc1(1, iss));
11013   PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
11014   PetscCall(ISCreateStride(subcomm, rend - rstart, rstart, 1, iss[0]));
11015   PetscCallMPI(MPI_Comm_free(&subcomm));
11016   PetscFunctionReturn(PETSC_SUCCESS);
11017 }
11018 
11019 /*@
11020   MatGalerkin - Constructs the coarse grid problem matrix via Galerkin projection.
11021 
11022   If the interpolation and restriction operators are the same, uses `MatPtAP()`.
11023   If they are not the same, uses `MatMatMatMult()`.
11024 
11025   Once the coarse grid problem is constructed, correct for interpolation operators
11026   that are not of full rank, which can legitimately happen in the case of non-nested
11027   geometric multigrid.
11028 
11029   Input Parameters:
11030 + restrct     - restriction operator
11031 . dA          - fine grid matrix
11032 . interpolate - interpolation operator
11033 . reuse       - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
11034 - fill        - expected fill, use `PETSC_DETERMINE` or `PETSC_DETERMINE` if you do not have a good estimate
11035 
11036   Output Parameter:
11037 . A - the Galerkin coarse matrix
11038 
11039   Options Database Key:
11040 . -pc_mg_galerkin <both,pmat,mat,none> - for what matrices the Galerkin process should be used
11041 
11042   Level: developer
11043 
11044   Note:
11045   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
11046 
11047 .seealso: [](ch_matrices), `Mat`, `MatPtAP()`, `MatMatMatMult()`
11048 @*/
11049 PetscErrorCode MatGalerkin(Mat restrct, Mat dA, Mat interpolate, MatReuse reuse, PetscReal fill, Mat *A)
11050 {
11051   IS  zerorows;
11052   Vec diag;
11053 
11054   PetscFunctionBegin;
11055   PetscCheck(reuse != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
11056   /* Construct the coarse grid matrix */
11057   if (interpolate == restrct) {
11058     PetscCall(MatPtAP(dA, interpolate, reuse, fill, A));
11059   } else {
11060     PetscCall(MatMatMatMult(restrct, dA, interpolate, reuse, fill, A));
11061   }
11062 
11063   /* If the interpolation matrix is not of full rank, A will have zero rows.
11064      This can legitimately happen in the case of non-nested geometric multigrid.
11065      In that event, we set the rows of the matrix to the rows of the identity,
11066      ignoring the equations (as the RHS will also be zero). */
11067 
11068   PetscCall(MatFindZeroRows(*A, &zerorows));
11069 
11070   if (zerorows != NULL) { /* if there are any zero rows */
11071     PetscCall(MatCreateVecs(*A, &diag, NULL));
11072     PetscCall(MatGetDiagonal(*A, diag));
11073     PetscCall(VecISSet(diag, zerorows, 1.0));
11074     PetscCall(MatDiagonalSet(*A, diag, INSERT_VALUES));
11075     PetscCall(VecDestroy(&diag));
11076     PetscCall(ISDestroy(&zerorows));
11077   }
11078   PetscFunctionReturn(PETSC_SUCCESS);
11079 }
11080 
11081 /*@C
11082   MatSetOperation - Allows user to set a matrix operation for any matrix type
11083 
11084   Logically Collective
11085 
11086   Input Parameters:
11087 + mat - the matrix
11088 . op  - the name of the operation
11089 - f   - the function that provides the operation
11090 
11091   Level: developer
11092 
11093   Example Usage:
11094 .vb
11095   extern PetscErrorCode usermult(Mat, Vec, Vec);
11096 
11097   PetscCall(MatCreateXXX(comm, ..., &A));
11098   PetscCall(MatSetOperation(A, MATOP_MULT, (PetscVoidFn *)usermult));
11099 .ve
11100 
11101   Notes:
11102   See the file `include/petscmat.h` for a complete list of matrix
11103   operations, which all have the form MATOP_<OPERATION>, where
11104   <OPERATION> is the name (in all capital letters) of the
11105   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11106 
11107   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
11108   sequence as the usual matrix interface routines, since they
11109   are intended to be accessed via the usual matrix interface
11110   routines, e.g.,
11111 .vb
11112   MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
11113 .ve
11114 
11115   In particular each function MUST return `PETSC_SUCCESS` on success and
11116   nonzero on failure.
11117 
11118   This routine is distinct from `MatShellSetOperation()` in that it can be called on any matrix type.
11119 
11120 .seealso: [](ch_matrices), `Mat`, `MatGetOperation()`, `MatCreateShell()`, `MatShellSetContext()`, `MatShellSetOperation()`
11121 @*/
11122 PetscErrorCode MatSetOperation(Mat mat, MatOperation op, void (*f)(void))
11123 {
11124   PetscFunctionBegin;
11125   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11126   if (op == MATOP_VIEW && !mat->ops->viewnative && f != (void (*)(void))mat->ops->view) mat->ops->viewnative = mat->ops->view;
11127   (((void (**)(void))mat->ops)[op]) = f;
11128   PetscFunctionReturn(PETSC_SUCCESS);
11129 }
11130 
11131 /*@C
11132   MatGetOperation - Gets a matrix operation for any matrix type.
11133 
11134   Not Collective
11135 
11136   Input Parameters:
11137 + mat - the matrix
11138 - op  - the name of the operation
11139 
11140   Output Parameter:
11141 . f - the function that provides the operation
11142 
11143   Level: developer
11144 
11145   Example Usage:
11146 .vb
11147   PetscErrorCode (*usermult)(Mat, Vec, Vec);
11148 
11149   MatGetOperation(A, MATOP_MULT, (void (**)(void))&usermult);
11150 .ve
11151 
11152   Notes:
11153   See the file include/petscmat.h for a complete list of matrix
11154   operations, which all have the form MATOP_<OPERATION>, where
11155   <OPERATION> is the name (in all capital letters) of the
11156   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11157 
11158   This routine is distinct from `MatShellGetOperation()` in that it can be called on any matrix type.
11159 
11160 .seealso: [](ch_matrices), `Mat`, `MatSetOperation()`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
11161 @*/
11162 PetscErrorCode MatGetOperation(Mat mat, MatOperation op, void (**f)(void))
11163 {
11164   PetscFunctionBegin;
11165   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11166   *f = (((void (**)(void))mat->ops)[op]);
11167   PetscFunctionReturn(PETSC_SUCCESS);
11168 }
11169 
11170 /*@
11171   MatHasOperation - Determines whether the given matrix supports the particular operation.
11172 
11173   Not Collective
11174 
11175   Input Parameters:
11176 + mat - the matrix
11177 - op  - the operation, for example, `MATOP_GET_DIAGONAL`
11178 
11179   Output Parameter:
11180 . has - either `PETSC_TRUE` or `PETSC_FALSE`
11181 
11182   Level: advanced
11183 
11184   Note:
11185   See `MatSetOperation()` for additional discussion on naming convention and usage of `op`.
11186 
11187 .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`, `MatGetOperation()`, `MatSetOperation()`
11188 @*/
11189 PetscErrorCode MatHasOperation(Mat mat, MatOperation op, PetscBool *has)
11190 {
11191   PetscFunctionBegin;
11192   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11193   PetscAssertPointer(has, 3);
11194   if (mat->ops->hasoperation) {
11195     PetscUseTypeMethod(mat, hasoperation, op, has);
11196   } else {
11197     if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
11198     else {
11199       *has = PETSC_FALSE;
11200       if (op == MATOP_CREATE_SUBMATRIX) {
11201         PetscMPIInt size;
11202 
11203         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
11204         if (size == 1) PetscCall(MatHasOperation(mat, MATOP_CREATE_SUBMATRICES, has));
11205       }
11206     }
11207   }
11208   PetscFunctionReturn(PETSC_SUCCESS);
11209 }
11210 
11211 /*@
11212   MatHasCongruentLayouts - Determines whether the rows and columns layouts of the matrix are congruent
11213 
11214   Collective
11215 
11216   Input Parameter:
11217 . mat - the matrix
11218 
11219   Output Parameter:
11220 . cong - either `PETSC_TRUE` or `PETSC_FALSE`
11221 
11222   Level: beginner
11223 
11224 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatSetSizes()`, `PetscLayout`
11225 @*/
11226 PetscErrorCode MatHasCongruentLayouts(Mat mat, PetscBool *cong)
11227 {
11228   PetscFunctionBegin;
11229   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11230   PetscValidType(mat, 1);
11231   PetscAssertPointer(cong, 2);
11232   if (!mat->rmap || !mat->cmap) {
11233     *cong = mat->rmap == mat->cmap ? PETSC_TRUE : PETSC_FALSE;
11234     PetscFunctionReturn(PETSC_SUCCESS);
11235   }
11236   if (mat->congruentlayouts == PETSC_DECIDE) { /* first time we compare rows and cols layouts */
11237     PetscCall(PetscLayoutSetUp(mat->rmap));
11238     PetscCall(PetscLayoutSetUp(mat->cmap));
11239     PetscCall(PetscLayoutCompare(mat->rmap, mat->cmap, cong));
11240     if (*cong) mat->congruentlayouts = 1;
11241     else mat->congruentlayouts = 0;
11242   } else *cong = mat->congruentlayouts ? PETSC_TRUE : PETSC_FALSE;
11243   PetscFunctionReturn(PETSC_SUCCESS);
11244 }
11245 
11246 PetscErrorCode MatSetInf(Mat A)
11247 {
11248   PetscFunctionBegin;
11249   PetscUseTypeMethod(A, setinf);
11250   PetscFunctionReturn(PETSC_SUCCESS);
11251 }
11252 
11253 /*@
11254   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
11255   and possibly removes small values from the graph structure.
11256 
11257   Collective
11258 
11259   Input Parameters:
11260 + A       - the matrix
11261 . sym     - `PETSC_TRUE` indicates that the graph should be symmetrized
11262 . scale   - `PETSC_TRUE` indicates that the graph edge weights should be symmetrically scaled with the diagonal entry
11263 . filter  - filter value - < 0: does nothing; == 0: removes only 0.0 entries; otherwise: removes entries with abs(entries) <= value
11264 . num_idx - size of 'index' array
11265 - index   - array of block indices to use for graph strength of connection weight
11266 
11267   Output Parameter:
11268 . graph - the resulting graph
11269 
11270   Level: advanced
11271 
11272 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PCGAMG`
11273 @*/
11274 PetscErrorCode MatCreateGraph(Mat A, PetscBool sym, PetscBool scale, PetscReal filter, PetscInt num_idx, PetscInt index[], Mat *graph)
11275 {
11276   PetscFunctionBegin;
11277   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11278   PetscValidType(A, 1);
11279   PetscValidLogicalCollectiveBool(A, scale, 3);
11280   PetscAssertPointer(graph, 7);
11281   PetscCall(PetscLogEventBegin(MAT_CreateGraph, A, 0, 0, 0));
11282   PetscUseTypeMethod(A, creategraph, sym, scale, filter, num_idx, index, graph);
11283   PetscCall(PetscLogEventEnd(MAT_CreateGraph, A, 0, 0, 0));
11284   PetscFunctionReturn(PETSC_SUCCESS);
11285 }
11286 
11287 /*@
11288   MatEliminateZeros - eliminate the nondiagonal zero entries in place from the nonzero structure of a sparse `Mat` in place,
11289   meaning the same memory is used for the matrix, and no new memory is allocated.
11290 
11291   Collective
11292 
11293   Input Parameters:
11294 + A    - the matrix
11295 - 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
11296 
11297   Level: intermediate
11298 
11299   Developer Note:
11300   The entries in the sparse matrix data structure are shifted to fill in the unneeded locations in the data. Thus the end
11301   of the arrays in the data structure are unneeded.
11302 
11303 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateGraph()`, `MatFilter()`
11304 @*/
11305 PetscErrorCode MatEliminateZeros(Mat A, PetscBool keep)
11306 {
11307   PetscFunctionBegin;
11308   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11309   PetscUseTypeMethod(A, eliminatezeros, keep);
11310   PetscFunctionReturn(PETSC_SUCCESS);
11311 }
11312