xref: /petsc/src/mat/interface/matrix.c (revision 174dc0c8cee294b82b85e4dd3b331b29396264fc)
1 /*
2    This is where the abstract matrix operations are defined
3    Portions of this code are under:
4    Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
5 */
6 
7 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
8 #include <petsc/private/isimpl.h>
9 #include <petsc/private/vecimpl.h>
10 
11 /* Logging support */
12 PetscClassId MAT_CLASSID;
13 PetscClassId MAT_COLORING_CLASSID;
14 PetscClassId MAT_FDCOLORING_CLASSID;
15 PetscClassId MAT_TRANSPOSECOLORING_CLASSID;
16 
17 PetscLogEvent MAT_Mult, MAT_MultAdd, MAT_MultTranspose;
18 PetscLogEvent MAT_MultTransposeAdd, MAT_Solve, MAT_Solves, MAT_SolveAdd, MAT_SolveTranspose, MAT_MatSolve, MAT_MatTrSolve;
19 PetscLogEvent MAT_SolveTransposeAdd, MAT_SOR, MAT_ForwardSolve, MAT_BackwardSolve, MAT_LUFactor, MAT_LUFactorSymbolic;
20 PetscLogEvent MAT_LUFactorNumeric, MAT_CholeskyFactor, MAT_CholeskyFactorSymbolic, MAT_CholeskyFactorNumeric, MAT_ILUFactor;
21 PetscLogEvent MAT_ILUFactorSymbolic, MAT_ICCFactorSymbolic, MAT_Copy, MAT_Convert, MAT_Scale, MAT_AssemblyBegin;
22 PetscLogEvent MAT_QRFactorNumeric, MAT_QRFactorSymbolic, MAT_QRFactor;
23 PetscLogEvent MAT_AssemblyEnd, MAT_SetValues, MAT_GetValues, MAT_GetRow, MAT_GetRowIJ, MAT_CreateSubMats, MAT_GetOrdering, MAT_RedundantMat, MAT_GetSeqNonzeroStructure;
24 PetscLogEvent MAT_IncreaseOverlap, MAT_Partitioning, MAT_PartitioningND, MAT_Coarsen, MAT_ZeroEntries, MAT_Load, MAT_View, MAT_AXPY, MAT_FDColoringCreate;
25 PetscLogEvent MAT_FDColoringSetUp, MAT_FDColoringApply, MAT_Transpose, MAT_FDColoringFunction, MAT_CreateSubMat;
26 PetscLogEvent MAT_TransposeColoringCreate;
27 PetscLogEvent MAT_MatMult, MAT_MatMultSymbolic, MAT_MatMultNumeric;
28 PetscLogEvent MAT_PtAP, MAT_PtAPSymbolic, MAT_PtAPNumeric, MAT_RARt, MAT_RARtSymbolic, MAT_RARtNumeric;
29 PetscLogEvent MAT_MatTransposeMult, MAT_MatTransposeMultSymbolic, MAT_MatTransposeMultNumeric;
30 PetscLogEvent MAT_TransposeMatMult, MAT_TransposeMatMultSymbolic, MAT_TransposeMatMultNumeric;
31 PetscLogEvent MAT_MatMatMult, MAT_MatMatMultSymbolic, MAT_MatMatMultNumeric;
32 PetscLogEvent MAT_MultHermitianTranspose, MAT_MultHermitianTransposeAdd;
33 PetscLogEvent MAT_Getsymtransreduced, MAT_GetBrowsOfAcols;
34 PetscLogEvent MAT_GetBrowsOfAocols, MAT_Getlocalmat, MAT_Getlocalmatcondensed, MAT_Seqstompi, MAT_Seqstompinum, MAT_Seqstompisym;
35 PetscLogEvent MAT_GetMultiProcBlock;
36 PetscLogEvent MAT_CUSPARSECopyToGPU, MAT_CUSPARSECopyFromGPU, MAT_CUSPARSEGenerateTranspose, MAT_CUSPARSESolveAnalysis;
37 PetscLogEvent MAT_HIPSPARSECopyToGPU, MAT_HIPSPARSECopyFromGPU, MAT_HIPSPARSEGenerateTranspose, MAT_HIPSPARSESolveAnalysis;
38 PetscLogEvent MAT_PreallCOO, MAT_SetVCOO;
39 PetscLogEvent MAT_CreateGraph;
40 PetscLogEvent MAT_SetValuesBatch;
41 PetscLogEvent MAT_ViennaCLCopyToGPU;
42 PetscLogEvent MAT_CUDACopyToGPU, MAT_HIPCopyToGPU;
43 PetscLogEvent MAT_DenseCopyToGPU, MAT_DenseCopyFromGPU;
44 PetscLogEvent MAT_Merge, MAT_Residual, MAT_SetRandom;
45 PetscLogEvent MAT_FactorFactS, MAT_FactorInvS;
46 PetscLogEvent MATCOLORING_Apply, MATCOLORING_Comm, MATCOLORING_Local, MATCOLORING_ISCreate, MATCOLORING_SetUp, MATCOLORING_Weights;
47 PetscLogEvent MAT_H2Opus_Build, MAT_H2Opus_Compress, MAT_H2Opus_Orthog, MAT_H2Opus_LR;
48 
49 const char *const MatFactorTypes[] = {"NONE", "LU", "CHOLESKY", "ILU", "ICC", "ILUDT", "QR", "MatFactorType", "MAT_FACTOR_", NULL};
50 
51 /*@
52   MatSetRandom - Sets all components of a matrix to random numbers.
53 
54   Logically Collective
55 
56   Input Parameters:
57 + x    - the matrix
58 - rctx - the `PetscRandom` object, formed by `PetscRandomCreate()`, or `NULL` and
59           it will create one internally.
60 
61   Example:
62 .vb
63      PetscRandomCreate(PETSC_COMM_WORLD,&rctx);
64      MatSetRandom(x,rctx);
65      PetscRandomDestroy(rctx);
66 .ve
67 
68   Level: intermediate
69 
70   Notes:
71   For sparse matrices that have been preallocated but not been assembled, it randomly selects appropriate locations,
72 
73   for sparse matrices that already have nonzero locations, it fills the locations with random numbers.
74 
75   It generates an error if used on unassembled sparse matrices that have not been preallocated.
76 
77 .seealso: [](ch_matrices), `Mat`, `PetscRandom`, `PetscRandomCreate()`, `MatZeroEntries()`, `MatSetValues()`, `PetscRandomDestroy()`
78 @*/
79 PetscErrorCode MatSetRandom(Mat x, PetscRandom rctx)
80 {
81   PetscRandom randObj = NULL;
82 
83   PetscFunctionBegin;
84   PetscValidHeaderSpecific(x, MAT_CLASSID, 1);
85   if (rctx) PetscValidHeaderSpecific(rctx, PETSC_RANDOM_CLASSID, 2);
86   PetscValidType(x, 1);
87   MatCheckPreallocated(x, 1);
88 
89   if (!rctx) {
90     MPI_Comm comm;
91     PetscCall(PetscObjectGetComm((PetscObject)x, &comm));
92     PetscCall(PetscRandomCreate(comm, &randObj));
93     PetscCall(PetscRandomSetType(randObj, x->defaultrandtype));
94     PetscCall(PetscRandomSetFromOptions(randObj));
95     rctx = randObj;
96   }
97   PetscCall(PetscLogEventBegin(MAT_SetRandom, x, rctx, 0, 0));
98   PetscUseTypeMethod(x, setrandom, rctx);
99   PetscCall(PetscLogEventEnd(MAT_SetRandom, x, rctx, 0, 0));
100 
101   PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
102   PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
103   PetscCall(PetscRandomDestroy(&randObj));
104   PetscFunctionReturn(PETSC_SUCCESS);
105 }
106 
107 /*@
108   MatCopyHashToXAIJ - copy hash table entries into an XAIJ matrix type
109 
110   Logically Collective
111 
112   Input Parameter:
113 . A - A matrix in unassembled, hash table form
114 
115   Output Parameter:
116 . B - The XAIJ matrix. This can either be `A` or some matrix of equivalent size, e.g. obtained from `A` via `MatDuplicate()`
117 
118   Example:
119 .vb
120      PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &B));
121      PetscCall(MatCopyHashToXAIJ(A, B));
122 .ve
123 
124   Level: advanced
125 
126   Notes:
127   If `B` is `A`, then the hash table data structure will be destroyed. `B` is assembled
128 
129 .seealso: [](ch_matrices), `Mat`, `MAT_USE_HASH_TABLE`
130 @*/
131 PetscErrorCode MatCopyHashToXAIJ(Mat A, Mat B)
132 {
133   PetscFunctionBegin;
134   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
135   PetscUseTypeMethod(A, copyhashtoxaij, B);
136   PetscFunctionReturn(PETSC_SUCCESS);
137 }
138 
139 /*@
140   MatFactorGetErrorZeroPivot - returns the pivot value that was determined to be zero and the row it occurred in
141 
142   Logically Collective
143 
144   Input Parameter:
145 . mat - the factored matrix
146 
147   Output Parameters:
148 + pivot - the pivot value computed
149 - row   - the row that the zero pivot occurred. This row value must be interpreted carefully due to row reorderings and which processes
150          the share the matrix
151 
152   Level: advanced
153 
154   Notes:
155   This routine does not work for factorizations done with external packages.
156 
157   This routine should only be called if `MatGetFactorError()` returns a value of `MAT_FACTOR_NUMERIC_ZEROPIVOT`
158 
159   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
160 
161 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`,
162 `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`, `MatFactorClearError()`,
163 `MAT_FACTOR_NUMERIC_ZEROPIVOT`
164 @*/
165 PetscErrorCode MatFactorGetErrorZeroPivot(Mat mat, PetscReal *pivot, PetscInt *row)
166 {
167   PetscFunctionBegin;
168   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
169   PetscAssertPointer(pivot, 2);
170   PetscAssertPointer(row, 3);
171   *pivot = mat->factorerror_zeropivot_value;
172   *row   = mat->factorerror_zeropivot_row;
173   PetscFunctionReturn(PETSC_SUCCESS);
174 }
175 
176 /*@
177   MatFactorGetError - gets the error code from a factorization
178 
179   Logically Collective
180 
181   Input Parameter:
182 . mat - the factored matrix
183 
184   Output Parameter:
185 . err - the error code
186 
187   Level: advanced
188 
189   Note:
190   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
191 
192 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`,
193           `MatFactorClearError()`, `MatFactorGetErrorZeroPivot()`, `MatFactorError`
194 @*/
195 PetscErrorCode MatFactorGetError(Mat mat, MatFactorError *err)
196 {
197   PetscFunctionBegin;
198   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
199   PetscAssertPointer(err, 2);
200   *err = mat->factorerrortype;
201   PetscFunctionReturn(PETSC_SUCCESS);
202 }
203 
204 /*@
205   MatFactorClearError - clears the error code in a factorization
206 
207   Logically Collective
208 
209   Input Parameter:
210 . mat - the factored matrix
211 
212   Level: developer
213 
214   Note:
215   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
216 
217 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`, `MatFactorGetError()`, `MatFactorGetErrorZeroPivot()`,
218           `MatGetErrorCode()`, `MatFactorError`
219 @*/
220 PetscErrorCode MatFactorClearError(Mat mat)
221 {
222   PetscFunctionBegin;
223   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
224   mat->factorerrortype             = MAT_FACTOR_NOERROR;
225   mat->factorerror_zeropivot_value = 0.0;
226   mat->factorerror_zeropivot_row   = 0;
227   PetscFunctionReturn(PETSC_SUCCESS);
228 }
229 
230 PetscErrorCode MatFindNonzeroRowsOrCols_Basic(Mat mat, PetscBool cols, PetscReal tol, IS *nonzero)
231 {
232   Vec                r, l;
233   const PetscScalar *al;
234   PetscInt           i, nz, gnz, N, n, st;
235 
236   PetscFunctionBegin;
237   PetscCall(MatCreateVecs(mat, &r, &l));
238   if (!cols) { /* nonzero rows */
239     PetscCall(MatGetOwnershipRange(mat, &st, NULL));
240     PetscCall(MatGetSize(mat, &N, NULL));
241     PetscCall(MatGetLocalSize(mat, &n, NULL));
242     PetscCall(VecSet(l, 0.0));
243     PetscCall(VecSetRandom(r, NULL));
244     PetscCall(MatMult(mat, r, l));
245     PetscCall(VecGetArrayRead(l, &al));
246   } else { /* nonzero columns */
247     PetscCall(MatGetOwnershipRangeColumn(mat, &st, NULL));
248     PetscCall(MatGetSize(mat, NULL, &N));
249     PetscCall(MatGetLocalSize(mat, NULL, &n));
250     PetscCall(VecSet(r, 0.0));
251     PetscCall(VecSetRandom(l, NULL));
252     PetscCall(MatMultTranspose(mat, l, r));
253     PetscCall(VecGetArrayRead(r, &al));
254   }
255   if (tol <= 0.0) {
256     for (i = 0, nz = 0; i < n; i++)
257       if (al[i] != 0.0) nz++;
258   } else {
259     for (i = 0, nz = 0; i < n; i++)
260       if (PetscAbsScalar(al[i]) > tol) nz++;
261   }
262   PetscCallMPI(MPIU_Allreduce(&nz, &gnz, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
263   if (gnz != N) {
264     PetscInt *nzr;
265     PetscCall(PetscMalloc1(nz, &nzr));
266     if (nz) {
267       if (tol < 0) {
268         for (i = 0, nz = 0; i < n; i++)
269           if (al[i] != 0.0) nzr[nz++] = i + st;
270       } else {
271         for (i = 0, nz = 0; i < n; i++)
272           if (PetscAbsScalar(al[i]) > tol) nzr[nz++] = i + st;
273       }
274     }
275     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nz, nzr, PETSC_OWN_POINTER, nonzero));
276   } else *nonzero = NULL;
277   if (!cols) { /* nonzero rows */
278     PetscCall(VecRestoreArrayRead(l, &al));
279   } else {
280     PetscCall(VecRestoreArrayRead(r, &al));
281   }
282   PetscCall(VecDestroy(&l));
283   PetscCall(VecDestroy(&r));
284   PetscFunctionReturn(PETSC_SUCCESS);
285 }
286 
287 /*@
288   MatFindNonzeroRows - Locate all rows that are not completely zero in the matrix
289 
290   Input Parameter:
291 . mat - the matrix
292 
293   Output Parameter:
294 . keptrows - the rows that are not completely zero
295 
296   Level: intermediate
297 
298   Note:
299   `keptrows` is set to `NULL` if all rows are nonzero.
300 
301   Developer Note:
302   If `keptrows` is not `NULL`, it must be sorted.
303 
304 .seealso: [](ch_matrices), `Mat`, `MatFindZeroRows()`
305  @*/
306 PetscErrorCode MatFindNonzeroRows(Mat mat, IS *keptrows)
307 {
308   PetscFunctionBegin;
309   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
310   PetscValidType(mat, 1);
311   PetscAssertPointer(keptrows, 2);
312   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
313   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
314   if (mat->ops->findnonzerorows) PetscUseTypeMethod(mat, findnonzerorows, keptrows);
315   else PetscCall(MatFindNonzeroRowsOrCols_Basic(mat, PETSC_FALSE, 0.0, keptrows));
316   if (keptrows && *keptrows) PetscCall(ISSetInfo(*keptrows, IS_SORTED, IS_GLOBAL, PETSC_FALSE, PETSC_TRUE));
317   PetscFunctionReturn(PETSC_SUCCESS);
318 }
319 
320 /*@
321   MatFindZeroRows - Locate all rows that are completely zero in the matrix
322 
323   Input Parameter:
324 . mat - the matrix
325 
326   Output Parameter:
327 . zerorows - the rows that are completely zero
328 
329   Level: intermediate
330 
331   Note:
332   `zerorows` is set to `NULL` if no rows are zero.
333 
334 .seealso: [](ch_matrices), `Mat`, `MatFindNonzeroRows()`
335  @*/
336 PetscErrorCode MatFindZeroRows(Mat mat, IS *zerorows)
337 {
338   IS       keptrows;
339   PetscInt m, n;
340 
341   PetscFunctionBegin;
342   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
343   PetscValidType(mat, 1);
344   PetscAssertPointer(zerorows, 2);
345   PetscCall(MatFindNonzeroRows(mat, &keptrows));
346   /* MatFindNonzeroRows sets keptrows to NULL if there are no zero rows.
347      In keeping with this convention, we set zerorows to NULL if there are no zero
348      rows. */
349   if (keptrows == NULL) {
350     *zerorows = NULL;
351   } else {
352     PetscCall(MatGetOwnershipRange(mat, &m, &n));
353     PetscCall(ISComplement(keptrows, m, n, zerorows));
354     PetscCall(ISDestroy(&keptrows));
355   }
356   PetscFunctionReturn(PETSC_SUCCESS);
357 }
358 
359 /*@
360   MatGetDiagonalBlock - Returns the part of the matrix associated with the on-process coupling
361 
362   Not Collective
363 
364   Input Parameter:
365 . A - the matrix
366 
367   Output Parameter:
368 . a - the diagonal part (which is a SEQUENTIAL matrix)
369 
370   Level: advanced
371 
372   Notes:
373   See `MatCreateAIJ()` for more information on the "diagonal part" of the matrix.
374 
375   Use caution, as the reference count on the returned matrix is not incremented and it is used as part of `A`'s normal operation.
376 
377 .seealso: [](ch_matrices), `Mat`, `MatCreateAIJ()`, `MATAIJ`, `MATBAIJ`, `MATSBAIJ`
378 @*/
379 PetscErrorCode MatGetDiagonalBlock(Mat A, Mat *a)
380 {
381   PetscFunctionBegin;
382   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
383   PetscValidType(A, 1);
384   PetscAssertPointer(a, 2);
385   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
386   if (A->ops->getdiagonalblock) PetscUseTypeMethod(A, getdiagonalblock, a);
387   else {
388     PetscMPIInt size;
389 
390     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
391     PetscCheck(size == 1, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for parallel matrix type %s", ((PetscObject)A)->type_name);
392     *a = A;
393   }
394   PetscFunctionReturn(PETSC_SUCCESS);
395 }
396 
397 /*@
398   MatGetTrace - Gets the trace of a matrix. The sum of the diagonal entries.
399 
400   Collective
401 
402   Input Parameter:
403 . mat - the matrix
404 
405   Output Parameter:
406 . trace - the sum of the diagonal entries
407 
408   Level: advanced
409 
410 .seealso: [](ch_matrices), `Mat`
411 @*/
412 PetscErrorCode MatGetTrace(Mat mat, PetscScalar *trace)
413 {
414   Vec diag;
415 
416   PetscFunctionBegin;
417   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
418   PetscAssertPointer(trace, 2);
419   PetscCall(MatCreateVecs(mat, &diag, NULL));
420   PetscCall(MatGetDiagonal(mat, diag));
421   PetscCall(VecSum(diag, trace));
422   PetscCall(VecDestroy(&diag));
423   PetscFunctionReturn(PETSC_SUCCESS);
424 }
425 
426 /*@
427   MatRealPart - Zeros out the imaginary part of the matrix
428 
429   Logically Collective
430 
431   Input Parameter:
432 . mat - the matrix
433 
434   Level: advanced
435 
436 .seealso: [](ch_matrices), `Mat`, `MatImaginaryPart()`
437 @*/
438 PetscErrorCode MatRealPart(Mat mat)
439 {
440   PetscFunctionBegin;
441   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
442   PetscValidType(mat, 1);
443   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
444   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
445   MatCheckPreallocated(mat, 1);
446   PetscUseTypeMethod(mat, realpart);
447   PetscFunctionReturn(PETSC_SUCCESS);
448 }
449 
450 /*@C
451   MatGetGhosts - Get the global indices of all ghost nodes defined by the sparse matrix
452 
453   Collective
454 
455   Input Parameter:
456 . mat - the matrix
457 
458   Output Parameters:
459 + nghosts - number of ghosts (for `MATBAIJ` and `MATSBAIJ` matrices there is one ghost for each matrix block)
460 - ghosts  - the global indices of the ghost points
461 
462   Level: advanced
463 
464   Note:
465   `nghosts` and `ghosts` are suitable to pass into `VecCreateGhost()` or `VecCreateGhostBlock()`
466 
467 .seealso: [](ch_matrices), `Mat`, `VecCreateGhost()`, `VecCreateGhostBlock()`
468 @*/
469 PetscErrorCode MatGetGhosts(Mat mat, PetscInt *nghosts, const PetscInt *ghosts[])
470 {
471   PetscFunctionBegin;
472   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
473   PetscValidType(mat, 1);
474   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
475   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
476   if (mat->ops->getghosts) PetscUseTypeMethod(mat, getghosts, nghosts, ghosts);
477   else {
478     if (nghosts) *nghosts = 0;
479     if (ghosts) *ghosts = NULL;
480   }
481   PetscFunctionReturn(PETSC_SUCCESS);
482 }
483 
484 /*@
485   MatImaginaryPart - Moves the imaginary part of the matrix to the real part and zeros the imaginary part
486 
487   Logically Collective
488 
489   Input Parameter:
490 . mat - the matrix
491 
492   Level: advanced
493 
494 .seealso: [](ch_matrices), `Mat`, `MatRealPart()`
495 @*/
496 PetscErrorCode MatImaginaryPart(Mat mat)
497 {
498   PetscFunctionBegin;
499   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
500   PetscValidType(mat, 1);
501   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
502   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
503   MatCheckPreallocated(mat, 1);
504   PetscUseTypeMethod(mat, imaginarypart);
505   PetscFunctionReturn(PETSC_SUCCESS);
506 }
507 
508 /*@
509   MatMissingDiagonal - Determine if sparse matrix is missing a diagonal entry (or block entry for `MATBAIJ` and `MATSBAIJ` matrices) in the nonzero structure
510 
511   Not Collective
512 
513   Input Parameter:
514 . mat - the matrix
515 
516   Output Parameters:
517 + missing - is any diagonal entry missing
518 - dd      - first diagonal entry that is missing (optional) on this process
519 
520   Level: advanced
521 
522   Note:
523   This does not return diagonal entries that are in the nonzero structure but happen to have a zero numerical value
524 
525 .seealso: [](ch_matrices), `Mat`
526 @*/
527 PetscErrorCode MatMissingDiagonal(Mat mat, PetscBool *missing, PetscInt *dd)
528 {
529   PetscFunctionBegin;
530   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
531   PetscValidType(mat, 1);
532   PetscAssertPointer(missing, 2);
533   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix %s", ((PetscObject)mat)->type_name);
534   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
535   PetscUseTypeMethod(mat, missingdiagonal, missing, dd);
536   PetscFunctionReturn(PETSC_SUCCESS);
537 }
538 
539 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
540 /*@C
541   MatGetRow - Gets a row of a matrix.  You MUST call `MatRestoreRow()`
542   for each row that you get to ensure that your application does
543   not bleed memory.
544 
545   Not Collective
546 
547   Input Parameters:
548 + mat - the matrix
549 - row - the row to get
550 
551   Output Parameters:
552 + ncols - if not `NULL`, the number of nonzeros in `row`
553 . cols  - if not `NULL`, the column numbers
554 - vals  - if not `NULL`, the numerical values
555 
556   Level: advanced
557 
558   Notes:
559   This routine is provided for people who need to have direct access
560   to the structure of a matrix.  We hope that we provide enough
561   high-level matrix routines that few users will need it.
562 
563   `MatGetRow()` always returns 0-based column indices, regardless of
564   whether the internal representation is 0-based (default) or 1-based.
565 
566   For better efficiency, set `cols` and/or `vals` to `NULL` if you do
567   not wish to extract these quantities.
568 
569   The user can only examine the values extracted with `MatGetRow()`;
570   the values CANNOT be altered.  To change the matrix entries, one
571   must use `MatSetValues()`.
572 
573   You can only have one call to `MatGetRow()` outstanding for a particular
574   matrix at a time, per processor. `MatGetRow()` can only obtain rows
575   associated with the given processor, it cannot get rows from the
576   other processors; for that we suggest using `MatCreateSubMatrices()`, then
577   `MatGetRow()` on the submatrix. The row index passed to `MatGetRow()`
578   is in the global number of rows.
579 
580   Use `MatGetRowIJ()` and `MatRestoreRowIJ()` to access all the local indices of the sparse matrix.
581 
582   Use `MatSeqAIJGetArray()` and similar functions to access the numerical values for certain matrix types directly.
583 
584   Fortran Note:
585 .vb
586   PetscInt, pointer :: cols(:)
587   PetscScalar, pointer :: vals(:)
588 .ve
589 
590 .seealso: [](ch_matrices), `Mat`, `MatRestoreRow()`, `MatSetValues()`, `MatGetValues()`, `MatCreateSubMatrices()`, `MatGetDiagonal()`, `MatGetRowIJ()`, `MatRestoreRowIJ()`
591 @*/
592 PetscErrorCode MatGetRow(Mat mat, PetscInt row, PetscInt *ncols, const PetscInt *cols[], const PetscScalar *vals[])
593 {
594   PetscInt incols;
595 
596   PetscFunctionBegin;
597   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
598   PetscValidType(mat, 1);
599   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
600   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
601   MatCheckPreallocated(mat, 1);
602   PetscCheck(row >= mat->rmap->rstart && row < mat->rmap->rend, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Only for local rows, %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ")", row, mat->rmap->rstart, mat->rmap->rend);
603   PetscCall(PetscLogEventBegin(MAT_GetRow, mat, 0, 0, 0));
604   PetscUseTypeMethod(mat, getrow, row, &incols, (PetscInt **)cols, (PetscScalar **)vals);
605   if (ncols) *ncols = incols;
606   PetscCall(PetscLogEventEnd(MAT_GetRow, mat, 0, 0, 0));
607   PetscFunctionReturn(PETSC_SUCCESS);
608 }
609 
610 /*@
611   MatConjugate - replaces the matrix values with their complex conjugates
612 
613   Logically Collective
614 
615   Input Parameter:
616 . mat - the matrix
617 
618   Level: advanced
619 
620 .seealso: [](ch_matrices), `Mat`, `MatRealPart()`, `MatImaginaryPart()`, `VecConjugate()`, `MatTranspose()`
621 @*/
622 PetscErrorCode MatConjugate(Mat mat)
623 {
624   PetscFunctionBegin;
625   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
626   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
627   if (PetscDefined(USE_COMPLEX) && mat->hermitian != PETSC_BOOL3_TRUE) {
628     PetscUseTypeMethod(mat, conjugate);
629     PetscCall(PetscObjectStateIncrease((PetscObject)mat));
630   }
631   PetscFunctionReturn(PETSC_SUCCESS);
632 }
633 
634 /*@C
635   MatRestoreRow - Frees any temporary space allocated by `MatGetRow()`.
636 
637   Not Collective
638 
639   Input Parameters:
640 + mat   - the matrix
641 . row   - the row to get
642 . ncols - the number of nonzeros
643 . cols  - the columns of the nonzeros
644 - vals  - if nonzero the column values
645 
646   Level: advanced
647 
648   Notes:
649   This routine should be called after you have finished examining the entries.
650 
651   This routine zeros out `ncols`, `cols`, and `vals`. This is to prevent accidental
652   us of the array after it has been restored. If you pass `NULL`, it will
653   not zero the pointers.  Use of `cols` or `vals` after `MatRestoreRow()` is invalid.
654 
655   Fortran Note:
656 .vb
657   PetscInt, pointer :: cols(:)
658   PetscScalar, pointer :: vals(:)
659 .ve
660 
661 .seealso: [](ch_matrices), `Mat`, `MatGetRow()`
662 @*/
663 PetscErrorCode MatRestoreRow(Mat mat, PetscInt row, PetscInt *ncols, const PetscInt *cols[], const PetscScalar *vals[])
664 {
665   PetscFunctionBegin;
666   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
667   if (ncols) PetscAssertPointer(ncols, 3);
668   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
669   PetscTryTypeMethod(mat, restorerow, row, ncols, (PetscInt **)cols, (PetscScalar **)vals);
670   if (ncols) *ncols = 0;
671   if (cols) *cols = NULL;
672   if (vals) *vals = NULL;
673   PetscFunctionReturn(PETSC_SUCCESS);
674 }
675 
676 /*@
677   MatGetRowUpperTriangular - Sets a flag to enable calls to `MatGetRow()` for matrix in `MATSBAIJ` format.
678   You should call `MatRestoreRowUpperTriangular()` after calling` MatGetRow()` and `MatRestoreRow()` to disable the flag.
679 
680   Not Collective
681 
682   Input Parameter:
683 . mat - the matrix
684 
685   Level: advanced
686 
687   Note:
688   The flag is to ensure that users are aware that `MatGetRow()` only provides the upper triangular part of the row for the matrices in `MATSBAIJ` format.
689 
690 .seealso: [](ch_matrices), `Mat`, `MATSBAIJ`, `MatRestoreRowUpperTriangular()`
691 @*/
692 PetscErrorCode MatGetRowUpperTriangular(Mat mat)
693 {
694   PetscFunctionBegin;
695   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
696   PetscValidType(mat, 1);
697   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
698   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
699   MatCheckPreallocated(mat, 1);
700   PetscTryTypeMethod(mat, getrowuppertriangular);
701   PetscFunctionReturn(PETSC_SUCCESS);
702 }
703 
704 /*@
705   MatRestoreRowUpperTriangular - Disable calls to `MatGetRow()` for matrix in `MATSBAIJ` format.
706 
707   Not Collective
708 
709   Input Parameter:
710 . mat - the matrix
711 
712   Level: advanced
713 
714   Note:
715   This routine should be called after you have finished calls to `MatGetRow()` and `MatRestoreRow()`.
716 
717 .seealso: [](ch_matrices), `Mat`, `MATSBAIJ`, `MatGetRowUpperTriangular()`
718 @*/
719 PetscErrorCode MatRestoreRowUpperTriangular(Mat mat)
720 {
721   PetscFunctionBegin;
722   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
723   PetscValidType(mat, 1);
724   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
725   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
726   MatCheckPreallocated(mat, 1);
727   PetscTryTypeMethod(mat, restorerowuppertriangular);
728   PetscFunctionReturn(PETSC_SUCCESS);
729 }
730 
731 /*@
732   MatSetOptionsPrefix - Sets the prefix used for searching for all
733   `Mat` options in the database.
734 
735   Logically Collective
736 
737   Input Parameters:
738 + A      - the matrix
739 - prefix - the prefix to prepend to all option names
740 
741   Level: advanced
742 
743   Notes:
744   A hyphen (-) must NOT be given at the beginning of the prefix name.
745   The first character of all runtime options is AUTOMATICALLY the hyphen.
746 
747   This is NOT used for options for the factorization of the matrix. Normally the
748   prefix is automatically passed in from the PC calling the factorization. To set
749   it directly use  `MatSetOptionsPrefixFactor()`
750 
751 .seealso: [](ch_matrices), `Mat`, `MatSetFromOptions()`, `MatSetOptionsPrefixFactor()`
752 @*/
753 PetscErrorCode MatSetOptionsPrefix(Mat A, const char prefix[])
754 {
755   PetscFunctionBegin;
756   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
757   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)A, prefix));
758   PetscTryMethod(A, "MatSetOptionsPrefix_C", (Mat, const char[]), (A, prefix));
759   PetscFunctionReturn(PETSC_SUCCESS);
760 }
761 
762 /*@
763   MatSetOptionsPrefixFactor - Sets the prefix used for searching for all matrix factor options in the database for
764   for matrices created with `MatGetFactor()`
765 
766   Logically Collective
767 
768   Input Parameters:
769 + A      - the matrix
770 - prefix - the prefix to prepend to all option names for the factored matrix
771 
772   Level: developer
773 
774   Notes:
775   A hyphen (-) must NOT be given at the beginning of the prefix name.
776   The first character of all runtime options is AUTOMATICALLY the hyphen.
777 
778   Normally the prefix is automatically passed in from the `PC` calling the factorization. To set
779   it directly when not using `KSP`/`PC` use  `MatSetOptionsPrefixFactor()`
780 
781 .seealso: [](ch_matrices), `Mat`,   [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSetFromOptions()`, `MatSetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`
782 @*/
783 PetscErrorCode MatSetOptionsPrefixFactor(Mat A, const char prefix[])
784 {
785   PetscFunctionBegin;
786   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
787   if (prefix) {
788     PetscAssertPointer(prefix, 2);
789     PetscCheck(prefix[0] != '-', PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
790     if (prefix != A->factorprefix) {
791       PetscCall(PetscFree(A->factorprefix));
792       PetscCall(PetscStrallocpy(prefix, &A->factorprefix));
793     }
794   } else PetscCall(PetscFree(A->factorprefix));
795   PetscFunctionReturn(PETSC_SUCCESS);
796 }
797 
798 /*@
799   MatAppendOptionsPrefixFactor - Appends to the prefix used for searching for all matrix factor options in the database for
800   for matrices created with `MatGetFactor()`
801 
802   Logically Collective
803 
804   Input Parameters:
805 + A      - the matrix
806 - prefix - the prefix to prepend to all option names for the factored matrix
807 
808   Level: developer
809 
810   Notes:
811   A hyphen (-) must NOT be given at the beginning of the prefix name.
812   The first character of all runtime options is AUTOMATICALLY the hyphen.
813 
814   Normally the prefix is automatically passed in from the `PC` calling the factorization. To set
815   it directly when not using `KSP`/`PC` use  `MatAppendOptionsPrefixFactor()`
816 
817 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `PetscOptionsCreate()`, `PetscOptionsDestroy()`, `PetscObjectSetOptionsPrefix()`, `PetscObjectPrependOptionsPrefix()`,
818           `PetscObjectGetOptionsPrefix()`, `TSAppendOptionsPrefix()`, `SNESAppendOptionsPrefix()`, `KSPAppendOptionsPrefix()`, `MatSetOptionsPrefixFactor()`,
819           `MatSetOptionsPrefix()`
820 @*/
821 PetscErrorCode MatAppendOptionsPrefixFactor(Mat A, const char prefix[])
822 {
823   size_t len1, len2, new_len;
824 
825   PetscFunctionBegin;
826   PetscValidHeader(A, 1);
827   if (!prefix) PetscFunctionReturn(PETSC_SUCCESS);
828   if (!A->factorprefix) {
829     PetscCall(MatSetOptionsPrefixFactor(A, prefix));
830     PetscFunctionReturn(PETSC_SUCCESS);
831   }
832   PetscCheck(prefix[0] != '-', PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
833 
834   PetscCall(PetscStrlen(A->factorprefix, &len1));
835   PetscCall(PetscStrlen(prefix, &len2));
836   new_len = len1 + len2 + 1;
837   PetscCall(PetscRealloc(new_len * sizeof(*A->factorprefix), &A->factorprefix));
838   PetscCall(PetscStrncpy(A->factorprefix + len1, prefix, len2 + 1));
839   PetscFunctionReturn(PETSC_SUCCESS);
840 }
841 
842 /*@
843   MatAppendOptionsPrefix - Appends to the prefix used for searching for all
844   matrix options in the database.
845 
846   Logically Collective
847 
848   Input Parameters:
849 + A      - the matrix
850 - prefix - the prefix to prepend to all option names
851 
852   Level: advanced
853 
854   Note:
855   A hyphen (-) must NOT be given at the beginning of the prefix name.
856   The first character of all runtime options is AUTOMATICALLY the hyphen.
857 
858 .seealso: [](ch_matrices), `Mat`, `MatGetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`, `MatSetOptionsPrefix()`
859 @*/
860 PetscErrorCode MatAppendOptionsPrefix(Mat A, const char prefix[])
861 {
862   PetscFunctionBegin;
863   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
864   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)A, prefix));
865   PetscTryMethod(A, "MatAppendOptionsPrefix_C", (Mat, const char[]), (A, prefix));
866   PetscFunctionReturn(PETSC_SUCCESS);
867 }
868 
869 /*@
870   MatGetOptionsPrefix - Gets the prefix used for searching for all
871   matrix options in the database.
872 
873   Not Collective
874 
875   Input Parameter:
876 . A - the matrix
877 
878   Output Parameter:
879 . prefix - pointer to the prefix string used
880 
881   Level: advanced
882 
883 .seealso: [](ch_matrices), `Mat`, `MatAppendOptionsPrefix()`, `MatSetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`, `MatSetOptionsPrefixFactor()`
884 @*/
885 PetscErrorCode MatGetOptionsPrefix(Mat A, const char *prefix[])
886 {
887   PetscFunctionBegin;
888   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
889   PetscAssertPointer(prefix, 2);
890   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)A, prefix));
891   PetscFunctionReturn(PETSC_SUCCESS);
892 }
893 
894 /*@
895   MatGetState - Gets the state of a `Mat`. Same value as returned by `PetscObjectStateGet()`
896 
897   Not Collective
898 
899   Input Parameter:
900 . A - the matrix
901 
902   Output Parameter:
903 . state - the object state
904 
905   Level: advanced
906 
907   Note:
908   Object state is an integer which gets increased every time
909   the object is changed. By saving and later querying the object state
910   one can determine whether information about the object is still current.
911 
912   See `MatGetNonzeroState()` to determine if the nonzero structure of the matrix has changed.
913 
914 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PetscObjectStateGet()`, `MatGetNonzeroState()`
915 @*/
916 PetscErrorCode MatGetState(Mat A, PetscObjectState *state)
917 {
918   PetscFunctionBegin;
919   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
920   PetscAssertPointer(state, 2);
921   PetscCall(PetscObjectStateGet((PetscObject)A, state));
922   PetscFunctionReturn(PETSC_SUCCESS);
923 }
924 
925 /*@
926   MatResetPreallocation - Reset matrix to use the original preallocation values provided by the user, for example with `MatXAIJSetPreallocation()`
927 
928   Collective
929 
930   Input Parameter:
931 . A - the matrix
932 
933   Level: beginner
934 
935   Notes:
936   After calling `MatAssemblyBegin()` and `MatAssemblyEnd()` with `MAT_FINAL_ASSEMBLY` the matrix data structures represent the nonzeros assigned to the
937   matrix. If that space is less than the preallocated space that extra preallocated space is no longer available to take on new values. `MatResetPreallocation()`
938   makes all of the preallocation space available
939 
940   Current values in the matrix are lost in this call
941 
942   Currently only supported for  `MATAIJ` matrices.
943 
944 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatXAIJSetPreallocation()`
945 @*/
946 PetscErrorCode MatResetPreallocation(Mat A)
947 {
948   PetscFunctionBegin;
949   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
950   PetscValidType(A, 1);
951   PetscUseMethod(A, "MatResetPreallocation_C", (Mat), (A));
952   PetscFunctionReturn(PETSC_SUCCESS);
953 }
954 
955 /*@
956   MatResetHash - Reset the matrix so that it will use a hash table for the next round of `MatSetValues()` and `MatAssemblyBegin()`/`MatAssemblyEnd()`.
957 
958   Collective
959 
960   Input Parameter:
961 . A - the matrix
962 
963   Level: intermediate
964 
965   Notes:
966   The matrix will again delete the hash table data structures after following calls to `MatAssemblyBegin()`/`MatAssemblyEnd()` with `MAT_FINAL_ASSEMBLY`.
967 
968   Currently only supported for `MATAIJ` matrices.
969 
970 .seealso: [](ch_matrices), `Mat`, `MatResetPreallocation()`
971 @*/
972 PetscErrorCode MatResetHash(Mat A)
973 {
974   PetscFunctionBegin;
975   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
976   PetscValidType(A, 1);
977   PetscCheck(A->insertmode == NOT_SET_VALUES, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot reset to hash state after setting some values but not yet calling MatAssemblyBegin()/MatAssemblyEnd()");
978   if (A->num_ass == 0) PetscFunctionReturn(PETSC_SUCCESS);
979   PetscUseMethod(A, "MatResetHash_C", (Mat), (A));
980   /* These flags are used to determine whether certain setups occur */
981   A->was_assembled = PETSC_FALSE;
982   A->assembled     = PETSC_FALSE;
983   /* Log that the state of this object has changed; this will help guarantee that preconditioners get re-setup */
984   PetscCall(PetscObjectStateIncrease((PetscObject)A));
985   PetscFunctionReturn(PETSC_SUCCESS);
986 }
987 
988 /*@
989   MatSetUp - Sets up the internal matrix data structures for later use by the matrix
990 
991   Collective
992 
993   Input Parameter:
994 . A - the matrix
995 
996   Level: advanced
997 
998   Notes:
999   If the user has not set preallocation for this matrix then an efficient algorithm will be used for the first round of
1000   setting values in the matrix.
1001 
1002   This routine is called internally by other `Mat` functions when needed so rarely needs to be called by users
1003 
1004 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatCreate()`, `MatDestroy()`, `MatXAIJSetPreallocation()`
1005 @*/
1006 PetscErrorCode MatSetUp(Mat A)
1007 {
1008   PetscFunctionBegin;
1009   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1010   if (!((PetscObject)A)->type_name) {
1011     PetscMPIInt size;
1012 
1013     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
1014     PetscCall(MatSetType(A, size == 1 ? MATSEQAIJ : MATMPIAIJ));
1015   }
1016   if (!A->preallocated) PetscTryTypeMethod(A, setup);
1017   PetscCall(PetscLayoutSetUp(A->rmap));
1018   PetscCall(PetscLayoutSetUp(A->cmap));
1019   A->preallocated = PETSC_TRUE;
1020   PetscFunctionReturn(PETSC_SUCCESS);
1021 }
1022 
1023 #if defined(PETSC_HAVE_SAWS)
1024   #include <petscviewersaws.h>
1025 #endif
1026 
1027 /*
1028    If threadsafety is on extraneous matrices may be printed
1029 
1030    This flag cannot be stored in the matrix because the original matrix in MatView() may assemble a new matrix which is passed into MatViewFromOptions()
1031 */
1032 #if !defined(PETSC_HAVE_THREADSAFETY)
1033 static PetscInt insidematview = 0;
1034 #endif
1035 
1036 /*@
1037   MatViewFromOptions - View properties of the matrix based on options set in the options database
1038 
1039   Collective
1040 
1041   Input Parameters:
1042 + A    - the matrix
1043 . obj  - optional additional object that provides the options prefix to use
1044 - name - command line option
1045 
1046   Options Database Key:
1047 . -mat_view [viewertype]:... - the viewer and its options
1048 
1049   Level: intermediate
1050 
1051   Note:
1052 .vb
1053     If no value is provided ascii:stdout is used
1054        ascii[:[filename][:[format][:append]]]    defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab,
1055                                                   for example ascii::ascii_info prints just the information about the object not all details
1056                                                   unless :append is given filename opens in write mode, overwriting what was already there
1057        binary[:[filename][:[format][:append]]]   defaults to the file binaryoutput
1058        draw[:drawtype[:filename]]                for example, draw:tikz, draw:tikz:figure.tex  or draw:x
1059        socket[:port]                             defaults to the standard output port
1060        saws[:communicatorname]                    publishes object to the Scientific Application Webserver (SAWs)
1061 .ve
1062 
1063 .seealso: [](ch_matrices), `Mat`, `MatView()`, `PetscObjectViewFromOptions()`, `MatCreate()`
1064 @*/
1065 PetscErrorCode MatViewFromOptions(Mat A, PetscObject obj, const char name[])
1066 {
1067   PetscFunctionBegin;
1068   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1069 #if !defined(PETSC_HAVE_THREADSAFETY)
1070   if (insidematview) PetscFunctionReturn(PETSC_SUCCESS);
1071 #endif
1072   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
1073   PetscFunctionReturn(PETSC_SUCCESS);
1074 }
1075 
1076 /*@
1077   MatView - display information about a matrix in a variety ways
1078 
1079   Collective on viewer
1080 
1081   Input Parameters:
1082 + mat    - the matrix
1083 - viewer - visualization context
1084 
1085   Options Database Keys:
1086 + -mat_view ::ascii_info           - Prints info on matrix at conclusion of `MatAssemblyEnd()`
1087 . -mat_view ::ascii_info_detail    - Prints more detailed info
1088 . -mat_view                        - Prints matrix in ASCII format
1089 . -mat_view ::ascii_matlab         - Prints matrix in MATLAB format
1090 . -mat_view draw                   - PetscDraws nonzero structure of matrix, using `MatView()` and `PetscDrawOpenX()`.
1091 . -display <name>                  - Sets display name (default is host)
1092 . -draw_pause <sec>                - Sets number of seconds to pause after display
1093 . -mat_view socket                 - Sends matrix to socket, can be accessed from MATLAB (see Users-Manual: ch_matlab for details)
1094 . -viewer_socket_machine <machine> - -
1095 . -viewer_socket_port <port>       - -
1096 . -mat_view binary                 - save matrix to file in binary format
1097 - -viewer_binary_filename <name>   - -
1098 
1099   Level: beginner
1100 
1101   Notes:
1102   The available visualization contexts include
1103 +    `PETSC_VIEWER_STDOUT_SELF`   - for sequential matrices
1104 .    `PETSC_VIEWER_STDOUT_WORLD`  - for parallel matrices created on `PETSC_COMM_WORLD`
1105 .    `PETSC_VIEWER_STDOUT_`(comm) - for matrices created on MPI communicator comm
1106 -     `PETSC_VIEWER_DRAW_WORLD`   - graphical display of nonzero structure
1107 
1108   The user can open alternative visualization contexts with
1109 +    `PetscViewerASCIIOpen()`  - Outputs matrix to a specified file
1110 .    `PetscViewerBinaryOpen()` - Outputs matrix in binary to a  specified file; corresponding input uses `MatLoad()`
1111 .    `PetscViewerDrawOpen()`   - Outputs nonzero matrix nonzero structure to an X window display
1112 -    `PetscViewerSocketOpen()` - Outputs matrix to Socket viewer, `PETSCVIEWERSOCKET`. Only the `MATSEQDENSE` and `MATAIJ` types support this viewer.
1113 
1114   The user can call `PetscViewerPushFormat()` to specify the output
1115   format of ASCII printed objects (when using `PETSC_VIEWER_STDOUT_SELF`,
1116   `PETSC_VIEWER_STDOUT_WORLD` and `PetscViewerASCIIOpen()`).  Available formats include
1117 +    `PETSC_VIEWER_DEFAULT`           - default, prints matrix contents
1118 .    `PETSC_VIEWER_ASCII_MATLAB`      - prints matrix contents in MATLAB format
1119 .    `PETSC_VIEWER_ASCII_DENSE`       - prints entire matrix including zeros
1120 .    `PETSC_VIEWER_ASCII_COMMON`      - prints matrix contents, using a sparse  format common among all matrix types
1121 .    `PETSC_VIEWER_ASCII_IMPL`        - prints matrix contents, using an implementation-specific format (which is in many cases the same as the default)
1122 .    `PETSC_VIEWER_ASCII_INFO`        - prints basic information about the matrix size and structure (not the matrix entries)
1123 -    `PETSC_VIEWER_ASCII_INFO_DETAIL` - prints more detailed information about the matrix nonzero structure (still not vector or matrix entries)
1124 
1125   The ASCII viewers are only recommended for small matrices on at most a moderate number of processes,
1126   the program will seemingly hang and take hours for larger matrices, for larger matrices one should use the binary format.
1127 
1128   In the debugger you can do "call MatView(mat,0)" to display the matrix. (The same holds for any PETSc object viewer).
1129 
1130   See the manual page for `MatLoad()` for the exact format of the binary file when the binary
1131   viewer is used.
1132 
1133   See share/petsc/matlab/PetscBinaryRead.m for a MATLAB code that can read in the binary file when the binary
1134   viewer is used and lib/petsc/bin/PetscBinaryIO.py for loading them into Python.
1135 
1136   One can use '-mat_view draw -draw_pause -1' to pause the graphical display of matrix nonzero structure,
1137   and then use the following mouse functions.
1138 .vb
1139   left mouse: zoom in
1140   middle mouse: zoom out
1141   right mouse: continue with the simulation
1142 .ve
1143 
1144 .seealso: [](ch_matrices), `Mat`, `PetscViewerPushFormat()`, `PetscViewerASCIIOpen()`, `PetscViewerDrawOpen()`, `PetscViewer`,
1145           `PetscViewerSocketOpen()`, `PetscViewerBinaryOpen()`, `MatLoad()`, `MatViewFromOptions()`
1146 @*/
1147 PetscErrorCode MatView(Mat mat, PetscViewer viewer)
1148 {
1149   PetscInt          rows, cols, rbs, cbs;
1150   PetscBool         isascii, isstring, issaws;
1151   PetscViewerFormat format;
1152   PetscMPIInt       size;
1153 
1154   PetscFunctionBegin;
1155   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1156   PetscValidType(mat, 1);
1157   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat), &viewer));
1158   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1159 
1160   PetscCall(PetscViewerGetFormat(viewer, &format));
1161   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
1162   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
1163 
1164 #if !defined(PETSC_HAVE_THREADSAFETY)
1165   insidematview++;
1166 #endif
1167   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
1168   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1169   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
1170   PetscCheck((isascii && (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL)) || !mat->factortype, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_WRONGSTATE, "No viewers for factored matrix except ASCII, info, or info_detail");
1171 
1172   PetscCall(PetscLogEventBegin(MAT_View, mat, viewer, 0, 0));
1173   if (isascii) {
1174     if (!mat->preallocated) {
1175       PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix has not been preallocated yet\n"));
1176 #if !defined(PETSC_HAVE_THREADSAFETY)
1177       insidematview--;
1178 #endif
1179       PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1180       PetscFunctionReturn(PETSC_SUCCESS);
1181     }
1182     if (!mat->assembled) {
1183       PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix has not been assembled yet\n"));
1184 #if !defined(PETSC_HAVE_THREADSAFETY)
1185       insidematview--;
1186 #endif
1187       PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1188       PetscFunctionReturn(PETSC_SUCCESS);
1189     }
1190     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)mat, viewer));
1191     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1192       MatNullSpace nullsp, transnullsp;
1193 
1194       PetscCall(PetscViewerASCIIPushTab(viewer));
1195       PetscCall(MatGetSize(mat, &rows, &cols));
1196       PetscCall(MatGetBlockSizes(mat, &rbs, &cbs));
1197       if (rbs != 1 || cbs != 1) {
1198         if (rbs != cbs) PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT ", rbs=%" PetscInt_FMT ", cbs=%" PetscInt_FMT "%s\n", rows, cols, rbs, cbs, mat->bsizes ? " variable blocks set" : ""));
1199         else PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT ", bs=%" PetscInt_FMT "%s\n", rows, cols, rbs, mat->bsizes ? " variable blocks set" : ""));
1200       } else PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", rows, cols));
1201       if (mat->factortype) {
1202         MatSolverType solver;
1203         PetscCall(MatFactorGetSolverType(mat, &solver));
1204         PetscCall(PetscViewerASCIIPrintf(viewer, "package used to perform factorization: %s\n", solver));
1205       }
1206       if (mat->ops->getinfo) {
1207         PetscBool is_constant_or_diagonal;
1208 
1209         // Don't print nonzero information for constant or diagonal matrices, it just adds noise to the output
1210         PetscCall(PetscObjectTypeCompareAny((PetscObject)mat, &is_constant_or_diagonal, MATCONSTANTDIAGONAL, MATDIAGONAL, ""));
1211         if (!is_constant_or_diagonal) {
1212           MatInfo info;
1213 
1214           PetscCall(MatGetInfo(mat, MAT_GLOBAL_SUM, &info));
1215           PetscCall(PetscViewerASCIIPrintf(viewer, "total: nonzeros=%.f, allocated nonzeros=%.f\n", info.nz_used, info.nz_allocated));
1216           if (!mat->factortype) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of mallocs used during MatSetValues calls=%" PetscInt_FMT "\n", (PetscInt)info.mallocs));
1217         }
1218       }
1219       PetscCall(MatGetNullSpace(mat, &nullsp));
1220       PetscCall(MatGetTransposeNullSpace(mat, &transnullsp));
1221       if (nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached null space\n"));
1222       if (transnullsp && transnullsp != nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached transposed null space\n"));
1223       PetscCall(MatGetNearNullSpace(mat, &nullsp));
1224       if (nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached near null space\n"));
1225       PetscCall(PetscViewerASCIIPushTab(viewer));
1226       PetscCall(MatProductView(mat, viewer));
1227       PetscCall(PetscViewerASCIIPopTab(viewer));
1228       if (mat->bsizes && format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1229         IS tmp;
1230 
1231         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), mat->nblocks, mat->bsizes, PETSC_USE_POINTER, &tmp));
1232         PetscCall(PetscObjectSetName((PetscObject)tmp, "Block Sizes"));
1233         PetscCall(PetscViewerASCIIPushTab(viewer));
1234         PetscCall(ISView(tmp, viewer));
1235         PetscCall(PetscViewerASCIIPopTab(viewer));
1236         PetscCall(ISDestroy(&tmp));
1237       }
1238     }
1239   } else if (issaws) {
1240 #if defined(PETSC_HAVE_SAWS)
1241     PetscMPIInt rank;
1242 
1243     PetscCall(PetscObjectName((PetscObject)mat));
1244     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1245     if (!((PetscObject)mat)->amsmem && rank == 0) PetscCall(PetscObjectViewSAWs((PetscObject)mat, viewer));
1246 #endif
1247   } else if (isstring) {
1248     const char *type;
1249     PetscCall(MatGetType(mat, &type));
1250     PetscCall(PetscViewerStringSPrintf(viewer, " MatType: %-7.7s", type));
1251     PetscTryTypeMethod(mat, view, viewer);
1252   }
1253   if ((format == PETSC_VIEWER_NATIVE || format == PETSC_VIEWER_LOAD_BALANCE) && mat->ops->viewnative) {
1254     PetscCall(PetscViewerASCIIPushTab(viewer));
1255     PetscUseTypeMethod(mat, viewnative, viewer);
1256     PetscCall(PetscViewerASCIIPopTab(viewer));
1257   } else if (mat->ops->view) {
1258     PetscCall(PetscViewerASCIIPushTab(viewer));
1259     PetscUseTypeMethod(mat, view, viewer);
1260     PetscCall(PetscViewerASCIIPopTab(viewer));
1261   }
1262   if (isascii) {
1263     PetscCall(PetscViewerGetFormat(viewer, &format));
1264     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscCall(PetscViewerASCIIPopTab(viewer));
1265   }
1266   PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1267 #if !defined(PETSC_HAVE_THREADSAFETY)
1268   insidematview--;
1269 #endif
1270   PetscFunctionReturn(PETSC_SUCCESS);
1271 }
1272 
1273 #if defined(PETSC_USE_DEBUG)
1274   #include <../src/sys/totalview/tv_data_display.h>
1275 PETSC_UNUSED static int TV_display_type(const struct _p_Mat *mat)
1276 {
1277   TV_add_row("Local rows", "int", &mat->rmap->n);
1278   TV_add_row("Local columns", "int", &mat->cmap->n);
1279   TV_add_row("Global rows", "int", &mat->rmap->N);
1280   TV_add_row("Global columns", "int", &mat->cmap->N);
1281   TV_add_row("Typename", TV_ascii_string_type, ((PetscObject)mat)->type_name);
1282   return TV_format_OK;
1283 }
1284 #endif
1285 
1286 /*@
1287   MatLoad - Loads a matrix that has been stored in binary/HDF5 format
1288   with `MatView()`.  The matrix format is determined from the options database.
1289   Generates a parallel MPI matrix if the communicator has more than one
1290   processor.  The default matrix type is `MATAIJ`.
1291 
1292   Collective
1293 
1294   Input Parameters:
1295 + mat    - the newly loaded matrix, this needs to have been created with `MatCreate()`
1296             or some related function before a call to `MatLoad()`
1297 - viewer - `PETSCVIEWERBINARY`/`PETSCVIEWERHDF5` file viewer
1298 
1299   Options Database Key:
1300 . -matload_block_size <bs> - set block size
1301 
1302   Level: beginner
1303 
1304   Notes:
1305   If the `Mat` type has not yet been given then `MATAIJ` is used, call `MatSetFromOptions()` on the
1306   `Mat` before calling this routine if you wish to set it from the options database.
1307 
1308   `MatLoad()` automatically loads into the options database any options
1309   given in the file filename.info where filename is the name of the file
1310   that was passed to the `PetscViewerBinaryOpen()`. The options in the info
1311   file will be ignored if you use the -viewer_binary_skip_info option.
1312 
1313   If the type or size of mat is not set before a call to `MatLoad()`, PETSc
1314   sets the default matrix type AIJ and sets the local and global sizes.
1315   If type and/or size is already set, then the same are used.
1316 
1317   In parallel, each processor can load a subset of rows (or the
1318   entire matrix).  This routine is especially useful when a large
1319   matrix is stored on disk and only part of it is desired on each
1320   processor.  For example, a parallel solver may access only some of
1321   the rows from each processor.  The algorithm used here reads
1322   relatively small blocks of data rather than reading the entire
1323   matrix and then subsetting it.
1324 
1325   Viewer's `PetscViewerType` must be either `PETSCVIEWERBINARY` or `PETSCVIEWERHDF5`.
1326   Such viewer can be created using `PetscViewerBinaryOpen()` or `PetscViewerHDF5Open()`,
1327   or the sequence like
1328 .vb
1329     `PetscViewer` v;
1330     `PetscViewerCreate`(`PETSC_COMM_WORLD`,&v);
1331     `PetscViewerSetType`(v,`PETSCVIEWERBINARY`);
1332     `PetscViewerSetFromOptions`(v);
1333     `PetscViewerFileSetMode`(v,`FILE_MODE_READ`);
1334     `PetscViewerFileSetName`(v,"datafile");
1335 .ve
1336   The optional `PetscViewerSetFromOptions()` call allows overriding `PetscViewerSetType()` using the option
1337 .vb
1338   -viewer_type {binary, hdf5}
1339 .ve
1340 
1341   See the example src/ksp/ksp/tutorials/ex27.c with the first approach,
1342   and src/mat/tutorials/ex10.c with the second approach.
1343 
1344   In case of `PETSCVIEWERBINARY`, a native PETSc binary format is used. Each of the blocks
1345   is read onto MPI rank 0 and then shipped to its destination MPI rank, one after another.
1346   Multiple objects, both matrices and vectors, can be stored within the same file.
1347   Their `PetscObject` name is ignored; they are loaded in the order of their storage.
1348 
1349   Most users should not need to know the details of the binary storage
1350   format, since `MatLoad()` and `MatView()` completely hide these details.
1351   But for anyone who is interested, the standard binary matrix storage
1352   format is
1353 
1354 .vb
1355     PetscInt    MAT_FILE_CLASSID
1356     PetscInt    number of rows
1357     PetscInt    number of columns
1358     PetscInt    total number of nonzeros
1359     PetscInt    *number nonzeros in each row
1360     PetscInt    *column indices of all nonzeros (starting index is zero)
1361     PetscScalar *values of all nonzeros
1362 .ve
1363   If PETSc was not configured with `--with-64-bit-indices` then only `MATMPIAIJ` matrices with more than `PETSC_INT_MAX` non-zeros can be
1364   stored or loaded (each MPI process part of the matrix must have less than `PETSC_INT_MAX` nonzeros). Since the total nonzero count in this
1365   case will not fit in a (32-bit) `PetscInt` the value `PETSC_INT_MAX` is used for the header entry `total number of nonzeros`.
1366 
1367   PETSc automatically does the byte swapping for
1368   machines that store the bytes reversed. Thus if you write your own binary
1369   read/write routines you have to swap the bytes; see `PetscBinaryRead()`
1370   and `PetscBinaryWrite()` to see how this may be done.
1371 
1372   In case of `PETSCVIEWERHDF5`, a parallel HDF5 reader is used.
1373   Each processor's chunk is loaded independently by its owning MPI process.
1374   Multiple objects, both matrices and vectors, can be stored within the same file.
1375   They are looked up by their PetscObject name.
1376 
1377   As the MATLAB MAT-File Version 7.3 format is also a HDF5 flavor, we decided to use
1378   by default the same structure and naming of the AIJ arrays and column count
1379   within the HDF5 file. This means that a MAT file saved with -v7.3 flag, e.g.
1380 .vb
1381   save example.mat A b -v7.3
1382 .ve
1383   can be directly read by this routine (see Reference 1 for details).
1384 
1385   Depending on your MATLAB version, this format might be a default,
1386   otherwise you can set it as default in Preferences.
1387 
1388   Unless -nocompression flag is used to save the file in MATLAB,
1389   PETSc must be configured with ZLIB package.
1390 
1391   See also examples src/mat/tutorials/ex10.c and src/ksp/ksp/tutorials/ex27.c
1392 
1393   This reader currently supports only real `MATSEQAIJ`, `MATMPIAIJ`, `MATSEQDENSE` and `MATMPIDENSE` matrices for `PETSCVIEWERHDF5`
1394 
1395   Corresponding `MatView()` is not yet implemented.
1396 
1397   The loaded matrix is actually a transpose of the original one in MATLAB,
1398   unless you push `PETSC_VIEWER_HDF5_MAT` format (see examples above).
1399   With this format, matrix is automatically transposed by PETSc,
1400   unless the matrix is marked as SPD or symmetric
1401   (see `MatSetOption()`, `MAT_SPD`, `MAT_SYMMETRIC`).
1402 
1403   See MATLAB Documentation on `save()`, <https://www.mathworks.com/help/matlab/ref/save.html#btox10b-1-version>
1404 
1405 .seealso: [](ch_matrices), `Mat`, `PetscViewerBinaryOpen()`, `PetscViewerSetType()`, `MatView()`, `VecLoad()`
1406  @*/
1407 PetscErrorCode MatLoad(Mat mat, PetscViewer viewer)
1408 {
1409   PetscBool flg;
1410 
1411   PetscFunctionBegin;
1412   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1413   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1414 
1415   if (!((PetscObject)mat)->type_name) PetscCall(MatSetType(mat, MATAIJ));
1416 
1417   flg = PETSC_FALSE;
1418   PetscCall(PetscOptionsGetBool(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matload_symmetric", &flg, NULL));
1419   if (flg) {
1420     PetscCall(MatSetOption(mat, MAT_SYMMETRIC, PETSC_TRUE));
1421     PetscCall(MatSetOption(mat, MAT_SYMMETRY_ETERNAL, PETSC_TRUE));
1422   }
1423   flg = PETSC_FALSE;
1424   PetscCall(PetscOptionsGetBool(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matload_spd", &flg, NULL));
1425   if (flg) PetscCall(MatSetOption(mat, MAT_SPD, PETSC_TRUE));
1426 
1427   PetscCall(PetscLogEventBegin(MAT_Load, mat, viewer, 0, 0));
1428   PetscUseTypeMethod(mat, load, viewer);
1429   PetscCall(PetscLogEventEnd(MAT_Load, mat, viewer, 0, 0));
1430   PetscFunctionReturn(PETSC_SUCCESS);
1431 }
1432 
1433 static PetscErrorCode MatDestroy_Redundant(Mat_Redundant **redundant)
1434 {
1435   Mat_Redundant *redund = *redundant;
1436 
1437   PetscFunctionBegin;
1438   if (redund) {
1439     if (redund->matseq) { /* via MatCreateSubMatrices()  */
1440       PetscCall(ISDestroy(&redund->isrow));
1441       PetscCall(ISDestroy(&redund->iscol));
1442       PetscCall(MatDestroySubMatrices(1, &redund->matseq));
1443     } else {
1444       PetscCall(PetscFree2(redund->send_rank, redund->recv_rank));
1445       PetscCall(PetscFree(redund->sbuf_j));
1446       PetscCall(PetscFree(redund->sbuf_a));
1447       for (PetscInt i = 0; i < redund->nrecvs; i++) {
1448         PetscCall(PetscFree(redund->rbuf_j[i]));
1449         PetscCall(PetscFree(redund->rbuf_a[i]));
1450       }
1451       PetscCall(PetscFree4(redund->sbuf_nz, redund->rbuf_nz, redund->rbuf_j, redund->rbuf_a));
1452     }
1453 
1454     if (redund->subcomm) PetscCall(PetscCommDestroy(&redund->subcomm));
1455     PetscCall(PetscFree(redund));
1456   }
1457   PetscFunctionReturn(PETSC_SUCCESS);
1458 }
1459 
1460 /*@
1461   MatDestroy - Frees space taken by a matrix.
1462 
1463   Collective
1464 
1465   Input Parameter:
1466 . A - the matrix
1467 
1468   Level: beginner
1469 
1470   Developer Note:
1471   Some special arrays of matrices are not destroyed in this routine but instead by the routines called by
1472   `MatDestroySubMatrices()`. Thus one must be sure that any changes here must also be made in those routines.
1473   `MatHeaderMerge()` and `MatHeaderReplace()` also manipulate the data in the `Mat` object and likely need changes
1474   if changes are needed here.
1475 
1476 .seealso: [](ch_matrices), `Mat`, `MatCreate()`
1477 @*/
1478 PetscErrorCode MatDestroy(Mat *A)
1479 {
1480   PetscFunctionBegin;
1481   if (!*A) PetscFunctionReturn(PETSC_SUCCESS);
1482   PetscValidHeaderSpecific(*A, MAT_CLASSID, 1);
1483   if (--((PetscObject)*A)->refct > 0) {
1484     *A = NULL;
1485     PetscFunctionReturn(PETSC_SUCCESS);
1486   }
1487 
1488   /* if memory was published with SAWs then destroy it */
1489   PetscCall(PetscObjectSAWsViewOff((PetscObject)*A));
1490   PetscTryTypeMethod(*A, destroy);
1491 
1492   PetscCall(PetscFree((*A)->factorprefix));
1493   PetscCall(PetscFree((*A)->defaultvectype));
1494   PetscCall(PetscFree((*A)->defaultrandtype));
1495   PetscCall(PetscFree((*A)->bsizes));
1496   PetscCall(PetscFree((*A)->solvertype));
1497   for (PetscInt i = 0; i < MAT_FACTOR_NUM_TYPES; i++) PetscCall(PetscFree((*A)->preferredordering[i]));
1498   if ((*A)->redundant && (*A)->redundant->matseq[0] == *A) (*A)->redundant->matseq[0] = NULL;
1499   PetscCall(MatDestroy_Redundant(&(*A)->redundant));
1500   PetscCall(MatProductClear(*A));
1501   PetscCall(MatNullSpaceDestroy(&(*A)->nullsp));
1502   PetscCall(MatNullSpaceDestroy(&(*A)->transnullsp));
1503   PetscCall(MatNullSpaceDestroy(&(*A)->nearnullsp));
1504   PetscCall(MatDestroy(&(*A)->schur));
1505   PetscCall(PetscLayoutDestroy(&(*A)->rmap));
1506   PetscCall(PetscLayoutDestroy(&(*A)->cmap));
1507   PetscCall(PetscHeaderDestroy(A));
1508   PetscFunctionReturn(PETSC_SUCCESS);
1509 }
1510 
1511 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1512 /*@
1513   MatSetValues - Inserts or adds a block of values into a matrix.
1514   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
1515   MUST be called after all calls to `MatSetValues()` have been completed.
1516 
1517   Not Collective
1518 
1519   Input Parameters:
1520 + mat  - the matrix
1521 . v    - a logically two-dimensional array of values
1522 . m    - the number of rows
1523 . idxm - the global indices of the rows
1524 . n    - the number of columns
1525 . idxn - the global indices of the columns
1526 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
1527 
1528   Level: beginner
1529 
1530   Notes:
1531   By default the values, `v`, are stored row-oriented. See `MatSetOption()` for other options.
1532 
1533   Calls to `MatSetValues()` with the `INSERT_VALUES` and `ADD_VALUES`
1534   options cannot be mixed without intervening calls to the assembly
1535   routines.
1536 
1537   `MatSetValues()` uses 0-based row and column numbers in Fortran
1538   as well as in C.
1539 
1540   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
1541   simply ignored. This allows easily inserting element stiffness matrices
1542   with homogeneous Dirichlet boundary conditions that you don't want represented
1543   in the matrix.
1544 
1545   Efficiency Alert:
1546   The routine `MatSetValuesBlocked()` may offer much better efficiency
1547   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1548 
1549   Fortran Notes:
1550   If any of `idxm`, `idxn`, and `v` are scalars pass them using, for example,
1551 .vb
1552   call MatSetValues(mat, one, [idxm], one, [idxn], [v], INSERT_VALUES, ierr)
1553 .ve
1554 
1555   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
1556 
1557   Developer Note:
1558   This is labeled with C so does not automatically generate Fortran stubs and interfaces
1559   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
1560 
1561 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1562           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1563 @*/
1564 PetscErrorCode MatSetValues(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar v[], InsertMode addv)
1565 {
1566   PetscFunctionBeginHot;
1567   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1568   PetscValidType(mat, 1);
1569   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1570   PetscAssertPointer(idxm, 3);
1571   PetscAssertPointer(idxn, 5);
1572   MatCheckPreallocated(mat, 1);
1573 
1574   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
1575   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
1576 
1577   if (PetscDefined(USE_DEBUG)) {
1578     PetscInt i, j;
1579 
1580     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1581     if (v) {
1582       for (i = 0; i < m; i++) {
1583         for (j = 0; j < n; j++) {
1584           if (mat->erroriffailure && PetscIsInfOrNanScalar(v[i * n + j]))
1585 #if defined(PETSC_USE_COMPLEX)
1586             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Inserting %g+i%g at matrix entry (%" PetscInt_FMT ",%" PetscInt_FMT ")", (double)PetscRealPart(v[i * n + j]), (double)PetscImaginaryPart(v[i * n + j]), idxm[i], idxn[j]);
1587 #else
1588             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Inserting %g at matrix entry (%" PetscInt_FMT ",%" PetscInt_FMT ")", (double)v[i * n + j], idxm[i], idxn[j]);
1589 #endif
1590         }
1591       }
1592     }
1593     for (i = 0; i < m; i++) PetscCheck(idxm[i] < mat->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot insert in row %" PetscInt_FMT ", maximum is %" PetscInt_FMT, idxm[i], mat->rmap->N - 1);
1594     for (i = 0; i < n; i++) PetscCheck(idxn[i] < mat->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot insert in column %" PetscInt_FMT ", maximum is %" PetscInt_FMT, idxn[i], mat->cmap->N - 1);
1595   }
1596 
1597   if (mat->assembled) {
1598     mat->was_assembled = PETSC_TRUE;
1599     mat->assembled     = PETSC_FALSE;
1600   }
1601   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
1602   PetscUseTypeMethod(mat, setvalues, m, idxm, n, idxn, v, addv);
1603   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
1604   PetscFunctionReturn(PETSC_SUCCESS);
1605 }
1606 
1607 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1608 /*@
1609   MatSetValuesIS - Inserts or adds a block of values into a matrix using an `IS` to indicate the rows and columns
1610   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
1611   MUST be called after all calls to `MatSetValues()` have been completed.
1612 
1613   Not Collective
1614 
1615   Input Parameters:
1616 + mat  - the matrix
1617 . v    - a logically two-dimensional array of values
1618 . ism  - the rows to provide
1619 . isn  - the columns to provide
1620 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
1621 
1622   Level: beginner
1623 
1624   Notes:
1625   By default the values, `v`, are stored row-oriented. See `MatSetOption()` for other options.
1626 
1627   Calls to `MatSetValues()` with the `INSERT_VALUES` and `ADD_VALUES`
1628   options cannot be mixed without intervening calls to the assembly
1629   routines.
1630 
1631   `MatSetValues()` uses 0-based row and column numbers in Fortran
1632   as well as in C.
1633 
1634   Negative indices may be passed in `ism` and `isn`, these rows and columns are
1635   simply ignored. This allows easily inserting element stiffness matrices
1636   with homogeneous Dirichlet boundary conditions that you don't want represented
1637   in the matrix.
1638 
1639   Efficiency Alert:
1640   The routine `MatSetValuesBlocked()` may offer much better efficiency
1641   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1642 
1643   This is currently not optimized for any particular `ISType`
1644 
1645 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatSetValues()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1646           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1647 @*/
1648 PetscErrorCode MatSetValuesIS(Mat mat, IS ism, IS isn, const PetscScalar v[], InsertMode addv)
1649 {
1650   PetscInt        m, n;
1651   const PetscInt *rows, *cols;
1652 
1653   PetscFunctionBeginHot;
1654   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1655   PetscCall(ISGetIndices(ism, &rows));
1656   PetscCall(ISGetIndices(isn, &cols));
1657   PetscCall(ISGetLocalSize(ism, &m));
1658   PetscCall(ISGetLocalSize(isn, &n));
1659   PetscCall(MatSetValues(mat, m, rows, n, cols, v, addv));
1660   PetscCall(ISRestoreIndices(ism, &rows));
1661   PetscCall(ISRestoreIndices(isn, &cols));
1662   PetscFunctionReturn(PETSC_SUCCESS);
1663 }
1664 
1665 /*@
1666   MatSetValuesRowLocal - Inserts a row (block row for `MATBAIJ` matrices) of nonzero
1667   values into a matrix
1668 
1669   Not Collective
1670 
1671   Input Parameters:
1672 + mat - the matrix
1673 . row - the (block) row to set
1674 - v   - a logically two-dimensional array of values
1675 
1676   Level: intermediate
1677 
1678   Notes:
1679   The values, `v`, are column-oriented (for the block version) and sorted
1680 
1681   All the nonzero values in `row` must be provided
1682 
1683   The matrix must have previously had its column indices set, likely by having been assembled.
1684 
1685   `row` must belong to this MPI process
1686 
1687 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1688           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`, `MatSetValues()`, `MatSetValuesRow()`, `MatSetLocalToGlobalMapping()`
1689 @*/
1690 PetscErrorCode MatSetValuesRowLocal(Mat mat, PetscInt row, const PetscScalar v[])
1691 {
1692   PetscInt globalrow;
1693 
1694   PetscFunctionBegin;
1695   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1696   PetscValidType(mat, 1);
1697   PetscAssertPointer(v, 3);
1698   PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, 1, &row, &globalrow));
1699   PetscCall(MatSetValuesRow(mat, globalrow, v));
1700   PetscFunctionReturn(PETSC_SUCCESS);
1701 }
1702 
1703 /*@
1704   MatSetValuesRow - Inserts a row (block row for `MATBAIJ` matrices) of nonzero
1705   values into a matrix
1706 
1707   Not Collective
1708 
1709   Input Parameters:
1710 + mat - the matrix
1711 . row - the (block) row to set
1712 - v   - a logically two-dimensional (column major) array of values for  block matrices with blocksize larger than one, otherwise a one dimensional array of values
1713 
1714   Level: advanced
1715 
1716   Notes:
1717   The values, `v`, are column-oriented for the block version.
1718 
1719   All the nonzeros in `row` must be provided
1720 
1721   THE MATRIX MUST HAVE PREVIOUSLY HAD ITS COLUMN INDICES SET. IT IS RARE THAT THIS ROUTINE IS USED, usually `MatSetValues()` is used.
1722 
1723   `row` must belong to this process
1724 
1725 .seealso: [](ch_matrices), `Mat`, `MatSetValues()`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1726           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1727 @*/
1728 PetscErrorCode MatSetValuesRow(Mat mat, PetscInt row, const PetscScalar v[])
1729 {
1730   PetscFunctionBeginHot;
1731   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1732   PetscValidType(mat, 1);
1733   MatCheckPreallocated(mat, 1);
1734   PetscAssertPointer(v, 3);
1735   PetscCheck(mat->insertmode != ADD_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add and insert values");
1736   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1737   mat->insertmode = INSERT_VALUES;
1738 
1739   if (mat->assembled) {
1740     mat->was_assembled = PETSC_TRUE;
1741     mat->assembled     = PETSC_FALSE;
1742   }
1743   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
1744   PetscUseTypeMethod(mat, setvaluesrow, row, v);
1745   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
1746   PetscFunctionReturn(PETSC_SUCCESS);
1747 }
1748 
1749 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1750 /*@
1751   MatSetValuesStencil - Inserts or adds a block of values into a matrix.
1752   Using structured grid indexing
1753 
1754   Not Collective
1755 
1756   Input Parameters:
1757 + mat  - the matrix
1758 . m    - number of rows being entered
1759 . idxm - grid coordinates (and component number when dof > 1) for matrix rows being entered
1760 . n    - number of columns being entered
1761 . idxn - grid coordinates (and component number when dof > 1) for matrix columns being entered
1762 . v    - a logically two-dimensional array of values
1763 - addv - either `ADD_VALUES` to add to existing entries at that location or `INSERT_VALUES` to replace existing entries with new values
1764 
1765   Level: beginner
1766 
1767   Notes:
1768   By default the values, `v`, are row-oriented.  See `MatSetOption()` for other options.
1769 
1770   Calls to `MatSetValuesStencil()` with the `INSERT_VALUES` and `ADD_VALUES`
1771   options cannot be mixed without intervening calls to the assembly
1772   routines.
1773 
1774   The grid coordinates are across the entire grid, not just the local portion
1775 
1776   `MatSetValuesStencil()` uses 0-based row and column numbers in Fortran
1777   as well as in C.
1778 
1779   For setting/accessing vector values via array coordinates you can use the `DMDAVecGetArray()` routine
1780 
1781   In order to use this routine you must either obtain the matrix with `DMCreateMatrix()`
1782   or call `MatSetLocalToGlobalMapping()` and `MatSetStencil()` first.
1783 
1784   The columns and rows in the stencil passed in MUST be contained within the
1785   ghost region of the given process as set with DMDACreateXXX() or `MatSetStencil()`. For example,
1786   if you create a `DMDA` with an overlap of one grid level and on a particular process its first
1787   local nonghost x logical coordinate is 6 (so its first ghost x logical coordinate is 5) the
1788   first i index you can use in your column and row indices in `MatSetStencil()` is 5.
1789 
1790   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
1791   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
1792   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
1793   `DM_BOUNDARY_PERIODIC` boundary type.
1794 
1795   For indices that don't mean anything for your case (like the k index when working in 2d) or the c index when you have
1796   a single value per point) you can skip filling those indices.
1797 
1798   Inspired by the structured grid interface to the HYPRE package
1799   (https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods)
1800 
1801   Efficiency Alert:
1802   The routine `MatSetValuesBlockedStencil()` may offer much better efficiency
1803   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1804 
1805 .seealso: [](ch_matrices), `Mat`, `DMDA`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1806           `MatSetValues()`, `MatSetValuesBlockedStencil()`, `MatSetStencil()`, `DMCreateMatrix()`, `DMDAVecGetArray()`, `MatStencil`
1807 @*/
1808 PetscErrorCode MatSetValuesStencil(Mat mat, PetscInt m, const MatStencil idxm[], PetscInt n, const MatStencil idxn[], const PetscScalar v[], InsertMode addv)
1809 {
1810   PetscInt  buf[8192], *bufm = NULL, *bufn = NULL, *jdxm, *jdxn;
1811   PetscInt  j, i, dim = mat->stencil.dim, *dims = mat->stencil.dims + 1, tmp;
1812   PetscInt *starts = mat->stencil.starts, *dxm = (PetscInt *)idxm, *dxn = (PetscInt *)idxn, sdim = dim - (1 - (PetscInt)mat->stencil.noc);
1813 
1814   PetscFunctionBegin;
1815   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1816   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1817   PetscValidType(mat, 1);
1818   PetscAssertPointer(idxm, 3);
1819   PetscAssertPointer(idxn, 5);
1820 
1821   if ((m + n) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
1822     jdxm = buf;
1823     jdxn = buf + m;
1824   } else {
1825     PetscCall(PetscMalloc2(m, &bufm, n, &bufn));
1826     jdxm = bufm;
1827     jdxn = bufn;
1828   }
1829   for (i = 0; i < m; i++) {
1830     for (j = 0; j < 3 - sdim; j++) dxm++;
1831     tmp = *dxm++ - starts[0];
1832     for (j = 0; j < dim - 1; j++) {
1833       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1834       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
1835     }
1836     if (mat->stencil.noc) dxm++;
1837     jdxm[i] = tmp;
1838   }
1839   for (i = 0; i < n; i++) {
1840     for (j = 0; j < 3 - sdim; j++) dxn++;
1841     tmp = *dxn++ - starts[0];
1842     for (j = 0; j < dim - 1; j++) {
1843       if ((*dxn++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1844       else tmp = tmp * dims[j] + *(dxn - 1) - starts[j + 1];
1845     }
1846     if (mat->stencil.noc) dxn++;
1847     jdxn[i] = tmp;
1848   }
1849   PetscCall(MatSetValuesLocal(mat, m, jdxm, n, jdxn, v, addv));
1850   PetscCall(PetscFree2(bufm, bufn));
1851   PetscFunctionReturn(PETSC_SUCCESS);
1852 }
1853 
1854 /*@
1855   MatSetValuesBlockedStencil - Inserts or adds a block of values into a matrix.
1856   Using structured grid indexing
1857 
1858   Not Collective
1859 
1860   Input Parameters:
1861 + mat  - the matrix
1862 . m    - number of rows being entered
1863 . idxm - grid coordinates for matrix rows being entered
1864 . n    - number of columns being entered
1865 . idxn - grid coordinates for matrix columns being entered
1866 . v    - a logically two-dimensional array of values
1867 - addv - either `ADD_VALUES` to add to existing entries or `INSERT_VALUES` to replace existing entries with new values
1868 
1869   Level: beginner
1870 
1871   Notes:
1872   By default the values, `v`, are row-oriented and unsorted.
1873   See `MatSetOption()` for other options.
1874 
1875   Calls to `MatSetValuesBlockedStencil()` with the `INSERT_VALUES` and `ADD_VALUES`
1876   options cannot be mixed without intervening calls to the assembly
1877   routines.
1878 
1879   The grid coordinates are across the entire grid, not just the local portion
1880 
1881   `MatSetValuesBlockedStencil()` uses 0-based row and column numbers in Fortran
1882   as well as in C.
1883 
1884   For setting/accessing vector values via array coordinates you can use the `DMDAVecGetArray()` routine
1885 
1886   In order to use this routine you must either obtain the matrix with `DMCreateMatrix()`
1887   or call `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()` and `MatSetStencil()` first.
1888 
1889   The columns and rows in the stencil passed in MUST be contained within the
1890   ghost region of the given process as set with DMDACreateXXX() or `MatSetStencil()`. For example,
1891   if you create a `DMDA` with an overlap of one grid level and on a particular process its first
1892   local nonghost x logical coordinate is 6 (so its first ghost x logical coordinate is 5) the
1893   first i index you can use in your column and row indices in `MatSetStencil()` is 5.
1894 
1895   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
1896   simply ignored. This allows easily inserting element stiffness matrices
1897   with homogeneous Dirichlet boundary conditions that you don't want represented
1898   in the matrix.
1899 
1900   Inspired by the structured grid interface to the HYPRE package
1901   (https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods)
1902 
1903   Fortran Note:
1904   `idxm` and `idxn` should be declared as
1905 .vb
1906     MatStencil idxm(4,m),idxn(4,n)
1907 .ve
1908   and the values inserted using
1909 .vb
1910     idxm(MatStencil_i,1) = i
1911     idxm(MatStencil_j,1) = j
1912     idxm(MatStencil_k,1) = k
1913    etc
1914 .ve
1915 
1916 .seealso: [](ch_matrices), `Mat`, `DMDA`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1917           `MatSetValues()`, `MatSetValuesStencil()`, `MatSetStencil()`, `DMCreateMatrix()`, `DMDAVecGetArray()`, `MatStencil`,
1918           `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()`
1919 @*/
1920 PetscErrorCode MatSetValuesBlockedStencil(Mat mat, PetscInt m, const MatStencil idxm[], PetscInt n, const MatStencil idxn[], const PetscScalar v[], InsertMode addv)
1921 {
1922   PetscInt  buf[8192], *bufm = NULL, *bufn = NULL, *jdxm, *jdxn;
1923   PetscInt  j, i, dim = mat->stencil.dim, *dims = mat->stencil.dims + 1, tmp;
1924   PetscInt *starts = mat->stencil.starts, *dxm = (PetscInt *)idxm, *dxn = (PetscInt *)idxn, sdim = dim - (1 - (PetscInt)mat->stencil.noc);
1925 
1926   PetscFunctionBegin;
1927   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1928   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1929   PetscValidType(mat, 1);
1930   PetscAssertPointer(idxm, 3);
1931   PetscAssertPointer(idxn, 5);
1932   PetscAssertPointer(v, 6);
1933 
1934   if ((m + n) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
1935     jdxm = buf;
1936     jdxn = buf + m;
1937   } else {
1938     PetscCall(PetscMalloc2(m, &bufm, n, &bufn));
1939     jdxm = bufm;
1940     jdxn = bufn;
1941   }
1942   for (i = 0; i < m; i++) {
1943     for (j = 0; j < 3 - sdim; j++) dxm++;
1944     tmp = *dxm++ - starts[0];
1945     for (j = 0; j < sdim - 1; j++) {
1946       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1947       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
1948     }
1949     dxm++;
1950     jdxm[i] = tmp;
1951   }
1952   for (i = 0; i < n; i++) {
1953     for (j = 0; j < 3 - sdim; j++) dxn++;
1954     tmp = *dxn++ - starts[0];
1955     for (j = 0; j < sdim - 1; j++) {
1956       if ((*dxn++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1957       else tmp = tmp * dims[j] + *(dxn - 1) - starts[j + 1];
1958     }
1959     dxn++;
1960     jdxn[i] = tmp;
1961   }
1962   PetscCall(MatSetValuesBlockedLocal(mat, m, jdxm, n, jdxn, v, addv));
1963   PetscCall(PetscFree2(bufm, bufn));
1964   PetscFunctionReturn(PETSC_SUCCESS);
1965 }
1966 
1967 /*@
1968   MatSetStencil - Sets the grid information for setting values into a matrix via
1969   `MatSetValuesStencil()`
1970 
1971   Not Collective
1972 
1973   Input Parameters:
1974 + mat    - the matrix
1975 . dim    - dimension of the grid 1, 2, or 3
1976 . dims   - number of grid points in x, y, and z direction, including ghost points on your processor
1977 . starts - starting point of ghost nodes on your processor in x, y, and z direction
1978 - dof    - number of degrees of freedom per node
1979 
1980   Level: beginner
1981 
1982   Notes:
1983   Inspired by the structured grid interface to the HYPRE package
1984   (www.llnl.gov/CASC/hyper)
1985 
1986   For matrices generated with `DMCreateMatrix()` this routine is automatically called and so not needed by the
1987   user.
1988 
1989 .seealso: [](ch_matrices), `Mat`, `MatStencil`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1990           `MatSetValues()`, `MatSetValuesBlockedStencil()`, `MatSetValuesStencil()`
1991 @*/
1992 PetscErrorCode MatSetStencil(Mat mat, PetscInt dim, const PetscInt dims[], const PetscInt starts[], PetscInt dof)
1993 {
1994   PetscFunctionBegin;
1995   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1996   PetscAssertPointer(dims, 3);
1997   PetscAssertPointer(starts, 4);
1998 
1999   mat->stencil.dim = dim + (dof > 1);
2000   for (PetscInt i = 0; i < dim; i++) {
2001     mat->stencil.dims[i]   = dims[dim - i - 1]; /* copy the values in backwards */
2002     mat->stencil.starts[i] = starts[dim - i - 1];
2003   }
2004   mat->stencil.dims[dim]   = dof;
2005   mat->stencil.starts[dim] = 0;
2006   mat->stencil.noc         = (PetscBool)(dof == 1);
2007   PetscFunctionReturn(PETSC_SUCCESS);
2008 }
2009 
2010 /*@
2011   MatSetValuesBlocked - Inserts or adds a block of values into a matrix.
2012 
2013   Not Collective
2014 
2015   Input Parameters:
2016 + mat  - the matrix
2017 . v    - a logically two-dimensional array of values
2018 . m    - the number of block rows
2019 . idxm - the global block indices
2020 . n    - the number of block columns
2021 . idxn - the global block indices
2022 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` replaces existing entries with new values
2023 
2024   Level: intermediate
2025 
2026   Notes:
2027   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call
2028   MatXXXXSetPreallocation() or `MatSetUp()` before using this routine.
2029 
2030   The `m` and `n` count the NUMBER of blocks in the row direction and column direction,
2031   NOT the total number of rows/columns; for example, if the block size is 2 and
2032   you are passing in values for rows 2,3,4,5  then `m` would be 2 (not 4).
2033   The values in `idxm` would be 1 2; that is the first index for each block divided by
2034   the block size.
2035 
2036   You must call `MatSetBlockSize()` when constructing this matrix (before
2037   preallocating it).
2038 
2039   By default the values, `v`, are row-oriented, so the layout of
2040   `v` is the same as for `MatSetValues()`. See `MatSetOption()` for other options.
2041 
2042   Calls to `MatSetValuesBlocked()` with the `INSERT_VALUES` and `ADD_VALUES`
2043   options cannot be mixed without intervening calls to the assembly
2044   routines.
2045 
2046   `MatSetValuesBlocked()` uses 0-based row and column numbers in Fortran
2047   as well as in C.
2048 
2049   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
2050   simply ignored. This allows easily inserting element stiffness matrices
2051   with homogeneous Dirichlet boundary conditions that you don't want represented
2052   in the matrix.
2053 
2054   Each time an entry is set within a sparse matrix via `MatSetValues()`,
2055   internal searching must be done to determine where to place the
2056   data in the matrix storage space.  By instead inserting blocks of
2057   entries via `MatSetValuesBlocked()`, the overhead of matrix assembly is
2058   reduced.
2059 
2060   Example:
2061 .vb
2062    Suppose m=n=2 and block size(bs) = 2 The array is
2063 
2064    1  2  | 3  4
2065    5  6  | 7  8
2066    - - - | - - -
2067    9  10 | 11 12
2068    13 14 | 15 16
2069 
2070    v[] should be passed in like
2071    v[] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
2072 
2073   If you are not using row-oriented storage of v (that is you called MatSetOption(mat,MAT_ROW_ORIENTED,PETSC_FALSE)) then
2074    v[] = [1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16]
2075 .ve
2076 
2077   Fortran Notes:
2078   If any of `idmx`, `idxn`, and `v` are scalars pass them using, for example,
2079 .vb
2080   call MatSetValuesBlocked(mat, one, [idxm], one, [idxn], [v], INSERT_VALUES, ierr)
2081 .ve
2082 
2083   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2084 
2085 .seealso: [](ch_matrices), `Mat`, `MatSetBlockSize()`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetValuesBlockedLocal()`
2086 @*/
2087 PetscErrorCode MatSetValuesBlocked(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar v[], InsertMode addv)
2088 {
2089   PetscFunctionBeginHot;
2090   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2091   PetscValidType(mat, 1);
2092   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2093   PetscAssertPointer(idxm, 3);
2094   PetscAssertPointer(idxn, 5);
2095   MatCheckPreallocated(mat, 1);
2096   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2097   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2098   if (PetscDefined(USE_DEBUG)) {
2099     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2100     PetscCheck(mat->ops->setvaluesblocked || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2101   }
2102   if (PetscDefined(USE_DEBUG)) {
2103     PetscInt rbs, cbs, M, N, i;
2104     PetscCall(MatGetBlockSizes(mat, &rbs, &cbs));
2105     PetscCall(MatGetSize(mat, &M, &N));
2106     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);
2107     for (i = 0; i < n; i++)
2108       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);
2109   }
2110   if (mat->assembled) {
2111     mat->was_assembled = PETSC_TRUE;
2112     mat->assembled     = PETSC_FALSE;
2113   }
2114   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2115   if (mat->ops->setvaluesblocked) {
2116     PetscUseTypeMethod(mat, setvaluesblocked, m, idxm, n, idxn, v, addv);
2117   } else {
2118     PetscInt buf[8192], *bufr = NULL, *bufc = NULL, *iidxm, *iidxn;
2119     PetscInt i, j, bs, cbs;
2120 
2121     PetscCall(MatGetBlockSizes(mat, &bs, &cbs));
2122     if ((m * bs + n * cbs) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2123       iidxm = buf;
2124       iidxn = buf + m * bs;
2125     } else {
2126       PetscCall(PetscMalloc2(m * bs, &bufr, n * cbs, &bufc));
2127       iidxm = bufr;
2128       iidxn = bufc;
2129     }
2130     for (i = 0; i < m; i++) {
2131       for (j = 0; j < bs; j++) iidxm[i * bs + j] = bs * idxm[i] + j;
2132     }
2133     if (m != n || bs != cbs || idxm != idxn) {
2134       for (i = 0; i < n; i++) {
2135         for (j = 0; j < cbs; j++) iidxn[i * cbs + j] = cbs * idxn[i] + j;
2136       }
2137     } else iidxn = iidxm;
2138     PetscCall(MatSetValues(mat, m * bs, iidxm, n * cbs, iidxn, v, addv));
2139     PetscCall(PetscFree2(bufr, bufc));
2140   }
2141   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2142   PetscFunctionReturn(PETSC_SUCCESS);
2143 }
2144 
2145 /*@
2146   MatGetValues - Gets a block of local values from a matrix.
2147 
2148   Not Collective; can only return values that are owned by the give process
2149 
2150   Input Parameters:
2151 + mat  - the matrix
2152 . v    - a logically two-dimensional array for storing the values
2153 . m    - the number of rows
2154 . idxm - the  global indices of the rows
2155 . n    - the number of columns
2156 - idxn - the global indices of the columns
2157 
2158   Level: advanced
2159 
2160   Notes:
2161   The user must allocate space (m*n `PetscScalar`s) for the values, `v`.
2162   The values, `v`, are then returned in a row-oriented format,
2163   analogous to that used by default in `MatSetValues()`.
2164 
2165   `MatGetValues()` uses 0-based row and column numbers in
2166   Fortran as well as in C.
2167 
2168   `MatGetValues()` requires that the matrix has been assembled
2169   with `MatAssemblyBegin()`/`MatAssemblyEnd()`.  Thus, calls to
2170   `MatSetValues()` and `MatGetValues()` CANNOT be made in succession
2171   without intermediate matrix assembly.
2172 
2173   Negative row or column indices will be ignored and those locations in `v` will be
2174   left unchanged.
2175 
2176   For the standard row-based matrix formats, `idxm` can only contain rows owned by the requesting MPI process.
2177   That is, rows with global index greater than or equal to rstart and less than rend where rstart and rend are obtainable
2178   from `MatGetOwnershipRange`(mat,&rstart,&rend).
2179 
2180 .seealso: [](ch_matrices), `Mat`, `MatGetRow()`, `MatCreateSubMatrices()`, `MatSetValues()`, `MatGetOwnershipRange()`, `MatGetValuesLocal()`, `MatGetValue()`
2181 @*/
2182 PetscErrorCode MatGetValues(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], PetscScalar v[])
2183 {
2184   PetscFunctionBegin;
2185   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2186   PetscValidType(mat, 1);
2187   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS);
2188   PetscAssertPointer(idxm, 3);
2189   PetscAssertPointer(idxn, 5);
2190   PetscAssertPointer(v, 6);
2191   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2192   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2193   MatCheckPreallocated(mat, 1);
2194 
2195   PetscCall(PetscLogEventBegin(MAT_GetValues, mat, 0, 0, 0));
2196   PetscUseTypeMethod(mat, getvalues, m, idxm, n, idxn, v);
2197   PetscCall(PetscLogEventEnd(MAT_GetValues, mat, 0, 0, 0));
2198   PetscFunctionReturn(PETSC_SUCCESS);
2199 }
2200 
2201 /*@
2202   MatGetValuesLocal - retrieves values from certain locations in a matrix using the local numbering of the indices
2203   defined previously by `MatSetLocalToGlobalMapping()`
2204 
2205   Not Collective
2206 
2207   Input Parameters:
2208 + mat  - the matrix
2209 . nrow - number of rows
2210 . irow - the row local indices
2211 . ncol - number of columns
2212 - icol - the column local indices
2213 
2214   Output Parameter:
2215 . y - a logically two-dimensional array of values
2216 
2217   Level: advanced
2218 
2219   Notes:
2220   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetLocalToGlobalMapping()` before using this routine.
2221 
2222   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,
2223   are greater than or equal to rstart and less than rend where rstart and rend are obtainable from `MatGetOwnershipRange`(mat,&rstart,&rend). One can
2224   determine if the resulting global row associated with the local row r is owned by the requesting MPI process by applying the `ISLocalToGlobalMapping` set
2225   with `MatSetLocalToGlobalMapping()`.
2226 
2227 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetLocalToGlobalMapping()`,
2228           `MatSetValuesLocal()`, `MatGetValues()`
2229 @*/
2230 PetscErrorCode MatGetValuesLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], PetscScalar y[])
2231 {
2232   PetscFunctionBeginHot;
2233   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2234   PetscValidType(mat, 1);
2235   MatCheckPreallocated(mat, 1);
2236   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to retrieve */
2237   PetscAssertPointer(irow, 3);
2238   PetscAssertPointer(icol, 5);
2239   if (PetscDefined(USE_DEBUG)) {
2240     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2241     PetscCheck(mat->ops->getvalueslocal || mat->ops->getvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2242   }
2243   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2244   PetscCall(PetscLogEventBegin(MAT_GetValues, mat, 0, 0, 0));
2245   if (mat->ops->getvalueslocal) PetscUseTypeMethod(mat, getvalueslocal, nrow, irow, ncol, icol, y);
2246   else {
2247     PetscInt buf[8192], *bufr = NULL, *bufc = NULL, *irowm, *icolm;
2248     if ((nrow + ncol) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2249       irowm = buf;
2250       icolm = buf + nrow;
2251     } else {
2252       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2253       irowm = bufr;
2254       icolm = bufc;
2255     }
2256     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MatGetValuesLocal() cannot proceed without local-to-global row mapping (See MatSetLocalToGlobalMapping()).");
2257     PetscCheck(mat->cmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MatGetValuesLocal() cannot proceed without local-to-global column mapping (See MatSetLocalToGlobalMapping()).");
2258     PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, nrow, irow, irowm));
2259     PetscCall(ISLocalToGlobalMappingApply(mat->cmap->mapping, ncol, icol, icolm));
2260     PetscCall(MatGetValues(mat, nrow, irowm, ncol, icolm, y));
2261     PetscCall(PetscFree2(bufr, bufc));
2262   }
2263   PetscCall(PetscLogEventEnd(MAT_GetValues, mat, 0, 0, 0));
2264   PetscFunctionReturn(PETSC_SUCCESS);
2265 }
2266 
2267 /*@
2268   MatSetValuesBatch - Adds (`ADD_VALUES`) many blocks of values into a matrix at once. The blocks must all be square and
2269   the same size. Currently, this can only be called once and creates the given matrix.
2270 
2271   Not Collective
2272 
2273   Input Parameters:
2274 + mat  - the matrix
2275 . nb   - the number of blocks
2276 . bs   - the number of rows (and columns) in each block
2277 . rows - a concatenation of the rows for each block
2278 - v    - a concatenation of logically two-dimensional arrays of values
2279 
2280   Level: advanced
2281 
2282   Notes:
2283   `MatSetPreallocationCOO()` and `MatSetValuesCOO()` may be a better way to provide the values
2284 
2285   In the future, we will extend this routine to handle rectangular blocks, and to allow multiple calls for a given matrix.
2286 
2287 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
2288           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`, `MatSetValues()`, `MatSetPreallocationCOO()`, `MatSetValuesCOO()`
2289 @*/
2290 PetscErrorCode MatSetValuesBatch(Mat mat, PetscInt nb, PetscInt bs, PetscInt rows[], const PetscScalar v[])
2291 {
2292   PetscFunctionBegin;
2293   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2294   PetscValidType(mat, 1);
2295   PetscAssertPointer(rows, 4);
2296   PetscAssertPointer(v, 5);
2297   PetscAssert(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2298 
2299   PetscCall(PetscLogEventBegin(MAT_SetValuesBatch, mat, 0, 0, 0));
2300   if (mat->ops->setvaluesbatch) PetscUseTypeMethod(mat, setvaluesbatch, nb, bs, rows, v);
2301   else {
2302     for (PetscInt b = 0; b < nb; ++b) PetscCall(MatSetValues(mat, bs, &rows[b * bs], bs, &rows[b * bs], &v[b * bs * bs], ADD_VALUES));
2303   }
2304   PetscCall(PetscLogEventEnd(MAT_SetValuesBatch, mat, 0, 0, 0));
2305   PetscFunctionReturn(PETSC_SUCCESS);
2306 }
2307 
2308 /*@
2309   MatSetLocalToGlobalMapping - Sets a local-to-global numbering for use by
2310   the routine `MatSetValuesLocal()` to allow users to insert matrix entries
2311   using a local (per-processor) numbering.
2312 
2313   Not Collective
2314 
2315   Input Parameters:
2316 + x        - the matrix
2317 . rmapping - row mapping created with `ISLocalToGlobalMappingCreate()` or `ISLocalToGlobalMappingCreateIS()`
2318 - cmapping - column mapping
2319 
2320   Level: intermediate
2321 
2322   Note:
2323   If the matrix is obtained with `DMCreateMatrix()` then this may already have been called on the matrix
2324 
2325 .seealso: [](ch_matrices), `Mat`, `DM`, `DMCreateMatrix()`, `MatGetLocalToGlobalMapping()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetValuesLocal()`, `MatGetValuesLocal()`
2326 @*/
2327 PetscErrorCode MatSetLocalToGlobalMapping(Mat x, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2328 {
2329   PetscFunctionBegin;
2330   PetscValidHeaderSpecific(x, MAT_CLASSID, 1);
2331   PetscValidType(x, 1);
2332   if (rmapping) PetscValidHeaderSpecific(rmapping, IS_LTOGM_CLASSID, 2);
2333   if (cmapping) PetscValidHeaderSpecific(cmapping, IS_LTOGM_CLASSID, 3);
2334   if (x->ops->setlocaltoglobalmapping) PetscUseTypeMethod(x, setlocaltoglobalmapping, rmapping, cmapping);
2335   else {
2336     PetscCall(PetscLayoutSetISLocalToGlobalMapping(x->rmap, rmapping));
2337     PetscCall(PetscLayoutSetISLocalToGlobalMapping(x->cmap, cmapping));
2338   }
2339   PetscFunctionReturn(PETSC_SUCCESS);
2340 }
2341 
2342 /*@
2343   MatGetLocalToGlobalMapping - Gets the local-to-global numbering set by `MatSetLocalToGlobalMapping()`
2344 
2345   Not Collective
2346 
2347   Input Parameter:
2348 . A - the matrix
2349 
2350   Output Parameters:
2351 + rmapping - row mapping
2352 - cmapping - column mapping
2353 
2354   Level: advanced
2355 
2356 .seealso: [](ch_matrices), `Mat`, `MatSetLocalToGlobalMapping()`, `MatSetValuesLocal()`
2357 @*/
2358 PetscErrorCode MatGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
2359 {
2360   PetscFunctionBegin;
2361   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2362   PetscValidType(A, 1);
2363   if (rmapping) {
2364     PetscAssertPointer(rmapping, 2);
2365     *rmapping = A->rmap->mapping;
2366   }
2367   if (cmapping) {
2368     PetscAssertPointer(cmapping, 3);
2369     *cmapping = A->cmap->mapping;
2370   }
2371   PetscFunctionReturn(PETSC_SUCCESS);
2372 }
2373 
2374 /*@
2375   MatSetLayouts - Sets the `PetscLayout` objects for rows and columns of a matrix
2376 
2377   Logically Collective
2378 
2379   Input Parameters:
2380 + A    - the matrix
2381 . rmap - row layout
2382 - cmap - column layout
2383 
2384   Level: advanced
2385 
2386   Note:
2387   The `PetscLayout` objects are usually created automatically for the matrix so this routine rarely needs to be called.
2388 
2389 .seealso: [](ch_matrices), `Mat`, `PetscLayout`, `MatCreateVecs()`, `MatGetLocalToGlobalMapping()`, `MatGetLayouts()`
2390 @*/
2391 PetscErrorCode MatSetLayouts(Mat A, PetscLayout rmap, PetscLayout cmap)
2392 {
2393   PetscFunctionBegin;
2394   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2395   PetscCall(PetscLayoutReference(rmap, &A->rmap));
2396   PetscCall(PetscLayoutReference(cmap, &A->cmap));
2397   PetscFunctionReturn(PETSC_SUCCESS);
2398 }
2399 
2400 /*@
2401   MatGetLayouts - Gets the `PetscLayout` objects for rows and columns
2402 
2403   Not Collective
2404 
2405   Input Parameter:
2406 . A - the matrix
2407 
2408   Output Parameters:
2409 + rmap - row layout
2410 - cmap - column layout
2411 
2412   Level: advanced
2413 
2414 .seealso: [](ch_matrices), `Mat`, [Matrix Layouts](sec_matlayout), `PetscLayout`, `MatCreateVecs()`, `MatGetLocalToGlobalMapping()`, `MatSetLayouts()`
2415 @*/
2416 PetscErrorCode MatGetLayouts(Mat A, PetscLayout *rmap, PetscLayout *cmap)
2417 {
2418   PetscFunctionBegin;
2419   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2420   PetscValidType(A, 1);
2421   if (rmap) {
2422     PetscAssertPointer(rmap, 2);
2423     *rmap = A->rmap;
2424   }
2425   if (cmap) {
2426     PetscAssertPointer(cmap, 3);
2427     *cmap = A->cmap;
2428   }
2429   PetscFunctionReturn(PETSC_SUCCESS);
2430 }
2431 
2432 /*@
2433   MatSetValuesLocal - Inserts or adds values into certain locations of a matrix,
2434   using a local numbering of the rows and columns.
2435 
2436   Not Collective
2437 
2438   Input Parameters:
2439 + mat  - the matrix
2440 . nrow - number of rows
2441 . irow - the row local indices
2442 . ncol - number of columns
2443 . icol - the column local indices
2444 . y    - a logically two-dimensional array of values
2445 - addv - either `INSERT_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
2446 
2447   Level: intermediate
2448 
2449   Notes:
2450   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetLocalToGlobalMapping()` before using this routine
2451 
2452   Calls to `MatSetValuesLocal()` with the `INSERT_VALUES` and `ADD_VALUES`
2453   options cannot be mixed without intervening calls to the assembly
2454   routines.
2455 
2456   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
2457   MUST be called after all calls to `MatSetValuesLocal()` have been completed.
2458 
2459   Fortran Notes:
2460   If any of `irow`, `icol`, and `y` are scalars pass them using, for example,
2461 .vb
2462   call MatSetValuesLocal(mat, one, [irow], one, [icol], [y], INSERT_VALUES, ierr)
2463 .ve
2464 
2465   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2466 
2467 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetLocalToGlobalMapping()`,
2468           `MatGetValuesLocal()`
2469 @*/
2470 PetscErrorCode MatSetValuesLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv)
2471 {
2472   PetscFunctionBeginHot;
2473   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2474   PetscValidType(mat, 1);
2475   MatCheckPreallocated(mat, 1);
2476   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2477   PetscAssertPointer(irow, 3);
2478   PetscAssertPointer(icol, 5);
2479   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2480   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2481   if (PetscDefined(USE_DEBUG)) {
2482     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2483     PetscCheck(mat->ops->setvalueslocal || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2484   }
2485 
2486   if (mat->assembled) {
2487     mat->was_assembled = PETSC_TRUE;
2488     mat->assembled     = PETSC_FALSE;
2489   }
2490   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2491   if (mat->ops->setvalueslocal) PetscUseTypeMethod(mat, setvalueslocal, nrow, irow, ncol, icol, y, addv);
2492   else {
2493     PetscInt        buf[8192], *bufr = NULL, *bufc = NULL;
2494     const PetscInt *irowm, *icolm;
2495 
2496     if ((!mat->rmap->mapping && !mat->cmap->mapping) || (nrow + ncol) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2497       bufr  = buf;
2498       bufc  = buf + nrow;
2499       irowm = bufr;
2500       icolm = bufc;
2501     } else {
2502       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2503       irowm = bufr;
2504       icolm = bufc;
2505     }
2506     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, nrow, irow, bufr));
2507     else irowm = irow;
2508     if (mat->cmap->mapping) {
2509       if (mat->cmap->mapping != mat->rmap->mapping || ncol != nrow || icol != irow) {
2510         PetscCall(ISLocalToGlobalMappingApply(mat->cmap->mapping, ncol, icol, bufc));
2511       } else icolm = irowm;
2512     } else icolm = icol;
2513     PetscCall(MatSetValues(mat, nrow, irowm, ncol, icolm, y, addv));
2514     if (bufr != buf) PetscCall(PetscFree2(bufr, bufc));
2515   }
2516   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2517   PetscFunctionReturn(PETSC_SUCCESS);
2518 }
2519 
2520 /*@
2521   MatSetValuesBlockedLocal - Inserts or adds values into certain locations of a matrix,
2522   using a local ordering of the nodes a block at a time.
2523 
2524   Not Collective
2525 
2526   Input Parameters:
2527 + mat  - the matrix
2528 . nrow - number of rows
2529 . irow - the row local indices
2530 . ncol - number of columns
2531 . icol - the column local indices
2532 . y    - a logically two-dimensional array of values
2533 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
2534 
2535   Level: intermediate
2536 
2537   Notes:
2538   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetBlockSize()` and `MatSetLocalToGlobalMapping()`
2539   before using this routineBefore calling `MatSetValuesLocal()`, the user must first set the
2540 
2541   Calls to `MatSetValuesBlockedLocal()` with the `INSERT_VALUES` and `ADD_VALUES`
2542   options cannot be mixed without intervening calls to the assembly
2543   routines.
2544 
2545   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
2546   MUST be called after all calls to `MatSetValuesBlockedLocal()` have been completed.
2547 
2548   Fortran Notes:
2549   If any of `irow`, `icol`, and `y` are scalars pass them using, for example,
2550 .vb
2551   call MatSetValuesBlockedLocal(mat, one, [irow], one, [icol], [y], INSERT_VALUES, ierr)
2552 .ve
2553 
2554   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2555 
2556 .seealso: [](ch_matrices), `Mat`, `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`,
2557           `MatSetValuesLocal()`, `MatSetValuesBlocked()`
2558 @*/
2559 PetscErrorCode MatSetValuesBlockedLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv)
2560 {
2561   PetscFunctionBeginHot;
2562   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2563   PetscValidType(mat, 1);
2564   MatCheckPreallocated(mat, 1);
2565   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2566   PetscAssertPointer(irow, 3);
2567   PetscAssertPointer(icol, 5);
2568   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2569   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2570   if (PetscDefined(USE_DEBUG)) {
2571     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2572     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);
2573   }
2574 
2575   if (mat->assembled) {
2576     mat->was_assembled = PETSC_TRUE;
2577     mat->assembled     = PETSC_FALSE;
2578   }
2579   if (PetscUnlikelyDebug(mat->rmap->mapping)) { /* Condition on the mapping existing, because MatSetValuesBlockedLocal_IS does not require it to be set. */
2580     PetscInt irbs, rbs;
2581     PetscCall(MatGetBlockSizes(mat, &rbs, NULL));
2582     PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &irbs));
2583     PetscCheck(rbs == irbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Different row block sizes! mat %" PetscInt_FMT ", row l2g map %" PetscInt_FMT, rbs, irbs);
2584   }
2585   if (PetscUnlikelyDebug(mat->cmap->mapping)) {
2586     PetscInt icbs, cbs;
2587     PetscCall(MatGetBlockSizes(mat, NULL, &cbs));
2588     PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &icbs));
2589     PetscCheck(cbs == icbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Different col block sizes! mat %" PetscInt_FMT ", col l2g map %" PetscInt_FMT, cbs, icbs);
2590   }
2591   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2592   if (mat->ops->setvaluesblockedlocal) PetscUseTypeMethod(mat, setvaluesblockedlocal, nrow, irow, ncol, icol, y, addv);
2593   else {
2594     PetscInt        buf[8192], *bufr = NULL, *bufc = NULL;
2595     const PetscInt *irowm, *icolm;
2596 
2597     if ((!mat->rmap->mapping && !mat->cmap->mapping) || (nrow + ncol) <= ((PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf))) {
2598       bufr  = buf;
2599       bufc  = buf + nrow;
2600       irowm = bufr;
2601       icolm = bufc;
2602     } else {
2603       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2604       irowm = bufr;
2605       icolm = bufc;
2606     }
2607     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingApplyBlock(mat->rmap->mapping, nrow, irow, bufr));
2608     else irowm = irow;
2609     if (mat->cmap->mapping) {
2610       if (mat->cmap->mapping != mat->rmap->mapping || ncol != nrow || icol != irow) {
2611         PetscCall(ISLocalToGlobalMappingApplyBlock(mat->cmap->mapping, ncol, icol, bufc));
2612       } else icolm = irowm;
2613     } else icolm = icol;
2614     PetscCall(MatSetValuesBlocked(mat, nrow, irowm, ncol, icolm, y, addv));
2615     if (bufr != buf) PetscCall(PetscFree2(bufr, bufc));
2616   }
2617   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2618   PetscFunctionReturn(PETSC_SUCCESS);
2619 }
2620 
2621 /*@
2622   MatMultDiagonalBlock - Computes the matrix-vector product, $y = Dx$. Where `D` is defined by the inode or block structure of the diagonal
2623 
2624   Collective
2625 
2626   Input Parameters:
2627 + mat - the matrix
2628 - x   - the vector to be multiplied
2629 
2630   Output Parameter:
2631 . y - the result
2632 
2633   Level: developer
2634 
2635   Note:
2636   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2637   call `MatMultDiagonalBlock`(A,y,y).
2638 
2639 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
2640 @*/
2641 PetscErrorCode MatMultDiagonalBlock(Mat mat, Vec x, Vec y)
2642 {
2643   PetscFunctionBegin;
2644   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2645   PetscValidType(mat, 1);
2646   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2647   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2648 
2649   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2650   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2651   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2652   MatCheckPreallocated(mat, 1);
2653 
2654   PetscUseTypeMethod(mat, multdiagonalblock, x, y);
2655   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2656   PetscFunctionReturn(PETSC_SUCCESS);
2657 }
2658 
2659 /*@
2660   MatMult - Computes the matrix-vector product, $y = Ax$.
2661 
2662   Neighbor-wise Collective
2663 
2664   Input Parameters:
2665 + mat - the matrix
2666 - x   - the vector to be multiplied
2667 
2668   Output Parameter:
2669 . y - the result
2670 
2671   Level: beginner
2672 
2673   Note:
2674   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2675   call `MatMult`(A,y,y).
2676 
2677 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
2678 @*/
2679 PetscErrorCode MatMult(Mat mat, Vec x, Vec y)
2680 {
2681   PetscFunctionBegin;
2682   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2683   PetscValidType(mat, 1);
2684   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2685   VecCheckAssembled(x);
2686   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2687   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2688   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2689   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2690   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);
2691   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);
2692   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);
2693   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);
2694   PetscCall(VecSetErrorIfLocked(y, 3));
2695   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2696   MatCheckPreallocated(mat, 1);
2697 
2698   PetscCall(VecLockReadPush(x));
2699   PetscCall(PetscLogEventBegin(MAT_Mult, mat, x, y, 0));
2700   PetscUseTypeMethod(mat, mult, x, y);
2701   PetscCall(PetscLogEventEnd(MAT_Mult, mat, x, y, 0));
2702   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(y, 3, PETSC_FALSE));
2703   PetscCall(VecLockReadPop(x));
2704   PetscFunctionReturn(PETSC_SUCCESS);
2705 }
2706 
2707 /*@
2708   MatMultTranspose - Computes matrix transpose times a vector $y = A^T * x$.
2709 
2710   Neighbor-wise Collective
2711 
2712   Input Parameters:
2713 + mat - the matrix
2714 - x   - the vector to be multiplied
2715 
2716   Output Parameter:
2717 . y - the result
2718 
2719   Level: beginner
2720 
2721   Notes:
2722   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2723   call `MatMultTranspose`(A,y,y).
2724 
2725   For complex numbers this does NOT compute the Hermitian (complex conjugate) transpose multiple,
2726   use `MatMultHermitianTranspose()`
2727 
2728 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatMultHermitianTranspose()`, `MatTranspose()`
2729 @*/
2730 PetscErrorCode MatMultTranspose(Mat mat, Vec x, Vec y)
2731 {
2732   PetscErrorCode (*op)(Mat, Vec, Vec) = NULL;
2733 
2734   PetscFunctionBegin;
2735   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2736   PetscValidType(mat, 1);
2737   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2738   VecCheckAssembled(x);
2739   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2740 
2741   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2742   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2743   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2744   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);
2745   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);
2746   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);
2747   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);
2748   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2749   MatCheckPreallocated(mat, 1);
2750 
2751   if (!mat->ops->multtranspose) {
2752     if (mat->symmetric == PETSC_BOOL3_TRUE && mat->ops->mult) op = mat->ops->mult;
2753     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);
2754   } else op = mat->ops->multtranspose;
2755   PetscCall(PetscLogEventBegin(MAT_MultTranspose, mat, x, y, 0));
2756   PetscCall(VecLockReadPush(x));
2757   PetscCall((*op)(mat, x, y));
2758   PetscCall(VecLockReadPop(x));
2759   PetscCall(PetscLogEventEnd(MAT_MultTranspose, mat, x, y, 0));
2760   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2761   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(y, 3, PETSC_FALSE));
2762   PetscFunctionReturn(PETSC_SUCCESS);
2763 }
2764 
2765 /*@
2766   MatMultHermitianTranspose - Computes matrix Hermitian-transpose times a vector $y = A^H * x$.
2767 
2768   Neighbor-wise Collective
2769 
2770   Input Parameters:
2771 + mat - the matrix
2772 - x   - the vector to be multiplied
2773 
2774   Output Parameter:
2775 . y - the result
2776 
2777   Level: beginner
2778 
2779   Notes:
2780   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2781   call `MatMultHermitianTranspose`(A,y,y).
2782 
2783   Also called the conjugate transpose, complex conjugate transpose, or adjoint.
2784 
2785   For real numbers `MatMultTranspose()` and `MatMultHermitianTranspose()` are identical.
2786 
2787 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `MatMultHermitianTransposeAdd()`, `MatMultTranspose()`
2788 @*/
2789 PetscErrorCode MatMultHermitianTranspose(Mat mat, Vec x, Vec y)
2790 {
2791   PetscFunctionBegin;
2792   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2793   PetscValidType(mat, 1);
2794   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2795   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2796 
2797   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2798   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2799   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2800   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);
2801   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);
2802   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);
2803   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);
2804   MatCheckPreallocated(mat, 1);
2805 
2806   PetscCall(PetscLogEventBegin(MAT_MultHermitianTranspose, mat, x, y, 0));
2807 #if defined(PETSC_USE_COMPLEX)
2808   if (mat->ops->multhermitiantranspose || (mat->hermitian == PETSC_BOOL3_TRUE && mat->ops->mult)) {
2809     PetscCall(VecLockReadPush(x));
2810     if (mat->ops->multhermitiantranspose) PetscUseTypeMethod(mat, multhermitiantranspose, x, y);
2811     else PetscUseTypeMethod(mat, mult, x, y);
2812     PetscCall(VecLockReadPop(x));
2813   } else {
2814     Vec w;
2815     PetscCall(VecDuplicate(x, &w));
2816     PetscCall(VecCopy(x, w));
2817     PetscCall(VecConjugate(w));
2818     PetscCall(MatMultTranspose(mat, w, y));
2819     PetscCall(VecDestroy(&w));
2820     PetscCall(VecConjugate(y));
2821   }
2822   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2823 #else
2824   PetscCall(MatMultTranspose(mat, x, y));
2825 #endif
2826   PetscCall(PetscLogEventEnd(MAT_MultHermitianTranspose, mat, x, y, 0));
2827   PetscFunctionReturn(PETSC_SUCCESS);
2828 }
2829 
2830 /*@
2831   MatMultAdd -  Computes $v3 = v2 + A * v1$.
2832 
2833   Neighbor-wise Collective
2834 
2835   Input Parameters:
2836 + mat - the matrix
2837 . v1  - the vector to be multiplied by `mat`
2838 - v2  - the vector to be added to the result
2839 
2840   Output Parameter:
2841 . v3 - the result
2842 
2843   Level: beginner
2844 
2845   Note:
2846   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2847   call `MatMultAdd`(A,v1,v2,v1).
2848 
2849 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMult()`, `MatMultTransposeAdd()`
2850 @*/
2851 PetscErrorCode MatMultAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2852 {
2853   PetscFunctionBegin;
2854   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2855   PetscValidType(mat, 1);
2856   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2857   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2858   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2859 
2860   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2861   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2862   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);
2863   /* 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);
2864      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); */
2865   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);
2866   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);
2867   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2868   MatCheckPreallocated(mat, 1);
2869 
2870   PetscCall(PetscLogEventBegin(MAT_MultAdd, mat, v1, v2, v3));
2871   PetscCall(VecLockReadPush(v1));
2872   PetscUseTypeMethod(mat, multadd, v1, v2, v3);
2873   PetscCall(VecLockReadPop(v1));
2874   PetscCall(PetscLogEventEnd(MAT_MultAdd, mat, v1, v2, v3));
2875   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2876   PetscFunctionReturn(PETSC_SUCCESS);
2877 }
2878 
2879 /*@
2880   MatMultTransposeAdd - Computes $v3 = v2 + A^T * v1$.
2881 
2882   Neighbor-wise Collective
2883 
2884   Input Parameters:
2885 + mat - the matrix
2886 . v1  - the vector to be multiplied by the transpose of the matrix
2887 - v2  - the vector to be added to the result
2888 
2889   Output Parameter:
2890 . v3 - the result
2891 
2892   Level: beginner
2893 
2894   Note:
2895   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2896   call `MatMultTransposeAdd`(A,v1,v2,v1).
2897 
2898 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMult()`
2899 @*/
2900 PetscErrorCode MatMultTransposeAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2901 {
2902   PetscErrorCode (*op)(Mat, Vec, Vec, Vec) = (!mat->ops->multtransposeadd && mat->symmetric) ? mat->ops->multadd : mat->ops->multtransposeadd;
2903 
2904   PetscFunctionBegin;
2905   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2906   PetscValidType(mat, 1);
2907   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2908   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2909   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2910 
2911   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2912   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2913   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);
2914   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);
2915   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);
2916   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2917   PetscCheck(op, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2918   MatCheckPreallocated(mat, 1);
2919 
2920   PetscCall(PetscLogEventBegin(MAT_MultTransposeAdd, mat, v1, v2, v3));
2921   PetscCall(VecLockReadPush(v1));
2922   PetscCall((*op)(mat, v1, v2, v3));
2923   PetscCall(VecLockReadPop(v1));
2924   PetscCall(PetscLogEventEnd(MAT_MultTransposeAdd, mat, v1, v2, v3));
2925   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2926   PetscFunctionReturn(PETSC_SUCCESS);
2927 }
2928 
2929 /*@
2930   MatMultHermitianTransposeAdd - Computes $v3 = v2 + A^H * v1$.
2931 
2932   Neighbor-wise Collective
2933 
2934   Input Parameters:
2935 + mat - the matrix
2936 . v1  - the vector to be multiplied by the Hermitian transpose
2937 - v2  - the vector to be added to the result
2938 
2939   Output Parameter:
2940 . v3 - the result
2941 
2942   Level: beginner
2943 
2944   Note:
2945   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2946   call `MatMultHermitianTransposeAdd`(A,v1,v2,v1).
2947 
2948 .seealso: [](ch_matrices), `Mat`, `MatMultHermitianTranspose()`, `MatMultTranspose()`, `MatMultAdd()`, `MatMult()`
2949 @*/
2950 PetscErrorCode MatMultHermitianTransposeAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2951 {
2952   PetscFunctionBegin;
2953   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2954   PetscValidType(mat, 1);
2955   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2956   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2957   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2958 
2959   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2960   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2961   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2962   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);
2963   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);
2964   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);
2965   MatCheckPreallocated(mat, 1);
2966 
2967   PetscCall(PetscLogEventBegin(MAT_MultHermitianTransposeAdd, mat, v1, v2, v3));
2968   PetscCall(VecLockReadPush(v1));
2969   if (mat->ops->multhermitiantransposeadd) PetscUseTypeMethod(mat, multhermitiantransposeadd, v1, v2, v3);
2970   else {
2971     Vec w, z;
2972     PetscCall(VecDuplicate(v1, &w));
2973     PetscCall(VecCopy(v1, w));
2974     PetscCall(VecConjugate(w));
2975     PetscCall(VecDuplicate(v3, &z));
2976     PetscCall(MatMultTranspose(mat, w, z));
2977     PetscCall(VecDestroy(&w));
2978     PetscCall(VecConjugate(z));
2979     if (v2 != v3) {
2980       PetscCall(VecWAXPY(v3, 1.0, v2, z));
2981     } else {
2982       PetscCall(VecAXPY(v3, 1.0, z));
2983     }
2984     PetscCall(VecDestroy(&z));
2985   }
2986   PetscCall(VecLockReadPop(v1));
2987   PetscCall(PetscLogEventEnd(MAT_MultHermitianTransposeAdd, mat, v1, v2, v3));
2988   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2989   PetscFunctionReturn(PETSC_SUCCESS);
2990 }
2991 
2992 /*@
2993   MatGetFactorType - gets the type of factorization a matrix is
2994 
2995   Not Collective
2996 
2997   Input Parameter:
2998 . mat - the matrix
2999 
3000   Output Parameter:
3001 . 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`
3002 
3003   Level: intermediate
3004 
3005 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatGetFactor()`, `MatSetFactorType()`, `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`,
3006           `MAT_FACTOR_ICC`,`MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3007 @*/
3008 PetscErrorCode MatGetFactorType(Mat mat, MatFactorType *t)
3009 {
3010   PetscFunctionBegin;
3011   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3012   PetscValidType(mat, 1);
3013   PetscAssertPointer(t, 2);
3014   *t = mat->factortype;
3015   PetscFunctionReturn(PETSC_SUCCESS);
3016 }
3017 
3018 /*@
3019   MatSetFactorType - sets the type of factorization a matrix is
3020 
3021   Logically Collective
3022 
3023   Input Parameters:
3024 + mat - the matrix
3025 - 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`
3026 
3027   Level: intermediate
3028 
3029 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatGetFactor()`, `MatGetFactorType()`, `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`,
3030           `MAT_FACTOR_ICC`,`MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3031 @*/
3032 PetscErrorCode MatSetFactorType(Mat mat, MatFactorType t)
3033 {
3034   PetscFunctionBegin;
3035   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3036   PetscValidType(mat, 1);
3037   mat->factortype = t;
3038   PetscFunctionReturn(PETSC_SUCCESS);
3039 }
3040 
3041 /*@
3042   MatGetInfo - Returns information about matrix storage (number of
3043   nonzeros, memory, etc.).
3044 
3045   Collective if `MAT_GLOBAL_MAX` or `MAT_GLOBAL_SUM` is used as the flag
3046 
3047   Input Parameters:
3048 + mat  - the matrix
3049 - 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)
3050 
3051   Output Parameter:
3052 . info - matrix information context
3053 
3054   Options Database Key:
3055 . -mat_view ::ascii_info - print matrix info to `PETSC_STDOUT`
3056 
3057   Level: intermediate
3058 
3059   Notes:
3060   The `MatInfo` context contains a variety of matrix data, including
3061   number of nonzeros allocated and used, number of mallocs during
3062   matrix assembly, etc.  Additional information for factored matrices
3063   is provided (such as the fill ratio, number of mallocs during
3064   factorization, etc.).
3065 
3066   Example:
3067   See the file ${PETSC_DIR}/include/petscmat.h for a complete list of
3068   data within the `MatInfo` context.  For example,
3069 .vb
3070       MatInfo info;
3071       Mat     A;
3072       double  mal, nz_a, nz_u;
3073 
3074       MatGetInfo(A, MAT_LOCAL, &info);
3075       mal  = info.mallocs;
3076       nz_a = info.nz_allocated;
3077 .ve
3078 
3079 .seealso: [](ch_matrices), `Mat`, `MatInfo`, `MatStashGetInfo()`
3080 @*/
3081 PetscErrorCode MatGetInfo(Mat mat, MatInfoType flag, MatInfo *info)
3082 {
3083   PetscFunctionBegin;
3084   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3085   PetscValidType(mat, 1);
3086   PetscAssertPointer(info, 3);
3087   MatCheckPreallocated(mat, 1);
3088   PetscUseTypeMethod(mat, getinfo, flag, info);
3089   PetscFunctionReturn(PETSC_SUCCESS);
3090 }
3091 
3092 /*
3093    This is used by external packages where it is not easy to get the info from the actual
3094    matrix factorization.
3095 */
3096 PetscErrorCode MatGetInfo_External(Mat A, MatInfoType flag, MatInfo *info)
3097 {
3098   PetscFunctionBegin;
3099   PetscCall(PetscMemzero(info, sizeof(MatInfo)));
3100   PetscFunctionReturn(PETSC_SUCCESS);
3101 }
3102 
3103 /*@
3104   MatLUFactor - Performs in-place LU factorization of matrix.
3105 
3106   Collective
3107 
3108   Input Parameters:
3109 + mat  - the matrix
3110 . row  - row permutation
3111 . col  - column permutation
3112 - info - options for factorization, includes
3113 .vb
3114           fill - expected fill as ratio of original fill.
3115           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3116                    Run with the option -info to determine an optimal value to use
3117 .ve
3118 
3119   Level: developer
3120 
3121   Notes:
3122   Most users should employ the `KSP` interface for linear solvers
3123   instead of working directly with matrix algebra routines such as this.
3124   See, e.g., `KSPCreate()`.
3125 
3126   This changes the state of the matrix to a factored matrix; it cannot be used
3127   for example with `MatSetValues()` unless one first calls `MatSetUnfactored()`.
3128 
3129   This is really in-place only for dense matrices, the preferred approach is to use `MatGetFactor()`, `MatLUFactorSymbolic()`, and `MatLUFactorNumeric()`
3130   when not using `KSP`.
3131 
3132   Fortran Note:
3133   A valid (non-null) `info` argument must be provided
3134 
3135 .seealso: [](ch_matrices), [Matrix Factorization](sec_matfactor), `Mat`, `MatFactorType`, `MatLUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`,
3136           `MatGetOrdering()`, `MatSetUnfactored()`, `MatFactorInfo`, `MatGetFactor()`
3137 @*/
3138 PetscErrorCode MatLUFactor(Mat mat, IS row, IS col, const MatFactorInfo *info)
3139 {
3140   MatFactorInfo tinfo;
3141 
3142   PetscFunctionBegin;
3143   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3144   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
3145   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3146   if (info) PetscAssertPointer(info, 4);
3147   PetscValidType(mat, 1);
3148   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3149   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3150   MatCheckPreallocated(mat, 1);
3151   if (!info) {
3152     PetscCall(MatFactorInfoInitialize(&tinfo));
3153     info = &tinfo;
3154   }
3155 
3156   PetscCall(PetscLogEventBegin(MAT_LUFactor, mat, row, col, 0));
3157   PetscUseTypeMethod(mat, lufactor, row, col, info);
3158   PetscCall(PetscLogEventEnd(MAT_LUFactor, mat, row, col, 0));
3159   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3160   PetscFunctionReturn(PETSC_SUCCESS);
3161 }
3162 
3163 /*@
3164   MatILUFactor - Performs in-place ILU factorization of matrix.
3165 
3166   Collective
3167 
3168   Input Parameters:
3169 + mat  - the matrix
3170 . row  - row permutation
3171 . col  - column permutation
3172 - info - structure containing
3173 .vb
3174       levels - number of levels of fill.
3175       expected fill - as ratio of original fill.
3176       1 or 0 - indicating force fill on diagonal (improves robustness for matrices
3177                 missing diagonal entries)
3178 .ve
3179 
3180   Level: developer
3181 
3182   Notes:
3183   Most users should employ the `KSP` interface for linear solvers
3184   instead of working directly with matrix algebra routines such as this.
3185   See, e.g., `KSPCreate()`.
3186 
3187   Probably really in-place only when level of fill is zero, otherwise allocates
3188   new space to store factored matrix and deletes previous memory. The preferred approach is to use `MatGetFactor()`, `MatILUFactorSymbolic()`, and `MatILUFactorNumeric()`
3189   when not using `KSP`.
3190 
3191   Fortran Note:
3192   A valid (non-null) `info` argument must be provided
3193 
3194 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatILUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`
3195 @*/
3196 PetscErrorCode MatILUFactor(Mat mat, IS row, IS col, const MatFactorInfo *info)
3197 {
3198   PetscFunctionBegin;
3199   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3200   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
3201   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3202   PetscAssertPointer(info, 4);
3203   PetscValidType(mat, 1);
3204   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
3205   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3206   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3207   MatCheckPreallocated(mat, 1);
3208 
3209   PetscCall(PetscLogEventBegin(MAT_ILUFactor, mat, row, col, 0));
3210   PetscUseTypeMethod(mat, ilufactor, row, col, info);
3211   PetscCall(PetscLogEventEnd(MAT_ILUFactor, mat, row, col, 0));
3212   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3213   PetscFunctionReturn(PETSC_SUCCESS);
3214 }
3215 
3216 /*@
3217   MatLUFactorSymbolic - Performs symbolic LU factorization of matrix.
3218   Call this routine before calling `MatLUFactorNumeric()` and after `MatGetFactor()`.
3219 
3220   Collective
3221 
3222   Input Parameters:
3223 + fact - the factor matrix obtained with `MatGetFactor()`
3224 . mat  - the matrix
3225 . row  - the row permutation
3226 . col  - the column permutation
3227 - info - options for factorization, includes
3228 .vb
3229           fill - expected fill as ratio of original fill. Run with the option -info to determine an optimal value to use
3230           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3231 .ve
3232 
3233   Level: developer
3234 
3235   Notes:
3236   See [Matrix Factorization](sec_matfactor) for additional information about factorizations
3237 
3238   Most users should employ the simplified `KSP` interface for linear solvers
3239   instead of working directly with matrix algebra routines such as this.
3240   See, e.g., `KSPCreate()`.
3241 
3242   Fortran Note:
3243   A valid (non-null) `info` argument must be provided
3244 
3245 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactor()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`, `MatFactorInfoInitialize()`
3246 @*/
3247 PetscErrorCode MatLUFactorSymbolic(Mat fact, Mat mat, IS row, IS col, const MatFactorInfo *info)
3248 {
3249   MatFactorInfo tinfo;
3250 
3251   PetscFunctionBegin;
3252   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3253   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3254   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 3);
3255   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 4);
3256   if (info) PetscAssertPointer(info, 5);
3257   PetscValidType(fact, 1);
3258   PetscValidType(mat, 2);
3259   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3260   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3261   MatCheckPreallocated(mat, 2);
3262   if (!info) {
3263     PetscCall(MatFactorInfoInitialize(&tinfo));
3264     info = &tinfo;
3265   }
3266 
3267   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_LUFactorSymbolic, mat, row, col, 0));
3268   PetscUseTypeMethod(fact, lufactorsymbolic, mat, row, col, info);
3269   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_LUFactorSymbolic, mat, row, col, 0));
3270   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3271   PetscFunctionReturn(PETSC_SUCCESS);
3272 }
3273 
3274 /*@
3275   MatLUFactorNumeric - Performs numeric LU factorization of a matrix.
3276   Call this routine after first calling `MatLUFactorSymbolic()` and `MatGetFactor()`.
3277 
3278   Collective
3279 
3280   Input Parameters:
3281 + fact - the factor matrix obtained with `MatGetFactor()`
3282 . mat  - the matrix
3283 - info - options for factorization
3284 
3285   Level: developer
3286 
3287   Notes:
3288   See `MatLUFactor()` for in-place factorization.  See
3289   `MatCholeskyFactorNumeric()` for the symmetric, positive definite case.
3290 
3291   Most users should employ the `KSP` interface for linear solvers
3292   instead of working directly with matrix algebra routines such as this.
3293   See, e.g., `KSPCreate()`.
3294 
3295   Fortran Note:
3296   A valid (non-null) `info` argument must be provided
3297 
3298 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatLUFactorSymbolic()`, `MatLUFactor()`, `MatCholeskyFactor()`
3299 @*/
3300 PetscErrorCode MatLUFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3301 {
3302   MatFactorInfo tinfo;
3303 
3304   PetscFunctionBegin;
3305   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3306   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3307   PetscValidType(fact, 1);
3308   PetscValidType(mat, 2);
3309   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3310   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,
3311              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3312 
3313   MatCheckPreallocated(mat, 2);
3314   if (!info) {
3315     PetscCall(MatFactorInfoInitialize(&tinfo));
3316     info = &tinfo;
3317   }
3318 
3319   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_LUFactorNumeric, mat, fact, 0, 0));
3320   else PetscCall(PetscLogEventBegin(MAT_LUFactor, mat, fact, 0, 0));
3321   PetscUseTypeMethod(fact, lufactornumeric, mat, info);
3322   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_LUFactorNumeric, mat, fact, 0, 0));
3323   else PetscCall(PetscLogEventEnd(MAT_LUFactor, mat, fact, 0, 0));
3324   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3325   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3326   PetscFunctionReturn(PETSC_SUCCESS);
3327 }
3328 
3329 /*@
3330   MatCholeskyFactor - Performs in-place Cholesky factorization of a
3331   symmetric matrix.
3332 
3333   Collective
3334 
3335   Input Parameters:
3336 + mat  - the matrix
3337 . perm - row and column permutations
3338 - info - expected fill as ratio of original fill
3339 
3340   Level: developer
3341 
3342   Notes:
3343   See `MatLUFactor()` for the nonsymmetric case.  See also `MatGetFactor()`,
3344   `MatCholeskyFactorSymbolic()`, and `MatCholeskyFactorNumeric()`.
3345 
3346   Most users should employ the `KSP` interface for linear solvers
3347   instead of working directly with matrix algebra routines such as this.
3348   See, e.g., `KSPCreate()`.
3349 
3350   Fortran Note:
3351   A valid (non-null) `info` argument must be provided
3352 
3353 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatLUFactor()`, `MatCholeskyFactorSymbolic()`, `MatCholeskyFactorNumeric()`
3354           `MatGetOrdering()`
3355 @*/
3356 PetscErrorCode MatCholeskyFactor(Mat mat, IS perm, const MatFactorInfo *info)
3357 {
3358   MatFactorInfo tinfo;
3359 
3360   PetscFunctionBegin;
3361   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3362   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 2);
3363   if (info) PetscAssertPointer(info, 3);
3364   PetscValidType(mat, 1);
3365   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Matrix must be square");
3366   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3367   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3368   MatCheckPreallocated(mat, 1);
3369   if (!info) {
3370     PetscCall(MatFactorInfoInitialize(&tinfo));
3371     info = &tinfo;
3372   }
3373 
3374   PetscCall(PetscLogEventBegin(MAT_CholeskyFactor, mat, perm, 0, 0));
3375   PetscUseTypeMethod(mat, choleskyfactor, perm, info);
3376   PetscCall(PetscLogEventEnd(MAT_CholeskyFactor, mat, perm, 0, 0));
3377   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3378   PetscFunctionReturn(PETSC_SUCCESS);
3379 }
3380 
3381 /*@
3382   MatCholeskyFactorSymbolic - Performs symbolic Cholesky factorization
3383   of a symmetric matrix.
3384 
3385   Collective
3386 
3387   Input Parameters:
3388 + fact - the factor matrix obtained with `MatGetFactor()`
3389 . mat  - the matrix
3390 . perm - row and column permutations
3391 - info - options for factorization, includes
3392 .vb
3393           fill - expected fill as ratio of original fill.
3394           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3395                    Run with the option -info to determine an optimal value to use
3396 .ve
3397 
3398   Level: developer
3399 
3400   Notes:
3401   See `MatLUFactorSymbolic()` for the nonsymmetric case.  See also
3402   `MatCholeskyFactor()` and `MatCholeskyFactorNumeric()`.
3403 
3404   Most users should employ the `KSP` interface for linear solvers
3405   instead of working directly with matrix algebra routines such as this.
3406   See, e.g., `KSPCreate()`.
3407 
3408   Fortran Note:
3409   A valid (non-null) `info` argument must be provided
3410 
3411 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactor()`, `MatCholeskyFactorNumeric()`
3412           `MatGetOrdering()`
3413 @*/
3414 PetscErrorCode MatCholeskyFactorSymbolic(Mat fact, Mat mat, IS perm, const MatFactorInfo *info)
3415 {
3416   MatFactorInfo tinfo;
3417 
3418   PetscFunctionBegin;
3419   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3420   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3421   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 3);
3422   if (info) PetscAssertPointer(info, 4);
3423   PetscValidType(fact, 1);
3424   PetscValidType(mat, 2);
3425   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Matrix must be square");
3426   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3427   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3428   MatCheckPreallocated(mat, 2);
3429   if (!info) {
3430     PetscCall(MatFactorInfoInitialize(&tinfo));
3431     info = &tinfo;
3432   }
3433 
3434   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_CholeskyFactorSymbolic, mat, perm, 0, 0));
3435   PetscUseTypeMethod(fact, choleskyfactorsymbolic, mat, perm, info);
3436   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_CholeskyFactorSymbolic, mat, perm, 0, 0));
3437   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3438   PetscFunctionReturn(PETSC_SUCCESS);
3439 }
3440 
3441 /*@
3442   MatCholeskyFactorNumeric - Performs numeric Cholesky factorization
3443   of a symmetric matrix. Call this routine after first calling `MatGetFactor()` and
3444   `MatCholeskyFactorSymbolic()`.
3445 
3446   Collective
3447 
3448   Input Parameters:
3449 + fact - the factor matrix obtained with `MatGetFactor()`, where the factored values are stored
3450 . mat  - the initial matrix that is to be factored
3451 - info - options for factorization
3452 
3453   Level: developer
3454 
3455   Note:
3456   Most users should employ the `KSP` interface for linear solvers
3457   instead of working directly with matrix algebra routines such as this.
3458   See, e.g., `KSPCreate()`.
3459 
3460   Fortran Note:
3461   A valid (non-null) `info` argument must be provided
3462 
3463 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatCholeskyFactorSymbolic()`, `MatCholeskyFactor()`, `MatLUFactorNumeric()`
3464 @*/
3465 PetscErrorCode MatCholeskyFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3466 {
3467   MatFactorInfo tinfo;
3468 
3469   PetscFunctionBegin;
3470   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3471   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3472   PetscValidType(fact, 1);
3473   PetscValidType(mat, 2);
3474   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3475   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,
3476              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3477   MatCheckPreallocated(mat, 2);
3478   if (!info) {
3479     PetscCall(MatFactorInfoInitialize(&tinfo));
3480     info = &tinfo;
3481   }
3482 
3483   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_CholeskyFactorNumeric, mat, fact, 0, 0));
3484   else PetscCall(PetscLogEventBegin(MAT_CholeskyFactor, mat, fact, 0, 0));
3485   PetscUseTypeMethod(fact, choleskyfactornumeric, mat, info);
3486   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_CholeskyFactorNumeric, mat, fact, 0, 0));
3487   else PetscCall(PetscLogEventEnd(MAT_CholeskyFactor, mat, fact, 0, 0));
3488   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3489   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3490   PetscFunctionReturn(PETSC_SUCCESS);
3491 }
3492 
3493 /*@
3494   MatQRFactor - Performs in-place QR factorization of matrix.
3495 
3496   Collective
3497 
3498   Input Parameters:
3499 + mat  - the matrix
3500 . col  - column permutation
3501 - info - options for factorization, includes
3502 .vb
3503           fill - expected fill as ratio of original fill.
3504           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3505                    Run with the option -info to determine an optimal value to use
3506 .ve
3507 
3508   Level: developer
3509 
3510   Notes:
3511   Most users should employ the `KSP` interface for linear solvers
3512   instead of working directly with matrix algebra routines such as this.
3513   See, e.g., `KSPCreate()`.
3514 
3515   This changes the state of the matrix to a factored matrix; it cannot be used
3516   for example with `MatSetValues()` unless one first calls `MatSetUnfactored()`.
3517 
3518   Fortran Note:
3519   A valid (non-null) `info` argument must be provided
3520 
3521 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatQRFactorSymbolic()`, `MatQRFactorNumeric()`, `MatLUFactor()`,
3522           `MatSetUnfactored()`
3523 @*/
3524 PetscErrorCode MatQRFactor(Mat mat, IS col, const MatFactorInfo *info)
3525 {
3526   PetscFunctionBegin;
3527   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3528   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 2);
3529   if (info) PetscAssertPointer(info, 3);
3530   PetscValidType(mat, 1);
3531   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3532   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3533   MatCheckPreallocated(mat, 1);
3534   PetscCall(PetscLogEventBegin(MAT_QRFactor, mat, col, 0, 0));
3535   PetscUseMethod(mat, "MatQRFactor_C", (Mat, IS, const MatFactorInfo *), (mat, col, info));
3536   PetscCall(PetscLogEventEnd(MAT_QRFactor, mat, col, 0, 0));
3537   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3538   PetscFunctionReturn(PETSC_SUCCESS);
3539 }
3540 
3541 /*@
3542   MatQRFactorSymbolic - Performs symbolic QR factorization of matrix.
3543   Call this routine after `MatGetFactor()` but before calling `MatQRFactorNumeric()`.
3544 
3545   Collective
3546 
3547   Input Parameters:
3548 + fact - the factor matrix obtained with `MatGetFactor()`
3549 . mat  - the matrix
3550 . col  - column permutation
3551 - info - options for factorization, includes
3552 .vb
3553           fill - expected fill as ratio of original fill.
3554           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3555                    Run with the option -info to determine an optimal value to use
3556 .ve
3557 
3558   Level: developer
3559 
3560   Note:
3561   Most users should employ the `KSP` interface for linear solvers
3562   instead of working directly with matrix algebra routines such as this.
3563   See, e.g., `KSPCreate()`.
3564 
3565   Fortran Note:
3566   A valid (non-null) `info` argument must be provided
3567 
3568 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatQRFactor()`, `MatQRFactorNumeric()`, `MatLUFactor()`, `MatFactorInfoInitialize()`
3569 @*/
3570 PetscErrorCode MatQRFactorSymbolic(Mat fact, Mat mat, IS col, const MatFactorInfo *info)
3571 {
3572   MatFactorInfo tinfo;
3573 
3574   PetscFunctionBegin;
3575   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3576   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3577   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3578   if (info) PetscAssertPointer(info, 4);
3579   PetscValidType(fact, 1);
3580   PetscValidType(mat, 2);
3581   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3582   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3583   MatCheckPreallocated(mat, 2);
3584   if (!info) {
3585     PetscCall(MatFactorInfoInitialize(&tinfo));
3586     info = &tinfo;
3587   }
3588 
3589   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_QRFactorSymbolic, fact, mat, col, 0));
3590   PetscUseMethod(fact, "MatQRFactorSymbolic_C", (Mat, Mat, IS, const MatFactorInfo *), (fact, mat, col, info));
3591   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_QRFactorSymbolic, fact, mat, col, 0));
3592   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3593   PetscFunctionReturn(PETSC_SUCCESS);
3594 }
3595 
3596 /*@
3597   MatQRFactorNumeric - Performs numeric QR factorization of a matrix.
3598   Call this routine after first calling `MatGetFactor()`, and `MatQRFactorSymbolic()`.
3599 
3600   Collective
3601 
3602   Input Parameters:
3603 + fact - the factor matrix obtained with `MatGetFactor()`
3604 . mat  - the matrix
3605 - info - options for factorization
3606 
3607   Level: developer
3608 
3609   Notes:
3610   See `MatQRFactor()` for in-place factorization.
3611 
3612   Most users should employ the `KSP` interface for linear solvers
3613   instead of working directly with matrix algebra routines such as this.
3614   See, e.g., `KSPCreate()`.
3615 
3616   Fortran Note:
3617   A valid (non-null) `info` argument must be provided
3618 
3619 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatQRFactor()`, `MatQRFactorSymbolic()`, `MatLUFactor()`
3620 @*/
3621 PetscErrorCode MatQRFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3622 {
3623   MatFactorInfo tinfo;
3624 
3625   PetscFunctionBegin;
3626   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3627   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3628   PetscValidType(fact, 1);
3629   PetscValidType(mat, 2);
3630   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3631   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,
3632              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3633 
3634   MatCheckPreallocated(mat, 2);
3635   if (!info) {
3636     PetscCall(MatFactorInfoInitialize(&tinfo));
3637     info = &tinfo;
3638   }
3639 
3640   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_QRFactorNumeric, mat, fact, 0, 0));
3641   else PetscCall(PetscLogEventBegin(MAT_QRFactor, mat, fact, 0, 0));
3642   PetscUseMethod(fact, "MatQRFactorNumeric_C", (Mat, Mat, const MatFactorInfo *), (fact, mat, info));
3643   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_QRFactorNumeric, mat, fact, 0, 0));
3644   else PetscCall(PetscLogEventEnd(MAT_QRFactor, mat, fact, 0, 0));
3645   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3646   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3647   PetscFunctionReturn(PETSC_SUCCESS);
3648 }
3649 
3650 /*@
3651   MatSolve - Solves $A x = b$, given a factored matrix.
3652 
3653   Neighbor-wise Collective
3654 
3655   Input Parameters:
3656 + mat - the factored matrix
3657 - b   - the right-hand-side vector
3658 
3659   Output Parameter:
3660 . x - the result vector
3661 
3662   Level: developer
3663 
3664   Notes:
3665   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3666   call `MatSolve`(A,x,x).
3667 
3668   Most users should employ the `KSP` interface for linear solvers
3669   instead of working directly with matrix algebra routines such as this.
3670   See, e.g., `KSPCreate()`.
3671 
3672 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactor()`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`
3673 @*/
3674 PetscErrorCode MatSolve(Mat mat, Vec b, Vec x)
3675 {
3676   PetscFunctionBegin;
3677   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3678   PetscValidType(mat, 1);
3679   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3680   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3681   PetscCheckSameComm(mat, 1, b, 2);
3682   PetscCheckSameComm(mat, 1, x, 3);
3683   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3684   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);
3685   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);
3686   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);
3687   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3688   MatCheckPreallocated(mat, 1);
3689 
3690   PetscCall(PetscLogEventBegin(MAT_Solve, mat, b, x, 0));
3691   PetscCall(VecFlag(x, mat->factorerrortype));
3692   if (mat->factorerrortype) {
3693     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
3694   } else PetscUseTypeMethod(mat, solve, b, x);
3695   PetscCall(PetscLogEventEnd(MAT_Solve, mat, b, x, 0));
3696   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3697   PetscFunctionReturn(PETSC_SUCCESS);
3698 }
3699 
3700 static PetscErrorCode MatMatSolve_Basic(Mat A, Mat B, Mat X, PetscBool trans)
3701 {
3702   Vec      b, x;
3703   PetscInt N, i;
3704   PetscErrorCode (*f)(Mat, Vec, Vec);
3705   PetscBool Abound, Bneedconv = PETSC_FALSE, Xneedconv = PETSC_FALSE;
3706 
3707   PetscFunctionBegin;
3708   if (A->factorerrortype) {
3709     PetscCall(PetscInfo(A, "MatFactorError %d\n", A->factorerrortype));
3710     PetscCall(MatSetInf(X));
3711     PetscFunctionReturn(PETSC_SUCCESS);
3712   }
3713   f = (!trans || (!A->ops->solvetranspose && A->symmetric)) ? A->ops->solve : A->ops->solvetranspose;
3714   PetscCheck(f, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Mat type %s", ((PetscObject)A)->type_name);
3715   PetscCall(MatBoundToCPU(A, &Abound));
3716   if (!Abound) {
3717     PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &Bneedconv, MATSEQDENSE, MATMPIDENSE, ""));
3718     PetscCall(PetscObjectTypeCompareAny((PetscObject)X, &Xneedconv, MATSEQDENSE, MATMPIDENSE, ""));
3719   }
3720 #if PetscDefined(HAVE_CUDA)
3721   if (Bneedconv) PetscCall(MatConvert(B, MATDENSECUDA, MAT_INPLACE_MATRIX, &B));
3722   if (Xneedconv) PetscCall(MatConvert(X, MATDENSECUDA, MAT_INPLACE_MATRIX, &X));
3723 #elif PetscDefined(HAVE_HIP)
3724   if (Bneedconv) PetscCall(MatConvert(B, MATDENSEHIP, MAT_INPLACE_MATRIX, &B));
3725   if (Xneedconv) PetscCall(MatConvert(X, MATDENSEHIP, MAT_INPLACE_MATRIX, &X));
3726 #endif
3727   PetscCall(MatGetSize(B, NULL, &N));
3728   for (i = 0; i < N; i++) {
3729     PetscCall(MatDenseGetColumnVecRead(B, i, &b));
3730     PetscCall(MatDenseGetColumnVecWrite(X, i, &x));
3731     PetscCall((*f)(A, b, x));
3732     PetscCall(MatDenseRestoreColumnVecWrite(X, i, &x));
3733     PetscCall(MatDenseRestoreColumnVecRead(B, i, &b));
3734   }
3735   if (Bneedconv) PetscCall(MatConvert(B, MATDENSE, MAT_INPLACE_MATRIX, &B));
3736   if (Xneedconv) PetscCall(MatConvert(X, MATDENSE, MAT_INPLACE_MATRIX, &X));
3737   PetscFunctionReturn(PETSC_SUCCESS);
3738 }
3739 
3740 /*@
3741   MatMatSolve - Solves $A X = B$, given a factored matrix.
3742 
3743   Neighbor-wise Collective
3744 
3745   Input Parameters:
3746 + A - the factored matrix
3747 - B - the right-hand-side matrix `MATDENSE` (or sparse `MATAIJ`-- when using MUMPS)
3748 
3749   Output Parameter:
3750 . X - the result matrix (dense matrix)
3751 
3752   Level: developer
3753 
3754   Note:
3755   If `B` is a `MATDENSE` matrix then one can call `MatMatSolve`(A,B,B) except with `MATSOLVERMKL_CPARDISO`;
3756   otherwise, `B` and `X` cannot be the same.
3757 
3758 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolve()`, `MatMatSolveTranspose()`, `MatLUFactor()`, `MatCholeskyFactor()`
3759 @*/
3760 PetscErrorCode MatMatSolve(Mat A, Mat B, Mat X)
3761 {
3762   PetscFunctionBegin;
3763   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3764   PetscValidType(A, 1);
3765   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
3766   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3767   PetscCheckSameComm(A, 1, B, 2);
3768   PetscCheckSameComm(A, 1, X, 3);
3769   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);
3770   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);
3771   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");
3772   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3773   MatCheckPreallocated(A, 1);
3774 
3775   PetscCall(PetscLogEventBegin(MAT_MatSolve, A, B, X, 0));
3776   if (!A->ops->matsolve) {
3777     PetscCall(PetscInfo(A, "Mat type %s using basic MatMatSolve\n", ((PetscObject)A)->type_name));
3778     PetscCall(MatMatSolve_Basic(A, B, X, PETSC_FALSE));
3779   } else PetscUseTypeMethod(A, matsolve, B, X);
3780   PetscCall(PetscLogEventEnd(MAT_MatSolve, A, B, X, 0));
3781   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3782   PetscFunctionReturn(PETSC_SUCCESS);
3783 }
3784 
3785 /*@
3786   MatMatSolveTranspose - Solves $A^T X = B $, given a factored matrix.
3787 
3788   Neighbor-wise Collective
3789 
3790   Input Parameters:
3791 + A - the factored matrix
3792 - B - the right-hand-side matrix  (`MATDENSE` matrix)
3793 
3794   Output Parameter:
3795 . X - the result matrix (dense matrix)
3796 
3797   Level: developer
3798 
3799   Note:
3800   The matrices `B` and `X` cannot be the same.  I.e., one cannot
3801   call `MatMatSolveTranspose`(A,X,X).
3802 
3803 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolveTranspose()`, `MatMatSolve()`, `MatLUFactor()`, `MatCholeskyFactor()`
3804 @*/
3805 PetscErrorCode MatMatSolveTranspose(Mat A, Mat B, Mat X)
3806 {
3807   PetscFunctionBegin;
3808   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3809   PetscValidType(A, 1);
3810   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
3811   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3812   PetscCheckSameComm(A, 1, B, 2);
3813   PetscCheckSameComm(A, 1, X, 3);
3814   PetscCheck(X != B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_IDN, "X and B must be different matrices");
3815   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);
3816   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);
3817   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);
3818   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");
3819   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3820   MatCheckPreallocated(A, 1);
3821 
3822   PetscCall(PetscLogEventBegin(MAT_MatSolve, A, B, X, 0));
3823   if (!A->ops->matsolvetranspose) {
3824     PetscCall(PetscInfo(A, "Mat type %s using basic MatMatSolveTranspose\n", ((PetscObject)A)->type_name));
3825     PetscCall(MatMatSolve_Basic(A, B, X, PETSC_TRUE));
3826   } else PetscUseTypeMethod(A, matsolvetranspose, B, X);
3827   PetscCall(PetscLogEventEnd(MAT_MatSolve, A, B, X, 0));
3828   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3829   PetscFunctionReturn(PETSC_SUCCESS);
3830 }
3831 
3832 /*@
3833   MatMatTransposeSolve - Solves $A X = B^T$, given a factored matrix.
3834 
3835   Neighbor-wise Collective
3836 
3837   Input Parameters:
3838 + A  - the factored matrix
3839 - Bt - the transpose of right-hand-side matrix as a `MATDENSE`
3840 
3841   Output Parameter:
3842 . X - the result matrix (dense matrix)
3843 
3844   Level: developer
3845 
3846   Note:
3847   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
3848   format on the host processor and call `MatMatTransposeSolve()` to implement MUMPS' `MatMatSolve()`.
3849 
3850 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatMatSolve()`, `MatMatSolveTranspose()`, `MatLUFactor()`, `MatCholeskyFactor()`
3851 @*/
3852 PetscErrorCode MatMatTransposeSolve(Mat A, Mat Bt, Mat X)
3853 {
3854   PetscFunctionBegin;
3855   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3856   PetscValidType(A, 1);
3857   PetscValidHeaderSpecific(Bt, MAT_CLASSID, 2);
3858   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3859   PetscCheckSameComm(A, 1, Bt, 2);
3860   PetscCheckSameComm(A, 1, X, 3);
3861 
3862   PetscCheck(X != Bt, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_IDN, "X and B must be different matrices");
3863   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);
3864   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);
3865   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");
3866   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3867   PetscCheck(A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
3868   MatCheckPreallocated(A, 1);
3869 
3870   PetscCall(PetscLogEventBegin(MAT_MatTrSolve, A, Bt, X, 0));
3871   PetscUseTypeMethod(A, mattransposesolve, Bt, X);
3872   PetscCall(PetscLogEventEnd(MAT_MatTrSolve, A, Bt, X, 0));
3873   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3874   PetscFunctionReturn(PETSC_SUCCESS);
3875 }
3876 
3877 /*@
3878   MatForwardSolve - Solves $ L x = b $, given a factored matrix, $A = LU $, or
3879   $U^T*D^(1/2) x = b$, given a factored symmetric matrix, $A = U^T*D*U$,
3880 
3881   Neighbor-wise Collective
3882 
3883   Input Parameters:
3884 + mat - the factored matrix
3885 - b   - the right-hand-side vector
3886 
3887   Output Parameter:
3888 . x - the result vector
3889 
3890   Level: developer
3891 
3892   Notes:
3893   `MatSolve()` should be used for most applications, as it performs
3894   a forward solve followed by a backward solve.
3895 
3896   The vectors `b` and `x` cannot be the same,  i.e., one cannot
3897   call `MatForwardSolve`(A,x,x).
3898 
3899   For matrix in `MATSEQBAIJ` format with block size larger than 1,
3900   the diagonal blocks are not implemented as $D = D^(1/2) * D^(1/2)$ yet.
3901   `MatForwardSolve()` solves $U^T*D y = b$, and
3902   `MatBackwardSolve()` solves $U x = y$.
3903   Thus they do not provide a symmetric preconditioner.
3904 
3905 .seealso: [](ch_matrices), `Mat`, `MatBackwardSolve()`, `MatGetFactor()`, `MatSolve()`
3906 @*/
3907 PetscErrorCode MatForwardSolve(Mat mat, Vec b, Vec x)
3908 {
3909   PetscFunctionBegin;
3910   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3911   PetscValidType(mat, 1);
3912   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3913   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3914   PetscCheckSameComm(mat, 1, b, 2);
3915   PetscCheckSameComm(mat, 1, x, 3);
3916   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3917   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);
3918   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);
3919   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);
3920   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3921   MatCheckPreallocated(mat, 1);
3922 
3923   PetscCall(PetscLogEventBegin(MAT_ForwardSolve, mat, b, x, 0));
3924   PetscUseTypeMethod(mat, forwardsolve, b, x);
3925   PetscCall(PetscLogEventEnd(MAT_ForwardSolve, mat, b, x, 0));
3926   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3927   PetscFunctionReturn(PETSC_SUCCESS);
3928 }
3929 
3930 /*@
3931   MatBackwardSolve - Solves $U x = b$, given a factored matrix, $A = LU$.
3932   $D^(1/2) U x = b$, given a factored symmetric matrix, $A = U^T*D*U$,
3933 
3934   Neighbor-wise Collective
3935 
3936   Input Parameters:
3937 + mat - the factored matrix
3938 - b   - the right-hand-side vector
3939 
3940   Output Parameter:
3941 . x - the result vector
3942 
3943   Level: developer
3944 
3945   Notes:
3946   `MatSolve()` should be used for most applications, as it performs
3947   a forward solve followed by a backward solve.
3948 
3949   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3950   call `MatBackwardSolve`(A,x,x).
3951 
3952   For matrix in `MATSEQBAIJ` format with block size larger than 1,
3953   the diagonal blocks are not implemented as $D = D^(1/2) * D^(1/2)$ yet.
3954   `MatForwardSolve()` solves $U^T*D y = b$, and
3955   `MatBackwardSolve()` solves $U x = y$.
3956   Thus they do not provide a symmetric preconditioner.
3957 
3958 .seealso: [](ch_matrices), `Mat`, `MatForwardSolve()`, `MatGetFactor()`, `MatSolve()`
3959 @*/
3960 PetscErrorCode MatBackwardSolve(Mat mat, Vec b, Vec x)
3961 {
3962   PetscFunctionBegin;
3963   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3964   PetscValidType(mat, 1);
3965   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3966   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3967   PetscCheckSameComm(mat, 1, b, 2);
3968   PetscCheckSameComm(mat, 1, x, 3);
3969   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3970   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);
3971   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);
3972   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);
3973   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3974   MatCheckPreallocated(mat, 1);
3975 
3976   PetscCall(PetscLogEventBegin(MAT_BackwardSolve, mat, b, x, 0));
3977   PetscUseTypeMethod(mat, backwardsolve, b, x);
3978   PetscCall(PetscLogEventEnd(MAT_BackwardSolve, mat, b, x, 0));
3979   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3980   PetscFunctionReturn(PETSC_SUCCESS);
3981 }
3982 
3983 /*@
3984   MatSolveAdd - Computes $x = y + A^{-1}*b$, given a factored matrix.
3985 
3986   Neighbor-wise Collective
3987 
3988   Input Parameters:
3989 + mat - the factored matrix
3990 . b   - the right-hand-side vector
3991 - y   - the vector to be added to
3992 
3993   Output Parameter:
3994 . x - the result vector
3995 
3996   Level: developer
3997 
3998   Note:
3999   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4000   call `MatSolveAdd`(A,x,y,x).
4001 
4002 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatSolve()`, `MatGetFactor()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`
4003 @*/
4004 PetscErrorCode MatSolveAdd(Mat mat, Vec b, Vec y, Vec x)
4005 {
4006   PetscScalar one = 1.0;
4007   Vec         tmp;
4008 
4009   PetscFunctionBegin;
4010   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4011   PetscValidType(mat, 1);
4012   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
4013   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4014   PetscValidHeaderSpecific(x, VEC_CLASSID, 4);
4015   PetscCheckSameComm(mat, 1, b, 2);
4016   PetscCheckSameComm(mat, 1, y, 3);
4017   PetscCheckSameComm(mat, 1, x, 4);
4018   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4019   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);
4020   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);
4021   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);
4022   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);
4023   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);
4024   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4025   MatCheckPreallocated(mat, 1);
4026 
4027   PetscCall(PetscLogEventBegin(MAT_SolveAdd, mat, b, x, y));
4028   PetscCall(VecFlag(x, mat->factorerrortype));
4029   if (mat->factorerrortype) {
4030     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4031   } else if (mat->ops->solveadd) {
4032     PetscUseTypeMethod(mat, solveadd, b, y, x);
4033   } else {
4034     /* do the solve then the add manually */
4035     if (x != y) {
4036       PetscCall(MatSolve(mat, b, x));
4037       PetscCall(VecAXPY(x, one, y));
4038     } else {
4039       PetscCall(VecDuplicate(x, &tmp));
4040       PetscCall(VecCopy(x, tmp));
4041       PetscCall(MatSolve(mat, b, x));
4042       PetscCall(VecAXPY(x, one, tmp));
4043       PetscCall(VecDestroy(&tmp));
4044     }
4045   }
4046   PetscCall(PetscLogEventEnd(MAT_SolveAdd, mat, b, x, y));
4047   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4048   PetscFunctionReturn(PETSC_SUCCESS);
4049 }
4050 
4051 /*@
4052   MatSolveTranspose - Solves $A^T x = b$, given a factored matrix.
4053 
4054   Neighbor-wise Collective
4055 
4056   Input Parameters:
4057 + mat - the factored matrix
4058 - b   - the right-hand-side vector
4059 
4060   Output Parameter:
4061 . x - the result vector
4062 
4063   Level: developer
4064 
4065   Notes:
4066   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4067   call `MatSolveTranspose`(A,x,x).
4068 
4069   Most users should employ the `KSP` interface for linear solvers
4070   instead of working directly with matrix algebra routines such as this.
4071   See, e.g., `KSPCreate()`.
4072 
4073 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `KSP`, `MatSolve()`, `MatSolveAdd()`, `MatSolveTransposeAdd()`
4074 @*/
4075 PetscErrorCode MatSolveTranspose(Mat mat, Vec b, Vec x)
4076 {
4077   PetscErrorCode (*f)(Mat, Vec, Vec) = (!mat->ops->solvetranspose && mat->symmetric) ? mat->ops->solve : mat->ops->solvetranspose;
4078 
4079   PetscFunctionBegin;
4080   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4081   PetscValidType(mat, 1);
4082   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4083   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
4084   PetscCheckSameComm(mat, 1, b, 2);
4085   PetscCheckSameComm(mat, 1, x, 3);
4086   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4087   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);
4088   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);
4089   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4090   MatCheckPreallocated(mat, 1);
4091   PetscCall(PetscLogEventBegin(MAT_SolveTranspose, mat, b, x, 0));
4092   PetscCall(VecFlag(x, mat->factorerrortype));
4093   if (mat->factorerrortype) {
4094     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4095   } else {
4096     PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Matrix type %s", ((PetscObject)mat)->type_name);
4097     PetscCall((*f)(mat, b, x));
4098   }
4099   PetscCall(PetscLogEventEnd(MAT_SolveTranspose, mat, b, x, 0));
4100   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4101   PetscFunctionReturn(PETSC_SUCCESS);
4102 }
4103 
4104 /*@
4105   MatSolveTransposeAdd - Computes $x = y + A^{-T} b$
4106   factored matrix.
4107 
4108   Neighbor-wise Collective
4109 
4110   Input Parameters:
4111 + mat - the factored matrix
4112 . b   - the right-hand-side vector
4113 - y   - the vector to be added to
4114 
4115   Output Parameter:
4116 . x - the result vector
4117 
4118   Level: developer
4119 
4120   Note:
4121   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4122   call `MatSolveTransposeAdd`(A,x,y,x).
4123 
4124 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatSolve()`, `MatSolveAdd()`, `MatSolveTranspose()`
4125 @*/
4126 PetscErrorCode MatSolveTransposeAdd(Mat mat, Vec b, Vec y, Vec x)
4127 {
4128   PetscScalar one = 1.0;
4129   Vec         tmp;
4130   PetscErrorCode (*f)(Mat, Vec, Vec, Vec) = (!mat->ops->solvetransposeadd && mat->symmetric) ? mat->ops->solveadd : mat->ops->solvetransposeadd;
4131 
4132   PetscFunctionBegin;
4133   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4134   PetscValidType(mat, 1);
4135   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
4136   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4137   PetscValidHeaderSpecific(x, VEC_CLASSID, 4);
4138   PetscCheckSameComm(mat, 1, b, 2);
4139   PetscCheckSameComm(mat, 1, y, 3);
4140   PetscCheckSameComm(mat, 1, x, 4);
4141   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4142   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);
4143   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);
4144   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);
4145   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);
4146   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4147   MatCheckPreallocated(mat, 1);
4148 
4149   PetscCall(PetscLogEventBegin(MAT_SolveTransposeAdd, mat, b, x, y));
4150   PetscCall(VecFlag(x, mat->factorerrortype));
4151   if (mat->factorerrortype) {
4152     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4153   } else if (f) {
4154     PetscCall((*f)(mat, b, y, x));
4155   } else {
4156     /* do the solve then the add manually */
4157     if (x != y) {
4158       PetscCall(MatSolveTranspose(mat, b, x));
4159       PetscCall(VecAXPY(x, one, y));
4160     } else {
4161       PetscCall(VecDuplicate(x, &tmp));
4162       PetscCall(VecCopy(x, tmp));
4163       PetscCall(MatSolveTranspose(mat, b, x));
4164       PetscCall(VecAXPY(x, one, tmp));
4165       PetscCall(VecDestroy(&tmp));
4166     }
4167   }
4168   PetscCall(PetscLogEventEnd(MAT_SolveTransposeAdd, mat, b, x, y));
4169   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4170   PetscFunctionReturn(PETSC_SUCCESS);
4171 }
4172 
4173 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
4174 /*@
4175   MatSOR - Computes relaxation (SOR, Gauss-Seidel) sweeps.
4176 
4177   Neighbor-wise Collective
4178 
4179   Input Parameters:
4180 + mat   - the matrix
4181 . b     - the right-hand side
4182 . omega - the relaxation factor
4183 . flag  - flag indicating the type of SOR (see below)
4184 . shift - diagonal shift
4185 . its   - the number of iterations
4186 - lits  - the number of local iterations
4187 
4188   Output Parameter:
4189 . x - the solution (can contain an initial guess, use option `SOR_ZERO_INITIAL_GUESS` to indicate no guess)
4190 
4191   SOR Flags:
4192 +     `SOR_FORWARD_SWEEP` - forward SOR
4193 .     `SOR_BACKWARD_SWEEP` - backward SOR
4194 .     `SOR_SYMMETRIC_SWEEP` - SSOR (symmetric SOR)
4195 .     `SOR_LOCAL_FORWARD_SWEEP` - local forward SOR
4196 .     `SOR_LOCAL_BACKWARD_SWEEP` - local forward SOR
4197 .     `SOR_LOCAL_SYMMETRIC_SWEEP` - local SSOR
4198 .     `SOR_EISENSTAT` - SOR with Eisenstat trick
4199 .     `SOR_APPLY_UPPER`, `SOR_APPLY_LOWER` - applies
4200   upper/lower triangular part of matrix to
4201   vector (with omega)
4202 -     `SOR_ZERO_INITIAL_GUESS` - zero initial guess
4203 
4204   Level: developer
4205 
4206   Notes:
4207   `SOR_LOCAL_FORWARD_SWEEP`, `SOR_LOCAL_BACKWARD_SWEEP`, and
4208   `SOR_LOCAL_SYMMETRIC_SWEEP` perform separate independent smoothings
4209   on each processor.
4210 
4211   Application programmers will not generally use `MatSOR()` directly,
4212   but instead will employ the `KSP`/`PC` interface.
4213 
4214   For `MATBAIJ`, `MATSBAIJ`, and `MATAIJ` matrices with Inodes this does a block SOR smoothing, otherwise it does a pointwise smoothing
4215 
4216   Most users should employ the `KSP` interface for linear solvers
4217   instead of working directly with matrix algebra routines such as this.
4218   See, e.g., `KSPCreate()`.
4219 
4220   Vectors `x` and `b` CANNOT be the same
4221 
4222   The flags are implemented as bitwise inclusive or operations.
4223   For example, use (`SOR_ZERO_INITIAL_GUESS` | `SOR_SYMMETRIC_SWEEP`)
4224   to specify a zero initial guess for SSOR.
4225 
4226   Developer Note:
4227   We should add block SOR support for `MATAIJ` matrices with block size set to great than one and no inodes
4228 
4229 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `KSP`, `PC`, `MatGetFactor()`
4230 @*/
4231 PetscErrorCode MatSOR(Mat mat, Vec b, PetscReal omega, MatSORType flag, PetscReal shift, PetscInt its, PetscInt lits, Vec x)
4232 {
4233   PetscFunctionBegin;
4234   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4235   PetscValidType(mat, 1);
4236   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4237   PetscValidHeaderSpecific(x, VEC_CLASSID, 8);
4238   PetscCheckSameComm(mat, 1, b, 2);
4239   PetscCheckSameComm(mat, 1, x, 8);
4240   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4241   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4242   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);
4243   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);
4244   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);
4245   PetscCheck(its > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires global its %" PetscInt_FMT " positive", its);
4246   PetscCheck(lits > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires local its %" PetscInt_FMT " positive", lits);
4247   PetscCheck(b != x, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "b and x vector cannot be the same");
4248 
4249   MatCheckPreallocated(mat, 1);
4250   PetscCall(PetscLogEventBegin(MAT_SOR, mat, b, x, 0));
4251   PetscUseTypeMethod(mat, sor, b, omega, flag, shift, its, lits, x);
4252   PetscCall(PetscLogEventEnd(MAT_SOR, mat, b, x, 0));
4253   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4254   PetscFunctionReturn(PETSC_SUCCESS);
4255 }
4256 
4257 /*
4258       Default matrix copy routine.
4259 */
4260 PetscErrorCode MatCopy_Basic(Mat A, Mat B, MatStructure str)
4261 {
4262   PetscInt           i, rstart = 0, rend = 0, nz;
4263   const PetscInt    *cwork;
4264   const PetscScalar *vwork;
4265 
4266   PetscFunctionBegin;
4267   if (B->assembled) PetscCall(MatZeroEntries(B));
4268   if (str == SAME_NONZERO_PATTERN) {
4269     PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
4270     for (i = rstart; i < rend; i++) {
4271       PetscCall(MatGetRow(A, i, &nz, &cwork, &vwork));
4272       PetscCall(MatSetValues(B, 1, &i, nz, cwork, vwork, INSERT_VALUES));
4273       PetscCall(MatRestoreRow(A, i, &nz, &cwork, &vwork));
4274     }
4275   } else {
4276     PetscCall(MatAYPX(B, 0.0, A, str));
4277   }
4278   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
4279   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
4280   PetscFunctionReturn(PETSC_SUCCESS);
4281 }
4282 
4283 /*@
4284   MatCopy - Copies a matrix to another matrix.
4285 
4286   Collective
4287 
4288   Input Parameters:
4289 + A   - the matrix
4290 - str - `SAME_NONZERO_PATTERN` or `DIFFERENT_NONZERO_PATTERN`
4291 
4292   Output Parameter:
4293 . B - where the copy is put
4294 
4295   Level: intermediate
4296 
4297   Notes:
4298   If you use `SAME_NONZERO_PATTERN`, then the two matrices must have the same nonzero pattern or the routine will crash.
4299 
4300   `MatCopy()` copies the matrix entries of a matrix to another existing
4301   matrix (after first zeroing the second matrix).  A related routine is
4302   `MatConvert()`, which first creates a new matrix and then copies the data.
4303 
4304 .seealso: [](ch_matrices), `Mat`, `MatConvert()`, `MatDuplicate()`
4305 @*/
4306 PetscErrorCode MatCopy(Mat A, Mat B, MatStructure str)
4307 {
4308   PetscInt i;
4309 
4310   PetscFunctionBegin;
4311   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
4312   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
4313   PetscValidType(A, 1);
4314   PetscValidType(B, 2);
4315   PetscCheckSameComm(A, 1, B, 2);
4316   MatCheckPreallocated(B, 2);
4317   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4318   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4319   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,
4320              A->cmap->N, B->cmap->N);
4321   MatCheckPreallocated(A, 1);
4322   if (A == B) PetscFunctionReturn(PETSC_SUCCESS);
4323 
4324   PetscCall(PetscLogEventBegin(MAT_Copy, A, B, 0, 0));
4325   if (A->ops->copy) PetscUseTypeMethod(A, copy, B, str);
4326   else PetscCall(MatCopy_Basic(A, B, str));
4327 
4328   B->stencil.dim = A->stencil.dim;
4329   B->stencil.noc = A->stencil.noc;
4330   for (i = 0; i <= A->stencil.dim + (A->stencil.noc ? 0 : -1); i++) {
4331     B->stencil.dims[i]   = A->stencil.dims[i];
4332     B->stencil.starts[i] = A->stencil.starts[i];
4333   }
4334 
4335   PetscCall(PetscLogEventEnd(MAT_Copy, A, B, 0, 0));
4336   PetscCall(PetscObjectStateIncrease((PetscObject)B));
4337   PetscFunctionReturn(PETSC_SUCCESS);
4338 }
4339 
4340 /*@
4341   MatConvert - Converts a matrix to another matrix, either of the same
4342   or different type.
4343 
4344   Collective
4345 
4346   Input Parameters:
4347 + mat     - the matrix
4348 . newtype - new matrix type.  Use `MATSAME` to create a new matrix of the
4349             same type as the original matrix.
4350 - reuse   - denotes if the destination matrix is to be created or reused.
4351             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
4352             `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).
4353 
4354   Output Parameter:
4355 . M - pointer to place new matrix
4356 
4357   Level: intermediate
4358 
4359   Notes:
4360   `MatConvert()` first creates a new matrix and then copies the data from
4361   the first matrix.  A related routine is `MatCopy()`, which copies the matrix
4362   entries of one matrix to another already existing matrix context.
4363 
4364   Cannot be used to convert a sequential matrix to parallel or parallel to sequential,
4365   the MPI communicator of the generated matrix is always the same as the communicator
4366   of the input matrix.
4367 
4368 .seealso: [](ch_matrices), `Mat`, `MatCopy()`, `MatDuplicate()`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
4369 @*/
4370 PetscErrorCode MatConvert(Mat mat, MatType newtype, MatReuse reuse, Mat *M)
4371 {
4372   PetscBool  sametype, issame, flg;
4373   PetscBool3 issymmetric, ishermitian;
4374   char       convname[256], mtype[256];
4375   Mat        B;
4376 
4377   PetscFunctionBegin;
4378   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4379   PetscValidType(mat, 1);
4380   PetscAssertPointer(M, 4);
4381   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4382   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4383   MatCheckPreallocated(mat, 1);
4384 
4385   PetscCall(PetscOptionsGetString(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matconvert_type", mtype, sizeof(mtype), &flg));
4386   if (flg) newtype = mtype;
4387 
4388   PetscCall(PetscObjectTypeCompare((PetscObject)mat, newtype, &sametype));
4389   PetscCall(PetscStrcmp(newtype, "same", &issame));
4390   PetscCheck(!(reuse == MAT_INPLACE_MATRIX) || !(mat != *M), PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX requires same input and output matrix");
4391   if (reuse == MAT_REUSE_MATRIX) {
4392     PetscValidHeaderSpecific(*M, MAT_CLASSID, 4);
4393     PetscCheck(mat != *M, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_REUSE_MATRIX means reuse matrix in final argument, perhaps you mean MAT_INPLACE_MATRIX");
4394   }
4395 
4396   if ((reuse == MAT_INPLACE_MATRIX) && (issame || sametype)) {
4397     PetscCall(PetscInfo(mat, "Early return for inplace %s %d %d\n", ((PetscObject)mat)->type_name, sametype, issame));
4398     PetscFunctionReturn(PETSC_SUCCESS);
4399   }
4400 
4401   /* Cache Mat options because some converters use MatHeaderReplace  */
4402   issymmetric = mat->symmetric;
4403   ishermitian = mat->hermitian;
4404 
4405   if ((sametype || issame) && (reuse == MAT_INITIAL_MATRIX) && mat->ops->duplicate) {
4406     PetscCall(PetscInfo(mat, "Calling duplicate for initial matrix %s %d %d\n", ((PetscObject)mat)->type_name, sametype, issame));
4407     PetscUseTypeMethod(mat, duplicate, MAT_COPY_VALUES, M);
4408   } else {
4409     PetscErrorCode (*conv)(Mat, MatType, MatReuse, Mat *) = NULL;
4410     const char *prefix[3]                                 = {"seq", "mpi", ""};
4411     PetscInt    i;
4412     /*
4413        Order of precedence:
4414        0) See if newtype is a superclass of the current matrix.
4415        1) See if a specialized converter is known to the current matrix.
4416        2) See if a specialized converter is known to the desired matrix class.
4417        3) See if a good general converter is registered for the desired class
4418           (as of 6/27/03 only MATMPIADJ falls into this category).
4419        4) See if a good general converter is known for the current matrix.
4420        5) Use a really basic converter.
4421     */
4422 
4423     /* 0) See if newtype is a superclass of the current matrix.
4424           i.e mat is mpiaij and newtype is aij */
4425     for (i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(prefix); i++) {
4426       PetscCall(PetscStrncpy(convname, prefix[i], sizeof(convname)));
4427       PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4428       PetscCall(PetscStrcmp(convname, ((PetscObject)mat)->type_name, &flg));
4429       PetscCall(PetscInfo(mat, "Check superclass %s %s -> %d\n", convname, ((PetscObject)mat)->type_name, flg));
4430       if (flg) {
4431         if (reuse == MAT_INPLACE_MATRIX) {
4432           PetscCall(PetscInfo(mat, "Early return\n"));
4433           PetscFunctionReturn(PETSC_SUCCESS);
4434         } else if (reuse == MAT_INITIAL_MATRIX && mat->ops->duplicate) {
4435           PetscCall(PetscInfo(mat, "Calling MatDuplicate\n"));
4436           PetscUseTypeMethod(mat, duplicate, MAT_COPY_VALUES, M);
4437           PetscFunctionReturn(PETSC_SUCCESS);
4438         } else if (reuse == MAT_REUSE_MATRIX && mat->ops->copy) {
4439           PetscCall(PetscInfo(mat, "Calling MatCopy\n"));
4440           PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
4441           PetscFunctionReturn(PETSC_SUCCESS);
4442         }
4443       }
4444     }
4445     /* 1) See if a specialized converter is known to the current matrix and the desired class */
4446     for (i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(prefix); i++) {
4447       PetscCall(PetscStrncpy(convname, "MatConvert_", sizeof(convname)));
4448       PetscCall(PetscStrlcat(convname, ((PetscObject)mat)->type_name, sizeof(convname)));
4449       PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4450       PetscCall(PetscStrlcat(convname, prefix[i], sizeof(convname)));
4451       PetscCall(PetscStrlcat(convname, issame ? ((PetscObject)mat)->type_name : newtype, sizeof(convname)));
4452       PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4453       PetscCall(PetscObjectQueryFunction((PetscObject)mat, convname, &conv));
4454       PetscCall(PetscInfo(mat, "Check specialized (1) %s (%s) -> %d\n", convname, ((PetscObject)mat)->type_name, !!conv));
4455       if (conv) goto foundconv;
4456     }
4457 
4458     /* 2)  See if a specialized converter is known to the desired matrix class. */
4459     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
4460     PetscCall(MatSetSizes(B, mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N));
4461     PetscCall(MatSetType(B, newtype));
4462     for (i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(prefix); i++) {
4463       PetscCall(PetscStrncpy(convname, "MatConvert_", sizeof(convname)));
4464       PetscCall(PetscStrlcat(convname, ((PetscObject)mat)->type_name, sizeof(convname)));
4465       PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4466       PetscCall(PetscStrlcat(convname, prefix[i], sizeof(convname)));
4467       PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4468       PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4469       PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4470       PetscCall(PetscInfo(mat, "Check specialized (2) %s (%s) -> %d\n", convname, ((PetscObject)B)->type_name, !!conv));
4471       if (conv) {
4472         PetscCall(MatDestroy(&B));
4473         goto foundconv;
4474       }
4475     }
4476 
4477     /* 3) See if a good general converter is registered for the desired class */
4478     conv = B->ops->convertfrom;
4479     PetscCall(PetscInfo(mat, "Check convertfrom (%s) -> %d\n", ((PetscObject)B)->type_name, !!conv));
4480     PetscCall(MatDestroy(&B));
4481     if (conv) goto foundconv;
4482 
4483     /* 4) See if a good general converter is known for the current matrix */
4484     if (mat->ops->convert) conv = mat->ops->convert;
4485     PetscCall(PetscInfo(mat, "Check general convert (%s) -> %d\n", ((PetscObject)mat)->type_name, !!conv));
4486     if (conv) goto foundconv;
4487 
4488     /* 5) Use a really basic converter. */
4489     PetscCall(PetscInfo(mat, "Using MatConvert_Basic\n"));
4490     conv = MatConvert_Basic;
4491 
4492   foundconv:
4493     PetscCall(PetscLogEventBegin(MAT_Convert, mat, 0, 0, 0));
4494     PetscCall((*conv)(mat, newtype, reuse, M));
4495     if (mat->rmap->mapping && mat->cmap->mapping && !(*M)->rmap->mapping && !(*M)->cmap->mapping) {
4496       /* the block sizes must be same if the mappings are copied over */
4497       (*M)->rmap->bs = mat->rmap->bs;
4498       (*M)->cmap->bs = mat->cmap->bs;
4499       PetscCall(PetscObjectReference((PetscObject)mat->rmap->mapping));
4500       PetscCall(PetscObjectReference((PetscObject)mat->cmap->mapping));
4501       (*M)->rmap->mapping = mat->rmap->mapping;
4502       (*M)->cmap->mapping = mat->cmap->mapping;
4503     }
4504     (*M)->stencil.dim = mat->stencil.dim;
4505     (*M)->stencil.noc = mat->stencil.noc;
4506     for (i = 0; i <= mat->stencil.dim + (mat->stencil.noc ? 0 : -1); i++) {
4507       (*M)->stencil.dims[i]   = mat->stencil.dims[i];
4508       (*M)->stencil.starts[i] = mat->stencil.starts[i];
4509     }
4510     PetscCall(PetscLogEventEnd(MAT_Convert, mat, 0, 0, 0));
4511   }
4512   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4513 
4514   /* Copy Mat options */
4515   if (issymmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*M, MAT_SYMMETRIC, PETSC_TRUE));
4516   else if (issymmetric == PETSC_BOOL3_FALSE) PetscCall(MatSetOption(*M, MAT_SYMMETRIC, PETSC_FALSE));
4517   if (ishermitian == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*M, MAT_HERMITIAN, PETSC_TRUE));
4518   else if (ishermitian == PETSC_BOOL3_FALSE) PetscCall(MatSetOption(*M, MAT_HERMITIAN, PETSC_FALSE));
4519   PetscFunctionReturn(PETSC_SUCCESS);
4520 }
4521 
4522 /*@
4523   MatFactorGetSolverType - Returns name of the package providing the factorization routines
4524 
4525   Not Collective
4526 
4527   Input Parameter:
4528 . mat - the matrix, must be a factored matrix
4529 
4530   Output Parameter:
4531 . type - the string name of the package (do not free this string)
4532 
4533   Level: intermediate
4534 
4535 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolverType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`
4536 @*/
4537 PetscErrorCode MatFactorGetSolverType(Mat mat, MatSolverType *type)
4538 {
4539   PetscErrorCode (*conv)(Mat, MatSolverType *);
4540 
4541   PetscFunctionBegin;
4542   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4543   PetscValidType(mat, 1);
4544   PetscAssertPointer(type, 2);
4545   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
4546   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorGetSolverType_C", &conv));
4547   if (conv) PetscCall((*conv)(mat, type));
4548   else *type = MATSOLVERPETSC;
4549   PetscFunctionReturn(PETSC_SUCCESS);
4550 }
4551 
4552 typedef struct _MatSolverTypeForSpecifcType *MatSolverTypeForSpecifcType;
4553 struct _MatSolverTypeForSpecifcType {
4554   MatType mtype;
4555   /* no entry for MAT_FACTOR_NONE */
4556   PetscErrorCode (*createfactor[MAT_FACTOR_NUM_TYPES - 1])(Mat, MatFactorType, Mat *);
4557   MatSolverTypeForSpecifcType next;
4558 };
4559 
4560 typedef struct _MatSolverTypeHolder *MatSolverTypeHolder;
4561 struct _MatSolverTypeHolder {
4562   char                       *name;
4563   MatSolverTypeForSpecifcType handlers;
4564   MatSolverTypeHolder         next;
4565 };
4566 
4567 static MatSolverTypeHolder MatSolverTypeHolders = NULL;
4568 
4569 /*@C
4570   MatSolverTypeRegister - Registers a `MatSolverType` that works for a particular matrix type
4571 
4572   Logically Collective, No Fortran Support
4573 
4574   Input Parameters:
4575 + package      - name of the package, for example `petsc` or `superlu`
4576 . mtype        - the matrix type that works with this package
4577 . ftype        - the type of factorization supported by the package
4578 - createfactor - routine that will create the factored matrix ready to be used
4579 
4580   Level: developer
4581 
4582 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorGetSolverType()`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`,
4583   `MatGetFactor()`
4584 @*/
4585 PetscErrorCode MatSolverTypeRegister(MatSolverType package, MatType mtype, MatFactorType ftype, PetscErrorCode (*createfactor)(Mat, MatFactorType, Mat *))
4586 {
4587   MatSolverTypeHolder         next = MatSolverTypeHolders, prev = NULL;
4588   PetscBool                   flg;
4589   MatSolverTypeForSpecifcType inext, iprev = NULL;
4590 
4591   PetscFunctionBegin;
4592   PetscCall(MatInitializePackage());
4593   if (!next) {
4594     PetscCall(PetscNew(&MatSolverTypeHolders));
4595     PetscCall(PetscStrallocpy(package, &MatSolverTypeHolders->name));
4596     PetscCall(PetscNew(&MatSolverTypeHolders->handlers));
4597     PetscCall(PetscStrallocpy(mtype, (char **)&MatSolverTypeHolders->handlers->mtype));
4598     MatSolverTypeHolders->handlers->createfactor[(int)ftype - 1] = createfactor;
4599     PetscFunctionReturn(PETSC_SUCCESS);
4600   }
4601   while (next) {
4602     PetscCall(PetscStrcasecmp(package, next->name, &flg));
4603     if (flg) {
4604       PetscCheck(next->handlers, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatSolverTypeHolder is missing handlers");
4605       inext = next->handlers;
4606       while (inext) {
4607         PetscCall(PetscStrcasecmp(mtype, inext->mtype, &flg));
4608         if (flg) {
4609           inext->createfactor[(int)ftype - 1] = createfactor;
4610           PetscFunctionReturn(PETSC_SUCCESS);
4611         }
4612         iprev = inext;
4613         inext = inext->next;
4614       }
4615       PetscCall(PetscNew(&iprev->next));
4616       PetscCall(PetscStrallocpy(mtype, (char **)&iprev->next->mtype));
4617       iprev->next->createfactor[(int)ftype - 1] = createfactor;
4618       PetscFunctionReturn(PETSC_SUCCESS);
4619     }
4620     prev = next;
4621     next = next->next;
4622   }
4623   PetscCall(PetscNew(&prev->next));
4624   PetscCall(PetscStrallocpy(package, &prev->next->name));
4625   PetscCall(PetscNew(&prev->next->handlers));
4626   PetscCall(PetscStrallocpy(mtype, (char **)&prev->next->handlers->mtype));
4627   prev->next->handlers->createfactor[(int)ftype - 1] = createfactor;
4628   PetscFunctionReturn(PETSC_SUCCESS);
4629 }
4630 
4631 /*@C
4632   MatSolverTypeGet - Gets the function that creates the factor matrix if it exist
4633 
4634   Input Parameters:
4635 + 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
4636 . ftype - the type of factorization supported by the type
4637 - mtype - the matrix type that works with this type
4638 
4639   Output Parameters:
4640 + foundtype    - `PETSC_TRUE` if the type was registered
4641 . foundmtype   - `PETSC_TRUE` if the type supports the requested mtype
4642 - createfactor - routine that will create the factored matrix ready to be used or `NULL` if not found
4643 
4644   Calling sequence of `createfactor`:
4645 + A     - the matrix providing the factor matrix
4646 . ftype - the `MatFactorType` of the factor requested
4647 - B     - the new factor matrix that responds to MatXXFactorSymbolic,Numeric() functions, such as `MatLUFactorSymbolic()`
4648 
4649   Level: developer
4650 
4651   Note:
4652   When `type` is `NULL` the available functions are searched for based on the order of the calls to `MatSolverTypeRegister()` in `MatInitializePackage()`.
4653   Since different PETSc configurations may have different external solvers, seemingly identical runs with different PETSc configurations may use a different solver.
4654   For example if one configuration had `--download-mumps` while a different one had `--download-superlu_dist`.
4655 
4656 .seealso: [](ch_matrices), `Mat`, `MatFactorType`, `MatType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatSolverTypeRegister()`, `MatGetFactor()`,
4657           `MatInitializePackage()`
4658 @*/
4659 PetscErrorCode MatSolverTypeGet(MatSolverType type, MatType mtype, MatFactorType ftype, PetscBool *foundtype, PetscBool *foundmtype, PetscErrorCode (**createfactor)(Mat A, MatFactorType ftype, Mat *B))
4660 {
4661   MatSolverTypeHolder         next = MatSolverTypeHolders;
4662   PetscBool                   flg;
4663   MatSolverTypeForSpecifcType inext;
4664 
4665   PetscFunctionBegin;
4666   if (foundtype) *foundtype = PETSC_FALSE;
4667   if (foundmtype) *foundmtype = PETSC_FALSE;
4668   if (createfactor) *createfactor = NULL;
4669 
4670   if (type) {
4671     while (next) {
4672       PetscCall(PetscStrcasecmp(type, next->name, &flg));
4673       if (flg) {
4674         if (foundtype) *foundtype = PETSC_TRUE;
4675         inext = next->handlers;
4676         while (inext) {
4677           PetscCall(PetscStrbeginswith(mtype, inext->mtype, &flg));
4678           if (flg) {
4679             if (foundmtype) *foundmtype = PETSC_TRUE;
4680             if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4681             PetscFunctionReturn(PETSC_SUCCESS);
4682           }
4683           inext = inext->next;
4684         }
4685       }
4686       next = next->next;
4687     }
4688   } else {
4689     while (next) {
4690       inext = next->handlers;
4691       while (inext) {
4692         PetscCall(PetscStrcmp(mtype, inext->mtype, &flg));
4693         if (flg && inext->createfactor[(int)ftype - 1]) {
4694           if (foundtype) *foundtype = PETSC_TRUE;
4695           if (foundmtype) *foundmtype = PETSC_TRUE;
4696           if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4697           PetscFunctionReturn(PETSC_SUCCESS);
4698         }
4699         inext = inext->next;
4700       }
4701       next = next->next;
4702     }
4703     /* try with base classes inext->mtype */
4704     next = MatSolverTypeHolders;
4705     while (next) {
4706       inext = next->handlers;
4707       while (inext) {
4708         PetscCall(PetscStrbeginswith(mtype, inext->mtype, &flg));
4709         if (flg && inext->createfactor[(int)ftype - 1]) {
4710           if (foundtype) *foundtype = PETSC_TRUE;
4711           if (foundmtype) *foundmtype = PETSC_TRUE;
4712           if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4713           PetscFunctionReturn(PETSC_SUCCESS);
4714         }
4715         inext = inext->next;
4716       }
4717       next = next->next;
4718     }
4719   }
4720   PetscFunctionReturn(PETSC_SUCCESS);
4721 }
4722 
4723 PetscErrorCode MatSolverTypeDestroy(void)
4724 {
4725   MatSolverTypeHolder         next = MatSolverTypeHolders, prev;
4726   MatSolverTypeForSpecifcType inext, iprev;
4727 
4728   PetscFunctionBegin;
4729   while (next) {
4730     PetscCall(PetscFree(next->name));
4731     inext = next->handlers;
4732     while (inext) {
4733       PetscCall(PetscFree(inext->mtype));
4734       iprev = inext;
4735       inext = inext->next;
4736       PetscCall(PetscFree(iprev));
4737     }
4738     prev = next;
4739     next = next->next;
4740     PetscCall(PetscFree(prev));
4741   }
4742   MatSolverTypeHolders = NULL;
4743   PetscFunctionReturn(PETSC_SUCCESS);
4744 }
4745 
4746 /*@
4747   MatFactorGetCanUseOrdering - Indicates if the factorization can use the ordering provided in `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4748 
4749   Logically Collective
4750 
4751   Input Parameter:
4752 . mat - the matrix
4753 
4754   Output Parameter:
4755 . flg - `PETSC_TRUE` if uses the ordering
4756 
4757   Level: developer
4758 
4759   Note:
4760   Most internal PETSc factorizations use the ordering passed to the factorization routine but external
4761   packages do not, thus we want to skip generating the ordering when it is not needed or used.
4762 
4763 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4764 @*/
4765 PetscErrorCode MatFactorGetCanUseOrdering(Mat mat, PetscBool *flg)
4766 {
4767   PetscFunctionBegin;
4768   *flg = mat->canuseordering;
4769   PetscFunctionReturn(PETSC_SUCCESS);
4770 }
4771 
4772 /*@
4773   MatFactorGetPreferredOrdering - The preferred ordering for a particular matrix factor object
4774 
4775   Logically Collective
4776 
4777   Input Parameters:
4778 + mat   - the matrix obtained with `MatGetFactor()`
4779 - ftype - the factorization type to be used
4780 
4781   Output Parameter:
4782 . otype - the preferred ordering type
4783 
4784   Level: developer
4785 
4786 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatOrderingType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4787 @*/
4788 PetscErrorCode MatFactorGetPreferredOrdering(Mat mat, MatFactorType ftype, MatOrderingType *otype)
4789 {
4790   PetscFunctionBegin;
4791   *otype = mat->preferredordering[ftype];
4792   PetscCheck(*otype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatFactor did not have a preferred ordering");
4793   PetscFunctionReturn(PETSC_SUCCESS);
4794 }
4795 
4796 /*@
4797   MatGetFactor - Returns a matrix suitable to calls to MatXXFactorSymbolic,Numeric()
4798 
4799   Collective
4800 
4801   Input Parameters:
4802 + mat   - the matrix
4803 . 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
4804           the other criteria is returned
4805 - ftype - factor type, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`
4806 
4807   Output Parameter:
4808 . f - the factor matrix used with MatXXFactorSymbolic,Numeric() calls. Can be `NULL` in some cases, see notes below.
4809 
4810   Options Database Keys:
4811 + -pc_factor_mat_solver_type <type>    - choose the type at run time. When using `KSP` solvers
4812 . -pc_factor_mat_factor_on_host <bool> - do mat factorization on host (with device matrices). Default is doing it on device
4813 - -pc_factor_mat_solve_on_host <bool>  - do mat solve on host (with device matrices). Default is doing it on device
4814 
4815   Level: intermediate
4816 
4817   Notes:
4818   The return matrix can be `NULL` if the requested factorization is not available, since some combinations of matrix types and factorization
4819   types registered with `MatSolverTypeRegister()` cannot be fully tested if not at runtime.
4820 
4821   Users usually access the factorization solvers via `KSP`
4822 
4823   Some PETSc matrix formats have alternative solvers available that are contained in alternative packages
4824   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
4825 
4826   When `type` is `NULL` the available results are searched for based on the order of the calls to `MatSolverTypeRegister()` in `MatInitializePackage()`.
4827   Since different PETSc configurations may have different external solvers, seemingly identical runs with different PETSc configurations may use a different solver.
4828   For example if one configuration had --download-mumps while a different one had --download-superlu_dist.
4829 
4830   Some of the packages have options for controlling the factorization, these are in the form -prefix_mat_packagename_packageoption
4831   where prefix is normally obtained from the calling `KSP`/`PC`. If `MatGetFactor()` is called directly one can set
4832   call `MatSetOptionsPrefixFactor()` on the originating matrix or  `MatSetOptionsPrefix()` on the resulting factor matrix.
4833 
4834   Developer Note:
4835   This should actually be called `MatCreateFactor()` since it creates a new factor object
4836 
4837 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `KSP`, `MatSolverType`, `MatFactorType`, `MatCopy()`, `MatDuplicate()`,
4838           `MatGetFactorAvailable()`, `MatFactorGetCanUseOrdering()`, `MatSolverTypeRegister()`, `MatSolverTypeGet()`
4839           `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`, `MatInitializePackage()`
4840 @*/
4841 PetscErrorCode MatGetFactor(Mat mat, MatSolverType type, MatFactorType ftype, Mat *f)
4842 {
4843   PetscBool foundtype, foundmtype, shell, hasop = PETSC_FALSE;
4844   PetscErrorCode (*conv)(Mat, MatFactorType, Mat *);
4845 
4846   PetscFunctionBegin;
4847   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4848   PetscValidType(mat, 1);
4849 
4850   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4851   MatCheckPreallocated(mat, 1);
4852 
4853   PetscCall(MatIsShell(mat, &shell));
4854   if (shell) PetscCall(MatHasOperation(mat, MATOP_GET_FACTOR, &hasop));
4855   if (hasop) {
4856     PetscUseTypeMethod(mat, getfactor, type, ftype, f);
4857     PetscFunctionReturn(PETSC_SUCCESS);
4858   }
4859 
4860   PetscCall(MatSolverTypeGet(type, ((PetscObject)mat)->type_name, ftype, &foundtype, &foundmtype, &conv));
4861   if (!foundtype) {
4862     if (type) {
4863       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],
4864               ((PetscObject)mat)->type_name, type);
4865     } else {
4866       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);
4867     }
4868   }
4869   PetscCheck(foundmtype, PetscObjectComm((PetscObject)mat), PETSC_ERR_MISSING_FACTOR, "MatSolverType %s does not support matrix type %s", type, ((PetscObject)mat)->type_name);
4870   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);
4871 
4872   PetscCall((*conv)(mat, ftype, f));
4873   if (mat->factorprefix) PetscCall(MatSetOptionsPrefix(*f, mat->factorprefix));
4874   PetscFunctionReturn(PETSC_SUCCESS);
4875 }
4876 
4877 /*@
4878   MatGetFactorAvailable - Returns a flag if matrix supports particular type and factor type
4879 
4880   Not Collective
4881 
4882   Input Parameters:
4883 + mat   - the matrix
4884 . type  - name of solver type, for example, `superlu`, `petsc` (to use PETSc's default)
4885 - ftype - factor type, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`
4886 
4887   Output Parameter:
4888 . flg - PETSC_TRUE if the factorization is available
4889 
4890   Level: intermediate
4891 
4892   Notes:
4893   Some PETSc matrix formats have alternative solvers available that are contained in alternative packages
4894   such as pastix, superlu, mumps etc.
4895 
4896   PETSc must have been ./configure to use the external solver, using the option --download-package
4897 
4898   Developer Note:
4899   This should actually be called `MatCreateFactorAvailable()` since `MatGetFactor()` creates a new factor object
4900 
4901 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatSolverType`, `MatFactorType`, `MatGetFactor()`, `MatCopy()`, `MatDuplicate()`, `MatSolverTypeRegister()`,
4902           `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`, `MatSolverTypeGet()`
4903 @*/
4904 PetscErrorCode MatGetFactorAvailable(Mat mat, MatSolverType type, MatFactorType ftype, PetscBool *flg)
4905 {
4906   PetscErrorCode (*gconv)(Mat, MatFactorType, Mat *);
4907 
4908   PetscFunctionBegin;
4909   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4910   PetscAssertPointer(flg, 4);
4911 
4912   *flg = PETSC_FALSE;
4913   if (!((PetscObject)mat)->type_name) PetscFunctionReturn(PETSC_SUCCESS);
4914 
4915   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4916   MatCheckPreallocated(mat, 1);
4917 
4918   PetscCall(MatSolverTypeGet(type, ((PetscObject)mat)->type_name, ftype, NULL, NULL, &gconv));
4919   *flg = gconv ? PETSC_TRUE : PETSC_FALSE;
4920   PetscFunctionReturn(PETSC_SUCCESS);
4921 }
4922 
4923 /*@
4924   MatDuplicate - Duplicates a matrix including the non-zero structure.
4925 
4926   Collective
4927 
4928   Input Parameters:
4929 + mat - the matrix
4930 - op  - One of `MAT_DO_NOT_COPY_VALUES`, `MAT_COPY_VALUES`, or `MAT_SHARE_NONZERO_PATTERN`.
4931         See the manual page for `MatDuplicateOption()` for an explanation of these options.
4932 
4933   Output Parameter:
4934 . M - pointer to place new matrix
4935 
4936   Level: intermediate
4937 
4938   Notes:
4939   You cannot change the nonzero pattern for the parent or child matrix later if you use `MAT_SHARE_NONZERO_PATTERN`.
4940 
4941   If `op` is not `MAT_COPY_VALUES` the numerical values in the new matrix are zeroed.
4942 
4943   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.
4944 
4945   When original mat is a product of matrix operation, e.g., an output of `MatMatMult()` or `MatCreateSubMatrix()`, only the matrix data structure of `mat`
4946   is duplicated and the internal data structures created for the reuse of previous matrix operations are not duplicated.
4947   User should not use `MatDuplicate()` to create new matrix `M` if `M` is intended to be reused as the product of matrix operation.
4948 
4949 .seealso: [](ch_matrices), `Mat`, `MatCopy()`, `MatConvert()`, `MatDuplicateOption`
4950 @*/
4951 PetscErrorCode MatDuplicate(Mat mat, MatDuplicateOption op, Mat *M)
4952 {
4953   Mat         B;
4954   VecType     vtype;
4955   PetscInt    i;
4956   PetscObject dm, container_h, container_d;
4957   void (*viewf)(void);
4958 
4959   PetscFunctionBegin;
4960   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4961   PetscValidType(mat, 1);
4962   PetscAssertPointer(M, 3);
4963   PetscCheck(op != MAT_COPY_VALUES || mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MAT_COPY_VALUES not allowed for unassembled matrix");
4964   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4965   MatCheckPreallocated(mat, 1);
4966 
4967   PetscCall(PetscLogEventBegin(MAT_Convert, mat, 0, 0, 0));
4968   PetscUseTypeMethod(mat, duplicate, op, M);
4969   PetscCall(PetscLogEventEnd(MAT_Convert, mat, 0, 0, 0));
4970   B = *M;
4971 
4972   PetscCall(MatGetOperation(mat, MATOP_VIEW, &viewf));
4973   if (viewf) PetscCall(MatSetOperation(B, MATOP_VIEW, viewf));
4974   PetscCall(MatGetVecType(mat, &vtype));
4975   PetscCall(MatSetVecType(B, vtype));
4976 
4977   B->stencil.dim = mat->stencil.dim;
4978   B->stencil.noc = mat->stencil.noc;
4979   for (i = 0; i <= mat->stencil.dim + (mat->stencil.noc ? 0 : -1); i++) {
4980     B->stencil.dims[i]   = mat->stencil.dims[i];
4981     B->stencil.starts[i] = mat->stencil.starts[i];
4982   }
4983 
4984   B->nooffproczerorows = mat->nooffproczerorows;
4985   B->nooffprocentries  = mat->nooffprocentries;
4986 
4987   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_dm", &dm));
4988   if (dm) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_dm", dm));
4989   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_MatCOOStruct_Host", &container_h));
4990   if (container_h) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_MatCOOStruct_Host", container_h));
4991   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_MatCOOStruct_Device", &container_d));
4992   if (container_d) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_MatCOOStruct_Device", container_d));
4993   if (op == MAT_COPY_VALUES) PetscCall(MatPropagateSymmetryOptions(mat, B));
4994   PetscCall(PetscObjectStateIncrease((PetscObject)B));
4995   PetscFunctionReturn(PETSC_SUCCESS);
4996 }
4997 
4998 /*@
4999   MatGetDiagonal - Gets the diagonal of a matrix as a `Vec`
5000 
5001   Logically Collective
5002 
5003   Input Parameter:
5004 . mat - the matrix
5005 
5006   Output Parameter:
5007 . v - the diagonal of the matrix
5008 
5009   Level: intermediate
5010 
5011   Note:
5012   If `mat` has local sizes `n` x `m`, this routine fills the first `ndiag = min(n, m)` entries
5013   of `v` with the diagonal values. Thus `v` must have local size of at least `ndiag`. If `v`
5014   is larger than `ndiag`, the values of the remaining entries are unspecified.
5015 
5016   Currently only correct in parallel for square matrices.
5017 
5018 .seealso: [](ch_matrices), `Mat`, `Vec`, `MatGetRow()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`
5019 @*/
5020 PetscErrorCode MatGetDiagonal(Mat mat, Vec v)
5021 {
5022   PetscFunctionBegin;
5023   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5024   PetscValidType(mat, 1);
5025   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5026   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5027   MatCheckPreallocated(mat, 1);
5028   if (PetscDefined(USE_DEBUG)) {
5029     PetscInt nv, row, col, ndiag;
5030 
5031     PetscCall(VecGetLocalSize(v, &nv));
5032     PetscCall(MatGetLocalSize(mat, &row, &col));
5033     ndiag = PetscMin(row, col);
5034     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);
5035   }
5036 
5037   PetscUseTypeMethod(mat, getdiagonal, v);
5038   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5039   PetscFunctionReturn(PETSC_SUCCESS);
5040 }
5041 
5042 /*@
5043   MatGetRowMin - Gets the minimum value (of the real part) of each
5044   row of the matrix
5045 
5046   Logically Collective
5047 
5048   Input Parameter:
5049 . mat - the matrix
5050 
5051   Output Parameters:
5052 + v   - the vector for storing the maximums
5053 - idx - the indices of the column found for each row (optional, pass `NULL` if not needed)
5054 
5055   Level: intermediate
5056 
5057   Note:
5058   The result of this call are the same as if one converted the matrix to dense format
5059   and found the minimum value in each row (i.e. the implicit zeros are counted as zeros).
5060 
5061   This code is only implemented for a couple of matrix formats.
5062 
5063 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`, `MatGetRowMinAbs()`,
5064           `MatGetRowMax()`
5065 @*/
5066 PetscErrorCode MatGetRowMin(Mat mat, Vec v, PetscInt idx[])
5067 {
5068   PetscFunctionBegin;
5069   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5070   PetscValidType(mat, 1);
5071   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5072   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5073 
5074   if (!mat->cmap->N) {
5075     PetscCall(VecSet(v, PETSC_MAX_REAL));
5076     if (idx) {
5077       PetscInt i, m = mat->rmap->n;
5078       for (i = 0; i < m; i++) idx[i] = -1;
5079     }
5080   } else {
5081     MatCheckPreallocated(mat, 1);
5082   }
5083   PetscUseTypeMethod(mat, getrowmin, v, idx);
5084   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5085   PetscFunctionReturn(PETSC_SUCCESS);
5086 }
5087 
5088 /*@
5089   MatGetRowMinAbs - Gets the minimum value (in absolute value) of each
5090   row of the matrix
5091 
5092   Logically Collective
5093 
5094   Input Parameter:
5095 . mat - the matrix
5096 
5097   Output Parameters:
5098 + v   - the vector for storing the minimums
5099 - idx - the indices of the column found for each row (or `NULL` if not needed)
5100 
5101   Level: intermediate
5102 
5103   Notes:
5104   if a row is completely empty or has only 0.0 values, then the `idx` value for that
5105   row is 0 (the first column).
5106 
5107   This code is only implemented for a couple of matrix formats.
5108 
5109 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMaxAbs()`, `MatGetRowMin()`
5110 @*/
5111 PetscErrorCode MatGetRowMinAbs(Mat mat, Vec v, PetscInt idx[])
5112 {
5113   PetscFunctionBegin;
5114   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5115   PetscValidType(mat, 1);
5116   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5117   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5118   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5119 
5120   if (!mat->cmap->N) {
5121     PetscCall(VecSet(v, 0.0));
5122     if (idx) {
5123       PetscInt i, m = mat->rmap->n;
5124       for (i = 0; i < m; i++) idx[i] = -1;
5125     }
5126   } else {
5127     MatCheckPreallocated(mat, 1);
5128     if (idx) PetscCall(PetscArrayzero(idx, mat->rmap->n));
5129     PetscUseTypeMethod(mat, getrowminabs, v, idx);
5130   }
5131   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5132   PetscFunctionReturn(PETSC_SUCCESS);
5133 }
5134 
5135 /*@
5136   MatGetRowMax - Gets the maximum value (of the real part) of each
5137   row of the matrix
5138 
5139   Logically Collective
5140 
5141   Input Parameter:
5142 . mat - the matrix
5143 
5144   Output Parameters:
5145 + v   - the vector for storing the maximums
5146 - idx - the indices of the column found for each row (optional, otherwise pass `NULL`)
5147 
5148   Level: intermediate
5149 
5150   Notes:
5151   The result of this call are the same as if one converted the matrix to dense format
5152   and found the minimum value in each row (i.e. the implicit zeros are counted as zeros).
5153 
5154   This code is only implemented for a couple of matrix formats.
5155 
5156 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5157 @*/
5158 PetscErrorCode MatGetRowMax(Mat mat, Vec v, PetscInt idx[])
5159 {
5160   PetscFunctionBegin;
5161   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5162   PetscValidType(mat, 1);
5163   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5164   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5165 
5166   if (!mat->cmap->N) {
5167     PetscCall(VecSet(v, PETSC_MIN_REAL));
5168     if (idx) {
5169       PetscInt i, m = mat->rmap->n;
5170       for (i = 0; i < m; i++) idx[i] = -1;
5171     }
5172   } else {
5173     MatCheckPreallocated(mat, 1);
5174     PetscUseTypeMethod(mat, getrowmax, v, idx);
5175   }
5176   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5177   PetscFunctionReturn(PETSC_SUCCESS);
5178 }
5179 
5180 /*@
5181   MatGetRowMaxAbs - Gets the maximum value (in absolute value) of each
5182   row of the matrix
5183 
5184   Logically Collective
5185 
5186   Input Parameter:
5187 . mat - the matrix
5188 
5189   Output Parameters:
5190 + v   - the vector for storing the maximums
5191 - idx - the indices of the column found for each row (or `NULL` if not needed)
5192 
5193   Level: intermediate
5194 
5195   Notes:
5196   if a row is completely empty or has only 0.0 values, then the `idx` value for that
5197   row is 0 (the first column).
5198 
5199   This code is only implemented for a couple of matrix formats.
5200 
5201 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowSum()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5202 @*/
5203 PetscErrorCode MatGetRowMaxAbs(Mat mat, Vec v, PetscInt idx[])
5204 {
5205   PetscFunctionBegin;
5206   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5207   PetscValidType(mat, 1);
5208   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5209   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5210 
5211   if (!mat->cmap->N) {
5212     PetscCall(VecSet(v, 0.0));
5213     if (idx) {
5214       PetscInt i, m = mat->rmap->n;
5215       for (i = 0; i < m; i++) idx[i] = -1;
5216     }
5217   } else {
5218     MatCheckPreallocated(mat, 1);
5219     if (idx) PetscCall(PetscArrayzero(idx, mat->rmap->n));
5220     PetscUseTypeMethod(mat, getrowmaxabs, v, idx);
5221   }
5222   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5223   PetscFunctionReturn(PETSC_SUCCESS);
5224 }
5225 
5226 /*@
5227   MatGetRowSumAbs - Gets the sum value (in absolute value) of each row of the matrix
5228 
5229   Logically Collective
5230 
5231   Input Parameter:
5232 . mat - the matrix
5233 
5234   Output Parameter:
5235 . v - the vector for storing the sum
5236 
5237   Level: intermediate
5238 
5239   This code is only implemented for a couple of matrix formats.
5240 
5241 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5242 @*/
5243 PetscErrorCode MatGetRowSumAbs(Mat mat, Vec v)
5244 {
5245   PetscFunctionBegin;
5246   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5247   PetscValidType(mat, 1);
5248   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5249   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5250 
5251   if (!mat->cmap->N) {
5252     PetscCall(VecSet(v, 0.0));
5253   } else {
5254     MatCheckPreallocated(mat, 1);
5255     PetscUseTypeMethod(mat, getrowsumabs, v);
5256   }
5257   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5258   PetscFunctionReturn(PETSC_SUCCESS);
5259 }
5260 
5261 /*@
5262   MatGetRowSum - Gets the sum of each row of the matrix
5263 
5264   Logically or Neighborhood Collective
5265 
5266   Input Parameter:
5267 . mat - the matrix
5268 
5269   Output Parameter:
5270 . v - the vector for storing the sum of rows
5271 
5272   Level: intermediate
5273 
5274   Note:
5275   This code is slow since it is not currently specialized for different formats
5276 
5277 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMin()`, `MatGetRowMaxAbs()`, `MatGetRowMinAbs()`, `MatGetRowSumAbs()`
5278 @*/
5279 PetscErrorCode MatGetRowSum(Mat mat, Vec v)
5280 {
5281   Vec ones;
5282 
5283   PetscFunctionBegin;
5284   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5285   PetscValidType(mat, 1);
5286   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5287   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5288   MatCheckPreallocated(mat, 1);
5289   PetscCall(MatCreateVecs(mat, &ones, NULL));
5290   PetscCall(VecSet(ones, 1.));
5291   PetscCall(MatMult(mat, ones, v));
5292   PetscCall(VecDestroy(&ones));
5293   PetscFunctionReturn(PETSC_SUCCESS);
5294 }
5295 
5296 /*@
5297   MatTransposeSetPrecursor - Set the matrix from which the second matrix will receive numerical transpose data with a call to `MatTranspose`(A,`MAT_REUSE_MATRIX`,&B)
5298   when B was not obtained with `MatTranspose`(A,`MAT_INITIAL_MATRIX`,&B)
5299 
5300   Collective
5301 
5302   Input Parameter:
5303 . mat - the matrix to provide the transpose
5304 
5305   Output Parameter:
5306 . 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
5307 
5308   Level: advanced
5309 
5310   Note:
5311   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
5312   routine allows bypassing that call.
5313 
5314 .seealso: [](ch_matrices), `Mat`, `MatTransposeSymbolic()`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
5315 @*/
5316 PetscErrorCode MatTransposeSetPrecursor(Mat mat, Mat B)
5317 {
5318   MatParentState *rb = NULL;
5319 
5320   PetscFunctionBegin;
5321   PetscCall(PetscNew(&rb));
5322   rb->id    = ((PetscObject)mat)->id;
5323   rb->state = 0;
5324   PetscCall(MatGetNonzeroState(mat, &rb->nonzerostate));
5325   PetscCall(PetscObjectContainerCompose((PetscObject)B, "MatTransposeParent", rb, PetscCtxDestroyDefault));
5326   PetscFunctionReturn(PETSC_SUCCESS);
5327 }
5328 
5329 /*@
5330   MatTranspose - Computes the transpose of a matrix, either in-place or out-of-place.
5331 
5332   Collective
5333 
5334   Input Parameters:
5335 + mat   - the matrix to transpose
5336 - reuse - either `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, or `MAT_INPLACE_MATRIX`
5337 
5338   Output Parameter:
5339 . B - the transpose of the matrix
5340 
5341   Level: intermediate
5342 
5343   Notes:
5344   If you use `MAT_INPLACE_MATRIX` then you must pass in `&mat` for `B`
5345 
5346   `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
5347   transpose, call `MatTransposeSetPrecursor(mat, B)` before calling this routine.
5348 
5349   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.
5350 
5351   Consider using `MatCreateTranspose()` instead if you only need a matrix that behaves like the transpose but don't need the storage to be changed.
5352   For example, the result of `MatCreateTranspose()` will compute the transpose of the given matrix times a vector for matrix-vector products computed with `MatMult()`.
5353 
5354   If `mat` is unchanged from the last call this function returns immediately without recomputing the result
5355 
5356   If you only need the symbolic transpose of a matrix, and not the numerical values, use `MatTransposeSymbolic()`
5357 
5358 .seealso: [](ch_matrices), `Mat`, `MatTransposeSetPrecursor()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`,
5359           `MatTransposeSymbolic()`, `MatCreateTranspose()`
5360 @*/
5361 PetscErrorCode MatTranspose(Mat mat, MatReuse reuse, Mat *B)
5362 {
5363   PetscContainer  rB = NULL;
5364   MatParentState *rb = NULL;
5365 
5366   PetscFunctionBegin;
5367   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5368   PetscValidType(mat, 1);
5369   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5370   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5371   PetscCheck(reuse != MAT_INPLACE_MATRIX || mat == *B, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX requires last matrix to match first");
5372   PetscCheck(reuse != MAT_REUSE_MATRIX || mat != *B, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Perhaps you mean MAT_INPLACE_MATRIX");
5373   MatCheckPreallocated(mat, 1);
5374   if (reuse == MAT_REUSE_MATRIX) {
5375     PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
5376     PetscCheck(rB, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose(). Suggest MatTransposeSetPrecursor().");
5377     PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5378     PetscCheck(rb->id == ((PetscObject)mat)->id, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from input matrix");
5379     if (rb->state == ((PetscObject)mat)->state) PetscFunctionReturn(PETSC_SUCCESS);
5380   }
5381 
5382   PetscCall(PetscLogEventBegin(MAT_Transpose, mat, 0, 0, 0));
5383   if (reuse != MAT_INPLACE_MATRIX || mat->symmetric != PETSC_BOOL3_TRUE) {
5384     PetscUseTypeMethod(mat, transpose, reuse, B);
5385     PetscCall(PetscObjectStateIncrease((PetscObject)*B));
5386   }
5387   PetscCall(PetscLogEventEnd(MAT_Transpose, mat, 0, 0, 0));
5388 
5389   if (reuse == MAT_INITIAL_MATRIX) PetscCall(MatTransposeSetPrecursor(mat, *B));
5390   if (reuse != MAT_INPLACE_MATRIX) {
5391     PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
5392     PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5393     rb->state        = ((PetscObject)mat)->state;
5394     rb->nonzerostate = mat->nonzerostate;
5395   }
5396   PetscFunctionReturn(PETSC_SUCCESS);
5397 }
5398 
5399 /*@
5400   MatTransposeSymbolic - Computes the symbolic part of the transpose of a matrix.
5401 
5402   Collective
5403 
5404   Input Parameter:
5405 . A - the matrix to transpose
5406 
5407   Output Parameter:
5408 . 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
5409       numerical portion.
5410 
5411   Level: intermediate
5412 
5413   Note:
5414   This is not supported for many matrix types, use `MatTranspose()` in those cases
5415 
5416 .seealso: [](ch_matrices), `Mat`, `MatTransposeSetPrecursor()`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
5417 @*/
5418 PetscErrorCode MatTransposeSymbolic(Mat A, Mat *B)
5419 {
5420   PetscFunctionBegin;
5421   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5422   PetscValidType(A, 1);
5423   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5424   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5425   PetscCall(PetscLogEventBegin(MAT_Transpose, A, 0, 0, 0));
5426   PetscUseTypeMethod(A, transposesymbolic, B);
5427   PetscCall(PetscLogEventEnd(MAT_Transpose, A, 0, 0, 0));
5428 
5429   PetscCall(MatTransposeSetPrecursor(A, *B));
5430   PetscFunctionReturn(PETSC_SUCCESS);
5431 }
5432 
5433 PetscErrorCode MatTransposeCheckNonzeroState_Private(Mat A, Mat B)
5434 {
5435   PetscContainer  rB;
5436   MatParentState *rb;
5437 
5438   PetscFunctionBegin;
5439   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5440   PetscValidType(A, 1);
5441   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5442   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5443   PetscCall(PetscObjectQuery((PetscObject)B, "MatTransposeParent", (PetscObject *)&rB));
5444   PetscCheck(rB, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose()");
5445   PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5446   PetscCheck(rb->id == ((PetscObject)A)->id, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from input matrix");
5447   PetscCheck(rb->nonzerostate == A->nonzerostate, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Reuse matrix has changed nonzero structure");
5448   PetscFunctionReturn(PETSC_SUCCESS);
5449 }
5450 
5451 /*@
5452   MatIsTranspose - Test whether a matrix is another one's transpose,
5453   or its own, in which case it tests symmetry.
5454 
5455   Collective
5456 
5457   Input Parameters:
5458 + A   - the matrix to test
5459 . B   - the matrix to test against, this can equal the first parameter
5460 - tol - tolerance, differences between entries smaller than this are counted as zero
5461 
5462   Output Parameter:
5463 . flg - the result
5464 
5465   Level: intermediate
5466 
5467   Notes:
5468   The sequential algorithm has a running time of the order of the number of nonzeros; the parallel
5469   test involves parallel copies of the block off-diagonal parts of the matrix.
5470 
5471 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsSymmetric()`, `MatIsHermitian()`
5472 @*/
5473 PetscErrorCode MatIsTranspose(Mat A, Mat B, PetscReal tol, PetscBool *flg)
5474 {
5475   PetscErrorCode (*f)(Mat, Mat, PetscReal, PetscBool *), (*g)(Mat, Mat, PetscReal, PetscBool *);
5476 
5477   PetscFunctionBegin;
5478   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5479   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5480   PetscAssertPointer(flg, 4);
5481   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatIsTranspose_C", &f));
5482   PetscCall(PetscObjectQueryFunction((PetscObject)B, "MatIsTranspose_C", &g));
5483   *flg = PETSC_FALSE;
5484   if (f && g) {
5485     PetscCheck(f == g, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_NOTSAMETYPE, "Matrices do not have the same comparator for symmetry test");
5486     PetscCall((*f)(A, B, tol, flg));
5487   } else {
5488     MatType mattype;
5489 
5490     PetscCall(MatGetType(f ? B : A, &mattype));
5491     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Matrix of type %s does not support checking for transpose", mattype);
5492   }
5493   PetscFunctionReturn(PETSC_SUCCESS);
5494 }
5495 
5496 /*@
5497   MatHermitianTranspose - Computes an in-place or out-of-place Hermitian transpose of a matrix in complex conjugate.
5498 
5499   Collective
5500 
5501   Input Parameters:
5502 + mat   - the matrix to transpose and complex conjugate
5503 - reuse - either `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, or `MAT_INPLACE_MATRIX`
5504 
5505   Output Parameter:
5506 . B - the Hermitian transpose
5507 
5508   Level: intermediate
5509 
5510 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`
5511 @*/
5512 PetscErrorCode MatHermitianTranspose(Mat mat, MatReuse reuse, Mat *B)
5513 {
5514   PetscFunctionBegin;
5515   PetscCall(MatTranspose(mat, reuse, B));
5516 #if defined(PETSC_USE_COMPLEX)
5517   PetscCall(MatConjugate(*B));
5518 #endif
5519   PetscFunctionReturn(PETSC_SUCCESS);
5520 }
5521 
5522 /*@
5523   MatIsHermitianTranspose - Test whether a matrix is another one's Hermitian transpose,
5524 
5525   Collective
5526 
5527   Input Parameters:
5528 + A   - the matrix to test
5529 . B   - the matrix to test against, this can equal the first parameter
5530 - tol - tolerance, differences between entries smaller than this are counted as zero
5531 
5532   Output Parameter:
5533 . flg - the result
5534 
5535   Level: intermediate
5536 
5537   Notes:
5538   Only available for `MATAIJ` matrices.
5539 
5540   The sequential algorithm
5541   has a running time of the order of the number of nonzeros; the parallel
5542   test involves parallel copies of the block off-diagonal parts of the matrix.
5543 
5544 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsTranspose()`
5545 @*/
5546 PetscErrorCode MatIsHermitianTranspose(Mat A, Mat B, PetscReal tol, PetscBool *flg)
5547 {
5548   PetscErrorCode (*f)(Mat, Mat, PetscReal, PetscBool *), (*g)(Mat, Mat, PetscReal, PetscBool *);
5549 
5550   PetscFunctionBegin;
5551   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5552   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5553   PetscAssertPointer(flg, 4);
5554   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatIsHermitianTranspose_C", &f));
5555   PetscCall(PetscObjectQueryFunction((PetscObject)B, "MatIsHermitianTranspose_C", &g));
5556   if (f && g) {
5557     PetscCheck(f != g, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_NOTSAMETYPE, "Matrices do not have the same comparator for Hermitian test");
5558     PetscCall((*f)(A, B, tol, flg));
5559   }
5560   PetscFunctionReturn(PETSC_SUCCESS);
5561 }
5562 
5563 /*@
5564   MatPermute - Creates a new matrix with rows and columns permuted from the
5565   original.
5566 
5567   Collective
5568 
5569   Input Parameters:
5570 + mat - the matrix to permute
5571 . row - row permutation, each processor supplies only the permutation for its rows
5572 - col - column permutation, each processor supplies only the permutation for its columns
5573 
5574   Output Parameter:
5575 . B - the permuted matrix
5576 
5577   Level: advanced
5578 
5579   Note:
5580   The index sets map from row/col of permuted matrix to row/col of original matrix.
5581   The index sets should be on the same communicator as mat and have the same local sizes.
5582 
5583   Developer Note:
5584   If you want to implement `MatPermute()` for a matrix type, and your approach doesn't
5585   exploit the fact that row and col are permutations, consider implementing the
5586   more general `MatCreateSubMatrix()` instead.
5587 
5588 .seealso: [](ch_matrices), `Mat`, `MatGetOrdering()`, `ISAllGather()`, `MatCreateSubMatrix()`
5589 @*/
5590 PetscErrorCode MatPermute(Mat mat, IS row, IS col, Mat *B)
5591 {
5592   PetscFunctionBegin;
5593   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5594   PetscValidType(mat, 1);
5595   PetscValidHeaderSpecific(row, IS_CLASSID, 2);
5596   PetscValidHeaderSpecific(col, IS_CLASSID, 3);
5597   PetscAssertPointer(B, 4);
5598   PetscCheckSameComm(mat, 1, row, 2);
5599   if (row != col) PetscCheckSameComm(row, 2, col, 3);
5600   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5601   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5602   PetscCheck(mat->ops->permute || mat->ops->createsubmatrix, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatPermute not available for Mat type %s", ((PetscObject)mat)->type_name);
5603   MatCheckPreallocated(mat, 1);
5604 
5605   if (mat->ops->permute) {
5606     PetscUseTypeMethod(mat, permute, row, col, B);
5607     PetscCall(PetscObjectStateIncrease((PetscObject)*B));
5608   } else {
5609     PetscCall(MatCreateSubMatrix(mat, row, col, MAT_INITIAL_MATRIX, B));
5610   }
5611   PetscFunctionReturn(PETSC_SUCCESS);
5612 }
5613 
5614 /*@
5615   MatEqual - Compares two matrices.
5616 
5617   Collective
5618 
5619   Input Parameters:
5620 + A - the first matrix
5621 - B - the second matrix
5622 
5623   Output Parameter:
5624 . flg - `PETSC_TRUE` if the matrices are equal; `PETSC_FALSE` otherwise.
5625 
5626   Level: intermediate
5627 
5628   Note:
5629   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
5630   using several randomly created vectors, see `MatMultEqual()`.
5631 
5632 .seealso: [](ch_matrices), `Mat`, `MatMultEqual()`
5633 @*/
5634 PetscErrorCode MatEqual(Mat A, Mat B, PetscBool *flg)
5635 {
5636   PetscFunctionBegin;
5637   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5638   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5639   PetscValidType(A, 1);
5640   PetscValidType(B, 2);
5641   PetscAssertPointer(flg, 3);
5642   PetscCheckSameComm(A, 1, B, 2);
5643   MatCheckPreallocated(A, 1);
5644   MatCheckPreallocated(B, 2);
5645   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5646   PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5647   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,
5648              B->cmap->N);
5649   if (A->ops->equal && A->ops->equal == B->ops->equal) {
5650     PetscUseTypeMethod(A, equal, B, flg);
5651   } else {
5652     PetscCall(MatMultEqual(A, B, 10, flg));
5653   }
5654   PetscFunctionReturn(PETSC_SUCCESS);
5655 }
5656 
5657 /*@
5658   MatDiagonalScale - Scales a matrix on the left and right by diagonal
5659   matrices that are stored as vectors.  Either of the two scaling
5660   matrices can be `NULL`.
5661 
5662   Collective
5663 
5664   Input Parameters:
5665 + mat - the matrix to be scaled
5666 . l   - the left scaling vector (or `NULL`)
5667 - r   - the right scaling vector (or `NULL`)
5668 
5669   Level: intermediate
5670 
5671   Note:
5672   `MatDiagonalScale()` computes $A = LAR$, where
5673   L = a diagonal matrix (stored as a vector), R = a diagonal matrix (stored as a vector)
5674   The L scales the rows of the matrix, the R scales the columns of the matrix.
5675 
5676 .seealso: [](ch_matrices), `Mat`, `MatScale()`, `MatShift()`, `MatDiagonalSet()`
5677 @*/
5678 PetscErrorCode MatDiagonalScale(Mat mat, Vec l, Vec r)
5679 {
5680   PetscFunctionBegin;
5681   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5682   PetscValidType(mat, 1);
5683   if (l) {
5684     PetscValidHeaderSpecific(l, VEC_CLASSID, 2);
5685     PetscCheckSameComm(mat, 1, l, 2);
5686   }
5687   if (r) {
5688     PetscValidHeaderSpecific(r, VEC_CLASSID, 3);
5689     PetscCheckSameComm(mat, 1, r, 3);
5690   }
5691   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5692   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5693   MatCheckPreallocated(mat, 1);
5694   if (!l && !r) PetscFunctionReturn(PETSC_SUCCESS);
5695 
5696   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
5697   PetscUseTypeMethod(mat, diagonalscale, l, r);
5698   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
5699   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5700   if (l != r) mat->symmetric = PETSC_BOOL3_FALSE;
5701   PetscFunctionReturn(PETSC_SUCCESS);
5702 }
5703 
5704 /*@
5705   MatScale - Scales all elements of a matrix by a given number.
5706 
5707   Logically Collective
5708 
5709   Input Parameters:
5710 + mat - the matrix to be scaled
5711 - a   - the scaling value
5712 
5713   Level: intermediate
5714 
5715 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
5716 @*/
5717 PetscErrorCode MatScale(Mat mat, PetscScalar a)
5718 {
5719   PetscFunctionBegin;
5720   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5721   PetscValidType(mat, 1);
5722   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5723   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5724   PetscValidLogicalCollectiveScalar(mat, a, 2);
5725   MatCheckPreallocated(mat, 1);
5726 
5727   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
5728   if (a != (PetscScalar)1.0) {
5729     PetscUseTypeMethod(mat, scale, a);
5730     PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5731   }
5732   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
5733   PetscFunctionReturn(PETSC_SUCCESS);
5734 }
5735 
5736 /*@
5737   MatNorm - Calculates various norms of a matrix.
5738 
5739   Collective
5740 
5741   Input Parameters:
5742 + mat  - the matrix
5743 - type - the type of norm, `NORM_1`, `NORM_FROBENIUS`, `NORM_INFINITY`
5744 
5745   Output Parameter:
5746 . nrm - the resulting norm
5747 
5748   Level: intermediate
5749 
5750 .seealso: [](ch_matrices), `Mat`
5751 @*/
5752 PetscErrorCode MatNorm(Mat mat, NormType type, PetscReal *nrm)
5753 {
5754   PetscFunctionBegin;
5755   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5756   PetscValidType(mat, 1);
5757   PetscAssertPointer(nrm, 3);
5758 
5759   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5760   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5761   MatCheckPreallocated(mat, 1);
5762 
5763   PetscUseTypeMethod(mat, norm, type, nrm);
5764   PetscFunctionReturn(PETSC_SUCCESS);
5765 }
5766 
5767 /*
5768      This variable is used to prevent counting of MatAssemblyBegin() that
5769    are called from within a MatAssemblyEnd().
5770 */
5771 static PetscInt MatAssemblyEnd_InUse = 0;
5772 /*@
5773   MatAssemblyBegin - Begins assembling the matrix.  This routine should
5774   be called after completing all calls to `MatSetValues()`.
5775 
5776   Collective
5777 
5778   Input Parameters:
5779 + mat  - the matrix
5780 - type - type of assembly, either `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY`
5781 
5782   Level: beginner
5783 
5784   Notes:
5785   `MatSetValues()` generally caches the values that belong to other MPI processes.  The matrix is ready to
5786   use only after `MatAssemblyBegin()` and `MatAssemblyEnd()` have been called.
5787 
5788   Use `MAT_FLUSH_ASSEMBLY` when switching between `ADD_VALUES` and `INSERT_VALUES`
5789   in `MatSetValues()`; use `MAT_FINAL_ASSEMBLY` for the final assembly before
5790   using the matrix.
5791 
5792   ALL processes that share a matrix MUST call `MatAssemblyBegin()` and `MatAssemblyEnd()` the SAME NUMBER of times, and each time with the
5793   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
5794   a global collective operation requiring all processes that share the matrix.
5795 
5796   Space for preallocated nonzeros that is not filled by a call to `MatSetValues()` or a related routine are compressed
5797   out by assembly. If you intend to use that extra space on a subsequent assembly, be sure to insert explicit zeros
5798   before `MAT_FINAL_ASSEMBLY` so the space is not compressed out.
5799 
5800 .seealso: [](ch_matrices), `Mat`, `MatAssemblyEnd()`, `MatSetValues()`, `MatAssembled()`
5801 @*/
5802 PetscErrorCode MatAssemblyBegin(Mat mat, MatAssemblyType type)
5803 {
5804   PetscFunctionBegin;
5805   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5806   PetscValidType(mat, 1);
5807   MatCheckPreallocated(mat, 1);
5808   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix. Did you forget to call MatSetUnfactored()?");
5809   if (mat->assembled) {
5810     mat->was_assembled = PETSC_TRUE;
5811     mat->assembled     = PETSC_FALSE;
5812   }
5813 
5814   if (!MatAssemblyEnd_InUse) {
5815     PetscCall(PetscLogEventBegin(MAT_AssemblyBegin, mat, 0, 0, 0));
5816     PetscTryTypeMethod(mat, assemblybegin, type);
5817     PetscCall(PetscLogEventEnd(MAT_AssemblyBegin, mat, 0, 0, 0));
5818   } else PetscTryTypeMethod(mat, assemblybegin, type);
5819   PetscFunctionReturn(PETSC_SUCCESS);
5820 }
5821 
5822 /*@
5823   MatAssembled - Indicates if a matrix has been assembled and is ready for
5824   use; for example, in matrix-vector product.
5825 
5826   Not Collective
5827 
5828   Input Parameter:
5829 . mat - the matrix
5830 
5831   Output Parameter:
5832 . assembled - `PETSC_TRUE` or `PETSC_FALSE`
5833 
5834   Level: advanced
5835 
5836 .seealso: [](ch_matrices), `Mat`, `MatAssemblyEnd()`, `MatSetValues()`, `MatAssemblyBegin()`
5837 @*/
5838 PetscErrorCode MatAssembled(Mat mat, PetscBool *assembled)
5839 {
5840   PetscFunctionBegin;
5841   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5842   PetscAssertPointer(assembled, 2);
5843   *assembled = mat->assembled;
5844   PetscFunctionReturn(PETSC_SUCCESS);
5845 }
5846 
5847 /*@
5848   MatAssemblyEnd - Completes assembling the matrix.  This routine should
5849   be called after `MatAssemblyBegin()`.
5850 
5851   Collective
5852 
5853   Input Parameters:
5854 + mat  - the matrix
5855 - type - type of assembly, either `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY`
5856 
5857   Options Database Keys:
5858 + -mat_view ::ascii_info             - Prints info on matrix at conclusion of `MatAssemblyEnd()`
5859 . -mat_view ::ascii_info_detail      - Prints more detailed info
5860 . -mat_view                          - Prints matrix in ASCII format
5861 . -mat_view ::ascii_matlab           - Prints matrix in MATLAB format
5862 . -mat_view draw                     - draws nonzero structure of matrix, using `MatView()` and `PetscDrawOpenX()`.
5863 . -display <name>                    - Sets display name (default is host)
5864 . -draw_pause <sec>                  - Sets number of seconds to pause after display
5865 . -mat_view socket                   - Sends matrix to socket, can be accessed from MATLAB (See [Using MATLAB with PETSc](ch_matlab))
5866 . -viewer_socket_machine <machine>   - Machine to use for socket
5867 . -viewer_socket_port <port>         - Port number to use for socket
5868 - -mat_view binary:filename[:append] - Save matrix to file in binary format
5869 
5870   Level: beginner
5871 
5872 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatSetValues()`, `PetscDrawOpenX()`, `PetscDrawCreate()`, `MatView()`, `MatAssembled()`, `PetscViewerSocketOpen()`
5873 @*/
5874 PetscErrorCode MatAssemblyEnd(Mat mat, MatAssemblyType type)
5875 {
5876   static PetscInt inassm = 0;
5877   PetscBool       flg    = PETSC_FALSE;
5878 
5879   PetscFunctionBegin;
5880   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5881   PetscValidType(mat, 1);
5882 
5883   inassm++;
5884   MatAssemblyEnd_InUse++;
5885   if (MatAssemblyEnd_InUse == 1) { /* Do the logging only the first time through */
5886     PetscCall(PetscLogEventBegin(MAT_AssemblyEnd, mat, 0, 0, 0));
5887     PetscTryTypeMethod(mat, assemblyend, type);
5888     PetscCall(PetscLogEventEnd(MAT_AssemblyEnd, mat, 0, 0, 0));
5889   } else PetscTryTypeMethod(mat, assemblyend, type);
5890 
5891   /* Flush assembly is not a true assembly */
5892   if (type != MAT_FLUSH_ASSEMBLY) {
5893     if (mat->num_ass) {
5894       if (!mat->symmetry_eternal) {
5895         mat->symmetric = PETSC_BOOL3_UNKNOWN;
5896         mat->hermitian = PETSC_BOOL3_UNKNOWN;
5897       }
5898       if (!mat->structural_symmetry_eternal && mat->ass_nonzerostate != mat->nonzerostate) mat->structurally_symmetric = PETSC_BOOL3_UNKNOWN;
5899       if (!mat->spd_eternal) mat->spd = PETSC_BOOL3_UNKNOWN;
5900     }
5901     mat->num_ass++;
5902     mat->assembled        = PETSC_TRUE;
5903     mat->ass_nonzerostate = mat->nonzerostate;
5904   }
5905 
5906   mat->insertmode = NOT_SET_VALUES;
5907   MatAssemblyEnd_InUse--;
5908   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5909   if (inassm == 1 && type != MAT_FLUSH_ASSEMBLY) {
5910     PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
5911 
5912     if (mat->checksymmetryonassembly) {
5913       PetscCall(MatIsSymmetric(mat, mat->checksymmetrytol, &flg));
5914       if (flg) {
5915         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "Matrix is symmetric (tolerance %g)\n", (double)mat->checksymmetrytol));
5916       } else {
5917         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "Matrix is not symmetric (tolerance %g)\n", (double)mat->checksymmetrytol));
5918       }
5919     }
5920     if (mat->nullsp && mat->checknullspaceonassembly) PetscCall(MatNullSpaceTest(mat->nullsp, mat, NULL));
5921   }
5922   inassm--;
5923   PetscFunctionReturn(PETSC_SUCCESS);
5924 }
5925 
5926 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
5927 /*@
5928   MatSetOption - Sets a parameter option for a matrix. Some options
5929   may be specific to certain storage formats.  Some options
5930   determine how values will be inserted (or added). Sorted,
5931   row-oriented input will generally assemble the fastest. The default
5932   is row-oriented.
5933 
5934   Logically Collective for certain operations, such as `MAT_SPD`, not collective for `MAT_ROW_ORIENTED`, see `MatOption`
5935 
5936   Input Parameters:
5937 + mat - the matrix
5938 . op  - the option, one of those listed below (and possibly others),
5939 - flg - turn the option on (`PETSC_TRUE`) or off (`PETSC_FALSE`)
5940 
5941   Options Describing Matrix Structure:
5942 + `MAT_SPD`                         - symmetric positive definite
5943 . `MAT_SYMMETRIC`                   - symmetric in terms of both structure and value
5944 . `MAT_HERMITIAN`                   - transpose is the complex conjugation
5945 . `MAT_STRUCTURALLY_SYMMETRIC`      - symmetric nonzero structure
5946 . `MAT_SYMMETRY_ETERNAL`            - indicates the symmetry (or Hermitian structure) or its absence will persist through any changes to the matrix
5947 . `MAT_STRUCTURAL_SYMMETRY_ETERNAL` - indicates the structural symmetry or its absence will persist through any changes to the matrix
5948 . `MAT_SPD_ETERNAL`                 - indicates the value of `MAT_SPD` (true or false) will persist through any changes to the matrix
5949 
5950    These are not really options of the matrix, they are knowledge about the structure of the matrix that users may provide so that they
5951    do not need to be computed (usually at a high cost)
5952 
5953    Options For Use with `MatSetValues()`:
5954    Insert a logically dense subblock, which can be
5955 . `MAT_ROW_ORIENTED`                - row-oriented (default)
5956 
5957    These options reflect the data you pass in with `MatSetValues()`; it has
5958    nothing to do with how the data is stored internally in the matrix
5959    data structure.
5960 
5961    When (re)assembling a matrix, we can restrict the input for
5962    efficiency/debugging purposes.  These options include
5963 . `MAT_NEW_NONZERO_LOCATIONS`       - additional insertions will be allowed if they generate a new nonzero (slow)
5964 . `MAT_FORCE_DIAGONAL_ENTRIES`      - forces diagonal entries to be allocated
5965 . `MAT_IGNORE_OFF_PROC_ENTRIES`     - drops off-processor entries
5966 . `MAT_NEW_NONZERO_LOCATION_ERR`    - generates an error for new matrix entry
5967 . `MAT_USE_HASH_TABLE`              - uses a hash table to speed up matrix assembly
5968 . `MAT_NO_OFF_PROC_ENTRIES`         - you know each process will only set values for its own rows, will generate an error if
5969         any process sets values for another process. This avoids all reductions in the MatAssembly routines and thus improves
5970         performance for very large process counts.
5971 - `MAT_SUBSET_OFF_PROC_ENTRIES`     - you know that the first assembly after setting this flag will set a superset
5972         of the off-process entries required for all subsequent assemblies. This avoids a rendezvous step in the MatAssembly
5973         functions, instead sending only neighbor messages.
5974 
5975   Level: intermediate
5976 
5977   Notes:
5978   Except for `MAT_UNUSED_NONZERO_LOCATION_ERR` and  `MAT_ROW_ORIENTED` all processes that share the matrix must pass the same value in flg!
5979 
5980   Some options are relevant only for particular matrix types and
5981   are thus ignored by others.  Other options are not supported by
5982   certain matrix types and will generate an error message if set.
5983 
5984   If using Fortran to compute a matrix, one may need to
5985   use the column-oriented option (or convert to the row-oriented
5986   format).
5987 
5988   `MAT_NEW_NONZERO_LOCATIONS` set to `PETSC_FALSE` indicates that any add or insertion
5989   that would generate a new entry in the nonzero structure is instead
5990   ignored.  Thus, if memory has not already been allocated for this particular
5991   data, then the insertion is ignored. For dense matrices, in which
5992   the entire array is allocated, no entries are ever ignored.
5993   Set after the first `MatAssemblyEnd()`. If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
5994 
5995   `MAT_NEW_NONZERO_LOCATION_ERR` set to PETSC_TRUE indicates that any add or insertion
5996   that would generate a new entry in the nonzero structure instead produces
5997   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
5998 
5999   `MAT_NEW_NONZERO_ALLOCATION_ERR` set to `PETSC_TRUE` indicates that any add or insertion
6000   that would generate a new entry that has not been preallocated will
6001   instead produce an error. (Currently supported for `MATAIJ` and `MATBAIJ` formats
6002   only.) This is a useful flag when debugging matrix memory preallocation.
6003   If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
6004 
6005   `MAT_IGNORE_OFF_PROC_ENTRIES` set to `PETSC_TRUE` indicates entries destined for
6006   other processors should be dropped, rather than stashed.
6007   This is useful if you know that the "owning" processor is also
6008   always generating the correct matrix entries, so that PETSc need
6009   not transfer duplicate entries generated on another processor.
6010 
6011   `MAT_USE_HASH_TABLE` indicates that a hash table be used to improve the
6012   searches during matrix assembly. When this flag is set, the hash table
6013   is created during the first matrix assembly. This hash table is
6014   used the next time through, during `MatSetValues()`/`MatSetValuesBlocked()`
6015   to improve the searching of indices. `MAT_NEW_NONZERO_LOCATIONS` flag
6016   should be used with `MAT_USE_HASH_TABLE` flag. This option is currently
6017   supported by `MATMPIBAIJ` format only.
6018 
6019   `MAT_KEEP_NONZERO_PATTERN` indicates when `MatZeroRows()` is called the zeroed entries
6020   are kept in the nonzero structure. This flag is not used for `MatZeroRowsColumns()`
6021 
6022   `MAT_IGNORE_ZERO_ENTRIES` - for `MATAIJ` and `MATIS` matrices this will stop zero values from creating
6023   a zero location in the matrix
6024 
6025   `MAT_USE_INODES` - indicates using inode version of the code - works with `MATAIJ` matrix types
6026 
6027   `MAT_NO_OFF_PROC_ZERO_ROWS` - you know each process will only zero its own rows. This avoids all reductions in the
6028   zero row routines and thus improves performance for very large process counts.
6029 
6030   `MAT_IGNORE_LOWER_TRIANGULAR` - For `MATSBAIJ` matrices will ignore any insertions you make in the lower triangular
6031   part of the matrix (since they should match the upper triangular part).
6032 
6033   `MAT_SORTED_FULL` - each process provides exactly its local rows; all column indices for a given row are passed in a
6034   single call to `MatSetValues()`, preallocation is perfect, row-oriented, `INSERT_VALUES` is used. Common
6035   with finite difference schemes with non-periodic boundary conditions.
6036 
6037   Developer Note:
6038   `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, and `MAT_SPD_ETERNAL` are used by `MatAssemblyEnd()` and in other
6039   places where otherwise the value of `MAT_SYMMETRIC`, `MAT_STRUCTURALLY_SYMMETRIC` or `MAT_SPD` would need to be changed back
6040   to `PETSC_BOOL3_UNKNOWN` because the matrix values had changed so the code cannot be certain that the related property had
6041   not changed.
6042 
6043 .seealso: [](ch_matrices), `MatOption`, `Mat`, `MatGetOption()`
6044 @*/
6045 PetscErrorCode MatSetOption(Mat mat, MatOption op, PetscBool flg)
6046 {
6047   PetscFunctionBegin;
6048   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6049   if (op > 0) {
6050     PetscValidLogicalCollectiveEnum(mat, op, 2);
6051     PetscValidLogicalCollectiveBool(mat, flg, 3);
6052   }
6053 
6054   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);
6055 
6056   switch (op) {
6057   case MAT_FORCE_DIAGONAL_ENTRIES:
6058     mat->force_diagonals = flg;
6059     PetscFunctionReturn(PETSC_SUCCESS);
6060   case MAT_NO_OFF_PROC_ENTRIES:
6061     mat->nooffprocentries = flg;
6062     PetscFunctionReturn(PETSC_SUCCESS);
6063   case MAT_SUBSET_OFF_PROC_ENTRIES:
6064     mat->assembly_subset = flg;
6065     if (!mat->assembly_subset) { /* See the same logic in VecAssembly wrt VEC_SUBSET_OFF_PROC_ENTRIES */
6066 #if !defined(PETSC_HAVE_MPIUNI)
6067       PetscCall(MatStashScatterDestroy_BTS(&mat->stash));
6068 #endif
6069       mat->stash.first_assembly_done = PETSC_FALSE;
6070     }
6071     PetscFunctionReturn(PETSC_SUCCESS);
6072   case MAT_NO_OFF_PROC_ZERO_ROWS:
6073     mat->nooffproczerorows = flg;
6074     PetscFunctionReturn(PETSC_SUCCESS);
6075   case MAT_SPD:
6076     if (flg) {
6077       mat->spd                    = PETSC_BOOL3_TRUE;
6078       mat->symmetric              = PETSC_BOOL3_TRUE;
6079       mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6080     } else {
6081       mat->spd = PETSC_BOOL3_FALSE;
6082     }
6083     break;
6084   case MAT_SYMMETRIC:
6085     mat->symmetric = PetscBoolToBool3(flg);
6086     if (flg) mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6087 #if !defined(PETSC_USE_COMPLEX)
6088     mat->hermitian = PetscBoolToBool3(flg);
6089 #endif
6090     break;
6091   case MAT_HERMITIAN:
6092     mat->hermitian = PetscBoolToBool3(flg);
6093     if (flg) mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6094 #if !defined(PETSC_USE_COMPLEX)
6095     mat->symmetric = PetscBoolToBool3(flg);
6096 #endif
6097     break;
6098   case MAT_STRUCTURALLY_SYMMETRIC:
6099     mat->structurally_symmetric = PetscBoolToBool3(flg);
6100     break;
6101   case MAT_SYMMETRY_ETERNAL:
6102     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");
6103     mat->symmetry_eternal = flg;
6104     if (flg) mat->structural_symmetry_eternal = PETSC_TRUE;
6105     break;
6106   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
6107     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");
6108     mat->structural_symmetry_eternal = flg;
6109     break;
6110   case MAT_SPD_ETERNAL:
6111     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");
6112     mat->spd_eternal = flg;
6113     if (flg) {
6114       mat->structural_symmetry_eternal = PETSC_TRUE;
6115       mat->symmetry_eternal            = PETSC_TRUE;
6116     }
6117     break;
6118   case MAT_STRUCTURE_ONLY:
6119     mat->structure_only = flg;
6120     break;
6121   case MAT_SORTED_FULL:
6122     mat->sortedfull = flg;
6123     break;
6124   default:
6125     break;
6126   }
6127   PetscTryTypeMethod(mat, setoption, op, flg);
6128   PetscFunctionReturn(PETSC_SUCCESS);
6129 }
6130 
6131 /*@
6132   MatGetOption - Gets a parameter option that has been set for a matrix.
6133 
6134   Logically Collective
6135 
6136   Input Parameters:
6137 + mat - the matrix
6138 - op  - the option, this only responds to certain options, check the code for which ones
6139 
6140   Output Parameter:
6141 . flg - turn the option on (`PETSC_TRUE`) or off (`PETSC_FALSE`)
6142 
6143   Level: intermediate
6144 
6145   Notes:
6146   Can only be called after `MatSetSizes()` and `MatSetType()` have been set.
6147 
6148   Certain option values may be unknown, for those use the routines `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, or
6149   `MatIsSymmetricKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
6150 
6151 .seealso: [](ch_matrices), `Mat`, `MatOption`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`,
6152     `MatIsSymmetricKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
6153 @*/
6154 PetscErrorCode MatGetOption(Mat mat, MatOption op, PetscBool *flg)
6155 {
6156   PetscFunctionBegin;
6157   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6158   PetscValidType(mat, 1);
6159 
6160   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);
6161   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()");
6162 
6163   switch (op) {
6164   case MAT_NO_OFF_PROC_ENTRIES:
6165     *flg = mat->nooffprocentries;
6166     break;
6167   case MAT_NO_OFF_PROC_ZERO_ROWS:
6168     *flg = mat->nooffproczerorows;
6169     break;
6170   case MAT_SYMMETRIC:
6171     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsSymmetric() or MatIsSymmetricKnown()");
6172     break;
6173   case MAT_HERMITIAN:
6174     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsHermitian() or MatIsHermitianKnown()");
6175     break;
6176   case MAT_STRUCTURALLY_SYMMETRIC:
6177     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsStructurallySymmetric() or MatIsStructurallySymmetricKnown()");
6178     break;
6179   case MAT_SPD:
6180     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsSPDKnown()");
6181     break;
6182   case MAT_SYMMETRY_ETERNAL:
6183     *flg = mat->symmetry_eternal;
6184     break;
6185   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
6186     *flg = mat->symmetry_eternal;
6187     break;
6188   default:
6189     break;
6190   }
6191   PetscFunctionReturn(PETSC_SUCCESS);
6192 }
6193 
6194 /*@
6195   MatZeroEntries - Zeros all entries of a matrix.  For sparse matrices
6196   this routine retains the old nonzero structure.
6197 
6198   Logically Collective
6199 
6200   Input Parameter:
6201 . mat - the matrix
6202 
6203   Level: intermediate
6204 
6205   Note:
6206   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.
6207   See the Performance chapter of the users manual for information on preallocating matrices.
6208 
6209 .seealso: [](ch_matrices), `Mat`, `MatZeroRows()`, `MatZeroRowsColumns()`
6210 @*/
6211 PetscErrorCode MatZeroEntries(Mat mat)
6212 {
6213   PetscFunctionBegin;
6214   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6215   PetscValidType(mat, 1);
6216   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6217   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");
6218   MatCheckPreallocated(mat, 1);
6219 
6220   PetscCall(PetscLogEventBegin(MAT_ZeroEntries, mat, 0, 0, 0));
6221   PetscUseTypeMethod(mat, zeroentries);
6222   PetscCall(PetscLogEventEnd(MAT_ZeroEntries, mat, 0, 0, 0));
6223   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6224   PetscFunctionReturn(PETSC_SUCCESS);
6225 }
6226 
6227 /*@
6228   MatZeroRowsColumns - Zeros all entries (except possibly the main diagonal)
6229   of a set of rows and columns of a matrix.
6230 
6231   Collective
6232 
6233   Input Parameters:
6234 + mat     - the matrix
6235 . numRows - the number of rows/columns to zero
6236 . rows    - the global row indices
6237 . diag    - value put in the diagonal of the eliminated rows
6238 . x       - optional vector of the solution for zeroed rows (other entries in vector are not used), these must be set before this call
6239 - b       - optional vector of the right-hand side, that will be adjusted by provided solution entries
6240 
6241   Level: intermediate
6242 
6243   Notes:
6244   This routine, along with `MatZeroRows()`, is typically used to eliminate known Dirichlet boundary conditions from a linear system.
6245 
6246   For each zeroed row, the value of the corresponding `b` is set to diag times the value of the corresponding `x`.
6247   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
6248 
6249   If the resulting linear system is to be solved with `KSP` then one can (but does not have to) call `KSPSetInitialGuessNonzero()` to allow the
6250   Krylov method to take advantage of the known solution on the zeroed rows.
6251 
6252   For the parallel case, all processes that share the matrix (i.e.,
6253   those in the communicator used for matrix creation) MUST call this
6254   routine, regardless of whether any rows being zeroed are owned by
6255   them.
6256 
6257   Unlike `MatZeroRows()`, this ignores the `MAT_KEEP_NONZERO_PATTERN` option value set with `MatSetOption()`, it merely zeros those entries in the matrix, but never
6258   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
6259   missing.
6260 
6261   Each processor can indicate any rows in the entire matrix to be zeroed (i.e. each process does NOT have to
6262   list only rows local to itself).
6263 
6264   The option `MAT_NO_OFF_PROC_ZERO_ROWS` does not apply to this routine.
6265 
6266 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRows()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6267           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6268 @*/
6269 PetscErrorCode MatZeroRowsColumns(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6270 {
6271   PetscFunctionBegin;
6272   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6273   PetscValidType(mat, 1);
6274   if (numRows) PetscAssertPointer(rows, 3);
6275   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6276   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6277   MatCheckPreallocated(mat, 1);
6278 
6279   PetscUseTypeMethod(mat, zerorowscolumns, numRows, rows, diag, x, b);
6280   PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
6281   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6282   PetscFunctionReturn(PETSC_SUCCESS);
6283 }
6284 
6285 /*@
6286   MatZeroRowsColumnsIS - Zeros all entries (except possibly the main diagonal)
6287   of a set of rows and columns of a matrix.
6288 
6289   Collective
6290 
6291   Input Parameters:
6292 + mat  - the matrix
6293 . is   - the rows to zero
6294 . diag - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6295 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6296 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6297 
6298   Level: intermediate
6299 
6300   Note:
6301   See `MatZeroRowsColumns()` for details on how this routine operates.
6302 
6303 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6304           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRows()`, `MatZeroRowsColumnsStencil()`
6305 @*/
6306 PetscErrorCode MatZeroRowsColumnsIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6307 {
6308   PetscInt        numRows;
6309   const PetscInt *rows;
6310 
6311   PetscFunctionBegin;
6312   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6313   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6314   PetscValidType(mat, 1);
6315   PetscValidType(is, 2);
6316   PetscCall(ISGetLocalSize(is, &numRows));
6317   PetscCall(ISGetIndices(is, &rows));
6318   PetscCall(MatZeroRowsColumns(mat, numRows, rows, diag, x, b));
6319   PetscCall(ISRestoreIndices(is, &rows));
6320   PetscFunctionReturn(PETSC_SUCCESS);
6321 }
6322 
6323 /*@
6324   MatZeroRows - Zeros all entries (except possibly the main diagonal)
6325   of a set of rows of a matrix.
6326 
6327   Collective
6328 
6329   Input Parameters:
6330 + mat     - the matrix
6331 . numRows - the number of rows to zero
6332 . rows    - the global row indices
6333 . diag    - value put in the diagonal of the zeroed rows
6334 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used), these must be set before this call
6335 - b       - optional vector of right-hand side, that will be adjusted by provided solution entries
6336 
6337   Level: intermediate
6338 
6339   Notes:
6340   This routine, along with `MatZeroRowsColumns()`, is typically used to eliminate known Dirichlet boundary conditions from a linear system.
6341 
6342   For each zeroed row, the value of the corresponding `b` is set to `diag` times the value of the corresponding `x`.
6343 
6344   If the resulting linear system is to be solved with `KSP` then one can (but does not have to) call `KSPSetInitialGuessNonzero()` to allow the
6345   Krylov method to take advantage of the known solution on the zeroed rows.
6346 
6347   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)
6348   from the matrix.
6349 
6350   Unlike `MatZeroRowsColumns()` for the `MATAIJ` and `MATBAIJ` matrix formats this removes the old nonzero structure, from the eliminated rows of the matrix
6351   but does not release memory.  Because of this removal matrix-vector products with the adjusted matrix will be a bit faster. For the dense
6352   formats this does not alter the nonzero structure.
6353 
6354   If the option `MatSetOption`(mat,`MAT_KEEP_NONZERO_PATTERN`,`PETSC_TRUE`) the nonzero structure
6355   of the matrix is not changed the values are
6356   merely zeroed.
6357 
6358   The user can set a value in the diagonal entry (or for the `MATAIJ` format
6359   formats can optionally remove the main diagonal entry from the
6360   nonzero structure as well, by passing 0.0 as the final argument).
6361 
6362   For the parallel case, all processes that share the matrix (i.e.,
6363   those in the communicator used for matrix creation) MUST call this
6364   routine, regardless of whether any rows being zeroed are owned by
6365   them.
6366 
6367   Each processor can indicate any rows in the entire matrix to be zeroed (i.e. each process does NOT have to
6368   list only rows local to itself).
6369 
6370   You can call `MatSetOption`(mat,`MAT_NO_OFF_PROC_ZERO_ROWS`,`PETSC_TRUE`) if each process indicates only rows it
6371   owns that are to be zeroed. This saves a global synchronization in the implementation.
6372 
6373 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6374           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`, `PCREDISTRIBUTE`, `MAT_KEEP_NONZERO_PATTERN`
6375 @*/
6376 PetscErrorCode MatZeroRows(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6377 {
6378   PetscFunctionBegin;
6379   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6380   PetscValidType(mat, 1);
6381   if (numRows) PetscAssertPointer(rows, 3);
6382   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6383   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6384   MatCheckPreallocated(mat, 1);
6385 
6386   PetscUseTypeMethod(mat, zerorows, numRows, rows, diag, x, b);
6387   PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
6388   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6389   PetscFunctionReturn(PETSC_SUCCESS);
6390 }
6391 
6392 /*@
6393   MatZeroRowsIS - Zeros all entries (except possibly the main diagonal)
6394   of a set of rows of a matrix indicated by an `IS`
6395 
6396   Collective
6397 
6398   Input Parameters:
6399 + mat  - the matrix
6400 . is   - index set, `IS`, of rows to remove (if `NULL` then no row is removed)
6401 . diag - value put in all diagonals of eliminated rows
6402 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6403 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6404 
6405   Level: intermediate
6406 
6407   Note:
6408   See `MatZeroRows()` for details on how this routine operates.
6409 
6410 .seealso: [](ch_matrices), `Mat`, `MatZeroRows()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6411           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`, `IS`
6412 @*/
6413 PetscErrorCode MatZeroRowsIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6414 {
6415   PetscInt        numRows = 0;
6416   const PetscInt *rows    = NULL;
6417 
6418   PetscFunctionBegin;
6419   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6420   PetscValidType(mat, 1);
6421   if (is) {
6422     PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6423     PetscCall(ISGetLocalSize(is, &numRows));
6424     PetscCall(ISGetIndices(is, &rows));
6425   }
6426   PetscCall(MatZeroRows(mat, numRows, rows, diag, x, b));
6427   if (is) PetscCall(ISRestoreIndices(is, &rows));
6428   PetscFunctionReturn(PETSC_SUCCESS);
6429 }
6430 
6431 /*@
6432   MatZeroRowsStencil - Zeros all entries (except possibly the main diagonal)
6433   of a set of rows of a matrix indicated by a `MatStencil`. These rows must be local to the process.
6434 
6435   Collective
6436 
6437   Input Parameters:
6438 + mat     - the matrix
6439 . numRows - the number of rows to remove
6440 . rows    - the grid coordinates (and component number when dof > 1) for matrix rows indicated by an array of `MatStencil`
6441 . diag    - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6442 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6443 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6444 
6445   Level: intermediate
6446 
6447   Notes:
6448   See `MatZeroRows()` for details on how this routine operates.
6449 
6450   The grid coordinates are across the entire grid, not just the local portion
6451 
6452   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
6453   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
6454   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
6455   `DM_BOUNDARY_PERIODIC` boundary type.
6456 
6457   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
6458   a single value per point) you can skip filling those indices.
6459 
6460   Fortran Note:
6461   `idxm` and `idxn` should be declared as
6462 .vb
6463     MatStencil idxm(4, m)
6464 .ve
6465   and the values inserted using
6466 .vb
6467     idxm(MatStencil_i, 1) = i
6468     idxm(MatStencil_j, 1) = j
6469     idxm(MatStencil_k, 1) = k
6470     idxm(MatStencil_c, 1) = c
6471    etc
6472 .ve
6473 
6474 .seealso: [](ch_matrices), `Mat`, `MatStencil`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRows()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6475           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6476 @*/
6477 PetscErrorCode MatZeroRowsStencil(Mat mat, PetscInt numRows, const MatStencil rows[], PetscScalar diag, Vec x, Vec b)
6478 {
6479   PetscInt  dim    = mat->stencil.dim;
6480   PetscInt  sdim   = dim - (1 - (PetscInt)mat->stencil.noc);
6481   PetscInt *dims   = mat->stencil.dims + 1;
6482   PetscInt *starts = mat->stencil.starts;
6483   PetscInt *dxm    = (PetscInt *)rows;
6484   PetscInt *jdxm, i, j, tmp, numNewRows = 0;
6485 
6486   PetscFunctionBegin;
6487   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6488   PetscValidType(mat, 1);
6489   if (numRows) PetscAssertPointer(rows, 3);
6490 
6491   PetscCall(PetscMalloc1(numRows, &jdxm));
6492   for (i = 0; i < numRows; ++i) {
6493     /* Skip unused dimensions (they are ordered k, j, i, c) */
6494     for (j = 0; j < 3 - sdim; ++j) dxm++;
6495     /* Local index in X dir */
6496     tmp = *dxm++ - starts[0];
6497     /* Loop over remaining dimensions */
6498     for (j = 0; j < dim - 1; ++j) {
6499       /* If nonlocal, set index to be negative */
6500       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = PETSC_INT_MIN;
6501       /* Update local index */
6502       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
6503     }
6504     /* Skip component slot if necessary */
6505     if (mat->stencil.noc) dxm++;
6506     /* Local row number */
6507     if (tmp >= 0) jdxm[numNewRows++] = tmp;
6508   }
6509   PetscCall(MatZeroRowsLocal(mat, numNewRows, jdxm, diag, x, b));
6510   PetscCall(PetscFree(jdxm));
6511   PetscFunctionReturn(PETSC_SUCCESS);
6512 }
6513 
6514 /*@
6515   MatZeroRowsColumnsStencil - Zeros all row and column entries (except possibly the main diagonal)
6516   of a set of rows and columns of a matrix.
6517 
6518   Collective
6519 
6520   Input Parameters:
6521 + mat     - the matrix
6522 . numRows - the number of rows/columns to remove
6523 . rows    - the grid coordinates (and component number when dof > 1) for matrix rows
6524 . diag    - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6525 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6526 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6527 
6528   Level: intermediate
6529 
6530   Notes:
6531   See `MatZeroRowsColumns()` for details on how this routine operates.
6532 
6533   The grid coordinates are across the entire grid, not just the local portion
6534 
6535   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
6536   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
6537   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
6538   `DM_BOUNDARY_PERIODIC` boundary type.
6539 
6540   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
6541   a single value per point) you can skip filling those indices.
6542 
6543   Fortran Note:
6544   `idxm` and `idxn` should be declared as
6545 .vb
6546     MatStencil idxm(4, m)
6547 .ve
6548   and the values inserted using
6549 .vb
6550     idxm(MatStencil_i, 1) = i
6551     idxm(MatStencil_j, 1) = j
6552     idxm(MatStencil_k, 1) = k
6553     idxm(MatStencil_c, 1) = c
6554     etc
6555 .ve
6556 
6557 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6558           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRows()`
6559 @*/
6560 PetscErrorCode MatZeroRowsColumnsStencil(Mat mat, PetscInt numRows, const MatStencil rows[], PetscScalar diag, Vec x, Vec b)
6561 {
6562   PetscInt  dim    = mat->stencil.dim;
6563   PetscInt  sdim   = dim - (1 - (PetscInt)mat->stencil.noc);
6564   PetscInt *dims   = mat->stencil.dims + 1;
6565   PetscInt *starts = mat->stencil.starts;
6566   PetscInt *dxm    = (PetscInt *)rows;
6567   PetscInt *jdxm, i, j, tmp, numNewRows = 0;
6568 
6569   PetscFunctionBegin;
6570   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6571   PetscValidType(mat, 1);
6572   if (numRows) PetscAssertPointer(rows, 3);
6573 
6574   PetscCall(PetscMalloc1(numRows, &jdxm));
6575   for (i = 0; i < numRows; ++i) {
6576     /* Skip unused dimensions (they are ordered k, j, i, c) */
6577     for (j = 0; j < 3 - sdim; ++j) dxm++;
6578     /* Local index in X dir */
6579     tmp = *dxm++ - starts[0];
6580     /* Loop over remaining dimensions */
6581     for (j = 0; j < dim - 1; ++j) {
6582       /* If nonlocal, set index to be negative */
6583       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = PETSC_INT_MIN;
6584       /* Update local index */
6585       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
6586     }
6587     /* Skip component slot if necessary */
6588     if (mat->stencil.noc) dxm++;
6589     /* Local row number */
6590     if (tmp >= 0) jdxm[numNewRows++] = tmp;
6591   }
6592   PetscCall(MatZeroRowsColumnsLocal(mat, numNewRows, jdxm, diag, x, b));
6593   PetscCall(PetscFree(jdxm));
6594   PetscFunctionReturn(PETSC_SUCCESS);
6595 }
6596 
6597 /*@
6598   MatZeroRowsLocal - Zeros all entries (except possibly the main diagonal)
6599   of a set of rows of a matrix; using local numbering of rows.
6600 
6601   Collective
6602 
6603   Input Parameters:
6604 + mat     - the matrix
6605 . numRows - the number of rows to remove
6606 . rows    - the local row indices
6607 . diag    - value put in all diagonals of eliminated rows
6608 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6609 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6610 
6611   Level: intermediate
6612 
6613   Notes:
6614   Before calling `MatZeroRowsLocal()`, the user must first set the
6615   local-to-global mapping by calling MatSetLocalToGlobalMapping(), this is often already set for matrices obtained with `DMCreateMatrix()`.
6616 
6617   See `MatZeroRows()` for details on how this routine operates.
6618 
6619 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRows()`, `MatSetOption()`,
6620           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6621 @*/
6622 PetscErrorCode MatZeroRowsLocal(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6623 {
6624   PetscFunctionBegin;
6625   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6626   PetscValidType(mat, 1);
6627   if (numRows) PetscAssertPointer(rows, 3);
6628   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6629   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6630   MatCheckPreallocated(mat, 1);
6631 
6632   if (mat->ops->zerorowslocal) {
6633     PetscUseTypeMethod(mat, zerorowslocal, numRows, rows, diag, x, b);
6634   } else {
6635     IS              is, newis;
6636     const PetscInt *newRows;
6637 
6638     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Need to provide local to global mapping to matrix first");
6639     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numRows, rows, PETSC_COPY_VALUES, &is));
6640     PetscCall(ISLocalToGlobalMappingApplyIS(mat->rmap->mapping, is, &newis));
6641     PetscCall(ISGetIndices(newis, &newRows));
6642     PetscUseTypeMethod(mat, zerorows, numRows, newRows, diag, x, b);
6643     PetscCall(ISRestoreIndices(newis, &newRows));
6644     PetscCall(ISDestroy(&newis));
6645     PetscCall(ISDestroy(&is));
6646   }
6647   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6648   PetscFunctionReturn(PETSC_SUCCESS);
6649 }
6650 
6651 /*@
6652   MatZeroRowsLocalIS - Zeros all entries (except possibly the main diagonal)
6653   of a set of rows of a matrix; using local numbering of rows.
6654 
6655   Collective
6656 
6657   Input Parameters:
6658 + mat  - the matrix
6659 . is   - index set of rows to remove
6660 . diag - value put in all diagonals of eliminated rows
6661 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6662 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6663 
6664   Level: intermediate
6665 
6666   Notes:
6667   Before calling `MatZeroRowsLocalIS()`, the user must first set the
6668   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6669 
6670   See `MatZeroRows()` for details on how this routine operates.
6671 
6672 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRows()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6673           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6674 @*/
6675 PetscErrorCode MatZeroRowsLocalIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6676 {
6677   PetscInt        numRows;
6678   const PetscInt *rows;
6679 
6680   PetscFunctionBegin;
6681   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6682   PetscValidType(mat, 1);
6683   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6684   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6685   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6686   MatCheckPreallocated(mat, 1);
6687 
6688   PetscCall(ISGetLocalSize(is, &numRows));
6689   PetscCall(ISGetIndices(is, &rows));
6690   PetscCall(MatZeroRowsLocal(mat, numRows, rows, diag, x, b));
6691   PetscCall(ISRestoreIndices(is, &rows));
6692   PetscFunctionReturn(PETSC_SUCCESS);
6693 }
6694 
6695 /*@
6696   MatZeroRowsColumnsLocal - Zeros all entries (except possibly the main diagonal)
6697   of a set of rows and columns of a matrix; using local numbering of rows.
6698 
6699   Collective
6700 
6701   Input Parameters:
6702 + mat     - the matrix
6703 . numRows - the number of rows to remove
6704 . rows    - the global row indices
6705 . diag    - value put in all diagonals of eliminated rows
6706 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6707 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6708 
6709   Level: intermediate
6710 
6711   Notes:
6712   Before calling `MatZeroRowsColumnsLocal()`, the user must first set the
6713   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6714 
6715   See `MatZeroRowsColumns()` for details on how this routine operates.
6716 
6717 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6718           `MatZeroRows()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6719 @*/
6720 PetscErrorCode MatZeroRowsColumnsLocal(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6721 {
6722   IS              is, newis;
6723   const PetscInt *newRows;
6724 
6725   PetscFunctionBegin;
6726   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6727   PetscValidType(mat, 1);
6728   if (numRows) PetscAssertPointer(rows, 3);
6729   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6730   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6731   MatCheckPreallocated(mat, 1);
6732 
6733   PetscCheck(mat->cmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Need to provide local to global mapping to matrix first");
6734   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numRows, rows, PETSC_COPY_VALUES, &is));
6735   PetscCall(ISLocalToGlobalMappingApplyIS(mat->cmap->mapping, is, &newis));
6736   PetscCall(ISGetIndices(newis, &newRows));
6737   PetscUseTypeMethod(mat, zerorowscolumns, numRows, newRows, diag, x, b);
6738   PetscCall(ISRestoreIndices(newis, &newRows));
6739   PetscCall(ISDestroy(&newis));
6740   PetscCall(ISDestroy(&is));
6741   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6742   PetscFunctionReturn(PETSC_SUCCESS);
6743 }
6744 
6745 /*@
6746   MatZeroRowsColumnsLocalIS - Zeros all entries (except possibly the main diagonal)
6747   of a set of rows and columns of a matrix; using local numbering of rows.
6748 
6749   Collective
6750 
6751   Input Parameters:
6752 + mat  - the matrix
6753 . is   - index set of rows to remove
6754 . diag - value put in all diagonals of eliminated rows
6755 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6756 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6757 
6758   Level: intermediate
6759 
6760   Notes:
6761   Before calling `MatZeroRowsColumnsLocalIS()`, the user must first set the
6762   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6763 
6764   See `MatZeroRowsColumns()` for details on how this routine operates.
6765 
6766 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6767           `MatZeroRowsColumnsLocal()`, `MatZeroRows()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6768 @*/
6769 PetscErrorCode MatZeroRowsColumnsLocalIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6770 {
6771   PetscInt        numRows;
6772   const PetscInt *rows;
6773 
6774   PetscFunctionBegin;
6775   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6776   PetscValidType(mat, 1);
6777   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6778   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6779   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6780   MatCheckPreallocated(mat, 1);
6781 
6782   PetscCall(ISGetLocalSize(is, &numRows));
6783   PetscCall(ISGetIndices(is, &rows));
6784   PetscCall(MatZeroRowsColumnsLocal(mat, numRows, rows, diag, x, b));
6785   PetscCall(ISRestoreIndices(is, &rows));
6786   PetscFunctionReturn(PETSC_SUCCESS);
6787 }
6788 
6789 /*@
6790   MatGetSize - Returns the numbers of rows and columns in a matrix.
6791 
6792   Not Collective
6793 
6794   Input Parameter:
6795 . mat - the matrix
6796 
6797   Output Parameters:
6798 + m - the number of global rows
6799 - n - the number of global columns
6800 
6801   Level: beginner
6802 
6803   Note:
6804   Both output parameters can be `NULL` on input.
6805 
6806 .seealso: [](ch_matrices), `Mat`, `MatSetSizes()`, `MatGetLocalSize()`
6807 @*/
6808 PetscErrorCode MatGetSize(Mat mat, PetscInt *m, PetscInt *n)
6809 {
6810   PetscFunctionBegin;
6811   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6812   if (m) *m = mat->rmap->N;
6813   if (n) *n = mat->cmap->N;
6814   PetscFunctionReturn(PETSC_SUCCESS);
6815 }
6816 
6817 /*@
6818   MatGetLocalSize - For most matrix formats, excluding `MATELEMENTAL` and `MATSCALAPACK`, Returns the number of local rows and local columns
6819   of a matrix. For all matrices this is the local size of the left and right vectors as returned by `MatCreateVecs()`.
6820 
6821   Not Collective
6822 
6823   Input Parameter:
6824 . mat - the matrix
6825 
6826   Output Parameters:
6827 + m - the number of local rows, use `NULL` to not obtain this value
6828 - n - the number of local columns, use `NULL` to not obtain this value
6829 
6830   Level: beginner
6831 
6832 .seealso: [](ch_matrices), `Mat`, `MatSetSizes()`, `MatGetSize()`
6833 @*/
6834 PetscErrorCode MatGetLocalSize(Mat mat, PetscInt *m, PetscInt *n)
6835 {
6836   PetscFunctionBegin;
6837   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6838   if (m) PetscAssertPointer(m, 2);
6839   if (n) PetscAssertPointer(n, 3);
6840   if (m) *m = mat->rmap->n;
6841   if (n) *n = mat->cmap->n;
6842   PetscFunctionReturn(PETSC_SUCCESS);
6843 }
6844 
6845 /*@
6846   MatGetOwnershipRangeColumn - Returns the range of matrix columns associated with rows of a
6847   vector one multiplies this matrix by that are owned by this processor.
6848 
6849   Not Collective, unless matrix has not been allocated, then collective
6850 
6851   Input Parameter:
6852 . mat - the matrix
6853 
6854   Output Parameters:
6855 + m - the global index of the first local column, use `NULL` to not obtain this value
6856 - n - one more than the global index of the last local column, use `NULL` to not obtain this value
6857 
6858   Level: developer
6859 
6860   Notes:
6861   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6862 
6863   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6864   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6865 
6866   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6867   the local values in the matrix.
6868 
6869   Returns the columns of the "diagonal block" for most sparse matrix formats. See [Matrix
6870   Layouts](sec_matlayout) for details on matrix layouts.
6871 
6872 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`,
6873           `MatSetSizes()`, `MatCreateAIJ()`, `DMDAGetGhostCorners()`, `DM`
6874 @*/
6875 PetscErrorCode MatGetOwnershipRangeColumn(Mat mat, PetscInt *m, PetscInt *n)
6876 {
6877   PetscFunctionBegin;
6878   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6879   PetscValidType(mat, 1);
6880   if (m) PetscAssertPointer(m, 2);
6881   if (n) PetscAssertPointer(n, 3);
6882   MatCheckPreallocated(mat, 1);
6883   if (m) *m = mat->cmap->rstart;
6884   if (n) *n = mat->cmap->rend;
6885   PetscFunctionReturn(PETSC_SUCCESS);
6886 }
6887 
6888 /*@
6889   MatGetOwnershipRange - For matrices that own values by row, excludes `MATELEMENTAL` and `MATSCALAPACK`, returns the range of matrix rows owned by
6890   this MPI process.
6891 
6892   Not Collective
6893 
6894   Input Parameter:
6895 . mat - the matrix
6896 
6897   Output Parameters:
6898 + m - the global index of the first local row, use `NULL` to not obtain this value
6899 - n - one more than the global index of the last local row, use `NULL` to not obtain this value
6900 
6901   Level: beginner
6902 
6903   Notes:
6904   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6905 
6906   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6907   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6908 
6909   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6910   the local values in the matrix.
6911 
6912   The high argument is one more than the last element stored locally.
6913 
6914   For all matrices  it returns the range of matrix rows associated with rows of a vector that
6915   would contain the result of a matrix vector product with this matrix. See [Matrix
6916   Layouts](sec_matlayout) for details on matrix layouts.
6917 
6918 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscSplitOwnership()`,
6919           `PetscSplitOwnershipBlock()`, `PetscLayout`, `MatSetSizes()`, `MatCreateAIJ()`, `DMDAGetGhostCorners()`, `DM`
6920 @*/
6921 PetscErrorCode MatGetOwnershipRange(Mat mat, PetscInt *m, PetscInt *n)
6922 {
6923   PetscFunctionBegin;
6924   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6925   PetscValidType(mat, 1);
6926   if (m) PetscAssertPointer(m, 2);
6927   if (n) PetscAssertPointer(n, 3);
6928   MatCheckPreallocated(mat, 1);
6929   if (m) *m = mat->rmap->rstart;
6930   if (n) *n = mat->rmap->rend;
6931   PetscFunctionReturn(PETSC_SUCCESS);
6932 }
6933 
6934 /*@C
6935   MatGetOwnershipRanges - For matrices that own values by row, excludes `MATELEMENTAL` and
6936   `MATSCALAPACK`, returns the range of matrix rows owned by each process.
6937 
6938   Not Collective, unless matrix has not been allocated
6939 
6940   Input Parameter:
6941 . mat - the matrix
6942 
6943   Output Parameter:
6944 . ranges - start of each processors portion plus one more than the total length at the end, of length `size` + 1
6945            where `size` is the number of MPI processes used by `mat`
6946 
6947   Level: beginner
6948 
6949   Notes:
6950   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6951 
6952   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6953   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6954 
6955   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6956   the local values in the matrix.
6957 
6958   For all matrices  it returns the ranges of matrix rows associated with rows of a vector that
6959   would contain the result of a matrix vector product with this matrix. See [Matrix
6960   Layouts](sec_matlayout) for details on matrix layouts.
6961 
6962 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`,
6963           `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`, `MatSetSizes()`, `MatCreateAIJ()`,
6964           `DMDAGetGhostCorners()`, `DM`
6965 @*/
6966 PetscErrorCode MatGetOwnershipRanges(Mat mat, const PetscInt *ranges[])
6967 {
6968   PetscFunctionBegin;
6969   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6970   PetscValidType(mat, 1);
6971   MatCheckPreallocated(mat, 1);
6972   PetscCall(PetscLayoutGetRanges(mat->rmap, ranges));
6973   PetscFunctionReturn(PETSC_SUCCESS);
6974 }
6975 
6976 /*@C
6977   MatGetOwnershipRangesColumn - Returns the ranges of matrix columns associated with rows of a
6978   vector one multiplies this vector by that are owned by each processor.
6979 
6980   Not Collective, unless matrix has not been allocated
6981 
6982   Input Parameter:
6983 . mat - the matrix
6984 
6985   Output Parameter:
6986 . ranges - start of each processors portion plus one more than the total length at the end
6987 
6988   Level: beginner
6989 
6990   Notes:
6991   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6992 
6993   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6994   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6995 
6996   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6997   the local values in the matrix.
6998 
6999   Returns the columns of the "diagonal blocks", for most sparse matrix formats. See [Matrix
7000   Layouts](sec_matlayout) for details on matrix layouts.
7001 
7002 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRanges()`,
7003           `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`, `PetscLayout`, `MatSetSizes()`, `MatCreateAIJ()`,
7004           `DMDAGetGhostCorners()`, `DM`
7005 @*/
7006 PetscErrorCode MatGetOwnershipRangesColumn(Mat mat, const PetscInt *ranges[])
7007 {
7008   PetscFunctionBegin;
7009   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7010   PetscValidType(mat, 1);
7011   MatCheckPreallocated(mat, 1);
7012   PetscCall(PetscLayoutGetRanges(mat->cmap, ranges));
7013   PetscFunctionReturn(PETSC_SUCCESS);
7014 }
7015 
7016 /*@
7017   MatGetOwnershipIS - Get row and column ownership of a matrices' values as index sets.
7018 
7019   Not Collective
7020 
7021   Input Parameter:
7022 . A - matrix
7023 
7024   Output Parameters:
7025 + rows - rows in which this process owns elements, , use `NULL` to not obtain this value
7026 - cols - columns in which this process owns elements, use `NULL` to not obtain this value
7027 
7028   Level: intermediate
7029 
7030   Note:
7031   You should call `ISDestroy()` on the returned `IS`
7032 
7033   For most matrices, excluding `MATELEMENTAL` and `MATSCALAPACK`, this corresponds to values
7034   returned by `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`. For `MATELEMENTAL` and
7035   `MATSCALAPACK` the ownership is more complicated. See [Matrix Layouts](sec_matlayout) for
7036   details on matrix layouts.
7037 
7038 .seealso: [](ch_matrices), `IS`, `Mat`, `MatGetOwnershipRanges()`, `MatSetValues()`, `MATELEMENTAL`, `MATSCALAPACK`
7039 @*/
7040 PetscErrorCode MatGetOwnershipIS(Mat A, IS *rows, IS *cols)
7041 {
7042   PetscErrorCode (*f)(Mat, IS *, IS *);
7043 
7044   PetscFunctionBegin;
7045   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
7046   PetscValidType(A, 1);
7047   MatCheckPreallocated(A, 1);
7048   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatGetOwnershipIS_C", &f));
7049   if (f) {
7050     PetscCall((*f)(A, rows, cols));
7051   } else { /* Create a standard row-based partition, each process is responsible for ALL columns in their row block */
7052     if (rows) PetscCall(ISCreateStride(PETSC_COMM_SELF, A->rmap->n, A->rmap->rstart, 1, rows));
7053     if (cols) PetscCall(ISCreateStride(PETSC_COMM_SELF, A->cmap->N, 0, 1, cols));
7054   }
7055   PetscFunctionReturn(PETSC_SUCCESS);
7056 }
7057 
7058 /*@
7059   MatILUFactorSymbolic - Performs symbolic ILU factorization of a matrix obtained with `MatGetFactor()`
7060   Uses levels of fill only, not drop tolerance. Use `MatLUFactorNumeric()`
7061   to complete the factorization.
7062 
7063   Collective
7064 
7065   Input Parameters:
7066 + fact - the factorized matrix obtained with `MatGetFactor()`
7067 . mat  - the matrix
7068 . row  - row permutation
7069 . col  - column permutation
7070 - info - structure containing
7071 .vb
7072       levels - number of levels of fill.
7073       expected fill - as ratio of original fill.
7074       1 or 0 - indicating force fill on diagonal (improves robustness for matrices
7075                 missing diagonal entries)
7076 .ve
7077 
7078   Level: developer
7079 
7080   Notes:
7081   See [Matrix Factorization](sec_matfactor) for additional information.
7082 
7083   Most users should employ the `KSP` interface for linear solvers
7084   instead of working directly with matrix algebra routines such as this.
7085   See, e.g., `KSPCreate()`.
7086 
7087   Uses the definition of level of fill as in Y. Saad, {cite}`saad2003`
7088 
7089   Fortran Note:
7090   A valid (non-null) `info` argument must be provided
7091 
7092 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
7093           `MatGetOrdering()`, `MatFactorInfo`
7094 @*/
7095 PetscErrorCode MatILUFactorSymbolic(Mat fact, Mat mat, IS row, IS col, const MatFactorInfo *info)
7096 {
7097   PetscFunctionBegin;
7098   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
7099   PetscValidType(mat, 2);
7100   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 3);
7101   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 4);
7102   PetscAssertPointer(info, 5);
7103   PetscAssertPointer(fact, 1);
7104   PetscCheck(info->levels >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Levels of fill negative %" PetscInt_FMT, (PetscInt)info->levels);
7105   PetscCheck(info->fill >= 1.0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Expected fill less than 1.0 %g", (double)info->fill);
7106   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7107   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7108   MatCheckPreallocated(mat, 2);
7109 
7110   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_ILUFactorSymbolic, mat, row, col, 0));
7111   PetscUseTypeMethod(fact, ilufactorsymbolic, mat, row, col, info);
7112   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_ILUFactorSymbolic, mat, row, col, 0));
7113   PetscFunctionReturn(PETSC_SUCCESS);
7114 }
7115 
7116 /*@
7117   MatICCFactorSymbolic - Performs symbolic incomplete
7118   Cholesky factorization for a symmetric matrix.  Use
7119   `MatCholeskyFactorNumeric()` to complete the factorization.
7120 
7121   Collective
7122 
7123   Input Parameters:
7124 + fact - the factorized matrix obtained with `MatGetFactor()`
7125 . mat  - the matrix to be factored
7126 . perm - row and column permutation
7127 - info - structure containing
7128 .vb
7129       levels - number of levels of fill.
7130       expected fill - as ratio of original fill.
7131 .ve
7132 
7133   Level: developer
7134 
7135   Notes:
7136   Most users should employ the `KSP` interface for linear solvers
7137   instead of working directly with matrix algebra routines such as this.
7138   See, e.g., `KSPCreate()`.
7139 
7140   This uses the definition of level of fill as in Y. Saad {cite}`saad2003`
7141 
7142   Fortran Note:
7143   A valid (non-null) `info` argument must be provided
7144 
7145 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`
7146 @*/
7147 PetscErrorCode MatICCFactorSymbolic(Mat fact, Mat mat, IS perm, const MatFactorInfo *info)
7148 {
7149   PetscFunctionBegin;
7150   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
7151   PetscValidType(mat, 2);
7152   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 3);
7153   PetscAssertPointer(info, 4);
7154   PetscAssertPointer(fact, 1);
7155   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7156   PetscCheck(info->levels >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Levels negative %" PetscInt_FMT, (PetscInt)info->levels);
7157   PetscCheck(info->fill >= 1.0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Expected fill less than 1.0 %g", (double)info->fill);
7158   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7159   MatCheckPreallocated(mat, 2);
7160 
7161   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_ICCFactorSymbolic, mat, perm, 0, 0));
7162   PetscUseTypeMethod(fact, iccfactorsymbolic, mat, perm, info);
7163   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_ICCFactorSymbolic, mat, perm, 0, 0));
7164   PetscFunctionReturn(PETSC_SUCCESS);
7165 }
7166 
7167 /*@C
7168   MatCreateSubMatrices - Extracts several submatrices from a matrix. If submat
7169   points to an array of valid matrices, they may be reused to store the new
7170   submatrices.
7171 
7172   Collective
7173 
7174   Input Parameters:
7175 + mat   - the matrix
7176 . n     - the number of submatrixes to be extracted (on this processor, may be zero)
7177 . irow  - index set of rows to extract
7178 . icol  - index set of columns to extract
7179 - scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
7180 
7181   Output Parameter:
7182 . submat - the array of submatrices
7183 
7184   Level: advanced
7185 
7186   Notes:
7187   `MatCreateSubMatrices()` can extract ONLY sequential submatrices
7188   (from both sequential and parallel matrices). Use `MatCreateSubMatrix()`
7189   to extract a parallel submatrix.
7190 
7191   Some matrix types place restrictions on the row and column
7192   indices, such as that they be sorted or that they be equal to each other.
7193 
7194   The index sets may not have duplicate entries.
7195 
7196   When extracting submatrices from a parallel matrix, each processor can
7197   form a different submatrix by setting the rows and columns of its
7198   individual index sets according to the local submatrix desired.
7199 
7200   When finished using the submatrices, the user should destroy
7201   them with `MatDestroySubMatrices()`.
7202 
7203   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
7204   original matrix has not changed from that last call to `MatCreateSubMatrices()`.
7205 
7206   This routine creates the matrices in submat; you should NOT create them before
7207   calling it. It also allocates the array of matrix pointers submat.
7208 
7209   For `MATBAIJ` matrices the index sets must respect the block structure, that is if they
7210   request one row/column in a block, they must request all rows/columns that are in
7211   that block. For example, if the block size is 2 you cannot request just row 0 and
7212   column 0.
7213 
7214   Fortran Note:
7215 .vb
7216   Mat, pointer :: submat(:)
7217 .ve
7218 
7219 .seealso: [](ch_matrices), `Mat`, `MatDestroySubMatrices()`, `MatCreateSubMatrix()`, `MatGetRow()`, `MatGetDiagonal()`, `MatReuse`
7220 @*/
7221 PetscErrorCode MatCreateSubMatrices(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
7222 {
7223   PetscInt  i;
7224   PetscBool eq;
7225 
7226   PetscFunctionBegin;
7227   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7228   PetscValidType(mat, 1);
7229   if (n) {
7230     PetscAssertPointer(irow, 3);
7231     for (i = 0; i < n; i++) PetscValidHeaderSpecific(irow[i], IS_CLASSID, 3);
7232     PetscAssertPointer(icol, 4);
7233     for (i = 0; i < n; i++) PetscValidHeaderSpecific(icol[i], IS_CLASSID, 4);
7234   }
7235   PetscAssertPointer(submat, 6);
7236   if (n && scall == MAT_REUSE_MATRIX) {
7237     PetscAssertPointer(*submat, 6);
7238     for (i = 0; i < n; i++) PetscValidHeaderSpecific((*submat)[i], MAT_CLASSID, 6);
7239   }
7240   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7241   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7242   MatCheckPreallocated(mat, 1);
7243   PetscCall(PetscLogEventBegin(MAT_CreateSubMats, mat, 0, 0, 0));
7244   PetscUseTypeMethod(mat, createsubmatrices, n, irow, icol, scall, submat);
7245   PetscCall(PetscLogEventEnd(MAT_CreateSubMats, mat, 0, 0, 0));
7246   for (i = 0; i < n; i++) {
7247     (*submat)[i]->factortype = MAT_FACTOR_NONE; /* in case in place factorization was previously done on submatrix */
7248     PetscCall(ISEqualUnsorted(irow[i], icol[i], &eq));
7249     if (eq) PetscCall(MatPropagateSymmetryOptions(mat, (*submat)[i]));
7250 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
7251     if (mat->boundtocpu && mat->bindingpropagates) {
7252       PetscCall(MatBindToCPU((*submat)[i], PETSC_TRUE));
7253       PetscCall(MatSetBindingPropagates((*submat)[i], PETSC_TRUE));
7254     }
7255 #endif
7256   }
7257   PetscFunctionReturn(PETSC_SUCCESS);
7258 }
7259 
7260 /*@C
7261   MatCreateSubMatricesMPI - Extracts MPI submatrices across a sub communicator of `mat` (by pairs of `IS` that may live on subcomms).
7262 
7263   Collective
7264 
7265   Input Parameters:
7266 + mat   - the matrix
7267 . n     - the number of submatrixes to be extracted
7268 . irow  - index set of rows to extract
7269 . icol  - index set of columns to extract
7270 - scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
7271 
7272   Output Parameter:
7273 . submat - the array of submatrices
7274 
7275   Level: advanced
7276 
7277   Note:
7278   This is used by `PCGASM`
7279 
7280 .seealso: [](ch_matrices), `Mat`, `PCGASM`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRow()`, `MatGetDiagonal()`, `MatReuse`
7281 @*/
7282 PetscErrorCode MatCreateSubMatricesMPI(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
7283 {
7284   PetscInt  i;
7285   PetscBool eq;
7286 
7287   PetscFunctionBegin;
7288   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7289   PetscValidType(mat, 1);
7290   if (n) {
7291     PetscAssertPointer(irow, 3);
7292     PetscValidHeaderSpecific(*irow, IS_CLASSID, 3);
7293     PetscAssertPointer(icol, 4);
7294     PetscValidHeaderSpecific(*icol, IS_CLASSID, 4);
7295   }
7296   PetscAssertPointer(submat, 6);
7297   if (n && scall == MAT_REUSE_MATRIX) {
7298     PetscAssertPointer(*submat, 6);
7299     PetscValidHeaderSpecific(**submat, MAT_CLASSID, 6);
7300   }
7301   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7302   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7303   MatCheckPreallocated(mat, 1);
7304 
7305   PetscCall(PetscLogEventBegin(MAT_CreateSubMats, mat, 0, 0, 0));
7306   PetscUseTypeMethod(mat, createsubmatricesmpi, n, irow, icol, scall, submat);
7307   PetscCall(PetscLogEventEnd(MAT_CreateSubMats, mat, 0, 0, 0));
7308   for (i = 0; i < n; i++) {
7309     PetscCall(ISEqualUnsorted(irow[i], icol[i], &eq));
7310     if (eq) PetscCall(MatPropagateSymmetryOptions(mat, (*submat)[i]));
7311   }
7312   PetscFunctionReturn(PETSC_SUCCESS);
7313 }
7314 
7315 /*@C
7316   MatDestroyMatrices - Destroys an array of matrices
7317 
7318   Collective
7319 
7320   Input Parameters:
7321 + n   - the number of local matrices
7322 - mat - the matrices (this is a pointer to the array of matrices)
7323 
7324   Level: advanced
7325 
7326   Notes:
7327   Frees not only the matrices, but also the array that contains the matrices
7328 
7329   For matrices obtained with  `MatCreateSubMatrices()` use `MatDestroySubMatrices()`
7330 
7331 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatDestroySubMatrices()`
7332 @*/
7333 PetscErrorCode MatDestroyMatrices(PetscInt n, Mat *mat[])
7334 {
7335   PetscInt i;
7336 
7337   PetscFunctionBegin;
7338   if (!*mat) PetscFunctionReturn(PETSC_SUCCESS);
7339   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy negative number of matrices %" PetscInt_FMT, n);
7340   PetscAssertPointer(mat, 2);
7341 
7342   for (i = 0; i < n; i++) PetscCall(MatDestroy(&(*mat)[i]));
7343 
7344   /* memory is allocated even if n = 0 */
7345   PetscCall(PetscFree(*mat));
7346   PetscFunctionReturn(PETSC_SUCCESS);
7347 }
7348 
7349 /*@C
7350   MatDestroySubMatrices - Destroys a set of matrices obtained with `MatCreateSubMatrices()`.
7351 
7352   Collective
7353 
7354   Input Parameters:
7355 + n   - the number of local matrices
7356 - mat - the matrices (this is a pointer to the array of matrices, to match the calling sequence of `MatCreateSubMatrices()`)
7357 
7358   Level: advanced
7359 
7360   Note:
7361   Frees not only the matrices, but also the array that contains the matrices
7362 
7363 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatDestroyMatrices()`
7364 @*/
7365 PetscErrorCode MatDestroySubMatrices(PetscInt n, Mat *mat[])
7366 {
7367   Mat mat0;
7368 
7369   PetscFunctionBegin;
7370   if (!*mat) PetscFunctionReturn(PETSC_SUCCESS);
7371   /* mat[] is an array of length n+1, see MatCreateSubMatrices_xxx() */
7372   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy negative number of matrices %" PetscInt_FMT, n);
7373   PetscAssertPointer(mat, 2);
7374 
7375   mat0 = (*mat)[0];
7376   if (mat0 && mat0->ops->destroysubmatrices) {
7377     PetscCall((*mat0->ops->destroysubmatrices)(n, mat));
7378   } else {
7379     PetscCall(MatDestroyMatrices(n, mat));
7380   }
7381   PetscFunctionReturn(PETSC_SUCCESS);
7382 }
7383 
7384 /*@
7385   MatGetSeqNonzeroStructure - Extracts the nonzero structure from a matrix and stores it, in its entirety, on each process
7386 
7387   Collective
7388 
7389   Input Parameter:
7390 . mat - the matrix
7391 
7392   Output Parameter:
7393 . matstruct - the sequential matrix with the nonzero structure of `mat`
7394 
7395   Level: developer
7396 
7397 .seealso: [](ch_matrices), `Mat`, `MatDestroySeqNonzeroStructure()`, `MatCreateSubMatrices()`, `MatDestroyMatrices()`
7398 @*/
7399 PetscErrorCode MatGetSeqNonzeroStructure(Mat mat, Mat *matstruct)
7400 {
7401   PetscFunctionBegin;
7402   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7403   PetscAssertPointer(matstruct, 2);
7404 
7405   PetscValidType(mat, 1);
7406   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7407   MatCheckPreallocated(mat, 1);
7408 
7409   PetscCall(PetscLogEventBegin(MAT_GetSeqNonzeroStructure, mat, 0, 0, 0));
7410   PetscUseTypeMethod(mat, getseqnonzerostructure, matstruct);
7411   PetscCall(PetscLogEventEnd(MAT_GetSeqNonzeroStructure, mat, 0, 0, 0));
7412   PetscFunctionReturn(PETSC_SUCCESS);
7413 }
7414 
7415 /*@C
7416   MatDestroySeqNonzeroStructure - Destroys matrix obtained with `MatGetSeqNonzeroStructure()`.
7417 
7418   Collective
7419 
7420   Input Parameter:
7421 . mat - the matrix
7422 
7423   Level: advanced
7424 
7425   Note:
7426   This is not needed, one can just call `MatDestroy()`
7427 
7428 .seealso: [](ch_matrices), `Mat`, `MatGetSeqNonzeroStructure()`
7429 @*/
7430 PetscErrorCode MatDestroySeqNonzeroStructure(Mat *mat)
7431 {
7432   PetscFunctionBegin;
7433   PetscAssertPointer(mat, 1);
7434   PetscCall(MatDestroy(mat));
7435   PetscFunctionReturn(PETSC_SUCCESS);
7436 }
7437 
7438 /*@
7439   MatIncreaseOverlap - Given a set of submatrices indicated by index sets,
7440   replaces the index sets by larger ones that represent submatrices with
7441   additional overlap.
7442 
7443   Collective
7444 
7445   Input Parameters:
7446 + mat - the matrix
7447 . n   - the number of index sets
7448 . is  - the array of index sets (these index sets will changed during the call)
7449 - ov  - the additional overlap requested
7450 
7451   Options Database Key:
7452 . -mat_increase_overlap_scalable - use a scalable algorithm to compute the overlap (supported by MPIAIJ matrix)
7453 
7454   Level: developer
7455 
7456   Note:
7457   The computed overlap preserves the matrix block sizes when the blocks are square.
7458   That is: if a matrix nonzero for a given block would increase the overlap all columns associated with
7459   that block are included in the overlap regardless of whether each specific column would increase the overlap.
7460 
7461 .seealso: [](ch_matrices), `Mat`, `PCASM`, `MatSetBlockSize()`, `MatIncreaseOverlapSplit()`, `MatCreateSubMatrices()`
7462 @*/
7463 PetscErrorCode MatIncreaseOverlap(Mat mat, PetscInt n, IS is[], PetscInt ov)
7464 {
7465   PetscInt i, bs, cbs;
7466 
7467   PetscFunctionBegin;
7468   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7469   PetscValidType(mat, 1);
7470   PetscValidLogicalCollectiveInt(mat, n, 2);
7471   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have one or more domains, you have %" PetscInt_FMT, n);
7472   if (n) {
7473     PetscAssertPointer(is, 3);
7474     for (i = 0; i < n; i++) PetscValidHeaderSpecific(is[i], IS_CLASSID, 3);
7475   }
7476   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7477   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7478   MatCheckPreallocated(mat, 1);
7479 
7480   if (!ov || !n) PetscFunctionReturn(PETSC_SUCCESS);
7481   PetscCall(PetscLogEventBegin(MAT_IncreaseOverlap, mat, 0, 0, 0));
7482   PetscUseTypeMethod(mat, increaseoverlap, n, is, ov);
7483   PetscCall(PetscLogEventEnd(MAT_IncreaseOverlap, mat, 0, 0, 0));
7484   PetscCall(MatGetBlockSizes(mat, &bs, &cbs));
7485   if (bs == cbs) {
7486     for (i = 0; i < n; i++) PetscCall(ISSetBlockSize(is[i], bs));
7487   }
7488   PetscFunctionReturn(PETSC_SUCCESS);
7489 }
7490 
7491 PetscErrorCode MatIncreaseOverlapSplit_Single(Mat, IS *, PetscInt);
7492 
7493 /*@
7494   MatIncreaseOverlapSplit - Given a set of submatrices indicated by index sets across
7495   a sub communicator, replaces the index sets by larger ones that represent submatrices with
7496   additional overlap.
7497 
7498   Collective
7499 
7500   Input Parameters:
7501 + mat - the matrix
7502 . n   - the number of index sets
7503 . is  - the array of index sets (these index sets will changed during the call)
7504 - ov  - the additional overlap requested
7505 
7506   `   Options Database Key:
7507 . -mat_increase_overlap_scalable - use a scalable algorithm to compute the overlap (supported by MPIAIJ matrix)
7508 
7509   Level: developer
7510 
7511 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatIncreaseOverlap()`
7512 @*/
7513 PetscErrorCode MatIncreaseOverlapSplit(Mat mat, PetscInt n, IS is[], PetscInt ov)
7514 {
7515   PetscInt i;
7516 
7517   PetscFunctionBegin;
7518   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7519   PetscValidType(mat, 1);
7520   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have one or more domains, you have %" PetscInt_FMT, n);
7521   if (n) {
7522     PetscAssertPointer(is, 3);
7523     PetscValidHeaderSpecific(*is, IS_CLASSID, 3);
7524   }
7525   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7526   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7527   MatCheckPreallocated(mat, 1);
7528   if (!ov) PetscFunctionReturn(PETSC_SUCCESS);
7529   PetscCall(PetscLogEventBegin(MAT_IncreaseOverlap, mat, 0, 0, 0));
7530   for (i = 0; i < n; i++) PetscCall(MatIncreaseOverlapSplit_Single(mat, &is[i], ov));
7531   PetscCall(PetscLogEventEnd(MAT_IncreaseOverlap, mat, 0, 0, 0));
7532   PetscFunctionReturn(PETSC_SUCCESS);
7533 }
7534 
7535 /*@
7536   MatGetBlockSize - Returns the matrix block size.
7537 
7538   Not Collective
7539 
7540   Input Parameter:
7541 . mat - the matrix
7542 
7543   Output Parameter:
7544 . bs - block size
7545 
7546   Level: intermediate
7547 
7548   Notes:
7549   Block row formats are `MATBAIJ` and `MATSBAIJ` ALWAYS have square block storage in the matrix.
7550 
7551   If the block size has not been set yet this routine returns 1.
7552 
7553 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSizes()`
7554 @*/
7555 PetscErrorCode MatGetBlockSize(Mat mat, PetscInt *bs)
7556 {
7557   PetscFunctionBegin;
7558   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7559   PetscAssertPointer(bs, 2);
7560   *bs = mat->rmap->bs;
7561   PetscFunctionReturn(PETSC_SUCCESS);
7562 }
7563 
7564 /*@
7565   MatGetBlockSizes - Returns the matrix block row and column sizes.
7566 
7567   Not Collective
7568 
7569   Input Parameter:
7570 . mat - the matrix
7571 
7572   Output Parameters:
7573 + rbs - row block size
7574 - cbs - column block size
7575 
7576   Level: intermediate
7577 
7578   Notes:
7579   Block row formats are `MATBAIJ` and `MATSBAIJ` ALWAYS have square block storage in the matrix.
7580   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
7581 
7582   If a block size has not been set yet this routine returns 1.
7583 
7584 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatSetBlockSizes()`
7585 @*/
7586 PetscErrorCode MatGetBlockSizes(Mat mat, PetscInt *rbs, PetscInt *cbs)
7587 {
7588   PetscFunctionBegin;
7589   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7590   if (rbs) PetscAssertPointer(rbs, 2);
7591   if (cbs) PetscAssertPointer(cbs, 3);
7592   if (rbs) *rbs = mat->rmap->bs;
7593   if (cbs) *cbs = mat->cmap->bs;
7594   PetscFunctionReturn(PETSC_SUCCESS);
7595 }
7596 
7597 /*@
7598   MatSetBlockSize - Sets the matrix block size.
7599 
7600   Logically Collective
7601 
7602   Input Parameters:
7603 + mat - the matrix
7604 - bs  - block size
7605 
7606   Level: intermediate
7607 
7608   Notes:
7609   Block row formats are `MATBAIJ` and `MATSBAIJ` formats ALWAYS have square block storage in the matrix.
7610   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
7611 
7612   For `MATAIJ` matrix format, this function can be called at a later stage, provided that the specified block size
7613   is compatible with the matrix local sizes.
7614 
7615 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MATAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`
7616 @*/
7617 PetscErrorCode MatSetBlockSize(Mat mat, PetscInt bs)
7618 {
7619   PetscFunctionBegin;
7620   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7621   PetscValidLogicalCollectiveInt(mat, bs, 2);
7622   PetscCall(MatSetBlockSizes(mat, bs, bs));
7623   PetscFunctionReturn(PETSC_SUCCESS);
7624 }
7625 
7626 typedef struct {
7627   PetscInt         n;
7628   IS              *is;
7629   Mat             *mat;
7630   PetscObjectState nonzerostate;
7631   Mat              C;
7632 } EnvelopeData;
7633 
7634 static PetscErrorCode EnvelopeDataDestroy(void **ptr)
7635 {
7636   EnvelopeData *edata = (EnvelopeData *)*ptr;
7637 
7638   PetscFunctionBegin;
7639   for (PetscInt i = 0; i < edata->n; i++) PetscCall(ISDestroy(&edata->is[i]));
7640   PetscCall(PetscFree(edata->is));
7641   PetscCall(PetscFree(edata));
7642   PetscFunctionReturn(PETSC_SUCCESS);
7643 }
7644 
7645 /*@
7646   MatComputeVariableBlockEnvelope - Given a matrix whose nonzeros are in blocks along the diagonal this computes and stores
7647   the sizes of these blocks in the matrix. An individual block may lie over several processes.
7648 
7649   Collective
7650 
7651   Input Parameter:
7652 . mat - the matrix
7653 
7654   Level: intermediate
7655 
7656   Notes:
7657   There can be zeros within the blocks
7658 
7659   The blocks can overlap between processes, including laying on more than two processes
7660 
7661 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatSetVariableBlockSizes()`
7662 @*/
7663 PetscErrorCode MatComputeVariableBlockEnvelope(Mat mat)
7664 {
7665   PetscInt           n, *sizes, *starts, i = 0, env = 0, tbs = 0, lblocks = 0, rstart, II, ln = 0, cnt = 0, cstart, cend;
7666   PetscInt          *diag, *odiag, sc;
7667   VecScatter         scatter;
7668   PetscScalar       *seqv;
7669   const PetscScalar *parv;
7670   const PetscInt    *ia, *ja;
7671   PetscBool          set, flag, done;
7672   Mat                AA = mat, A;
7673   MPI_Comm           comm;
7674   PetscMPIInt        rank, size, tag;
7675   MPI_Status         status;
7676   PetscContainer     container;
7677   EnvelopeData      *edata;
7678   Vec                seq, par;
7679   IS                 isglobal;
7680 
7681   PetscFunctionBegin;
7682   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7683   PetscCall(MatIsSymmetricKnown(mat, &set, &flag));
7684   if (!set || !flag) {
7685     /* TODO: only needs nonzero structure of transpose */
7686     PetscCall(MatTranspose(mat, MAT_INITIAL_MATRIX, &AA));
7687     PetscCall(MatAXPY(AA, 1.0, mat, DIFFERENT_NONZERO_PATTERN));
7688   }
7689   PetscCall(MatAIJGetLocalMat(AA, &A));
7690   PetscCall(MatGetRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ia, &ja, &done));
7691   PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Unable to get IJ structure from matrix");
7692 
7693   PetscCall(MatGetLocalSize(mat, &n, NULL));
7694   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag));
7695   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
7696   PetscCallMPI(MPI_Comm_size(comm, &size));
7697   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7698 
7699   PetscCall(PetscMalloc2(n, &sizes, n, &starts));
7700 
7701   if (rank > 0) {
7702     PetscCallMPI(MPI_Recv(&env, 1, MPIU_INT, rank - 1, tag, comm, &status));
7703     PetscCallMPI(MPI_Recv(&tbs, 1, MPIU_INT, rank - 1, tag, comm, &status));
7704   }
7705   PetscCall(MatGetOwnershipRange(mat, &rstart, NULL));
7706   for (i = 0; i < n; i++) {
7707     env = PetscMax(env, ja[ia[i + 1] - 1]);
7708     II  = rstart + i;
7709     if (env == II) {
7710       starts[lblocks]  = tbs;
7711       sizes[lblocks++] = 1 + II - tbs;
7712       tbs              = 1 + II;
7713     }
7714   }
7715   if (rank < size - 1) {
7716     PetscCallMPI(MPI_Send(&env, 1, MPIU_INT, rank + 1, tag, comm));
7717     PetscCallMPI(MPI_Send(&tbs, 1, MPIU_INT, rank + 1, tag, comm));
7718   }
7719 
7720   PetscCall(MatRestoreRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ia, &ja, &done));
7721   if (!set || !flag) PetscCall(MatDestroy(&AA));
7722   PetscCall(MatDestroy(&A));
7723 
7724   PetscCall(PetscNew(&edata));
7725   PetscCall(MatGetNonzeroState(mat, &edata->nonzerostate));
7726   edata->n = lblocks;
7727   /* create IS needed for extracting blocks from the original matrix */
7728   PetscCall(PetscMalloc1(lblocks, &edata->is));
7729   for (PetscInt i = 0; i < lblocks; i++) PetscCall(ISCreateStride(PETSC_COMM_SELF, sizes[i], starts[i], 1, &edata->is[i]));
7730 
7731   /* Create the resulting inverse matrix nonzero structure with preallocation information */
7732   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &edata->C));
7733   PetscCall(MatSetSizes(edata->C, mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N));
7734   PetscCall(MatSetBlockSizesFromMats(edata->C, mat, mat));
7735   PetscCall(MatSetType(edata->C, MATAIJ));
7736 
7737   /* Communicate the start and end of each row, from each block to the correct rank */
7738   /* TODO: Use PetscSF instead of VecScatter */
7739   for (PetscInt i = 0; i < lblocks; i++) ln += sizes[i];
7740   PetscCall(VecCreateSeq(PETSC_COMM_SELF, 2 * ln, &seq));
7741   PetscCall(VecGetArrayWrite(seq, &seqv));
7742   for (PetscInt i = 0; i < lblocks; i++) {
7743     for (PetscInt j = 0; j < sizes[i]; j++) {
7744       seqv[cnt]     = starts[i];
7745       seqv[cnt + 1] = starts[i] + sizes[i];
7746       cnt += 2;
7747     }
7748   }
7749   PetscCall(VecRestoreArrayWrite(seq, &seqv));
7750   PetscCallMPI(MPI_Scan(&cnt, &sc, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
7751   sc -= cnt;
7752   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)mat), 2 * mat->rmap->n, 2 * mat->rmap->N, &par));
7753   PetscCall(ISCreateStride(PETSC_COMM_SELF, cnt, sc, 1, &isglobal));
7754   PetscCall(VecScatterCreate(seq, NULL, par, isglobal, &scatter));
7755   PetscCall(ISDestroy(&isglobal));
7756   PetscCall(VecScatterBegin(scatter, seq, par, INSERT_VALUES, SCATTER_FORWARD));
7757   PetscCall(VecScatterEnd(scatter, seq, par, INSERT_VALUES, SCATTER_FORWARD));
7758   PetscCall(VecScatterDestroy(&scatter));
7759   PetscCall(VecDestroy(&seq));
7760   PetscCall(MatGetOwnershipRangeColumn(mat, &cstart, &cend));
7761   PetscCall(PetscMalloc2(mat->rmap->n, &diag, mat->rmap->n, &odiag));
7762   PetscCall(VecGetArrayRead(par, &parv));
7763   cnt = 0;
7764   PetscCall(MatGetSize(mat, NULL, &n));
7765   for (PetscInt i = 0; i < mat->rmap->n; i++) {
7766     PetscInt start, end, d = 0, od = 0;
7767 
7768     start = (PetscInt)PetscRealPart(parv[cnt]);
7769     end   = (PetscInt)PetscRealPart(parv[cnt + 1]);
7770     cnt += 2;
7771 
7772     if (start < cstart) {
7773       od += cstart - start + n - cend;
7774       d += cend - cstart;
7775     } else if (start < cend) {
7776       od += n - cend;
7777       d += cend - start;
7778     } else od += n - start;
7779     if (end <= cstart) {
7780       od -= cstart - end + n - cend;
7781       d -= cend - cstart;
7782     } else if (end < cend) {
7783       od -= n - cend;
7784       d -= cend - end;
7785     } else od -= n - end;
7786 
7787     odiag[i] = od;
7788     diag[i]  = d;
7789   }
7790   PetscCall(VecRestoreArrayRead(par, &parv));
7791   PetscCall(VecDestroy(&par));
7792   PetscCall(MatXAIJSetPreallocation(edata->C, mat->rmap->bs, diag, odiag, NULL, NULL));
7793   PetscCall(PetscFree2(diag, odiag));
7794   PetscCall(PetscFree2(sizes, starts));
7795 
7796   PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container));
7797   PetscCall(PetscContainerSetPointer(container, edata));
7798   PetscCall(PetscContainerSetCtxDestroy(container, EnvelopeDataDestroy));
7799   PetscCall(PetscObjectCompose((PetscObject)mat, "EnvelopeData", (PetscObject)container));
7800   PetscCall(PetscObjectDereference((PetscObject)container));
7801   PetscFunctionReturn(PETSC_SUCCESS);
7802 }
7803 
7804 /*@
7805   MatInvertVariableBlockEnvelope - set matrix C to be the inverted block diagonal of matrix A
7806 
7807   Collective
7808 
7809   Input Parameters:
7810 + A     - the matrix
7811 - reuse - indicates if the `C` matrix was obtained from a previous call to this routine
7812 
7813   Output Parameter:
7814 . C - matrix with inverted block diagonal of `A`
7815 
7816   Level: advanced
7817 
7818   Note:
7819   For efficiency the matrix `A` should have all the nonzero entries clustered in smallish blocks along the diagonal.
7820 
7821 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatComputeBlockDiagonal()`
7822 @*/
7823 PetscErrorCode MatInvertVariableBlockEnvelope(Mat A, MatReuse reuse, Mat *C)
7824 {
7825   PetscContainer   container;
7826   EnvelopeData    *edata;
7827   PetscObjectState nonzerostate;
7828 
7829   PetscFunctionBegin;
7830   PetscCall(PetscObjectQuery((PetscObject)A, "EnvelopeData", (PetscObject *)&container));
7831   if (!container) {
7832     PetscCall(MatComputeVariableBlockEnvelope(A));
7833     PetscCall(PetscObjectQuery((PetscObject)A, "EnvelopeData", (PetscObject *)&container));
7834   }
7835   PetscCall(PetscContainerGetPointer(container, (void **)&edata));
7836   PetscCall(MatGetNonzeroState(A, &nonzerostate));
7837   PetscCheck(nonzerostate <= edata->nonzerostate, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot handle changes to matrix nonzero structure");
7838   PetscCheck(reuse != MAT_REUSE_MATRIX || *C == edata->C, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "C matrix must be the same as previously output");
7839 
7840   PetscCall(MatCreateSubMatrices(A, edata->n, edata->is, edata->is, MAT_INITIAL_MATRIX, &edata->mat));
7841   *C = edata->C;
7842 
7843   for (PetscInt i = 0; i < edata->n; i++) {
7844     Mat          D;
7845     PetscScalar *dvalues;
7846 
7847     PetscCall(MatConvert(edata->mat[i], MATSEQDENSE, MAT_INITIAL_MATRIX, &D));
7848     PetscCall(MatSetOption(*C, MAT_ROW_ORIENTED, PETSC_FALSE));
7849     PetscCall(MatSeqDenseInvert(D));
7850     PetscCall(MatDenseGetArray(D, &dvalues));
7851     PetscCall(MatSetValuesIS(*C, edata->is[i], edata->is[i], dvalues, INSERT_VALUES));
7852     PetscCall(MatDestroy(&D));
7853   }
7854   PetscCall(MatDestroySubMatrices(edata->n, &edata->mat));
7855   PetscCall(MatAssemblyBegin(*C, MAT_FINAL_ASSEMBLY));
7856   PetscCall(MatAssemblyEnd(*C, MAT_FINAL_ASSEMBLY));
7857   PetscFunctionReturn(PETSC_SUCCESS);
7858 }
7859 
7860 /*@
7861   MatSetVariableBlockSizes - Sets diagonal point-blocks of the matrix that need not be of the same size
7862 
7863   Not Collective
7864 
7865   Input Parameters:
7866 + mat     - the matrix
7867 . nblocks - the number of blocks on this process, each block can only exist on a single process
7868 - bsizes  - the block sizes
7869 
7870   Level: intermediate
7871 
7872   Notes:
7873   Currently used by `PCVPBJACOBI` for `MATAIJ` matrices
7874 
7875   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.
7876 
7877 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`, `MatGetVariableBlockSizes()`,
7878           `MatComputeVariableBlockEnvelope()`, `PCVPBJACOBI`
7879 @*/
7880 PetscErrorCode MatSetVariableBlockSizes(Mat mat, PetscInt nblocks, const PetscInt bsizes[])
7881 {
7882   PetscInt ncnt = 0, nlocal;
7883 
7884   PetscFunctionBegin;
7885   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7886   PetscCall(MatGetLocalSize(mat, &nlocal, NULL));
7887   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);
7888   for (PetscInt i = 0; i < nblocks; i++) ncnt += bsizes[i];
7889   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);
7890   PetscCall(PetscFree(mat->bsizes));
7891   mat->nblocks = nblocks;
7892   PetscCall(PetscMalloc1(nblocks, &mat->bsizes));
7893   PetscCall(PetscArraycpy(mat->bsizes, bsizes, nblocks));
7894   PetscFunctionReturn(PETSC_SUCCESS);
7895 }
7896 
7897 /*@C
7898   MatGetVariableBlockSizes - Gets a diagonal blocks of the matrix that need not be of the same size
7899 
7900   Not Collective; No Fortran Support
7901 
7902   Input Parameter:
7903 . mat - the matrix
7904 
7905   Output Parameters:
7906 + nblocks - the number of blocks on this process
7907 - bsizes  - the block sizes
7908 
7909   Level: intermediate
7910 
7911 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`, `MatSetVariableBlockSizes()`, `MatComputeVariableBlockEnvelope()`
7912 @*/
7913 PetscErrorCode MatGetVariableBlockSizes(Mat mat, PetscInt *nblocks, const PetscInt *bsizes[])
7914 {
7915   PetscFunctionBegin;
7916   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7917   if (nblocks) *nblocks = mat->nblocks;
7918   if (bsizes) *bsizes = mat->bsizes;
7919   PetscFunctionReturn(PETSC_SUCCESS);
7920 }
7921 
7922 /*@
7923   MatSetBlockSizes - Sets the matrix block row and column sizes.
7924 
7925   Logically Collective
7926 
7927   Input Parameters:
7928 + mat - the matrix
7929 . rbs - row block size
7930 - cbs - column block size
7931 
7932   Level: intermediate
7933 
7934   Notes:
7935   Block row formats are `MATBAIJ` and  `MATSBAIJ`. These formats ALWAYS have square block storage in the matrix.
7936   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
7937   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
7938 
7939   For `MATAIJ` matrix this function can be called at a later stage, provided that the specified block sizes
7940   are compatible with the matrix local sizes.
7941 
7942   The row and column block size determine the blocksize of the "row" and "column" vectors returned by `MatCreateVecs()`.
7943 
7944 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatGetBlockSizes()`
7945 @*/
7946 PetscErrorCode MatSetBlockSizes(Mat mat, PetscInt rbs, PetscInt cbs)
7947 {
7948   PetscFunctionBegin;
7949   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7950   PetscValidLogicalCollectiveInt(mat, rbs, 2);
7951   PetscValidLogicalCollectiveInt(mat, cbs, 3);
7952   PetscTryTypeMethod(mat, setblocksizes, rbs, cbs);
7953   if (mat->rmap->refcnt) {
7954     ISLocalToGlobalMapping l2g  = NULL;
7955     PetscLayout            nmap = NULL;
7956 
7957     PetscCall(PetscLayoutDuplicate(mat->rmap, &nmap));
7958     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->rmap->mapping, &l2g));
7959     PetscCall(PetscLayoutDestroy(&mat->rmap));
7960     mat->rmap          = nmap;
7961     mat->rmap->mapping = l2g;
7962   }
7963   if (mat->cmap->refcnt) {
7964     ISLocalToGlobalMapping l2g  = NULL;
7965     PetscLayout            nmap = NULL;
7966 
7967     PetscCall(PetscLayoutDuplicate(mat->cmap, &nmap));
7968     if (mat->cmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->cmap->mapping, &l2g));
7969     PetscCall(PetscLayoutDestroy(&mat->cmap));
7970     mat->cmap          = nmap;
7971     mat->cmap->mapping = l2g;
7972   }
7973   PetscCall(PetscLayoutSetBlockSize(mat->rmap, rbs));
7974   PetscCall(PetscLayoutSetBlockSize(mat->cmap, cbs));
7975   PetscFunctionReturn(PETSC_SUCCESS);
7976 }
7977 
7978 /*@
7979   MatSetBlockSizesFromMats - Sets the matrix block row and column sizes to match a pair of matrices
7980 
7981   Logically Collective
7982 
7983   Input Parameters:
7984 + mat     - the matrix
7985 . fromRow - matrix from which to copy row block size
7986 - fromCol - matrix from which to copy column block size (can be same as fromRow)
7987 
7988   Level: developer
7989 
7990 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`
7991 @*/
7992 PetscErrorCode MatSetBlockSizesFromMats(Mat mat, Mat fromRow, Mat fromCol)
7993 {
7994   PetscFunctionBegin;
7995   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7996   PetscValidHeaderSpecific(fromRow, MAT_CLASSID, 2);
7997   PetscValidHeaderSpecific(fromCol, MAT_CLASSID, 3);
7998   PetscCall(PetscLayoutSetBlockSize(mat->rmap, fromRow->rmap->bs));
7999   PetscCall(PetscLayoutSetBlockSize(mat->cmap, fromCol->cmap->bs));
8000   PetscFunctionReturn(PETSC_SUCCESS);
8001 }
8002 
8003 /*@
8004   MatResidual - Default routine to calculate the residual r = b - Ax
8005 
8006   Collective
8007 
8008   Input Parameters:
8009 + mat - the matrix
8010 . b   - the right-hand-side
8011 - x   - the approximate solution
8012 
8013   Output Parameter:
8014 . r - location to store the residual
8015 
8016   Level: developer
8017 
8018 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `PCMGSetResidual()`
8019 @*/
8020 PetscErrorCode MatResidual(Mat mat, Vec b, Vec x, Vec r)
8021 {
8022   PetscFunctionBegin;
8023   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8024   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
8025   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
8026   PetscValidHeaderSpecific(r, VEC_CLASSID, 4);
8027   PetscValidType(mat, 1);
8028   MatCheckPreallocated(mat, 1);
8029   PetscCall(PetscLogEventBegin(MAT_Residual, mat, 0, 0, 0));
8030   if (!mat->ops->residual) {
8031     PetscCall(MatMult(mat, x, r));
8032     PetscCall(VecAYPX(r, -1.0, b));
8033   } else {
8034     PetscUseTypeMethod(mat, residual, b, x, r);
8035   }
8036   PetscCall(PetscLogEventEnd(MAT_Residual, mat, 0, 0, 0));
8037   PetscFunctionReturn(PETSC_SUCCESS);
8038 }
8039 
8040 /*@C
8041   MatGetRowIJ - Returns the compressed row storage i and j indices for the local rows of a sparse matrix
8042 
8043   Collective
8044 
8045   Input Parameters:
8046 + mat             - the matrix
8047 . shift           - 0 or 1 indicating we want the indices starting at 0 or 1
8048 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8049 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE`  indicating if the nonzero structure of the
8050                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8051                  always used.
8052 
8053   Output Parameters:
8054 + n    - number of local rows in the (possibly compressed) matrix, use `NULL` if not needed
8055 . 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
8056 . ja   - the column indices, use `NULL` if not needed
8057 - done - indicates if the routine actually worked and returned appropriate ia[] and ja[] arrays; callers
8058            are responsible for handling the case when done == `PETSC_FALSE` and ia and ja are not set
8059 
8060   Level: developer
8061 
8062   Notes:
8063   You CANNOT change any of the ia[] or ja[] values.
8064 
8065   Use `MatRestoreRowIJ()` when you are finished accessing the ia[] and ja[] values.
8066 
8067   Fortran Notes:
8068   Use
8069 .vb
8070     PetscInt, pointer :: ia(:),ja(:)
8071     call MatGetRowIJ(mat,shift,symmetric,inodecompressed,n,ia,ja,done,ierr)
8072     ! Access the ith and jth entries via ia(i) and ja(j)
8073 .ve
8074 
8075 .seealso: [](ch_matrices), `Mat`, `MATAIJ`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`, `MatSeqAIJGetArray()`
8076 @*/
8077 PetscErrorCode MatGetRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8078 {
8079   PetscFunctionBegin;
8080   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8081   PetscValidType(mat, 1);
8082   if (n) PetscAssertPointer(n, 5);
8083   if (ia) PetscAssertPointer(ia, 6);
8084   if (ja) PetscAssertPointer(ja, 7);
8085   if (done) PetscAssertPointer(done, 8);
8086   MatCheckPreallocated(mat, 1);
8087   if (!mat->ops->getrowij && done) *done = PETSC_FALSE;
8088   else {
8089     if (done) *done = PETSC_TRUE;
8090     PetscCall(PetscLogEventBegin(MAT_GetRowIJ, mat, 0, 0, 0));
8091     PetscUseTypeMethod(mat, getrowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8092     PetscCall(PetscLogEventEnd(MAT_GetRowIJ, mat, 0, 0, 0));
8093   }
8094   PetscFunctionReturn(PETSC_SUCCESS);
8095 }
8096 
8097 /*@C
8098   MatGetColumnIJ - Returns the compressed column storage i and j indices for sequential matrices.
8099 
8100   Collective
8101 
8102   Input Parameters:
8103 + mat             - the matrix
8104 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8105 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be
8106                 symmetrized
8107 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8108                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8109                  always used.
8110 . n               - number of columns in the (possibly compressed) matrix
8111 . ia              - the column pointers; that is ia[0] = 0, ia[col] = i[col-1] + number of elements in that col of the matrix
8112 - ja              - the row indices
8113 
8114   Output Parameter:
8115 . done - `PETSC_TRUE` or `PETSC_FALSE`, indicating whether the values have been returned
8116 
8117   Level: developer
8118 
8119 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8120 @*/
8121 PetscErrorCode MatGetColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8122 {
8123   PetscFunctionBegin;
8124   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8125   PetscValidType(mat, 1);
8126   PetscAssertPointer(n, 5);
8127   if (ia) PetscAssertPointer(ia, 6);
8128   if (ja) PetscAssertPointer(ja, 7);
8129   PetscAssertPointer(done, 8);
8130   MatCheckPreallocated(mat, 1);
8131   if (!mat->ops->getcolumnij) *done = PETSC_FALSE;
8132   else {
8133     *done = PETSC_TRUE;
8134     PetscUseTypeMethod(mat, getcolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8135   }
8136   PetscFunctionReturn(PETSC_SUCCESS);
8137 }
8138 
8139 /*@C
8140   MatRestoreRowIJ - Call after you are completed with the ia,ja indices obtained with `MatGetRowIJ()`.
8141 
8142   Collective
8143 
8144   Input Parameters:
8145 + mat             - the matrix
8146 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8147 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8148 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8149                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8150                     always used.
8151 . n               - size of (possibly compressed) matrix
8152 . ia              - the row pointers
8153 - ja              - the column indices
8154 
8155   Output Parameter:
8156 . done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8157 
8158   Level: developer
8159 
8160   Note:
8161   This routine zeros out `n`, `ia`, and `ja`. This is to prevent accidental
8162   us of the array after it has been restored. If you pass `NULL`, it will
8163   not zero the pointers.  Use of ia or ja after `MatRestoreRowIJ()` is invalid.
8164 
8165 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8166 @*/
8167 PetscErrorCode MatRestoreRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8168 {
8169   PetscFunctionBegin;
8170   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8171   PetscValidType(mat, 1);
8172   if (ia) PetscAssertPointer(ia, 6);
8173   if (ja) PetscAssertPointer(ja, 7);
8174   if (done) PetscAssertPointer(done, 8);
8175   MatCheckPreallocated(mat, 1);
8176 
8177   if (!mat->ops->restorerowij && done) *done = PETSC_FALSE;
8178   else {
8179     if (done) *done = PETSC_TRUE;
8180     PetscUseTypeMethod(mat, restorerowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8181     if (n) *n = 0;
8182     if (ia) *ia = NULL;
8183     if (ja) *ja = NULL;
8184   }
8185   PetscFunctionReturn(PETSC_SUCCESS);
8186 }
8187 
8188 /*@C
8189   MatRestoreColumnIJ - Call after you are completed with the ia,ja indices obtained with `MatGetColumnIJ()`.
8190 
8191   Collective
8192 
8193   Input Parameters:
8194 + mat             - the matrix
8195 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8196 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8197 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8198                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8199                     always used.
8200 
8201   Output Parameters:
8202 + n    - size of (possibly compressed) matrix
8203 . ia   - the column pointers
8204 . ja   - the row indices
8205 - done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8206 
8207   Level: developer
8208 
8209 .seealso: [](ch_matrices), `Mat`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`
8210 @*/
8211 PetscErrorCode MatRestoreColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8212 {
8213   PetscFunctionBegin;
8214   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8215   PetscValidType(mat, 1);
8216   if (ia) PetscAssertPointer(ia, 6);
8217   if (ja) PetscAssertPointer(ja, 7);
8218   PetscAssertPointer(done, 8);
8219   MatCheckPreallocated(mat, 1);
8220 
8221   if (!mat->ops->restorecolumnij) *done = PETSC_FALSE;
8222   else {
8223     *done = PETSC_TRUE;
8224     PetscUseTypeMethod(mat, restorecolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8225     if (n) *n = 0;
8226     if (ia) *ia = NULL;
8227     if (ja) *ja = NULL;
8228   }
8229   PetscFunctionReturn(PETSC_SUCCESS);
8230 }
8231 
8232 /*@
8233   MatColoringPatch - Used inside matrix coloring routines that use `MatGetRowIJ()` and/or
8234   `MatGetColumnIJ()`.
8235 
8236   Collective
8237 
8238   Input Parameters:
8239 + mat        - the matrix
8240 . ncolors    - maximum color value
8241 . n          - number of entries in colorarray
8242 - colorarray - array indicating color for each column
8243 
8244   Output Parameter:
8245 . iscoloring - coloring generated using colorarray information
8246 
8247   Level: developer
8248 
8249 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatGetColumnIJ()`
8250 @*/
8251 PetscErrorCode MatColoringPatch(Mat mat, PetscInt ncolors, PetscInt n, ISColoringValue colorarray[], ISColoring *iscoloring)
8252 {
8253   PetscFunctionBegin;
8254   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8255   PetscValidType(mat, 1);
8256   PetscAssertPointer(colorarray, 4);
8257   PetscAssertPointer(iscoloring, 5);
8258   MatCheckPreallocated(mat, 1);
8259 
8260   if (!mat->ops->coloringpatch) {
8261     PetscCall(ISColoringCreate(PetscObjectComm((PetscObject)mat), ncolors, n, colorarray, PETSC_OWN_POINTER, iscoloring));
8262   } else {
8263     PetscUseTypeMethod(mat, coloringpatch, ncolors, n, colorarray, iscoloring);
8264   }
8265   PetscFunctionReturn(PETSC_SUCCESS);
8266 }
8267 
8268 /*@
8269   MatSetUnfactored - Resets a factored matrix to be treated as unfactored.
8270 
8271   Logically Collective
8272 
8273   Input Parameter:
8274 . mat - the factored matrix to be reset
8275 
8276   Level: developer
8277 
8278   Notes:
8279   This routine should be used only with factored matrices formed by in-place
8280   factorization via ILU(0) (or by in-place LU factorization for the `MATSEQDENSE`
8281   format).  This option can save memory, for example, when solving nonlinear
8282   systems with a matrix-free Newton-Krylov method and a matrix-based, in-place
8283   ILU(0) preconditioner.
8284 
8285   One can specify in-place ILU(0) factorization by calling
8286 .vb
8287      PCType(pc,PCILU);
8288      PCFactorSeUseInPlace(pc);
8289 .ve
8290   or by using the options -pc_type ilu -pc_factor_in_place
8291 
8292   In-place factorization ILU(0) can also be used as a local
8293   solver for the blocks within the block Jacobi or additive Schwarz
8294   methods (runtime option: -sub_pc_factor_in_place).  See Users-Manual: ch_pc
8295   for details on setting local solver options.
8296 
8297   Most users should employ the `KSP` interface for linear solvers
8298   instead of working directly with matrix algebra routines such as this.
8299   See, e.g., `KSPCreate()`.
8300 
8301 .seealso: [](ch_matrices), `Mat`, `PCFactorSetUseInPlace()`, `PCFactorGetUseInPlace()`
8302 @*/
8303 PetscErrorCode MatSetUnfactored(Mat mat)
8304 {
8305   PetscFunctionBegin;
8306   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8307   PetscValidType(mat, 1);
8308   MatCheckPreallocated(mat, 1);
8309   mat->factortype = MAT_FACTOR_NONE;
8310   if (!mat->ops->setunfactored) PetscFunctionReturn(PETSC_SUCCESS);
8311   PetscUseTypeMethod(mat, setunfactored);
8312   PetscFunctionReturn(PETSC_SUCCESS);
8313 }
8314 
8315 /*@
8316   MatCreateSubMatrix - Gets a single submatrix on the same number of processors
8317   as the original matrix.
8318 
8319   Collective
8320 
8321   Input Parameters:
8322 + mat   - the original matrix
8323 . isrow - parallel `IS` containing the rows this processor should obtain
8324 . 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.
8325 - cll   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
8326 
8327   Output Parameter:
8328 . newmat - the new submatrix, of the same type as the original matrix
8329 
8330   Level: advanced
8331 
8332   Notes:
8333   The submatrix will be able to be multiplied with vectors using the same layout as `iscol`.
8334 
8335   Some matrix types place restrictions on the row and column indices, such
8336   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;
8337   for example, if the block size is 3 one cannot select the 0 and 2 rows without selecting the 1 row.
8338 
8339   The index sets may not have duplicate entries.
8340 
8341   The first time this is called you should use a cll of `MAT_INITIAL_MATRIX`,
8342   the `MatCreateSubMatrix()` routine will create the newmat for you. Any additional calls
8343   to this routine with a mat of the same nonzero structure and with a call of `MAT_REUSE_MATRIX`
8344   will reuse the matrix generated the first time.  You should call `MatDestroy()` on `newmat` when
8345   you are finished using it.
8346 
8347   The communicator of the newly obtained matrix is ALWAYS the same as the communicator of
8348   the input matrix.
8349 
8350   If `iscol` is `NULL` then all columns are obtained (not supported in Fortran).
8351 
8352   If `isrow` and `iscol` have a nontrivial block-size, then the resulting matrix has this block-size as well. This feature
8353   is used by `PCFIELDSPLIT` to allow easy nesting of its use.
8354 
8355   Example usage:
8356   Consider the following 8x8 matrix with 34 non-zero values, that is
8357   assembled across 3 processors. Let's assume that proc0 owns 3 rows,
8358   proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
8359   as follows
8360 .vb
8361             1  2  0  |  0  3  0  |  0  4
8362     Proc0   0  5  6  |  7  0  0  |  8  0
8363             9  0 10  | 11  0  0  | 12  0
8364     -------------------------------------
8365            13  0 14  | 15 16 17  |  0  0
8366     Proc1   0 18  0  | 19 20 21  |  0  0
8367             0  0  0  | 22 23  0  | 24  0
8368     -------------------------------------
8369     Proc2  25 26 27  |  0  0 28  | 29  0
8370            30  0  0  | 31 32 33  |  0 34
8371 .ve
8372 
8373   Suppose `isrow` = [0 1 | 4 | 6 7] and `iscol` = [1 2 | 3 4 5 | 6].  The resulting submatrix is
8374 
8375 .vb
8376             2  0  |  0  3  0  |  0
8377     Proc0   5  6  |  7  0  0  |  8
8378     -------------------------------
8379     Proc1  18  0  | 19 20 21  |  0
8380     -------------------------------
8381     Proc2  26 27  |  0  0 28  | 29
8382             0  0  | 31 32 33  |  0
8383 .ve
8384 
8385 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatCreateSubMatricesMPI()`, `MatCreateSubMatrixVirtual()`, `MatSubMatrixVirtualUpdate()`
8386 @*/
8387 PetscErrorCode MatCreateSubMatrix(Mat mat, IS isrow, IS iscol, MatReuse cll, Mat *newmat)
8388 {
8389   PetscMPIInt size;
8390   Mat        *local;
8391   IS          iscoltmp;
8392   PetscBool   flg;
8393 
8394   PetscFunctionBegin;
8395   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8396   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
8397   if (iscol) PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
8398   PetscAssertPointer(newmat, 5);
8399   if (cll == MAT_REUSE_MATRIX) PetscValidHeaderSpecific(*newmat, MAT_CLASSID, 5);
8400   PetscValidType(mat, 1);
8401   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
8402   PetscCheck(cll != MAT_IGNORE_MATRIX, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot use MAT_IGNORE_MATRIX");
8403 
8404   MatCheckPreallocated(mat, 1);
8405   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
8406 
8407   if (!iscol || isrow == iscol) {
8408     PetscBool   stride;
8409     PetscMPIInt grabentirematrix = 0, grab;
8410     PetscCall(PetscObjectTypeCompare((PetscObject)isrow, ISSTRIDE, &stride));
8411     if (stride) {
8412       PetscInt first, step, n, rstart, rend;
8413       PetscCall(ISStrideGetInfo(isrow, &first, &step));
8414       if (step == 1) {
8415         PetscCall(MatGetOwnershipRange(mat, &rstart, &rend));
8416         if (rstart == first) {
8417           PetscCall(ISGetLocalSize(isrow, &n));
8418           if (n == rend - rstart) grabentirematrix = 1;
8419         }
8420       }
8421     }
8422     PetscCallMPI(MPIU_Allreduce(&grabentirematrix, &grab, 1, MPI_INT, MPI_MIN, PetscObjectComm((PetscObject)mat)));
8423     if (grab) {
8424       PetscCall(PetscInfo(mat, "Getting entire matrix as submatrix\n"));
8425       if (cll == MAT_INITIAL_MATRIX) {
8426         *newmat = mat;
8427         PetscCall(PetscObjectReference((PetscObject)mat));
8428       }
8429       PetscFunctionReturn(PETSC_SUCCESS);
8430     }
8431   }
8432 
8433   if (!iscol) {
8434     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)mat), mat->cmap->n, mat->cmap->rstart, 1, &iscoltmp));
8435   } else {
8436     iscoltmp = iscol;
8437   }
8438 
8439   /* if original matrix is on just one processor then use submatrix generated */
8440   if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1 && cll == MAT_REUSE_MATRIX) {
8441     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_REUSE_MATRIX, &newmat));
8442     goto setproperties;
8443   } else if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1) {
8444     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_INITIAL_MATRIX, &local));
8445     *newmat = *local;
8446     PetscCall(PetscFree(local));
8447     goto setproperties;
8448   } else if (!mat->ops->createsubmatrix) {
8449     /* Create a new matrix type that implements the operation using the full matrix */
8450     PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8451     switch (cll) {
8452     case MAT_INITIAL_MATRIX:
8453       PetscCall(MatCreateSubMatrixVirtual(mat, isrow, iscoltmp, newmat));
8454       break;
8455     case MAT_REUSE_MATRIX:
8456       PetscCall(MatSubMatrixVirtualUpdate(*newmat, mat, isrow, iscoltmp));
8457       break;
8458     default:
8459       SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Invalid MatReuse, must be either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX");
8460     }
8461     PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8462     goto setproperties;
8463   }
8464 
8465   PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8466   PetscUseTypeMethod(mat, createsubmatrix, isrow, iscoltmp, cll, newmat);
8467   PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8468 
8469 setproperties:
8470   if ((*newmat)->symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->structurally_symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->spd == PETSC_BOOL3_UNKNOWN && (*newmat)->hermitian == PETSC_BOOL3_UNKNOWN) {
8471     PetscCall(ISEqualUnsorted(isrow, iscoltmp, &flg));
8472     if (flg) PetscCall(MatPropagateSymmetryOptions(mat, *newmat));
8473   }
8474   if (!iscol) PetscCall(ISDestroy(&iscoltmp));
8475   if (*newmat && cll == MAT_INITIAL_MATRIX) PetscCall(PetscObjectStateIncrease((PetscObject)*newmat));
8476   PetscFunctionReturn(PETSC_SUCCESS);
8477 }
8478 
8479 /*@
8480   MatPropagateSymmetryOptions - Propagates symmetry options set on a matrix to another matrix
8481 
8482   Not Collective
8483 
8484   Input Parameters:
8485 + A - the matrix we wish to propagate options from
8486 - B - the matrix we wish to propagate options to
8487 
8488   Level: beginner
8489 
8490   Note:
8491   Propagates the options associated to `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_HERMITIAN`, `MAT_SPD`, `MAT_SYMMETRIC`, and `MAT_STRUCTURAL_SYMMETRY_ETERNAL`
8492 
8493 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatIsSymmetricKnown()`, `MatIsSPDKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
8494 @*/
8495 PetscErrorCode MatPropagateSymmetryOptions(Mat A, Mat B)
8496 {
8497   PetscFunctionBegin;
8498   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8499   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
8500   B->symmetry_eternal            = A->symmetry_eternal;
8501   B->structural_symmetry_eternal = A->structural_symmetry_eternal;
8502   B->symmetric                   = A->symmetric;
8503   B->structurally_symmetric      = A->structurally_symmetric;
8504   B->spd                         = A->spd;
8505   B->hermitian                   = A->hermitian;
8506   PetscFunctionReturn(PETSC_SUCCESS);
8507 }
8508 
8509 /*@
8510   MatStashSetInitialSize - sets the sizes of the matrix stash, that is
8511   used during the assembly process to store values that belong to
8512   other processors.
8513 
8514   Not Collective
8515 
8516   Input Parameters:
8517 + mat   - the matrix
8518 . size  - the initial size of the stash.
8519 - bsize - the initial size of the block-stash(if used).
8520 
8521   Options Database Keys:
8522 + -matstash_initial_size <size> or <size0,size1,...sizep-1>            - set initial size
8523 - -matstash_block_initial_size <bsize>  or <bsize0,bsize1,...bsizep-1> - set initial block size
8524 
8525   Level: intermediate
8526 
8527   Notes:
8528   The block-stash is used for values set with `MatSetValuesBlocked()` while
8529   the stash is used for values set with `MatSetValues()`
8530 
8531   Run with the option -info and look for output of the form
8532   MatAssemblyBegin_MPIXXX:Stash has MM entries, uses nn mallocs.
8533   to determine the appropriate value, MM, to use for size and
8534   MatAssemblyBegin_MPIXXX:Block-Stash has BMM entries, uses nn mallocs.
8535   to determine the value, BMM to use for bsize
8536 
8537 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashGetInfo()`
8538 @*/
8539 PetscErrorCode MatStashSetInitialSize(Mat mat, PetscInt size, PetscInt bsize)
8540 {
8541   PetscFunctionBegin;
8542   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8543   PetscValidType(mat, 1);
8544   PetscCall(MatStashSetInitialSize_Private(&mat->stash, size));
8545   PetscCall(MatStashSetInitialSize_Private(&mat->bstash, bsize));
8546   PetscFunctionReturn(PETSC_SUCCESS);
8547 }
8548 
8549 /*@
8550   MatInterpolateAdd - $w = y + A*x$ or $A^T*x$ depending on the shape of
8551   the matrix
8552 
8553   Neighbor-wise Collective
8554 
8555   Input Parameters:
8556 + A - the matrix
8557 . x - the vector to be multiplied by the interpolation operator
8558 - y - the vector to be added to the result
8559 
8560   Output Parameter:
8561 . w - the resulting vector
8562 
8563   Level: intermediate
8564 
8565   Notes:
8566   `w` may be the same vector as `y`.
8567 
8568   This allows one to use either the restriction or interpolation (its transpose)
8569   matrix to do the interpolation
8570 
8571 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8572 @*/
8573 PetscErrorCode MatInterpolateAdd(Mat A, Vec x, Vec y, Vec w)
8574 {
8575   PetscInt M, N, Ny;
8576 
8577   PetscFunctionBegin;
8578   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8579   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8580   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8581   PetscValidHeaderSpecific(w, VEC_CLASSID, 4);
8582   PetscCall(MatGetSize(A, &M, &N));
8583   PetscCall(VecGetSize(y, &Ny));
8584   if (M == Ny) {
8585     PetscCall(MatMultAdd(A, x, y, w));
8586   } else {
8587     PetscCall(MatMultTransposeAdd(A, x, y, w));
8588   }
8589   PetscFunctionReturn(PETSC_SUCCESS);
8590 }
8591 
8592 /*@
8593   MatInterpolate - $y = A*x$ or $A^T*x$ depending on the shape of
8594   the matrix
8595 
8596   Neighbor-wise Collective
8597 
8598   Input Parameters:
8599 + A - the matrix
8600 - x - the vector to be interpolated
8601 
8602   Output Parameter:
8603 . y - the resulting vector
8604 
8605   Level: intermediate
8606 
8607   Note:
8608   This allows one to use either the restriction or interpolation (its transpose)
8609   matrix to do the interpolation
8610 
8611 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8612 @*/
8613 PetscErrorCode MatInterpolate(Mat A, Vec x, Vec y)
8614 {
8615   PetscInt M, N, Ny;
8616 
8617   PetscFunctionBegin;
8618   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8619   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8620   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8621   PetscCall(MatGetSize(A, &M, &N));
8622   PetscCall(VecGetSize(y, &Ny));
8623   if (M == Ny) {
8624     PetscCall(MatMult(A, x, y));
8625   } else {
8626     PetscCall(MatMultTranspose(A, x, y));
8627   }
8628   PetscFunctionReturn(PETSC_SUCCESS);
8629 }
8630 
8631 /*@
8632   MatRestrict - $y = A*x$ or $A^T*x$
8633 
8634   Neighbor-wise Collective
8635 
8636   Input Parameters:
8637 + A - the matrix
8638 - x - the vector to be restricted
8639 
8640   Output Parameter:
8641 . y - the resulting vector
8642 
8643   Level: intermediate
8644 
8645   Note:
8646   This allows one to use either the restriction or interpolation (its transpose)
8647   matrix to do the restriction
8648 
8649 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatInterpolate()`, `PCMG`
8650 @*/
8651 PetscErrorCode MatRestrict(Mat A, Vec x, Vec y)
8652 {
8653   PetscInt M, N, Nx;
8654 
8655   PetscFunctionBegin;
8656   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8657   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8658   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8659   PetscCall(MatGetSize(A, &M, &N));
8660   PetscCall(VecGetSize(x, &Nx));
8661   if (M == Nx) {
8662     PetscCall(MatMultTranspose(A, x, y));
8663   } else {
8664     PetscCall(MatMult(A, x, y));
8665   }
8666   PetscFunctionReturn(PETSC_SUCCESS);
8667 }
8668 
8669 /*@
8670   MatMatInterpolateAdd - $Y = W + A*X$ or $W + A^T*X$ depending on the shape of `A`
8671 
8672   Neighbor-wise Collective
8673 
8674   Input Parameters:
8675 + A - the matrix
8676 . x - the input dense matrix to be multiplied
8677 - w - the input dense matrix to be added to the result
8678 
8679   Output Parameter:
8680 . y - the output dense matrix
8681 
8682   Level: intermediate
8683 
8684   Note:
8685   This allows one to use either the restriction or interpolation (its transpose)
8686   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8687   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8688 
8689 .seealso: [](ch_matrices), `Mat`, `MatInterpolateAdd()`, `MatMatInterpolate()`, `MatMatRestrict()`, `PCMG`
8690 @*/
8691 PetscErrorCode MatMatInterpolateAdd(Mat A, Mat x, Mat w, Mat *y)
8692 {
8693   PetscInt  M, N, Mx, Nx, Mo, My = 0, Ny = 0;
8694   PetscBool trans = PETSC_TRUE;
8695   MatReuse  reuse = MAT_INITIAL_MATRIX;
8696 
8697   PetscFunctionBegin;
8698   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8699   PetscValidHeaderSpecific(x, MAT_CLASSID, 2);
8700   PetscValidType(x, 2);
8701   if (w) PetscValidHeaderSpecific(w, MAT_CLASSID, 3);
8702   if (*y) PetscValidHeaderSpecific(*y, MAT_CLASSID, 4);
8703   PetscCall(MatGetSize(A, &M, &N));
8704   PetscCall(MatGetSize(x, &Mx, &Nx));
8705   if (N == Mx) trans = PETSC_FALSE;
8706   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);
8707   Mo = trans ? N : M;
8708   if (*y) {
8709     PetscCall(MatGetSize(*y, &My, &Ny));
8710     if (Mo == My && Nx == Ny) {
8711       reuse = MAT_REUSE_MATRIX;
8712     } else {
8713       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);
8714       PetscCall(MatDestroy(y));
8715     }
8716   }
8717 
8718   if (w && *y == w) { /* this is to minimize changes in PCMG */
8719     PetscBool flg;
8720 
8721     PetscCall(PetscObjectQuery((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject *)&w));
8722     if (w) {
8723       PetscInt My, Ny, Mw, Nw;
8724 
8725       PetscCall(PetscObjectTypeCompare((PetscObject)*y, ((PetscObject)w)->type_name, &flg));
8726       PetscCall(MatGetSize(*y, &My, &Ny));
8727       PetscCall(MatGetSize(w, &Mw, &Nw));
8728       if (!flg || My != Mw || Ny != Nw) w = NULL;
8729     }
8730     if (!w) {
8731       PetscCall(MatDuplicate(*y, MAT_COPY_VALUES, &w));
8732       PetscCall(PetscObjectCompose((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject)w));
8733       PetscCall(PetscObjectDereference((PetscObject)w));
8734     } else {
8735       PetscCall(MatCopy(*y, w, UNKNOWN_NONZERO_PATTERN));
8736     }
8737   }
8738   if (!trans) {
8739     PetscCall(MatMatMult(A, x, reuse, PETSC_DETERMINE, y));
8740   } else {
8741     PetscCall(MatTransposeMatMult(A, x, reuse, PETSC_DETERMINE, y));
8742   }
8743   if (w) PetscCall(MatAXPY(*y, 1.0, w, UNKNOWN_NONZERO_PATTERN));
8744   PetscFunctionReturn(PETSC_SUCCESS);
8745 }
8746 
8747 /*@
8748   MatMatInterpolate - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8749 
8750   Neighbor-wise Collective
8751 
8752   Input Parameters:
8753 + A - the matrix
8754 - x - the input dense matrix
8755 
8756   Output Parameter:
8757 . y - the output dense matrix
8758 
8759   Level: intermediate
8760 
8761   Note:
8762   This allows one to use either the restriction or interpolation (its transpose)
8763   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8764   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8765 
8766 .seealso: [](ch_matrices), `Mat`, `MatInterpolate()`, `MatRestrict()`, `MatMatRestrict()`, `PCMG`
8767 @*/
8768 PetscErrorCode MatMatInterpolate(Mat A, Mat x, Mat *y)
8769 {
8770   PetscFunctionBegin;
8771   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8772   PetscFunctionReturn(PETSC_SUCCESS);
8773 }
8774 
8775 /*@
8776   MatMatRestrict - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8777 
8778   Neighbor-wise Collective
8779 
8780   Input Parameters:
8781 + A - the matrix
8782 - x - the input dense matrix
8783 
8784   Output Parameter:
8785 . y - the output dense matrix
8786 
8787   Level: intermediate
8788 
8789   Note:
8790   This allows one to use either the restriction or interpolation (its transpose)
8791   matrix to do the restriction. `y` matrix can be reused if already created with the proper sizes,
8792   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8793 
8794 .seealso: [](ch_matrices), `Mat`, `MatRestrict()`, `MatInterpolate()`, `MatMatInterpolate()`, `PCMG`
8795 @*/
8796 PetscErrorCode MatMatRestrict(Mat A, Mat x, Mat *y)
8797 {
8798   PetscFunctionBegin;
8799   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8800   PetscFunctionReturn(PETSC_SUCCESS);
8801 }
8802 
8803 /*@
8804   MatGetNullSpace - retrieves the null space of a matrix.
8805 
8806   Logically Collective
8807 
8808   Input Parameters:
8809 + mat    - the matrix
8810 - nullsp - the null space object
8811 
8812   Level: developer
8813 
8814 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetNullSpace()`, `MatNullSpace`
8815 @*/
8816 PetscErrorCode MatGetNullSpace(Mat mat, MatNullSpace *nullsp)
8817 {
8818   PetscFunctionBegin;
8819   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8820   PetscAssertPointer(nullsp, 2);
8821   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->nullsp) ? mat->transnullsp : mat->nullsp;
8822   PetscFunctionReturn(PETSC_SUCCESS);
8823 }
8824 
8825 /*@C
8826   MatGetNullSpaces - gets the null spaces, transpose null spaces, and near null spaces from an array of matrices
8827 
8828   Logically Collective
8829 
8830   Input Parameters:
8831 + n   - the number of matrices
8832 - mat - the array of matrices
8833 
8834   Output Parameters:
8835 . nullsp - an array of null spaces, `NULL` for each matrix that does not have a null space, length 3 * `n`
8836 
8837   Level: developer
8838 
8839   Note:
8840   Call `MatRestoreNullspaces()` to provide these to another array of matrices
8841 
8842 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
8843           `MatNullSpaceRemove()`, `MatRestoreNullSpaces()`
8844 @*/
8845 PetscErrorCode MatGetNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
8846 {
8847   PetscFunctionBegin;
8848   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
8849   PetscAssertPointer(mat, 2);
8850   PetscAssertPointer(nullsp, 3);
8851 
8852   PetscCall(PetscCalloc1(3 * n, nullsp));
8853   for (PetscInt i = 0; i < n; i++) {
8854     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
8855     (*nullsp)[i] = mat[i]->nullsp;
8856     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[i]));
8857     (*nullsp)[n + i] = mat[i]->nearnullsp;
8858     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[n + i]));
8859     (*nullsp)[2 * n + i] = mat[i]->transnullsp;
8860     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[2 * n + i]));
8861   }
8862   PetscFunctionReturn(PETSC_SUCCESS);
8863 }
8864 
8865 /*@C
8866   MatRestoreNullSpaces - sets the null spaces, transpose null spaces, and near null spaces obtained with `MatGetNullSpaces()` for an array of matrices
8867 
8868   Logically Collective
8869 
8870   Input Parameters:
8871 + n      - the number of matrices
8872 . mat    - the array of matrices
8873 - nullsp - an array of null spaces
8874 
8875   Level: developer
8876 
8877   Note:
8878   Call `MatGetNullSpaces()` to create `nullsp`
8879 
8880 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
8881           `MatNullSpaceRemove()`, `MatGetNullSpaces()`
8882 @*/
8883 PetscErrorCode MatRestoreNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
8884 {
8885   PetscFunctionBegin;
8886   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
8887   PetscAssertPointer(mat, 2);
8888   PetscAssertPointer(nullsp, 3);
8889   PetscAssertPointer(*nullsp, 3);
8890 
8891   for (PetscInt i = 0; i < n; i++) {
8892     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
8893     PetscCall(MatSetNullSpace(mat[i], (*nullsp)[i]));
8894     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[i]));
8895     PetscCall(MatSetNearNullSpace(mat[i], (*nullsp)[n + i]));
8896     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[n + i]));
8897     PetscCall(MatSetTransposeNullSpace(mat[i], (*nullsp)[2 * n + i]));
8898     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[2 * n + i]));
8899   }
8900   PetscCall(PetscFree(*nullsp));
8901   PetscFunctionReturn(PETSC_SUCCESS);
8902 }
8903 
8904 /*@
8905   MatSetNullSpace - attaches a null space to a matrix.
8906 
8907   Logically Collective
8908 
8909   Input Parameters:
8910 + mat    - the matrix
8911 - nullsp - the null space object
8912 
8913   Level: advanced
8914 
8915   Notes:
8916   This null space is used by the `KSP` linear solvers to solve singular systems.
8917 
8918   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`
8919 
8920   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
8921   to zero but the linear system will still be solved in a least squares sense.
8922 
8923   The fundamental theorem of linear algebra (Gilbert Strang, Introduction to Applied Mathematics, page 72) states that
8924   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)$.
8925   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
8926   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
8927   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$).
8928   This  \hat{b} can be obtained by calling `MatNullSpaceRemove()` with the null space of the transpose of the matrix.
8929 
8930   If the matrix is known to be symmetric because it is an `MATSBAIJ` matrix or one as called
8931   `MatSetOption`(mat,`MAT_SYMMETRIC` or possibly `MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`); this
8932   routine also automatically calls `MatSetTransposeNullSpace()`.
8933 
8934   The user should call `MatNullSpaceDestroy()`.
8935 
8936 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`,
8937           `KSPSetPCSide()`
8938 @*/
8939 PetscErrorCode MatSetNullSpace(Mat mat, MatNullSpace nullsp)
8940 {
8941   PetscFunctionBegin;
8942   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8943   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
8944   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
8945   PetscCall(MatNullSpaceDestroy(&mat->nullsp));
8946   mat->nullsp = nullsp;
8947   if (mat->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetTransposeNullSpace(mat, nullsp));
8948   PetscFunctionReturn(PETSC_SUCCESS);
8949 }
8950 
8951 /*@
8952   MatGetTransposeNullSpace - retrieves the null space of the transpose of a matrix.
8953 
8954   Logically Collective
8955 
8956   Input Parameters:
8957 + mat    - the matrix
8958 - nullsp - the null space object
8959 
8960   Level: developer
8961 
8962 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetTransposeNullSpace()`, `MatSetNullSpace()`, `MatGetNullSpace()`
8963 @*/
8964 PetscErrorCode MatGetTransposeNullSpace(Mat mat, MatNullSpace *nullsp)
8965 {
8966   PetscFunctionBegin;
8967   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8968   PetscValidType(mat, 1);
8969   PetscAssertPointer(nullsp, 2);
8970   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->transnullsp) ? mat->nullsp : mat->transnullsp;
8971   PetscFunctionReturn(PETSC_SUCCESS);
8972 }
8973 
8974 /*@
8975   MatSetTransposeNullSpace - attaches the null space of a transpose of a matrix to the matrix
8976 
8977   Logically Collective
8978 
8979   Input Parameters:
8980 + mat    - the matrix
8981 - nullsp - the null space object
8982 
8983   Level: advanced
8984 
8985   Notes:
8986   This allows solving singular linear systems defined by the transpose of the matrix using `KSP` solvers with left preconditioning.
8987 
8988   See `MatSetNullSpace()`
8989 
8990 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`, `KSPSetPCSide()`
8991 @*/
8992 PetscErrorCode MatSetTransposeNullSpace(Mat mat, MatNullSpace nullsp)
8993 {
8994   PetscFunctionBegin;
8995   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8996   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
8997   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
8998   PetscCall(MatNullSpaceDestroy(&mat->transnullsp));
8999   mat->transnullsp = nullsp;
9000   PetscFunctionReturn(PETSC_SUCCESS);
9001 }
9002 
9003 /*@
9004   MatSetNearNullSpace - attaches a null space to a matrix, which is often the null space (rigid body modes) of the operator without boundary conditions
9005   This null space will be used to provide near null space vectors to a multigrid preconditioner built from this matrix.
9006 
9007   Logically Collective
9008 
9009   Input Parameters:
9010 + mat    - the matrix
9011 - nullsp - the null space object
9012 
9013   Level: advanced
9014 
9015   Notes:
9016   Overwrites any previous near null space that may have been attached
9017 
9018   You can remove the null space by calling this routine with an `nullsp` of `NULL`
9019 
9020 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNullSpace()`, `MatNullSpaceCreateRigidBody()`, `MatGetNearNullSpace()`
9021 @*/
9022 PetscErrorCode MatSetNearNullSpace(Mat mat, MatNullSpace nullsp)
9023 {
9024   PetscFunctionBegin;
9025   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9026   PetscValidType(mat, 1);
9027   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9028   MatCheckPreallocated(mat, 1);
9029   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9030   PetscCall(MatNullSpaceDestroy(&mat->nearnullsp));
9031   mat->nearnullsp = nullsp;
9032   PetscFunctionReturn(PETSC_SUCCESS);
9033 }
9034 
9035 /*@
9036   MatGetNearNullSpace - Get null space attached with `MatSetNearNullSpace()`
9037 
9038   Not Collective
9039 
9040   Input Parameter:
9041 . mat - the matrix
9042 
9043   Output Parameter:
9044 . nullsp - the null space object, `NULL` if not set
9045 
9046   Level: advanced
9047 
9048 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatNullSpaceCreate()`
9049 @*/
9050 PetscErrorCode MatGetNearNullSpace(Mat mat, MatNullSpace *nullsp)
9051 {
9052   PetscFunctionBegin;
9053   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9054   PetscValidType(mat, 1);
9055   PetscAssertPointer(nullsp, 2);
9056   MatCheckPreallocated(mat, 1);
9057   *nullsp = mat->nearnullsp;
9058   PetscFunctionReturn(PETSC_SUCCESS);
9059 }
9060 
9061 /*@
9062   MatICCFactor - Performs in-place incomplete Cholesky factorization of matrix.
9063 
9064   Collective
9065 
9066   Input Parameters:
9067 + mat  - the matrix
9068 . row  - row/column permutation
9069 - info - information on desired factorization process
9070 
9071   Level: developer
9072 
9073   Notes:
9074   Probably really in-place only when level of fill is zero, otherwise allocates
9075   new space to store factored matrix and deletes previous memory.
9076 
9077   Most users should employ the `KSP` interface for linear solvers
9078   instead of working directly with matrix algebra routines such as this.
9079   See, e.g., `KSPCreate()`.
9080 
9081   Fortran Note:
9082   A valid (non-null) `info` argument must be provided
9083 
9084 .seealso: [](ch_matrices), `Mat`, `MatFactorInfo`, `MatGetFactor()`, `MatICCFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
9085 @*/
9086 PetscErrorCode MatICCFactor(Mat mat, IS row, const MatFactorInfo *info)
9087 {
9088   PetscFunctionBegin;
9089   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9090   PetscValidType(mat, 1);
9091   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
9092   PetscAssertPointer(info, 3);
9093   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
9094   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
9095   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9096   MatCheckPreallocated(mat, 1);
9097   PetscUseTypeMethod(mat, iccfactor, row, info);
9098   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9099   PetscFunctionReturn(PETSC_SUCCESS);
9100 }
9101 
9102 /*@
9103   MatDiagonalScaleLocal - Scales columns of a matrix given the scaling values including the
9104   ghosted ones.
9105 
9106   Not Collective
9107 
9108   Input Parameters:
9109 + mat  - the matrix
9110 - diag - the diagonal values, including ghost ones
9111 
9112   Level: developer
9113 
9114   Notes:
9115   Works only for `MATMPIAIJ` and `MATMPIBAIJ` matrices
9116 
9117   This allows one to avoid during communication to perform the scaling that must be done with `MatDiagonalScale()`
9118 
9119 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
9120 @*/
9121 PetscErrorCode MatDiagonalScaleLocal(Mat mat, Vec diag)
9122 {
9123   PetscMPIInt size;
9124 
9125   PetscFunctionBegin;
9126   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9127   PetscValidHeaderSpecific(diag, VEC_CLASSID, 2);
9128   PetscValidType(mat, 1);
9129 
9130   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must be already assembled");
9131   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
9132   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
9133   if (size == 1) {
9134     PetscInt n, m;
9135     PetscCall(VecGetSize(diag, &n));
9136     PetscCall(MatGetSize(mat, NULL, &m));
9137     PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supported for sequential matrices when no ghost points/periodic conditions");
9138     PetscCall(MatDiagonalScale(mat, NULL, diag));
9139   } else {
9140     PetscUseMethod(mat, "MatDiagonalScaleLocal_C", (Mat, Vec), (mat, diag));
9141   }
9142   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
9143   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9144   PetscFunctionReturn(PETSC_SUCCESS);
9145 }
9146 
9147 /*@
9148   MatGetInertia - Gets the inertia from a factored matrix
9149 
9150   Collective
9151 
9152   Input Parameter:
9153 . mat - the matrix
9154 
9155   Output Parameters:
9156 + nneg  - number of negative eigenvalues
9157 . nzero - number of zero eigenvalues
9158 - npos  - number of positive eigenvalues
9159 
9160   Level: advanced
9161 
9162   Note:
9163   Matrix must have been factored by `MatCholeskyFactor()`
9164 
9165 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactor()`
9166 @*/
9167 PetscErrorCode MatGetInertia(Mat mat, PetscInt *nneg, PetscInt *nzero, PetscInt *npos)
9168 {
9169   PetscFunctionBegin;
9170   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9171   PetscValidType(mat, 1);
9172   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9173   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Numeric factor mat is not assembled");
9174   PetscUseTypeMethod(mat, getinertia, nneg, nzero, npos);
9175   PetscFunctionReturn(PETSC_SUCCESS);
9176 }
9177 
9178 /*@C
9179   MatSolves - Solves $A x = b$, given a factored matrix, for a collection of vectors
9180 
9181   Neighbor-wise Collective
9182 
9183   Input Parameters:
9184 + mat - the factored matrix obtained with `MatGetFactor()`
9185 - b   - the right-hand-side vectors
9186 
9187   Output Parameter:
9188 . x - the result vectors
9189 
9190   Level: developer
9191 
9192   Note:
9193   The vectors `b` and `x` cannot be the same.  I.e., one cannot
9194   call `MatSolves`(A,x,x).
9195 
9196 .seealso: [](ch_matrices), `Mat`, `Vecs`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`, `MatSolve()`
9197 @*/
9198 PetscErrorCode MatSolves(Mat mat, Vecs b, Vecs x)
9199 {
9200   PetscFunctionBegin;
9201   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9202   PetscValidType(mat, 1);
9203   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
9204   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9205   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
9206 
9207   MatCheckPreallocated(mat, 1);
9208   PetscCall(PetscLogEventBegin(MAT_Solves, mat, 0, 0, 0));
9209   PetscUseTypeMethod(mat, solves, b, x);
9210   PetscCall(PetscLogEventEnd(MAT_Solves, mat, 0, 0, 0));
9211   PetscFunctionReturn(PETSC_SUCCESS);
9212 }
9213 
9214 /*@
9215   MatIsSymmetric - Test whether a matrix is symmetric
9216 
9217   Collective
9218 
9219   Input Parameters:
9220 + A   - the matrix to test
9221 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact transpose)
9222 
9223   Output Parameter:
9224 . flg - the result
9225 
9226   Level: intermediate
9227 
9228   Notes:
9229   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9230 
9231   If the matrix does not yet know if it is symmetric or not this can be an expensive operation, also available `MatIsSymmetricKnown()`
9232 
9233   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9234   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9235 
9236 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetricKnown()`,
9237           `MAT_SYMMETRIC`, `MAT_SYMMETRY_ETERNAL`
9238 @*/
9239 PetscErrorCode MatIsSymmetric(Mat A, PetscReal tol, PetscBool *flg)
9240 {
9241   PetscFunctionBegin;
9242   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9243   PetscAssertPointer(flg, 3);
9244   if (A->symmetric != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->symmetric);
9245   else {
9246     if (A->ops->issymmetric) PetscUseTypeMethod(A, issymmetric, tol, flg);
9247     else PetscCall(MatIsTranspose(A, A, tol, flg));
9248     if (!tol) PetscCall(MatSetOption(A, MAT_SYMMETRIC, *flg));
9249   }
9250   PetscFunctionReturn(PETSC_SUCCESS);
9251 }
9252 
9253 /*@
9254   MatIsHermitian - Test whether a matrix is Hermitian
9255 
9256   Collective
9257 
9258   Input Parameters:
9259 + A   - the matrix to test
9260 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact Hermitian)
9261 
9262   Output Parameter:
9263 . flg - the result
9264 
9265   Level: intermediate
9266 
9267   Notes:
9268   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9269 
9270   If the matrix does not yet know if it is Hermitian or not this can be an expensive operation, also available `MatIsHermitianKnown()`
9271 
9272   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9273   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMEMTRY_ETERNAL`,`PETSC_TRUE`)
9274 
9275 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetric()`, `MatSetOption()`,
9276           `MatIsSymmetricKnown()`, `MatIsSymmetric()`, `MAT_HERMITIAN`, `MAT_SYMMETRY_ETERNAL`
9277 @*/
9278 PetscErrorCode MatIsHermitian(Mat A, PetscReal tol, PetscBool *flg)
9279 {
9280   PetscFunctionBegin;
9281   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9282   PetscAssertPointer(flg, 3);
9283   if (A->hermitian != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->hermitian);
9284   else {
9285     if (A->ops->ishermitian) PetscUseTypeMethod(A, ishermitian, tol, flg);
9286     else PetscCall(MatIsHermitianTranspose(A, A, tol, flg));
9287     if (!tol) PetscCall(MatSetOption(A, MAT_HERMITIAN, *flg));
9288   }
9289   PetscFunctionReturn(PETSC_SUCCESS);
9290 }
9291 
9292 /*@
9293   MatIsSymmetricKnown - Checks if a matrix knows if it is symmetric or not and its symmetric state
9294 
9295   Not Collective
9296 
9297   Input Parameter:
9298 . A - the matrix to check
9299 
9300   Output Parameters:
9301 + set - `PETSC_TRUE` if the matrix knows its symmetry state (this tells you if the next flag is valid)
9302 - flg - the result (only valid if set is `PETSC_TRUE`)
9303 
9304   Level: advanced
9305 
9306   Notes:
9307   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsSymmetric()`
9308   if you want it explicitly checked
9309 
9310   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9311   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9312 
9313 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9314 @*/
9315 PetscErrorCode MatIsSymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9316 {
9317   PetscFunctionBegin;
9318   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9319   PetscAssertPointer(set, 2);
9320   PetscAssertPointer(flg, 3);
9321   if (A->symmetric != PETSC_BOOL3_UNKNOWN) {
9322     *set = PETSC_TRUE;
9323     *flg = PetscBool3ToBool(A->symmetric);
9324   } else {
9325     *set = PETSC_FALSE;
9326   }
9327   PetscFunctionReturn(PETSC_SUCCESS);
9328 }
9329 
9330 /*@
9331   MatIsSPDKnown - Checks if a matrix knows if it is symmetric positive definite or not and its symmetric positive definite state
9332 
9333   Not Collective
9334 
9335   Input Parameter:
9336 . A - the matrix to check
9337 
9338   Output Parameters:
9339 + set - `PETSC_TRUE` if the matrix knows its symmetric positive definite state (this tells you if the next flag is valid)
9340 - flg - the result (only valid if set is `PETSC_TRUE`)
9341 
9342   Level: advanced
9343 
9344   Notes:
9345   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`).
9346 
9347   One can declare that a matrix is SPD with `MatSetOption`(mat,`MAT_SPD`,`PETSC_TRUE`) and if it is known to remain SPD
9348   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SPD_ETERNAL`,`PETSC_TRUE`)
9349 
9350 .seealso: [](ch_matrices), `Mat`, `MAT_SPD_ETERNAL`, `MAT_SPD`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9351 @*/
9352 PetscErrorCode MatIsSPDKnown(Mat A, PetscBool *set, PetscBool *flg)
9353 {
9354   PetscFunctionBegin;
9355   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9356   PetscAssertPointer(set, 2);
9357   PetscAssertPointer(flg, 3);
9358   if (A->spd != PETSC_BOOL3_UNKNOWN) {
9359     *set = PETSC_TRUE;
9360     *flg = PetscBool3ToBool(A->spd);
9361   } else {
9362     *set = PETSC_FALSE;
9363   }
9364   PetscFunctionReturn(PETSC_SUCCESS);
9365 }
9366 
9367 /*@
9368   MatIsHermitianKnown - Checks if a matrix knows if it is Hermitian or not and its Hermitian state
9369 
9370   Not Collective
9371 
9372   Input Parameter:
9373 . A - the matrix to check
9374 
9375   Output Parameters:
9376 + set - `PETSC_TRUE` if the matrix knows its Hermitian state (this tells you if the next flag is valid)
9377 - flg - the result (only valid if set is `PETSC_TRUE`)
9378 
9379   Level: advanced
9380 
9381   Notes:
9382   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsHermitian()`
9383   if you want it explicitly checked
9384 
9385   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9386   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9387 
9388 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MAT_HERMITIAN`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`
9389 @*/
9390 PetscErrorCode MatIsHermitianKnown(Mat A, PetscBool *set, PetscBool *flg)
9391 {
9392   PetscFunctionBegin;
9393   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9394   PetscAssertPointer(set, 2);
9395   PetscAssertPointer(flg, 3);
9396   if (A->hermitian != PETSC_BOOL3_UNKNOWN) {
9397     *set = PETSC_TRUE;
9398     *flg = PetscBool3ToBool(A->hermitian);
9399   } else {
9400     *set = PETSC_FALSE;
9401   }
9402   PetscFunctionReturn(PETSC_SUCCESS);
9403 }
9404 
9405 /*@
9406   MatIsStructurallySymmetric - Test whether a matrix is structurally symmetric
9407 
9408   Collective
9409 
9410   Input Parameter:
9411 . A - the matrix to test
9412 
9413   Output Parameter:
9414 . flg - the result
9415 
9416   Level: intermediate
9417 
9418   Notes:
9419   If the matrix does yet know it is structurally symmetric this can be an expensive operation, also available `MatIsStructurallySymmetricKnown()`
9420 
9421   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
9422   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9423 
9424 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsSymmetric()`, `MatSetOption()`, `MatIsStructurallySymmetricKnown()`
9425 @*/
9426 PetscErrorCode MatIsStructurallySymmetric(Mat A, PetscBool *flg)
9427 {
9428   PetscFunctionBegin;
9429   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9430   PetscAssertPointer(flg, 2);
9431   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9432     *flg = PetscBool3ToBool(A->structurally_symmetric);
9433   } else {
9434     PetscUseTypeMethod(A, isstructurallysymmetric, flg);
9435     PetscCall(MatSetOption(A, MAT_STRUCTURALLY_SYMMETRIC, *flg));
9436   }
9437   PetscFunctionReturn(PETSC_SUCCESS);
9438 }
9439 
9440 /*@
9441   MatIsStructurallySymmetricKnown - Checks if a matrix knows if it is structurally symmetric or not and its structurally symmetric state
9442 
9443   Not Collective
9444 
9445   Input Parameter:
9446 . A - the matrix to check
9447 
9448   Output Parameters:
9449 + set - PETSC_TRUE if the matrix knows its structurally symmetric state (this tells you if the next flag is valid)
9450 - flg - the result (only valid if set is PETSC_TRUE)
9451 
9452   Level: advanced
9453 
9454   Notes:
9455   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
9456   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9457 
9458   Use `MatIsStructurallySymmetric()` to explicitly check if a matrix is structurally symmetric (this is an expensive operation)
9459 
9460 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9461 @*/
9462 PetscErrorCode MatIsStructurallySymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9463 {
9464   PetscFunctionBegin;
9465   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9466   PetscAssertPointer(set, 2);
9467   PetscAssertPointer(flg, 3);
9468   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9469     *set = PETSC_TRUE;
9470     *flg = PetscBool3ToBool(A->structurally_symmetric);
9471   } else {
9472     *set = PETSC_FALSE;
9473   }
9474   PetscFunctionReturn(PETSC_SUCCESS);
9475 }
9476 
9477 /*@
9478   MatStashGetInfo - Gets how many values are currently in the matrix stash, i.e. need
9479   to be communicated to other processors during the `MatAssemblyBegin()`/`MatAssemblyEnd()` process
9480 
9481   Not Collective
9482 
9483   Input Parameter:
9484 . mat - the matrix
9485 
9486   Output Parameters:
9487 + nstash    - the size of the stash
9488 . reallocs  - the number of additional mallocs incurred.
9489 . bnstash   - the size of the block stash
9490 - breallocs - the number of additional mallocs incurred.in the block stash
9491 
9492   Level: advanced
9493 
9494 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashSetInitialSize()`
9495 @*/
9496 PetscErrorCode MatStashGetInfo(Mat mat, PetscInt *nstash, PetscInt *reallocs, PetscInt *bnstash, PetscInt *breallocs)
9497 {
9498   PetscFunctionBegin;
9499   PetscCall(MatStashGetInfo_Private(&mat->stash, nstash, reallocs));
9500   PetscCall(MatStashGetInfo_Private(&mat->bstash, bnstash, breallocs));
9501   PetscFunctionReturn(PETSC_SUCCESS);
9502 }
9503 
9504 /*@
9505   MatCreateVecs - Get vector(s) compatible with the matrix, i.e. with the same
9506   parallel layout, `PetscLayout` for rows and columns
9507 
9508   Collective
9509 
9510   Input Parameter:
9511 . mat - the matrix
9512 
9513   Output Parameters:
9514 + right - (optional) vector that the matrix can be multiplied against
9515 - left  - (optional) vector that the matrix vector product can be stored in
9516 
9517   Level: advanced
9518 
9519   Notes:
9520   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()`.
9521 
9522   These are new vectors which are not owned by the mat, they should be destroyed in `VecDestroy()` when no longer needed
9523 
9524 .seealso: [](ch_matrices), `Mat`, `Vec`, `VecCreate()`, `VecDestroy()`, `DMCreateGlobalVector()`
9525 @*/
9526 PetscErrorCode MatCreateVecs(Mat mat, Vec *right, Vec *left)
9527 {
9528   PetscFunctionBegin;
9529   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9530   PetscValidType(mat, 1);
9531   if (mat->ops->getvecs) {
9532     PetscUseTypeMethod(mat, getvecs, right, left);
9533   } else {
9534     if (right) {
9535       PetscCheck(mat->cmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for columns not yet setup");
9536       PetscCall(VecCreateWithLayout_Private(mat->cmap, right));
9537       PetscCall(VecSetType(*right, mat->defaultvectype));
9538 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9539       if (mat->boundtocpu && mat->bindingpropagates) {
9540         PetscCall(VecSetBindingPropagates(*right, PETSC_TRUE));
9541         PetscCall(VecBindToCPU(*right, PETSC_TRUE));
9542       }
9543 #endif
9544     }
9545     if (left) {
9546       PetscCheck(mat->rmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for rows not yet setup");
9547       PetscCall(VecCreateWithLayout_Private(mat->rmap, left));
9548       PetscCall(VecSetType(*left, mat->defaultvectype));
9549 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9550       if (mat->boundtocpu && mat->bindingpropagates) {
9551         PetscCall(VecSetBindingPropagates(*left, PETSC_TRUE));
9552         PetscCall(VecBindToCPU(*left, PETSC_TRUE));
9553       }
9554 #endif
9555     }
9556   }
9557   PetscFunctionReturn(PETSC_SUCCESS);
9558 }
9559 
9560 /*@
9561   MatFactorInfoInitialize - Initializes a `MatFactorInfo` data structure
9562   with default values.
9563 
9564   Not Collective
9565 
9566   Input Parameter:
9567 . info - the `MatFactorInfo` data structure
9568 
9569   Level: developer
9570 
9571   Notes:
9572   The solvers are generally used through the `KSP` and `PC` objects, for example
9573   `PCLU`, `PCILU`, `PCCHOLESKY`, `PCICC`
9574 
9575   Once the data structure is initialized one may change certain entries as desired for the particular factorization to be performed
9576 
9577 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorInfo`
9578 @*/
9579 PetscErrorCode MatFactorInfoInitialize(MatFactorInfo *info)
9580 {
9581   PetscFunctionBegin;
9582   PetscCall(PetscMemzero(info, sizeof(MatFactorInfo)));
9583   PetscFunctionReturn(PETSC_SUCCESS);
9584 }
9585 
9586 /*@
9587   MatFactorSetSchurIS - Set indices corresponding to the Schur complement you wish to have computed
9588 
9589   Collective
9590 
9591   Input Parameters:
9592 + mat - the factored matrix
9593 - is  - the index set defining the Schur indices (0-based)
9594 
9595   Level: advanced
9596 
9597   Notes:
9598   Call `MatFactorSolveSchurComplement()` or `MatFactorSolveSchurComplementTranspose()` after this call to solve a Schur complement system.
9599 
9600   You can call `MatFactorGetSchurComplement()` or `MatFactorCreateSchurComplement()` after this call.
9601 
9602   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9603 
9604 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorGetSchurComplement()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSolveSchurComplement()`,
9605           `MatFactorSolveSchurComplementTranspose()`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9606 @*/
9607 PetscErrorCode MatFactorSetSchurIS(Mat mat, IS is)
9608 {
9609   PetscErrorCode (*f)(Mat, IS);
9610 
9611   PetscFunctionBegin;
9612   PetscValidType(mat, 1);
9613   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9614   PetscValidType(is, 2);
9615   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
9616   PetscCheckSameComm(mat, 1, is, 2);
9617   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
9618   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorSetSchurIS_C", &f));
9619   PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "The selected MatSolverType does not support Schur complement computation. You should use MATSOLVERMUMPS or MATSOLVERMKL_PARDISO");
9620   PetscCall(MatDestroy(&mat->schur));
9621   PetscCall((*f)(mat, is));
9622   PetscCheck(mat->schur, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Schur complement has not been created");
9623   PetscFunctionReturn(PETSC_SUCCESS);
9624 }
9625 
9626 /*@
9627   MatFactorCreateSchurComplement - Create a Schur complement matrix object using Schur data computed during the factorization step
9628 
9629   Logically Collective
9630 
9631   Input Parameters:
9632 + F      - the factored matrix obtained by calling `MatGetFactor()`
9633 . S      - location where to return the Schur complement, can be `NULL`
9634 - status - the status of the Schur complement matrix, can be `NULL`
9635 
9636   Level: advanced
9637 
9638   Notes:
9639   You must call `MatFactorSetSchurIS()` before calling this routine.
9640 
9641   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9642 
9643   The routine provides a copy of the Schur matrix stored within the solver data structures.
9644   The caller must destroy the object when it is no longer needed.
9645   If `MatFactorInvertSchurComplement()` has been called, the routine gets back the inverse.
9646 
9647   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)
9648 
9649   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9650 
9651   Developer Note:
9652   The reason this routine exists is because the representation of the Schur complement within the factor matrix may be different than a standard PETSc
9653   matrix representation and we normally do not want to use the time or memory to make a copy as a regular PETSc matrix.
9654 
9655 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorSchurStatus`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9656 @*/
9657 PetscErrorCode MatFactorCreateSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9658 {
9659   PetscFunctionBegin;
9660   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9661   if (S) PetscAssertPointer(S, 2);
9662   if (status) PetscAssertPointer(status, 3);
9663   if (S) {
9664     PetscErrorCode (*f)(Mat, Mat *);
9665 
9666     PetscCall(PetscObjectQueryFunction((PetscObject)F, "MatFactorCreateSchurComplement_C", &f));
9667     if (f) {
9668       PetscCall((*f)(F, S));
9669     } else {
9670       PetscCall(MatDuplicate(F->schur, MAT_COPY_VALUES, S));
9671     }
9672   }
9673   if (status) *status = F->schur_status;
9674   PetscFunctionReturn(PETSC_SUCCESS);
9675 }
9676 
9677 /*@
9678   MatFactorGetSchurComplement - Gets access to a Schur complement matrix using the current Schur data within a factored matrix
9679 
9680   Logically Collective
9681 
9682   Input Parameters:
9683 + F      - the factored matrix obtained by calling `MatGetFactor()`
9684 . S      - location where to return the Schur complement, can be `NULL`
9685 - status - the status of the Schur complement matrix, can be `NULL`
9686 
9687   Level: advanced
9688 
9689   Notes:
9690   You must call `MatFactorSetSchurIS()` before calling this routine.
9691 
9692   Schur complement mode is currently implemented for sequential matrices with factor type of `MATSOLVERMUMPS`
9693 
9694   The routine returns a the Schur Complement stored within the data structures of the solver.
9695 
9696   If `MatFactorInvertSchurComplement()` has previously been called, the returned matrix is actually the inverse of the Schur complement.
9697 
9698   The returned matrix should not be destroyed; the caller should call `MatFactorRestoreSchurComplement()` when the object is no longer needed.
9699 
9700   Use `MatFactorCreateSchurComplement()` to create a copy of the Schur complement matrix that is within a factored matrix
9701 
9702   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9703 
9704 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9705 @*/
9706 PetscErrorCode MatFactorGetSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9707 {
9708   PetscFunctionBegin;
9709   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9710   if (S) {
9711     PetscAssertPointer(S, 2);
9712     *S = F->schur;
9713   }
9714   if (status) {
9715     PetscAssertPointer(status, 3);
9716     *status = F->schur_status;
9717   }
9718   PetscFunctionReturn(PETSC_SUCCESS);
9719 }
9720 
9721 static PetscErrorCode MatFactorUpdateSchurStatus_Private(Mat F)
9722 {
9723   Mat S = F->schur;
9724 
9725   PetscFunctionBegin;
9726   switch (F->schur_status) {
9727   case MAT_FACTOR_SCHUR_UNFACTORED: // fall-through
9728   case MAT_FACTOR_SCHUR_INVERTED:
9729     if (S) {
9730       S->ops->solve             = NULL;
9731       S->ops->matsolve          = NULL;
9732       S->ops->solvetranspose    = NULL;
9733       S->ops->matsolvetranspose = NULL;
9734       S->ops->solveadd          = NULL;
9735       S->ops->solvetransposeadd = NULL;
9736       S->factortype             = MAT_FACTOR_NONE;
9737       PetscCall(PetscFree(S->solvertype));
9738     }
9739   case MAT_FACTOR_SCHUR_FACTORED: // fall-through
9740     break;
9741   default:
9742     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9743   }
9744   PetscFunctionReturn(PETSC_SUCCESS);
9745 }
9746 
9747 /*@
9748   MatFactorRestoreSchurComplement - Restore the Schur complement matrix object obtained from a call to `MatFactorGetSchurComplement()`
9749 
9750   Logically Collective
9751 
9752   Input Parameters:
9753 + F      - the factored matrix obtained by calling `MatGetFactor()`
9754 . S      - location where the Schur complement is stored
9755 - status - the status of the Schur complement matrix (see `MatFactorSchurStatus`)
9756 
9757   Level: advanced
9758 
9759 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9760 @*/
9761 PetscErrorCode MatFactorRestoreSchurComplement(Mat F, Mat *S, MatFactorSchurStatus status)
9762 {
9763   PetscFunctionBegin;
9764   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9765   if (S) {
9766     PetscValidHeaderSpecific(*S, MAT_CLASSID, 2);
9767     *S = NULL;
9768   }
9769   F->schur_status = status;
9770   PetscCall(MatFactorUpdateSchurStatus_Private(F));
9771   PetscFunctionReturn(PETSC_SUCCESS);
9772 }
9773 
9774 /*@
9775   MatFactorSolveSchurComplementTranspose - Solve the transpose of the Schur complement system computed during the factorization step
9776 
9777   Logically Collective
9778 
9779   Input Parameters:
9780 + F   - the factored matrix obtained by calling `MatGetFactor()`
9781 . rhs - location where the right-hand side of the Schur complement system is stored
9782 - sol - location where the solution of the Schur complement system has to be returned
9783 
9784   Level: advanced
9785 
9786   Notes:
9787   The sizes of the vectors should match the size of the Schur complement
9788 
9789   Must be called after `MatFactorSetSchurIS()`
9790 
9791 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplement()`
9792 @*/
9793 PetscErrorCode MatFactorSolveSchurComplementTranspose(Mat F, Vec rhs, Vec sol)
9794 {
9795   PetscFunctionBegin;
9796   PetscValidType(F, 1);
9797   PetscValidType(rhs, 2);
9798   PetscValidType(sol, 3);
9799   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9800   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
9801   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
9802   PetscCheckSameComm(F, 1, rhs, 2);
9803   PetscCheckSameComm(F, 1, sol, 3);
9804   PetscCall(MatFactorFactorizeSchurComplement(F));
9805   switch (F->schur_status) {
9806   case MAT_FACTOR_SCHUR_FACTORED:
9807     PetscCall(MatSolveTranspose(F->schur, rhs, sol));
9808     break;
9809   case MAT_FACTOR_SCHUR_INVERTED:
9810     PetscCall(MatMultTranspose(F->schur, rhs, sol));
9811     break;
9812   default:
9813     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9814   }
9815   PetscFunctionReturn(PETSC_SUCCESS);
9816 }
9817 
9818 /*@
9819   MatFactorSolveSchurComplement - Solve the Schur complement system computed during the factorization step
9820 
9821   Logically Collective
9822 
9823   Input Parameters:
9824 + F   - the factored matrix obtained by calling `MatGetFactor()`
9825 . rhs - location where the right-hand side of the Schur complement system is stored
9826 - sol - location where the solution of the Schur complement system has to be returned
9827 
9828   Level: advanced
9829 
9830   Notes:
9831   The sizes of the vectors should match the size of the Schur complement
9832 
9833   Must be called after `MatFactorSetSchurIS()`
9834 
9835 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplementTranspose()`
9836 @*/
9837 PetscErrorCode MatFactorSolveSchurComplement(Mat F, Vec rhs, Vec sol)
9838 {
9839   PetscFunctionBegin;
9840   PetscValidType(F, 1);
9841   PetscValidType(rhs, 2);
9842   PetscValidType(sol, 3);
9843   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9844   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
9845   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
9846   PetscCheckSameComm(F, 1, rhs, 2);
9847   PetscCheckSameComm(F, 1, sol, 3);
9848   PetscCall(MatFactorFactorizeSchurComplement(F));
9849   switch (F->schur_status) {
9850   case MAT_FACTOR_SCHUR_FACTORED:
9851     PetscCall(MatSolve(F->schur, rhs, sol));
9852     break;
9853   case MAT_FACTOR_SCHUR_INVERTED:
9854     PetscCall(MatMult(F->schur, rhs, sol));
9855     break;
9856   default:
9857     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9858   }
9859   PetscFunctionReturn(PETSC_SUCCESS);
9860 }
9861 
9862 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode MatSeqDenseInvertFactors_Private(Mat);
9863 #if PetscDefined(HAVE_CUDA)
9864 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode MatSeqDenseCUDAInvertFactors_Internal(Mat);
9865 #endif
9866 
9867 /* Schur status updated in the interface */
9868 static PetscErrorCode MatFactorInvertSchurComplement_Private(Mat F)
9869 {
9870   Mat S = F->schur;
9871 
9872   PetscFunctionBegin;
9873   if (S) {
9874     PetscMPIInt size;
9875     PetscBool   isdense, isdensecuda;
9876 
9877     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)S), &size));
9878     PetscCheck(size <= 1, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not yet implemented");
9879     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSE, &isdense));
9880     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSECUDA, &isdensecuda));
9881     PetscCheck(isdense || isdensecuda, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not implemented for type %s", ((PetscObject)S)->type_name);
9882     PetscCall(PetscLogEventBegin(MAT_FactorInvS, F, 0, 0, 0));
9883     if (isdense) {
9884       PetscCall(MatSeqDenseInvertFactors_Private(S));
9885     } else if (isdensecuda) {
9886 #if defined(PETSC_HAVE_CUDA)
9887       PetscCall(MatSeqDenseCUDAInvertFactors_Internal(S));
9888 #endif
9889     }
9890     // HIP??????????????
9891     PetscCall(PetscLogEventEnd(MAT_FactorInvS, F, 0, 0, 0));
9892   }
9893   PetscFunctionReturn(PETSC_SUCCESS);
9894 }
9895 
9896 /*@
9897   MatFactorInvertSchurComplement - Invert the Schur complement matrix computed during the factorization step
9898 
9899   Logically Collective
9900 
9901   Input Parameter:
9902 . F - the factored matrix obtained by calling `MatGetFactor()`
9903 
9904   Level: advanced
9905 
9906   Notes:
9907   Must be called after `MatFactorSetSchurIS()`.
9908 
9909   Call `MatFactorGetSchurComplement()` or  `MatFactorCreateSchurComplement()` AFTER this call to actually compute the inverse and get access to it.
9910 
9911 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorCreateSchurComplement()`
9912 @*/
9913 PetscErrorCode MatFactorInvertSchurComplement(Mat F)
9914 {
9915   PetscFunctionBegin;
9916   PetscValidType(F, 1);
9917   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9918   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED) PetscFunctionReturn(PETSC_SUCCESS);
9919   PetscCall(MatFactorFactorizeSchurComplement(F));
9920   PetscCall(MatFactorInvertSchurComplement_Private(F));
9921   F->schur_status = MAT_FACTOR_SCHUR_INVERTED;
9922   PetscFunctionReturn(PETSC_SUCCESS);
9923 }
9924 
9925 /*@
9926   MatFactorFactorizeSchurComplement - Factorize the Schur complement matrix computed during the factorization step
9927 
9928   Logically Collective
9929 
9930   Input Parameter:
9931 . F - the factored matrix obtained by calling `MatGetFactor()`
9932 
9933   Level: advanced
9934 
9935   Note:
9936   Must be called after `MatFactorSetSchurIS()`
9937 
9938 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorInvertSchurComplement()`
9939 @*/
9940 PetscErrorCode MatFactorFactorizeSchurComplement(Mat F)
9941 {
9942   MatFactorInfo info;
9943 
9944   PetscFunctionBegin;
9945   PetscValidType(F, 1);
9946   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9947   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED || F->schur_status == MAT_FACTOR_SCHUR_FACTORED) PetscFunctionReturn(PETSC_SUCCESS);
9948   PetscCall(PetscLogEventBegin(MAT_FactorFactS, F, 0, 0, 0));
9949   PetscCall(PetscMemzero(&info, sizeof(MatFactorInfo)));
9950   if (F->factortype == MAT_FACTOR_CHOLESKY) { /* LDL^t regarded as Cholesky */
9951     PetscCall(MatCholeskyFactor(F->schur, NULL, &info));
9952   } else {
9953     PetscCall(MatLUFactor(F->schur, NULL, NULL, &info));
9954   }
9955   PetscCall(PetscLogEventEnd(MAT_FactorFactS, F, 0, 0, 0));
9956   F->schur_status = MAT_FACTOR_SCHUR_FACTORED;
9957   PetscFunctionReturn(PETSC_SUCCESS);
9958 }
9959 
9960 /*@
9961   MatPtAP - Creates the matrix product $C = P^T * A * P$
9962 
9963   Neighbor-wise Collective
9964 
9965   Input Parameters:
9966 + A     - the matrix
9967 . P     - the projection matrix
9968 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
9969 - 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
9970           if the result is a dense matrix this is irrelevant
9971 
9972   Output Parameter:
9973 . C - the product matrix
9974 
9975   Level: intermediate
9976 
9977   Notes:
9978   C will be created and must be destroyed by the user with `MatDestroy()`.
9979 
9980   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
9981 
9982   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
9983 
9984   Developer Note:
9985   For matrix types without special implementation the function fallbacks to `MatMatMult()` followed by `MatTransposeMatMult()`.
9986 
9987 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatRARt()`
9988 @*/
9989 PetscErrorCode MatPtAP(Mat A, Mat P, MatReuse scall, PetscReal fill, Mat *C)
9990 {
9991   PetscFunctionBegin;
9992   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
9993   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
9994 
9995   if (scall == MAT_INITIAL_MATRIX) {
9996     PetscCall(MatProductCreate(A, P, NULL, C));
9997     PetscCall(MatProductSetType(*C, MATPRODUCT_PtAP));
9998     PetscCall(MatProductSetAlgorithm(*C, "default"));
9999     PetscCall(MatProductSetFill(*C, fill));
10000 
10001     (*C)->product->api_user = PETSC_TRUE;
10002     PetscCall(MatProductSetFromOptions(*C));
10003     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);
10004     PetscCall(MatProductSymbolic(*C));
10005   } else { /* scall == MAT_REUSE_MATRIX */
10006     PetscCall(MatProductReplaceMats(A, P, NULL, *C));
10007   }
10008 
10009   PetscCall(MatProductNumeric(*C));
10010   (*C)->symmetric = A->symmetric;
10011   (*C)->spd       = A->spd;
10012   PetscFunctionReturn(PETSC_SUCCESS);
10013 }
10014 
10015 /*@
10016   MatRARt - Creates the matrix product $C = R * A * R^T$
10017 
10018   Neighbor-wise Collective
10019 
10020   Input Parameters:
10021 + A     - the matrix
10022 . R     - the projection matrix
10023 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10024 - fill  - expected fill as ratio of nnz(C)/nnz(A), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10025           if the result is a dense matrix this is irrelevant
10026 
10027   Output Parameter:
10028 . C - the product matrix
10029 
10030   Level: intermediate
10031 
10032   Notes:
10033   `C` will be created and must be destroyed by the user with `MatDestroy()`.
10034 
10035   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
10036 
10037   This routine is currently only implemented for pairs of `MATAIJ` matrices and classes
10038   which inherit from `MATAIJ`. Due to PETSc sparse matrix block row distribution among processes,
10039   the parallel `MatRARt()` is implemented computing the explicit transpose of `R`, which can be very expensive.
10040   We recommend using `MatPtAP()` when possible.
10041 
10042   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10043 
10044 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatPtAP()`
10045 @*/
10046 PetscErrorCode MatRARt(Mat A, Mat R, MatReuse scall, PetscReal fill, Mat *C)
10047 {
10048   PetscFunctionBegin;
10049   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10050   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10051 
10052   if (scall == MAT_INITIAL_MATRIX) {
10053     PetscCall(MatProductCreate(A, R, NULL, C));
10054     PetscCall(MatProductSetType(*C, MATPRODUCT_RARt));
10055     PetscCall(MatProductSetAlgorithm(*C, "default"));
10056     PetscCall(MatProductSetFill(*C, fill));
10057 
10058     (*C)->product->api_user = PETSC_TRUE;
10059     PetscCall(MatProductSetFromOptions(*C));
10060     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);
10061     PetscCall(MatProductSymbolic(*C));
10062   } else { /* scall == MAT_REUSE_MATRIX */
10063     PetscCall(MatProductReplaceMats(A, R, NULL, *C));
10064   }
10065 
10066   PetscCall(MatProductNumeric(*C));
10067   if (A->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10068   PetscFunctionReturn(PETSC_SUCCESS);
10069 }
10070 
10071 static PetscErrorCode MatProduct_Private(Mat A, Mat B, MatReuse scall, PetscReal fill, MatProductType ptype, Mat *C)
10072 {
10073   PetscBool flg = PETSC_TRUE;
10074 
10075   PetscFunctionBegin;
10076   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX product not supported");
10077   if (scall == MAT_INITIAL_MATRIX) {
10078     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_INITIAL_MATRIX and product type %s\n", MatProductTypes[ptype]));
10079     PetscCall(MatProductCreate(A, B, NULL, C));
10080     PetscCall(MatProductSetAlgorithm(*C, MATPRODUCTALGORITHMDEFAULT));
10081     PetscCall(MatProductSetFill(*C, fill));
10082   } else { /* scall == MAT_REUSE_MATRIX */
10083     Mat_Product *product = (*C)->product;
10084 
10085     PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)*C, &flg, MATSEQDENSE, MATMPIDENSE, ""));
10086     if (flg && product && product->type != ptype) {
10087       PetscCall(MatProductClear(*C));
10088       product = NULL;
10089     }
10090     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_REUSE_MATRIX %s product present and product type %s\n", product ? "with" : "without", MatProductTypes[ptype]));
10091     if (!product) { /* user provide the dense matrix *C without calling MatProductCreate() or reusing it from previous calls */
10092       PetscCheck(flg, PetscObjectComm((PetscObject)*C), PETSC_ERR_SUP, "Call MatProductCreate() first");
10093       PetscCall(MatProductCreate_Private(A, B, NULL, *C));
10094       product        = (*C)->product;
10095       product->fill  = fill;
10096       product->clear = PETSC_TRUE;
10097     } else { /* user may change input matrices A or B when MAT_REUSE_MATRIX */
10098       flg = PETSC_FALSE;
10099       PetscCall(MatProductReplaceMats(A, B, NULL, *C));
10100     }
10101   }
10102   if (flg) {
10103     (*C)->product->api_user = PETSC_TRUE;
10104     PetscCall(MatProductSetType(*C, ptype));
10105     PetscCall(MatProductSetFromOptions(*C));
10106     PetscCall(MatProductSymbolic(*C));
10107   }
10108   PetscCall(MatProductNumeric(*C));
10109   PetscFunctionReturn(PETSC_SUCCESS);
10110 }
10111 
10112 /*@
10113   MatMatMult - Performs matrix-matrix multiplication C=A*B.
10114 
10115   Neighbor-wise Collective
10116 
10117   Input Parameters:
10118 + A     - the left matrix
10119 . B     - the right matrix
10120 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10121 - 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
10122           if the result is a dense matrix this is irrelevant
10123 
10124   Output Parameter:
10125 . C - the product matrix
10126 
10127   Notes:
10128   Unless scall is `MAT_REUSE_MATRIX` C will be created.
10129 
10130   `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
10131   call to this function with `MAT_INITIAL_MATRIX`.
10132 
10133   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value actually needed.
10134 
10135   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`,
10136   rather than first having `MatMatMult()` create it for you. You can NEVER do this if the matrix `C` is sparse.
10137 
10138   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10139 
10140   Example of Usage:
10141 .vb
10142      MatProductCreate(A,B,NULL,&C);
10143      MatProductSetType(C,MATPRODUCT_AB);
10144      MatProductSymbolic(C);
10145      MatProductNumeric(C); // compute C=A * B
10146      MatProductReplaceMats(A1,B1,NULL,C); // compute C=A1 * B1
10147      MatProductNumeric(C);
10148      MatProductReplaceMats(A2,NULL,NULL,C); // compute C=A2 * B1
10149      MatProductNumeric(C);
10150 .ve
10151 
10152   Level: intermediate
10153 
10154 .seealso: [](ch_matrices), `Mat`, `MatProductType`, `MATPRODUCT_AB`, `MatTransposeMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`, `MatProductCreate()`, `MatProductSymbolic()`, `MatProductReplaceMats()`, `MatProductNumeric()`
10155 @*/
10156 PetscErrorCode MatMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10157 {
10158   PetscFunctionBegin;
10159   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AB, C));
10160   PetscFunctionReturn(PETSC_SUCCESS);
10161 }
10162 
10163 /*@
10164   MatMatTransposeMult - Performs matrix-matrix multiplication $C = A*B^T$.
10165 
10166   Neighbor-wise Collective
10167 
10168   Input Parameters:
10169 + A     - the left matrix
10170 . B     - the right matrix
10171 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10172 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10173 
10174   Output Parameter:
10175 . C - the product matrix
10176 
10177   Options Database Key:
10178 . -matmattransmult_mpidense_mpidense_via {allgatherv,cyclic} - Choose between algorithms for `MATMPIDENSE` matrices: the
10179               first redundantly copies the transposed `B` matrix on each process and requires O(log P) communication complexity;
10180               the second never stores more than one portion of the `B` matrix at a time but requires O(P) communication complexity.
10181 
10182   Level: intermediate
10183 
10184   Notes:
10185   C will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10186 
10187   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call
10188 
10189   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10190   actually needed.
10191 
10192   This routine is currently only implemented for pairs of `MATSEQAIJ` matrices, for the `MATSEQDENSE` class,
10193   and for pairs of `MATMPIDENSE` matrices.
10194 
10195   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABt`
10196 
10197   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10198 
10199 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABt`, `MatMatMult()`, `MatTransposeMatMult()` `MatPtAP()`, `MatProductAlgorithm`, `MatProductType`
10200 @*/
10201 PetscErrorCode MatMatTransposeMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10202 {
10203   PetscFunctionBegin;
10204   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_ABt, C));
10205   if (A == B) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10206   PetscFunctionReturn(PETSC_SUCCESS);
10207 }
10208 
10209 /*@
10210   MatTransposeMatMult - Performs matrix-matrix multiplication $C = A^T*B$.
10211 
10212   Neighbor-wise Collective
10213 
10214   Input Parameters:
10215 + A     - the left matrix
10216 . B     - the right matrix
10217 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10218 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10219 
10220   Output Parameter:
10221 . C - the product matrix
10222 
10223   Level: intermediate
10224 
10225   Notes:
10226   `C` will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10227 
10228   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call.
10229 
10230   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_AtB`
10231 
10232   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10233   actually needed.
10234 
10235   This routine is currently implemented for pairs of `MATAIJ` matrices and pairs of `MATSEQDENSE` matrices and classes
10236   which inherit from `MATSEQAIJ`.  `C` will be of the same type as the input matrices.
10237 
10238   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10239 
10240 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_AtB`, `MatMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`
10241 @*/
10242 PetscErrorCode MatTransposeMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10243 {
10244   PetscFunctionBegin;
10245   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AtB, C));
10246   PetscFunctionReturn(PETSC_SUCCESS);
10247 }
10248 
10249 /*@
10250   MatMatMatMult - Performs matrix-matrix-matrix multiplication D=A*B*C.
10251 
10252   Neighbor-wise Collective
10253 
10254   Input Parameters:
10255 + A     - the left matrix
10256 . B     - the middle matrix
10257 . C     - the right matrix
10258 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10259 - 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
10260           if the result is a dense matrix this is irrelevant
10261 
10262   Output Parameter:
10263 . D - the product matrix
10264 
10265   Level: intermediate
10266 
10267   Notes:
10268   Unless `scall` is `MAT_REUSE_MATRIX` `D` will be created.
10269 
10270   `MAT_REUSE_MATRIX` can only be used if the matrices `A`, `B`, and `C` have the same nonzero pattern as in the previous call
10271 
10272   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABC`
10273 
10274   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value
10275   actually needed.
10276 
10277   If you have many matrices with the same non-zero structure to multiply, you
10278   should use `MAT_REUSE_MATRIX` in all calls but the first
10279 
10280   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10281 
10282 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABC`, `MatMatMult`, `MatPtAP()`, `MatMatTransposeMult()`, `MatTransposeMatMult()`
10283 @*/
10284 PetscErrorCode MatMatMatMult(Mat A, Mat B, Mat C, MatReuse scall, PetscReal fill, Mat *D)
10285 {
10286   PetscFunctionBegin;
10287   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*D, 6);
10288   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10289 
10290   if (scall == MAT_INITIAL_MATRIX) {
10291     PetscCall(MatProductCreate(A, B, C, D));
10292     PetscCall(MatProductSetType(*D, MATPRODUCT_ABC));
10293     PetscCall(MatProductSetAlgorithm(*D, "default"));
10294     PetscCall(MatProductSetFill(*D, fill));
10295 
10296     (*D)->product->api_user = PETSC_TRUE;
10297     PetscCall(MatProductSetFromOptions(*D));
10298     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,
10299                ((PetscObject)C)->type_name);
10300     PetscCall(MatProductSymbolic(*D));
10301   } else { /* user may change input matrices when REUSE */
10302     PetscCall(MatProductReplaceMats(A, B, C, *D));
10303   }
10304   PetscCall(MatProductNumeric(*D));
10305   PetscFunctionReturn(PETSC_SUCCESS);
10306 }
10307 
10308 /*@
10309   MatCreateRedundantMatrix - Create redundant matrices and put them into processors of subcommunicators.
10310 
10311   Collective
10312 
10313   Input Parameters:
10314 + mat      - the matrix
10315 . nsubcomm - the number of subcommunicators (= number of redundant parallel or sequential matrices)
10316 . subcomm  - MPI communicator split from the communicator where mat resides in (or `MPI_COMM_NULL` if nsubcomm is used)
10317 - reuse    - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10318 
10319   Output Parameter:
10320 . matredundant - redundant matrix
10321 
10322   Level: advanced
10323 
10324   Notes:
10325   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
10326   original matrix has not changed from that last call to `MatCreateRedundantMatrix()`.
10327 
10328   This routine creates the duplicated matrices in the subcommunicators; you should NOT create them before
10329   calling it.
10330 
10331   `PetscSubcommCreate()` can be used to manage the creation of the subcomm but need not be.
10332 
10333 .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `PetscSubcommCreate()`, `PetscSubcomm`
10334 @*/
10335 PetscErrorCode MatCreateRedundantMatrix(Mat mat, PetscInt nsubcomm, MPI_Comm subcomm, MatReuse reuse, Mat *matredundant)
10336 {
10337   MPI_Comm       comm;
10338   PetscMPIInt    size;
10339   PetscInt       mloc_sub, nloc_sub, rstart, rend, M = mat->rmap->N, N = mat->cmap->N, bs = mat->rmap->bs;
10340   Mat_Redundant *redund     = NULL;
10341   PetscSubcomm   psubcomm   = NULL;
10342   MPI_Comm       subcomm_in = subcomm;
10343   Mat           *matseq;
10344   IS             isrow, iscol;
10345   PetscBool      newsubcomm = PETSC_FALSE;
10346 
10347   PetscFunctionBegin;
10348   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10349   if (nsubcomm && reuse == MAT_REUSE_MATRIX) {
10350     PetscAssertPointer(*matredundant, 5);
10351     PetscValidHeaderSpecific(*matredundant, MAT_CLASSID, 5);
10352   }
10353 
10354   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
10355   if (size == 1 || nsubcomm == 1) {
10356     if (reuse == MAT_INITIAL_MATRIX) {
10357       PetscCall(MatDuplicate(mat, MAT_COPY_VALUES, matredundant));
10358     } else {
10359       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");
10360       PetscCall(MatCopy(mat, *matredundant, SAME_NONZERO_PATTERN));
10361     }
10362     PetscFunctionReturn(PETSC_SUCCESS);
10363   }
10364 
10365   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10366   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10367   MatCheckPreallocated(mat, 1);
10368 
10369   PetscCall(PetscLogEventBegin(MAT_RedundantMat, mat, 0, 0, 0));
10370   if (subcomm_in == MPI_COMM_NULL && reuse == MAT_INITIAL_MATRIX) { /* get subcomm if user does not provide subcomm */
10371     /* create psubcomm, then get subcomm */
10372     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10373     PetscCallMPI(MPI_Comm_size(comm, &size));
10374     PetscCheck(nsubcomm >= 1 && nsubcomm <= size, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "nsubcomm must between 1 and %d", size);
10375 
10376     PetscCall(PetscSubcommCreate(comm, &psubcomm));
10377     PetscCall(PetscSubcommSetNumber(psubcomm, nsubcomm));
10378     PetscCall(PetscSubcommSetType(psubcomm, PETSC_SUBCOMM_CONTIGUOUS));
10379     PetscCall(PetscSubcommSetFromOptions(psubcomm));
10380     PetscCall(PetscCommDuplicate(PetscSubcommChild(psubcomm), &subcomm, NULL));
10381     newsubcomm = PETSC_TRUE;
10382     PetscCall(PetscSubcommDestroy(&psubcomm));
10383   }
10384 
10385   /* get isrow, iscol and a local sequential matrix matseq[0] */
10386   if (reuse == MAT_INITIAL_MATRIX) {
10387     mloc_sub = PETSC_DECIDE;
10388     nloc_sub = PETSC_DECIDE;
10389     if (bs < 1) {
10390       PetscCall(PetscSplitOwnership(subcomm, &mloc_sub, &M));
10391       PetscCall(PetscSplitOwnership(subcomm, &nloc_sub, &N));
10392     } else {
10393       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &mloc_sub, &M));
10394       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &nloc_sub, &N));
10395     }
10396     PetscCallMPI(MPI_Scan(&mloc_sub, &rend, 1, MPIU_INT, MPI_SUM, subcomm));
10397     rstart = rend - mloc_sub;
10398     PetscCall(ISCreateStride(PETSC_COMM_SELF, mloc_sub, rstart, 1, &isrow));
10399     PetscCall(ISCreateStride(PETSC_COMM_SELF, N, 0, 1, &iscol));
10400     PetscCall(ISSetIdentity(iscol));
10401   } else { /* reuse == MAT_REUSE_MATRIX */
10402     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");
10403     /* retrieve subcomm */
10404     PetscCall(PetscObjectGetComm((PetscObject)*matredundant, &subcomm));
10405     redund = (*matredundant)->redundant;
10406     isrow  = redund->isrow;
10407     iscol  = redund->iscol;
10408     matseq = redund->matseq;
10409   }
10410   PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscol, reuse, &matseq));
10411 
10412   /* get matredundant over subcomm */
10413   if (reuse == MAT_INITIAL_MATRIX) {
10414     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], nloc_sub, reuse, matredundant));
10415 
10416     /* create a supporting struct and attach it to C for reuse */
10417     PetscCall(PetscNew(&redund));
10418     (*matredundant)->redundant = redund;
10419     redund->isrow              = isrow;
10420     redund->iscol              = iscol;
10421     redund->matseq             = matseq;
10422     if (newsubcomm) {
10423       redund->subcomm = subcomm;
10424     } else {
10425       redund->subcomm = MPI_COMM_NULL;
10426     }
10427   } else {
10428     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], PETSC_DECIDE, reuse, matredundant));
10429   }
10430 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
10431   if (matseq[0]->boundtocpu && matseq[0]->bindingpropagates) {
10432     PetscCall(MatBindToCPU(*matredundant, PETSC_TRUE));
10433     PetscCall(MatSetBindingPropagates(*matredundant, PETSC_TRUE));
10434   }
10435 #endif
10436   PetscCall(PetscLogEventEnd(MAT_RedundantMat, mat, 0, 0, 0));
10437   PetscFunctionReturn(PETSC_SUCCESS);
10438 }
10439 
10440 /*@C
10441   MatGetMultiProcBlock - Create multiple 'parallel submatrices' from
10442   a given `Mat`. Each submatrix can span multiple procs.
10443 
10444   Collective
10445 
10446   Input Parameters:
10447 + mat     - the matrix
10448 . subComm - the sub communicator obtained as if by `MPI_Comm_split(PetscObjectComm((PetscObject)mat))`
10449 - scall   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10450 
10451   Output Parameter:
10452 . subMat - parallel sub-matrices each spanning a given `subcomm`
10453 
10454   Level: advanced
10455 
10456   Notes:
10457   The submatrix partition across processors is dictated by `subComm` a
10458   communicator obtained by `MPI_comm_split()` or via `PetscSubcommCreate()`. The `subComm`
10459   is not restricted to be grouped with consecutive original MPI processes.
10460 
10461   Due the `MPI_Comm_split()` usage, the parallel layout of the submatrices
10462   map directly to the layout of the original matrix [wrt the local
10463   row,col partitioning]. So the original 'DiagonalMat' naturally maps
10464   into the 'DiagonalMat' of the `subMat`, hence it is used directly from
10465   the `subMat`. However the offDiagMat looses some columns - and this is
10466   reconstructed with `MatSetValues()`
10467 
10468   This is used by `PCBJACOBI` when a single block spans multiple MPI processes.
10469 
10470 .seealso: [](ch_matrices), `Mat`, `MatCreateRedundantMatrix()`, `MatCreateSubMatrices()`, `PCBJACOBI`
10471 @*/
10472 PetscErrorCode MatGetMultiProcBlock(Mat mat, MPI_Comm subComm, MatReuse scall, Mat *subMat)
10473 {
10474   PetscMPIInt commsize, subCommSize;
10475 
10476   PetscFunctionBegin;
10477   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &commsize));
10478   PetscCallMPI(MPI_Comm_size(subComm, &subCommSize));
10479   PetscCheck(subCommSize <= commsize, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "CommSize %d < SubCommZize %d", commsize, subCommSize);
10480 
10481   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");
10482   PetscCall(PetscLogEventBegin(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10483   PetscUseTypeMethod(mat, getmultiprocblock, subComm, scall, subMat);
10484   PetscCall(PetscLogEventEnd(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10485   PetscFunctionReturn(PETSC_SUCCESS);
10486 }
10487 
10488 /*@
10489   MatGetLocalSubMatrix - Gets a reference to a submatrix specified in local numbering
10490 
10491   Not Collective
10492 
10493   Input Parameters:
10494 + mat   - matrix to extract local submatrix from
10495 . isrow - local row indices for submatrix
10496 - iscol - local column indices for submatrix
10497 
10498   Output Parameter:
10499 . submat - the submatrix
10500 
10501   Level: intermediate
10502 
10503   Notes:
10504   `submat` should be disposed of with `MatRestoreLocalSubMatrix()`.
10505 
10506   Depending on the format of `mat`, the returned `submat` may not implement `MatMult()`.  Its communicator may be
10507   the same as `mat`, it may be `PETSC_COMM_SELF`, or some other sub-communictor of `mat`'s.
10508 
10509   `submat` always implements `MatSetValuesLocal()`.  If `isrow` and `iscol` have the same block size, then
10510   `MatSetValuesBlockedLocal()` will also be implemented.
10511 
10512   `mat` must have had a `ISLocalToGlobalMapping` provided to it with `MatSetLocalToGlobalMapping()`.
10513   Matrices obtained with `DMCreateMatrix()` generally already have the local to global mapping provided.
10514 
10515 .seealso: [](ch_matrices), `Mat`, `MatRestoreLocalSubMatrix()`, `MatCreateLocalRef()`, `MatSetLocalToGlobalMapping()`
10516 @*/
10517 PetscErrorCode MatGetLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10518 {
10519   PetscFunctionBegin;
10520   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10521   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10522   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10523   PetscCheckSameComm(isrow, 2, iscol, 3);
10524   PetscAssertPointer(submat, 4);
10525   PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must have local to global mapping provided before this call");
10526 
10527   if (mat->ops->getlocalsubmatrix) {
10528     PetscUseTypeMethod(mat, getlocalsubmatrix, isrow, iscol, submat);
10529   } else {
10530     PetscCall(MatCreateLocalRef(mat, isrow, iscol, submat));
10531   }
10532   PetscFunctionReturn(PETSC_SUCCESS);
10533 }
10534 
10535 /*@
10536   MatRestoreLocalSubMatrix - Restores a reference to a submatrix specified in local numbering obtained with `MatGetLocalSubMatrix()`
10537 
10538   Not Collective
10539 
10540   Input Parameters:
10541 + mat    - matrix to extract local submatrix from
10542 . isrow  - local row indices for submatrix
10543 . iscol  - local column indices for submatrix
10544 - submat - the submatrix
10545 
10546   Level: intermediate
10547 
10548 .seealso: [](ch_matrices), `Mat`, `MatGetLocalSubMatrix()`
10549 @*/
10550 PetscErrorCode MatRestoreLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10551 {
10552   PetscFunctionBegin;
10553   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10554   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10555   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10556   PetscCheckSameComm(isrow, 2, iscol, 3);
10557   PetscAssertPointer(submat, 4);
10558   if (*submat) PetscValidHeaderSpecific(*submat, MAT_CLASSID, 4);
10559 
10560   if (mat->ops->restorelocalsubmatrix) {
10561     PetscUseTypeMethod(mat, restorelocalsubmatrix, isrow, iscol, submat);
10562   } else {
10563     PetscCall(MatDestroy(submat));
10564   }
10565   *submat = NULL;
10566   PetscFunctionReturn(PETSC_SUCCESS);
10567 }
10568 
10569 /*@
10570   MatFindZeroDiagonals - Finds all the rows of a matrix that have zero or no diagonal entry in the matrix
10571 
10572   Collective
10573 
10574   Input Parameter:
10575 . mat - the matrix
10576 
10577   Output Parameter:
10578 . is - if any rows have zero diagonals this contains the list of them
10579 
10580   Level: developer
10581 
10582 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10583 @*/
10584 PetscErrorCode MatFindZeroDiagonals(Mat mat, IS *is)
10585 {
10586   PetscFunctionBegin;
10587   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10588   PetscValidType(mat, 1);
10589   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10590   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10591 
10592   if (!mat->ops->findzerodiagonals) {
10593     Vec                diag;
10594     const PetscScalar *a;
10595     PetscInt          *rows;
10596     PetscInt           rStart, rEnd, r, nrow = 0;
10597 
10598     PetscCall(MatCreateVecs(mat, &diag, NULL));
10599     PetscCall(MatGetDiagonal(mat, diag));
10600     PetscCall(MatGetOwnershipRange(mat, &rStart, &rEnd));
10601     PetscCall(VecGetArrayRead(diag, &a));
10602     for (r = 0; r < rEnd - rStart; ++r)
10603       if (a[r] == 0.0) ++nrow;
10604     PetscCall(PetscMalloc1(nrow, &rows));
10605     nrow = 0;
10606     for (r = 0; r < rEnd - rStart; ++r)
10607       if (a[r] == 0.0) rows[nrow++] = r + rStart;
10608     PetscCall(VecRestoreArrayRead(diag, &a));
10609     PetscCall(VecDestroy(&diag));
10610     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nrow, rows, PETSC_OWN_POINTER, is));
10611   } else {
10612     PetscUseTypeMethod(mat, findzerodiagonals, is);
10613   }
10614   PetscFunctionReturn(PETSC_SUCCESS);
10615 }
10616 
10617 /*@
10618   MatFindOffBlockDiagonalEntries - Finds all the rows of a matrix that have entries outside of the main diagonal block (defined by the matrix block size)
10619 
10620   Collective
10621 
10622   Input Parameter:
10623 . mat - the matrix
10624 
10625   Output Parameter:
10626 . is - contains the list of rows with off block diagonal entries
10627 
10628   Level: developer
10629 
10630 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10631 @*/
10632 PetscErrorCode MatFindOffBlockDiagonalEntries(Mat mat, IS *is)
10633 {
10634   PetscFunctionBegin;
10635   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10636   PetscValidType(mat, 1);
10637   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10638   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10639 
10640   PetscUseTypeMethod(mat, findoffblockdiagonalentries, is);
10641   PetscFunctionReturn(PETSC_SUCCESS);
10642 }
10643 
10644 /*@C
10645   MatInvertBlockDiagonal - Inverts the block diagonal entries.
10646 
10647   Collective; No Fortran Support
10648 
10649   Input Parameter:
10650 . mat - the matrix
10651 
10652   Output Parameter:
10653 . values - the block inverses in column major order (FORTRAN-like)
10654 
10655   Level: advanced
10656 
10657   Notes:
10658   The size of the blocks is determined by the block size of the matrix.
10659 
10660   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10661 
10662   The blocks all have the same size, use `MatInvertVariableBlockDiagonal()` for variable block size
10663 
10664 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatInvertBlockDiagonalMat()`
10665 @*/
10666 PetscErrorCode MatInvertBlockDiagonal(Mat mat, const PetscScalar *values[])
10667 {
10668   PetscFunctionBegin;
10669   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10670   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10671   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10672   PetscUseTypeMethod(mat, invertblockdiagonal, values);
10673   PetscFunctionReturn(PETSC_SUCCESS);
10674 }
10675 
10676 /*@
10677   MatInvertVariableBlockDiagonal - Inverts the point block diagonal entries.
10678 
10679   Collective; No Fortran Support
10680 
10681   Input Parameters:
10682 + mat     - the matrix
10683 . nblocks - the number of blocks on the process, set with `MatSetVariableBlockSizes()`
10684 - bsizes  - the size of each block on the process, set with `MatSetVariableBlockSizes()`
10685 
10686   Output Parameter:
10687 . values - the block inverses in column major order (FORTRAN-like)
10688 
10689   Level: advanced
10690 
10691   Notes:
10692   Use `MatInvertBlockDiagonal()` if all blocks have the same size
10693 
10694   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10695 
10696 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatSetVariableBlockSizes()`, `MatInvertVariableBlockEnvelope()`
10697 @*/
10698 PetscErrorCode MatInvertVariableBlockDiagonal(Mat mat, PetscInt nblocks, const PetscInt bsizes[], PetscScalar values[])
10699 {
10700   PetscFunctionBegin;
10701   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10702   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10703   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10704   PetscUseTypeMethod(mat, invertvariableblockdiagonal, nblocks, bsizes, values);
10705   PetscFunctionReturn(PETSC_SUCCESS);
10706 }
10707 
10708 /*@
10709   MatInvertBlockDiagonalMat - set the values of matrix C to be the inverted block diagonal of matrix A
10710 
10711   Collective
10712 
10713   Input Parameters:
10714 + A - the matrix
10715 - C - matrix with inverted block diagonal of `A`.  This matrix should be created and may have its type set.
10716 
10717   Level: advanced
10718 
10719   Note:
10720   The blocksize of the matrix is used to determine the blocks on the diagonal of `C`
10721 
10722 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`
10723 @*/
10724 PetscErrorCode MatInvertBlockDiagonalMat(Mat A, Mat C)
10725 {
10726   const PetscScalar *vals;
10727   PetscInt          *dnnz;
10728   PetscInt           m, rstart, rend, bs, i, j;
10729 
10730   PetscFunctionBegin;
10731   PetscCall(MatInvertBlockDiagonal(A, &vals));
10732   PetscCall(MatGetBlockSize(A, &bs));
10733   PetscCall(MatGetLocalSize(A, &m, NULL));
10734   PetscCall(MatSetLayouts(C, A->rmap, A->cmap));
10735   PetscCall(MatSetBlockSizes(C, A->rmap->bs, A->cmap->bs));
10736   PetscCall(PetscMalloc1(m / bs, &dnnz));
10737   for (j = 0; j < m / bs; j++) dnnz[j] = 1;
10738   PetscCall(MatXAIJSetPreallocation(C, bs, dnnz, NULL, NULL, NULL));
10739   PetscCall(PetscFree(dnnz));
10740   PetscCall(MatGetOwnershipRange(C, &rstart, &rend));
10741   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_FALSE));
10742   for (i = rstart / bs; i < rend / bs; i++) PetscCall(MatSetValuesBlocked(C, 1, &i, 1, &i, &vals[(i - rstart / bs) * bs * bs], INSERT_VALUES));
10743   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
10744   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
10745   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_TRUE));
10746   PetscFunctionReturn(PETSC_SUCCESS);
10747 }
10748 
10749 /*@
10750   MatTransposeColoringDestroy - Destroys a coloring context for matrix product $C = A*B^T$ that was created
10751   via `MatTransposeColoringCreate()`.
10752 
10753   Collective
10754 
10755   Input Parameter:
10756 . c - coloring context
10757 
10758   Level: intermediate
10759 
10760 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`
10761 @*/
10762 PetscErrorCode MatTransposeColoringDestroy(MatTransposeColoring *c)
10763 {
10764   MatTransposeColoring matcolor = *c;
10765 
10766   PetscFunctionBegin;
10767   if (!matcolor) PetscFunctionReturn(PETSC_SUCCESS);
10768   if (--((PetscObject)matcolor)->refct > 0) {
10769     matcolor = NULL;
10770     PetscFunctionReturn(PETSC_SUCCESS);
10771   }
10772 
10773   PetscCall(PetscFree3(matcolor->ncolumns, matcolor->nrows, matcolor->colorforrow));
10774   PetscCall(PetscFree(matcolor->rows));
10775   PetscCall(PetscFree(matcolor->den2sp));
10776   PetscCall(PetscFree(matcolor->colorforcol));
10777   PetscCall(PetscFree(matcolor->columns));
10778   if (matcolor->brows > 0) PetscCall(PetscFree(matcolor->lstart));
10779   PetscCall(PetscHeaderDestroy(c));
10780   PetscFunctionReturn(PETSC_SUCCESS);
10781 }
10782 
10783 /*@
10784   MatTransColoringApplySpToDen - Given a symbolic matrix product $C = A*B^T$ for which
10785   a `MatTransposeColoring` context has been created, computes a dense $B^T$ by applying
10786   `MatTransposeColoring` to sparse `B`.
10787 
10788   Collective
10789 
10790   Input Parameters:
10791 + coloring - coloring context created with `MatTransposeColoringCreate()`
10792 - B        - sparse matrix
10793 
10794   Output Parameter:
10795 . Btdense - dense matrix $B^T$
10796 
10797   Level: developer
10798 
10799   Note:
10800   These are used internally for some implementations of `MatRARt()`
10801 
10802 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplyDenToSp()`
10803 @*/
10804 PetscErrorCode MatTransColoringApplySpToDen(MatTransposeColoring coloring, Mat B, Mat Btdense)
10805 {
10806   PetscFunctionBegin;
10807   PetscValidHeaderSpecific(coloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
10808   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
10809   PetscValidHeaderSpecific(Btdense, MAT_CLASSID, 3);
10810 
10811   PetscCall((*B->ops->transcoloringapplysptoden)(coloring, B, Btdense));
10812   PetscFunctionReturn(PETSC_SUCCESS);
10813 }
10814 
10815 /*@
10816   MatTransColoringApplyDenToSp - Given a symbolic matrix product $C_{sp} = A*B^T$ for which
10817   a `MatTransposeColoring` context has been created and a dense matrix $C_{den} = A*B^T_{dense}$
10818   in which `B^T_{dens}` is obtained from `MatTransColoringApplySpToDen()`, recover sparse matrix
10819   $C_{sp}$ from $C_{den}$.
10820 
10821   Collective
10822 
10823   Input Parameters:
10824 + matcoloring - coloring context created with `MatTransposeColoringCreate()`
10825 - Cden        - matrix product of a sparse matrix and a dense matrix Btdense
10826 
10827   Output Parameter:
10828 . Csp - sparse matrix
10829 
10830   Level: developer
10831 
10832   Note:
10833   These are used internally for some implementations of `MatRARt()`
10834 
10835 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`
10836 @*/
10837 PetscErrorCode MatTransColoringApplyDenToSp(MatTransposeColoring matcoloring, Mat Cden, Mat Csp)
10838 {
10839   PetscFunctionBegin;
10840   PetscValidHeaderSpecific(matcoloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
10841   PetscValidHeaderSpecific(Cden, MAT_CLASSID, 2);
10842   PetscValidHeaderSpecific(Csp, MAT_CLASSID, 3);
10843 
10844   PetscCall((*Csp->ops->transcoloringapplydentosp)(matcoloring, Cden, Csp));
10845   PetscCall(MatAssemblyBegin(Csp, MAT_FINAL_ASSEMBLY));
10846   PetscCall(MatAssemblyEnd(Csp, MAT_FINAL_ASSEMBLY));
10847   PetscFunctionReturn(PETSC_SUCCESS);
10848 }
10849 
10850 /*@
10851   MatTransposeColoringCreate - Creates a matrix coloring context for the matrix product $C = A*B^T$.
10852 
10853   Collective
10854 
10855   Input Parameters:
10856 + mat        - the matrix product C
10857 - iscoloring - the coloring of the matrix; usually obtained with `MatColoringCreate()` or `DMCreateColoring()`
10858 
10859   Output Parameter:
10860 . color - the new coloring context
10861 
10862   Level: intermediate
10863 
10864 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`,
10865           `MatTransColoringApplyDenToSp()`
10866 @*/
10867 PetscErrorCode MatTransposeColoringCreate(Mat mat, ISColoring iscoloring, MatTransposeColoring *color)
10868 {
10869   MatTransposeColoring c;
10870   MPI_Comm             comm;
10871 
10872   PetscFunctionBegin;
10873   PetscAssertPointer(color, 3);
10874 
10875   PetscCall(PetscLogEventBegin(MAT_TransposeColoringCreate, mat, 0, 0, 0));
10876   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10877   PetscCall(PetscHeaderCreate(c, MAT_TRANSPOSECOLORING_CLASSID, "MatTransposeColoring", "Matrix product C=A*B^T via coloring", "Mat", comm, MatTransposeColoringDestroy, NULL));
10878   c->ctype = iscoloring->ctype;
10879   PetscUseTypeMethod(mat, transposecoloringcreate, iscoloring, c);
10880   *color = c;
10881   PetscCall(PetscLogEventEnd(MAT_TransposeColoringCreate, mat, 0, 0, 0));
10882   PetscFunctionReturn(PETSC_SUCCESS);
10883 }
10884 
10885 /*@
10886   MatGetNonzeroState - Returns a 64-bit integer representing the current state of nonzeros in the matrix. If the
10887   matrix has had new nonzero locations added to (or removed from) the matrix since the previous call, the value will be larger.
10888 
10889   Not Collective
10890 
10891   Input Parameter:
10892 . mat - the matrix
10893 
10894   Output Parameter:
10895 . state - the current state
10896 
10897   Level: intermediate
10898 
10899   Notes:
10900   You can only compare states from two different calls to the SAME matrix, you cannot compare calls between
10901   different matrices
10902 
10903   Use `PetscObjectStateGet()` to check for changes to the numerical values in a matrix
10904 
10905   Use the result of `PetscObjectGetId()` to compare if a previously checked matrix is the same as the current matrix, do not compare object pointers.
10906 
10907 .seealso: [](ch_matrices), `Mat`, `PetscObjectStateGet()`, `PetscObjectGetId()`
10908 @*/
10909 PetscErrorCode MatGetNonzeroState(Mat mat, PetscObjectState *state)
10910 {
10911   PetscFunctionBegin;
10912   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10913   *state = mat->nonzerostate;
10914   PetscFunctionReturn(PETSC_SUCCESS);
10915 }
10916 
10917 /*@
10918   MatCreateMPIMatConcatenateSeqMat - Creates a single large PETSc matrix by concatenating sequential
10919   matrices from each processor
10920 
10921   Collective
10922 
10923   Input Parameters:
10924 + comm   - the communicators the parallel matrix will live on
10925 . seqmat - the input sequential matrices
10926 . n      - number of local columns (or `PETSC_DECIDE`)
10927 - reuse  - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10928 
10929   Output Parameter:
10930 . mpimat - the parallel matrix generated
10931 
10932   Level: developer
10933 
10934   Note:
10935   The number of columns of the matrix in EACH processor MUST be the same.
10936 
10937 .seealso: [](ch_matrices), `Mat`
10938 @*/
10939 PetscErrorCode MatCreateMPIMatConcatenateSeqMat(MPI_Comm comm, Mat seqmat, PetscInt n, MatReuse reuse, Mat *mpimat)
10940 {
10941   PetscMPIInt size;
10942 
10943   PetscFunctionBegin;
10944   PetscCallMPI(MPI_Comm_size(comm, &size));
10945   if (size == 1) {
10946     if (reuse == MAT_INITIAL_MATRIX) {
10947       PetscCall(MatDuplicate(seqmat, MAT_COPY_VALUES, mpimat));
10948     } else {
10949       PetscCall(MatCopy(seqmat, *mpimat, SAME_NONZERO_PATTERN));
10950     }
10951     PetscFunctionReturn(PETSC_SUCCESS);
10952   }
10953 
10954   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");
10955 
10956   PetscCall(PetscLogEventBegin(MAT_Merge, seqmat, 0, 0, 0));
10957   PetscCall((*seqmat->ops->creatempimatconcatenateseqmat)(comm, seqmat, n, reuse, mpimat));
10958   PetscCall(PetscLogEventEnd(MAT_Merge, seqmat, 0, 0, 0));
10959   PetscFunctionReturn(PETSC_SUCCESS);
10960 }
10961 
10962 /*@
10963   MatSubdomainsCreateCoalesce - Creates index subdomains by coalescing adjacent MPI processes' ownership ranges.
10964 
10965   Collective
10966 
10967   Input Parameters:
10968 + A - the matrix to create subdomains from
10969 - N - requested number of subdomains
10970 
10971   Output Parameters:
10972 + n   - number of subdomains resulting on this MPI process
10973 - iss - `IS` list with indices of subdomains on this MPI process
10974 
10975   Level: advanced
10976 
10977   Note:
10978   The number of subdomains must be smaller than the communicator size
10979 
10980 .seealso: [](ch_matrices), `Mat`, `IS`
10981 @*/
10982 PetscErrorCode MatSubdomainsCreateCoalesce(Mat A, PetscInt N, PetscInt *n, IS *iss[])
10983 {
10984   MPI_Comm    comm, subcomm;
10985   PetscMPIInt size, rank, color;
10986   PetscInt    rstart, rend, k;
10987 
10988   PetscFunctionBegin;
10989   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
10990   PetscCallMPI(MPI_Comm_size(comm, &size));
10991   PetscCallMPI(MPI_Comm_rank(comm, &rank));
10992   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);
10993   *n    = 1;
10994   k     = size / N + (size % N > 0); /* There are up to k ranks to a color */
10995   color = rank / k;
10996   PetscCallMPI(MPI_Comm_split(comm, color, rank, &subcomm));
10997   PetscCall(PetscMalloc1(1, iss));
10998   PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
10999   PetscCall(ISCreateStride(subcomm, rend - rstart, rstart, 1, iss[0]));
11000   PetscCallMPI(MPI_Comm_free(&subcomm));
11001   PetscFunctionReturn(PETSC_SUCCESS);
11002 }
11003 
11004 /*@
11005   MatGalerkin - Constructs the coarse grid problem matrix via Galerkin projection.
11006 
11007   If the interpolation and restriction operators are the same, uses `MatPtAP()`.
11008   If they are not the same, uses `MatMatMatMult()`.
11009 
11010   Once the coarse grid problem is constructed, correct for interpolation operators
11011   that are not of full rank, which can legitimately happen in the case of non-nested
11012   geometric multigrid.
11013 
11014   Input Parameters:
11015 + restrct     - restriction operator
11016 . dA          - fine grid matrix
11017 . interpolate - interpolation operator
11018 . reuse       - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
11019 - fill        - expected fill, use `PETSC_DETERMINE` or `PETSC_DETERMINE` if you do not have a good estimate
11020 
11021   Output Parameter:
11022 . A - the Galerkin coarse matrix
11023 
11024   Options Database Key:
11025 . -pc_mg_galerkin <both,pmat,mat,none> - for what matrices the Galerkin process should be used
11026 
11027   Level: developer
11028 
11029   Note:
11030   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
11031 
11032 .seealso: [](ch_matrices), `Mat`, `MatPtAP()`, `MatMatMatMult()`
11033 @*/
11034 PetscErrorCode MatGalerkin(Mat restrct, Mat dA, Mat interpolate, MatReuse reuse, PetscReal fill, Mat *A)
11035 {
11036   IS  zerorows;
11037   Vec diag;
11038 
11039   PetscFunctionBegin;
11040   PetscCheck(reuse != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
11041   /* Construct the coarse grid matrix */
11042   if (interpolate == restrct) {
11043     PetscCall(MatPtAP(dA, interpolate, reuse, fill, A));
11044   } else {
11045     PetscCall(MatMatMatMult(restrct, dA, interpolate, reuse, fill, A));
11046   }
11047 
11048   /* If the interpolation matrix is not of full rank, A will have zero rows.
11049      This can legitimately happen in the case of non-nested geometric multigrid.
11050      In that event, we set the rows of the matrix to the rows of the identity,
11051      ignoring the equations (as the RHS will also be zero). */
11052 
11053   PetscCall(MatFindZeroRows(*A, &zerorows));
11054 
11055   if (zerorows != NULL) { /* if there are any zero rows */
11056     PetscCall(MatCreateVecs(*A, &diag, NULL));
11057     PetscCall(MatGetDiagonal(*A, diag));
11058     PetscCall(VecISSet(diag, zerorows, 1.0));
11059     PetscCall(MatDiagonalSet(*A, diag, INSERT_VALUES));
11060     PetscCall(VecDestroy(&diag));
11061     PetscCall(ISDestroy(&zerorows));
11062   }
11063   PetscFunctionReturn(PETSC_SUCCESS);
11064 }
11065 
11066 /*@C
11067   MatSetOperation - Allows user to set a matrix operation for any matrix type
11068 
11069   Logically Collective
11070 
11071   Input Parameters:
11072 + mat - the matrix
11073 . op  - the name of the operation
11074 - f   - the function that provides the operation
11075 
11076   Level: developer
11077 
11078   Example Usage:
11079 .vb
11080   extern PetscErrorCode usermult(Mat, Vec, Vec);
11081 
11082   PetscCall(MatCreateXXX(comm, ..., &A));
11083   PetscCall(MatSetOperation(A, MATOP_MULT, (PetscVoidFn *)usermult));
11084 .ve
11085 
11086   Notes:
11087   See the file `include/petscmat.h` for a complete list of matrix
11088   operations, which all have the form MATOP_<OPERATION>, where
11089   <OPERATION> is the name (in all capital letters) of the
11090   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11091 
11092   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
11093   sequence as the usual matrix interface routines, since they
11094   are intended to be accessed via the usual matrix interface
11095   routines, e.g.,
11096 .vb
11097   MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
11098 .ve
11099 
11100   In particular each function MUST return `PETSC_SUCCESS` on success and
11101   nonzero on failure.
11102 
11103   This routine is distinct from `MatShellSetOperation()` in that it can be called on any matrix type.
11104 
11105 .seealso: [](ch_matrices), `Mat`, `MatGetOperation()`, `MatCreateShell()`, `MatShellSetContext()`, `MatShellSetOperation()`
11106 @*/
11107 PetscErrorCode MatSetOperation(Mat mat, MatOperation op, void (*f)(void))
11108 {
11109   PetscFunctionBegin;
11110   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11111   if (op == MATOP_VIEW && !mat->ops->viewnative && f != (void (*)(void))mat->ops->view) mat->ops->viewnative = mat->ops->view;
11112   (((void (**)(void))mat->ops)[op]) = f;
11113   PetscFunctionReturn(PETSC_SUCCESS);
11114 }
11115 
11116 /*@C
11117   MatGetOperation - Gets a matrix operation for any matrix type.
11118 
11119   Not Collective
11120 
11121   Input Parameters:
11122 + mat - the matrix
11123 - op  - the name of the operation
11124 
11125   Output Parameter:
11126 . f - the function that provides the operation
11127 
11128   Level: developer
11129 
11130   Example Usage:
11131 .vb
11132   PetscErrorCode (*usermult)(Mat, Vec, Vec);
11133 
11134   MatGetOperation(A, MATOP_MULT, (void (**)(void))&usermult);
11135 .ve
11136 
11137   Notes:
11138   See the file include/petscmat.h for a complete list of matrix
11139   operations, which all have the form MATOP_<OPERATION>, where
11140   <OPERATION> is the name (in all capital letters) of the
11141   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11142 
11143   This routine is distinct from `MatShellGetOperation()` in that it can be called on any matrix type.
11144 
11145 .seealso: [](ch_matrices), `Mat`, `MatSetOperation()`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
11146 @*/
11147 PetscErrorCode MatGetOperation(Mat mat, MatOperation op, void (**f)(void))
11148 {
11149   PetscFunctionBegin;
11150   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11151   *f = (((void (**)(void))mat->ops)[op]);
11152   PetscFunctionReturn(PETSC_SUCCESS);
11153 }
11154 
11155 /*@
11156   MatHasOperation - Determines whether the given matrix supports the particular operation.
11157 
11158   Not Collective
11159 
11160   Input Parameters:
11161 + mat - the matrix
11162 - op  - the operation, for example, `MATOP_GET_DIAGONAL`
11163 
11164   Output Parameter:
11165 . has - either `PETSC_TRUE` or `PETSC_FALSE`
11166 
11167   Level: advanced
11168 
11169   Note:
11170   See `MatSetOperation()` for additional discussion on naming convention and usage of `op`.
11171 
11172 .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`, `MatGetOperation()`, `MatSetOperation()`
11173 @*/
11174 PetscErrorCode MatHasOperation(Mat mat, MatOperation op, PetscBool *has)
11175 {
11176   PetscFunctionBegin;
11177   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11178   PetscAssertPointer(has, 3);
11179   if (mat->ops->hasoperation) {
11180     PetscUseTypeMethod(mat, hasoperation, op, has);
11181   } else {
11182     if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
11183     else {
11184       *has = PETSC_FALSE;
11185       if (op == MATOP_CREATE_SUBMATRIX) {
11186         PetscMPIInt size;
11187 
11188         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
11189         if (size == 1) PetscCall(MatHasOperation(mat, MATOP_CREATE_SUBMATRICES, has));
11190       }
11191     }
11192   }
11193   PetscFunctionReturn(PETSC_SUCCESS);
11194 }
11195 
11196 /*@
11197   MatHasCongruentLayouts - Determines whether the rows and columns layouts of the matrix are congruent
11198 
11199   Collective
11200 
11201   Input Parameter:
11202 . mat - the matrix
11203 
11204   Output Parameter:
11205 . cong - either `PETSC_TRUE` or `PETSC_FALSE`
11206 
11207   Level: beginner
11208 
11209 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatSetSizes()`, `PetscLayout`
11210 @*/
11211 PetscErrorCode MatHasCongruentLayouts(Mat mat, PetscBool *cong)
11212 {
11213   PetscFunctionBegin;
11214   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11215   PetscValidType(mat, 1);
11216   PetscAssertPointer(cong, 2);
11217   if (!mat->rmap || !mat->cmap) {
11218     *cong = mat->rmap == mat->cmap ? PETSC_TRUE : PETSC_FALSE;
11219     PetscFunctionReturn(PETSC_SUCCESS);
11220   }
11221   if (mat->congruentlayouts == PETSC_DECIDE) { /* first time we compare rows and cols layouts */
11222     PetscCall(PetscLayoutSetUp(mat->rmap));
11223     PetscCall(PetscLayoutSetUp(mat->cmap));
11224     PetscCall(PetscLayoutCompare(mat->rmap, mat->cmap, cong));
11225     if (*cong) mat->congruentlayouts = 1;
11226     else mat->congruentlayouts = 0;
11227   } else *cong = mat->congruentlayouts ? PETSC_TRUE : PETSC_FALSE;
11228   PetscFunctionReturn(PETSC_SUCCESS);
11229 }
11230 
11231 PetscErrorCode MatSetInf(Mat A)
11232 {
11233   PetscFunctionBegin;
11234   PetscUseTypeMethod(A, setinf);
11235   PetscFunctionReturn(PETSC_SUCCESS);
11236 }
11237 
11238 /*@
11239   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
11240   and possibly removes small values from the graph structure.
11241 
11242   Collective
11243 
11244   Input Parameters:
11245 + A       - the matrix
11246 . sym     - `PETSC_TRUE` indicates that the graph should be symmetrized
11247 . scale   - `PETSC_TRUE` indicates that the graph edge weights should be symmetrically scaled with the diagonal entry
11248 . filter  - filter value - < 0: does nothing; == 0: removes only 0.0 entries; otherwise: removes entries with abs(entries) <= value
11249 . num_idx - size of 'index' array
11250 - index   - array of block indices to use for graph strength of connection weight
11251 
11252   Output Parameter:
11253 . graph - the resulting graph
11254 
11255   Level: advanced
11256 
11257 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PCGAMG`
11258 @*/
11259 PetscErrorCode MatCreateGraph(Mat A, PetscBool sym, PetscBool scale, PetscReal filter, PetscInt num_idx, PetscInt index[], Mat *graph)
11260 {
11261   PetscFunctionBegin;
11262   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11263   PetscValidType(A, 1);
11264   PetscValidLogicalCollectiveBool(A, scale, 3);
11265   PetscAssertPointer(graph, 7);
11266   PetscCall(PetscLogEventBegin(MAT_CreateGraph, A, 0, 0, 0));
11267   PetscUseTypeMethod(A, creategraph, sym, scale, filter, num_idx, index, graph);
11268   PetscCall(PetscLogEventEnd(MAT_CreateGraph, A, 0, 0, 0));
11269   PetscFunctionReturn(PETSC_SUCCESS);
11270 }
11271 
11272 /*@
11273   MatEliminateZeros - eliminate the nondiagonal zero entries in place from the nonzero structure of a sparse `Mat` in place,
11274   meaning the same memory is used for the matrix, and no new memory is allocated.
11275 
11276   Collective
11277 
11278   Input Parameters:
11279 + A    - the matrix
11280 - 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
11281 
11282   Level: intermediate
11283 
11284   Developer Note:
11285   The entries in the sparse matrix data structure are shifted to fill in the unneeded locations in the data. Thus the end
11286   of the arrays in the data structure are unneeded.
11287 
11288 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateGraph()`, `MatFilter()`
11289 @*/
11290 PetscErrorCode MatEliminateZeros(Mat A, PetscBool keep)
11291 {
11292   PetscFunctionBegin;
11293   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11294   PetscUseTypeMethod(A, eliminatezeros, keep);
11295   PetscFunctionReturn(PETSC_SUCCESS);
11296 }
11297