xref: /petsc/src/mat/interface/matrix.c (revision be39004295a98ced168607de69334a8b204d0588)
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   MatSelectVariableBlockSizes - When creating a submatrix, pass on the variable block sizes
7924 
7925   Not Collective
7926 
7927   Input Parameter:
7928 + subA  - the submatrix
7929 . A     - the original matrix
7930 - isrow - The `IS` of selected rows for the submatrix
7931 
7932   Level: developer
7933 
7934 .seealso: [](ch_matrices), `Mat`, `MatSetVariableBlockSizes()`, `MatComputeVariableBlockEnvelope()`
7935 */
7936 static PetscErrorCode MatSelectVariableBlockSizes(Mat subA, Mat A, IS isrow)
7937 {
7938   const PetscInt *rows;
7939   PetscInt        n, rStart, rEnd, Nb = 0;
7940 
7941   PetscFunctionBegin;
7942   if (!A->bsizes) PetscFunctionReturn(PETSC_SUCCESS);
7943   // The IS contains global row numbers, we cannot preserve blocks if it contains off-process entries
7944   PetscCall(MatGetOwnershipRange(A, &rStart, &rEnd));
7945   PetscCall(ISGetIndices(isrow, &rows));
7946   PetscCall(ISGetLocalSize(isrow, &n));
7947   for (PetscInt i = 0; i < n; ++i) {
7948     if (rows[i] < rStart || rows[i] >= rEnd) {
7949       PetscCall(ISRestoreIndices(isrow, &rows));
7950       PetscFunctionReturn(PETSC_SUCCESS);
7951     }
7952   }
7953   for (PetscInt b = 0, gr = rStart, i = 0; b < A->nblocks; ++b) {
7954     PetscBool occupied = PETSC_FALSE;
7955 
7956     for (PetscInt br = 0; br < A->bsizes[b]; ++br) {
7957       const PetscInt row = gr + br;
7958 
7959       if (i == n) break;
7960       if (rows[i] == row) {
7961         occupied = PETSC_TRUE;
7962         ++i;
7963       }
7964       while (i < n && rows[i] < row) ++i;
7965     }
7966     gr += A->bsizes[b];
7967     if (occupied) ++Nb;
7968   }
7969   subA->nblocks = Nb;
7970   PetscCall(PetscFree(subA->bsizes));
7971   PetscCall(PetscMalloc1(subA->nblocks, &subA->bsizes));
7972   PetscInt sb = 0;
7973   for (PetscInt b = 0, gr = rStart, i = 0; b < A->nblocks; ++b) {
7974     if (sb < subA->nblocks) subA->bsizes[sb] = 0;
7975     for (PetscInt br = 0; br < A->bsizes[b]; ++br) {
7976       const PetscInt row = gr + br;
7977 
7978       if (i == n) break;
7979       if (rows[i] == row) {
7980         ++subA->bsizes[sb];
7981         ++i;
7982       }
7983       while (i < n && rows[i] < row) ++i;
7984     }
7985     gr += A->bsizes[b];
7986     if (sb < subA->nblocks && subA->bsizes[sb]) ++sb;
7987   }
7988   PetscCheck(sb == subA->nblocks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of blocks %" PetscInt_FMT " != %" PetscInt_FMT, sb, subA->nblocks);
7989   PetscInt nlocal, ncnt = 0;
7990   PetscCall(MatGetLocalSize(subA, &nlocal, NULL));
7991   PetscCheck(subA->nblocks >= 0 && subA->nblocks <= nlocal, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of local blocks %" PetscInt_FMT " is not in [0, %" PetscInt_FMT "]", subA->nblocks, nlocal);
7992   for (PetscInt i = 0; i < subA->nblocks; i++) ncnt += subA->bsizes[i];
7993   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);
7994   PetscCall(ISRestoreIndices(isrow, &rows));
7995   PetscFunctionReturn(PETSC_SUCCESS);
7996 }
7997 
7998 /*@
7999   MatSetBlockSizes - Sets the matrix block row and column sizes.
8000 
8001   Logically Collective
8002 
8003   Input Parameters:
8004 + mat - the matrix
8005 . rbs - row block size
8006 - cbs - column block size
8007 
8008   Level: intermediate
8009 
8010   Notes:
8011   Block row formats are `MATBAIJ` and  `MATSBAIJ`. These formats ALWAYS have square block storage in the matrix.
8012   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
8013   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
8014 
8015   For `MATAIJ` matrix this function can be called at a later stage, provided that the specified block sizes
8016   are compatible with the matrix local sizes.
8017 
8018   The row and column block size determine the blocksize of the "row" and "column" vectors returned by `MatCreateVecs()`.
8019 
8020 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatGetBlockSizes()`
8021 @*/
8022 PetscErrorCode MatSetBlockSizes(Mat mat, PetscInt rbs, PetscInt cbs)
8023 {
8024   PetscFunctionBegin;
8025   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8026   PetscValidLogicalCollectiveInt(mat, rbs, 2);
8027   PetscValidLogicalCollectiveInt(mat, cbs, 3);
8028   PetscTryTypeMethod(mat, setblocksizes, rbs, cbs);
8029   if (mat->rmap->refcnt) {
8030     ISLocalToGlobalMapping l2g  = NULL;
8031     PetscLayout            nmap = NULL;
8032 
8033     PetscCall(PetscLayoutDuplicate(mat->rmap, &nmap));
8034     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->rmap->mapping, &l2g));
8035     PetscCall(PetscLayoutDestroy(&mat->rmap));
8036     mat->rmap          = nmap;
8037     mat->rmap->mapping = l2g;
8038   }
8039   if (mat->cmap->refcnt) {
8040     ISLocalToGlobalMapping l2g  = NULL;
8041     PetscLayout            nmap = NULL;
8042 
8043     PetscCall(PetscLayoutDuplicate(mat->cmap, &nmap));
8044     if (mat->cmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->cmap->mapping, &l2g));
8045     PetscCall(PetscLayoutDestroy(&mat->cmap));
8046     mat->cmap          = nmap;
8047     mat->cmap->mapping = l2g;
8048   }
8049   PetscCall(PetscLayoutSetBlockSize(mat->rmap, rbs));
8050   PetscCall(PetscLayoutSetBlockSize(mat->cmap, cbs));
8051   PetscFunctionReturn(PETSC_SUCCESS);
8052 }
8053 
8054 /*@
8055   MatSetBlockSizesFromMats - Sets the matrix block row and column sizes to match a pair of matrices
8056 
8057   Logically Collective
8058 
8059   Input Parameters:
8060 + mat     - the matrix
8061 . fromRow - matrix from which to copy row block size
8062 - fromCol - matrix from which to copy column block size (can be same as fromRow)
8063 
8064   Level: developer
8065 
8066 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`
8067 @*/
8068 PetscErrorCode MatSetBlockSizesFromMats(Mat mat, Mat fromRow, Mat fromCol)
8069 {
8070   PetscFunctionBegin;
8071   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8072   PetscValidHeaderSpecific(fromRow, MAT_CLASSID, 2);
8073   PetscValidHeaderSpecific(fromCol, MAT_CLASSID, 3);
8074   PetscCall(PetscLayoutSetBlockSize(mat->rmap, fromRow->rmap->bs));
8075   PetscCall(PetscLayoutSetBlockSize(mat->cmap, fromCol->cmap->bs));
8076   PetscFunctionReturn(PETSC_SUCCESS);
8077 }
8078 
8079 /*@
8080   MatResidual - Default routine to calculate the residual r = b - Ax
8081 
8082   Collective
8083 
8084   Input Parameters:
8085 + mat - the matrix
8086 . b   - the right-hand-side
8087 - x   - the approximate solution
8088 
8089   Output Parameter:
8090 . r - location to store the residual
8091 
8092   Level: developer
8093 
8094 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `PCMGSetResidual()`
8095 @*/
8096 PetscErrorCode MatResidual(Mat mat, Vec b, Vec x, Vec r)
8097 {
8098   PetscFunctionBegin;
8099   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8100   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
8101   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
8102   PetscValidHeaderSpecific(r, VEC_CLASSID, 4);
8103   PetscValidType(mat, 1);
8104   MatCheckPreallocated(mat, 1);
8105   PetscCall(PetscLogEventBegin(MAT_Residual, mat, 0, 0, 0));
8106   if (!mat->ops->residual) {
8107     PetscCall(MatMult(mat, x, r));
8108     PetscCall(VecAYPX(r, -1.0, b));
8109   } else {
8110     PetscUseTypeMethod(mat, residual, b, x, r);
8111   }
8112   PetscCall(PetscLogEventEnd(MAT_Residual, mat, 0, 0, 0));
8113   PetscFunctionReturn(PETSC_SUCCESS);
8114 }
8115 
8116 /*@C
8117   MatGetRowIJ - Returns the compressed row storage i and j indices for the local rows of a sparse matrix
8118 
8119   Collective
8120 
8121   Input Parameters:
8122 + mat             - the matrix
8123 . shift           - 0 or 1 indicating we want the indices starting at 0 or 1
8124 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8125 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE`  indicating if the nonzero structure of the
8126                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8127                  always used.
8128 
8129   Output Parameters:
8130 + n    - number of local rows in the (possibly compressed) matrix, use `NULL` if not needed
8131 . 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
8132 . ja   - the column indices, use `NULL` if not needed
8133 - done - indicates if the routine actually worked and returned appropriate ia[] and ja[] arrays; callers
8134            are responsible for handling the case when done == `PETSC_FALSE` and ia and ja are not set
8135 
8136   Level: developer
8137 
8138   Notes:
8139   You CANNOT change any of the ia[] or ja[] values.
8140 
8141   Use `MatRestoreRowIJ()` when you are finished accessing the ia[] and ja[] values.
8142 
8143   Fortran Notes:
8144   Use
8145 .vb
8146     PetscInt, pointer :: ia(:),ja(:)
8147     call MatGetRowIJ(mat,shift,symmetric,inodecompressed,n,ia,ja,done,ierr)
8148     ! Access the ith and jth entries via ia(i) and ja(j)
8149 .ve
8150 
8151 .seealso: [](ch_matrices), `Mat`, `MATAIJ`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`, `MatSeqAIJGetArray()`
8152 @*/
8153 PetscErrorCode MatGetRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8154 {
8155   PetscFunctionBegin;
8156   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8157   PetscValidType(mat, 1);
8158   if (n) PetscAssertPointer(n, 5);
8159   if (ia) PetscAssertPointer(ia, 6);
8160   if (ja) PetscAssertPointer(ja, 7);
8161   if (done) PetscAssertPointer(done, 8);
8162   MatCheckPreallocated(mat, 1);
8163   if (!mat->ops->getrowij && done) *done = PETSC_FALSE;
8164   else {
8165     if (done) *done = PETSC_TRUE;
8166     PetscCall(PetscLogEventBegin(MAT_GetRowIJ, mat, 0, 0, 0));
8167     PetscUseTypeMethod(mat, getrowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8168     PetscCall(PetscLogEventEnd(MAT_GetRowIJ, mat, 0, 0, 0));
8169   }
8170   PetscFunctionReturn(PETSC_SUCCESS);
8171 }
8172 
8173 /*@C
8174   MatGetColumnIJ - Returns the compressed column storage i and j indices for sequential matrices.
8175 
8176   Collective
8177 
8178   Input Parameters:
8179 + mat             - the matrix
8180 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8181 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be
8182                 symmetrized
8183 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8184                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8185                  always used.
8186 . n               - number of columns in the (possibly compressed) matrix
8187 . ia              - the column pointers; that is ia[0] = 0, ia[col] = i[col-1] + number of elements in that col of the matrix
8188 - ja              - the row indices
8189 
8190   Output Parameter:
8191 . done - `PETSC_TRUE` or `PETSC_FALSE`, indicating whether the values have been returned
8192 
8193   Level: developer
8194 
8195 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8196 @*/
8197 PetscErrorCode MatGetColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8198 {
8199   PetscFunctionBegin;
8200   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8201   PetscValidType(mat, 1);
8202   PetscAssertPointer(n, 5);
8203   if (ia) PetscAssertPointer(ia, 6);
8204   if (ja) PetscAssertPointer(ja, 7);
8205   PetscAssertPointer(done, 8);
8206   MatCheckPreallocated(mat, 1);
8207   if (!mat->ops->getcolumnij) *done = PETSC_FALSE;
8208   else {
8209     *done = PETSC_TRUE;
8210     PetscUseTypeMethod(mat, getcolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8211   }
8212   PetscFunctionReturn(PETSC_SUCCESS);
8213 }
8214 
8215 /*@C
8216   MatRestoreRowIJ - Call after you are completed with the ia,ja indices obtained with `MatGetRowIJ()`.
8217 
8218   Collective
8219 
8220   Input Parameters:
8221 + mat             - the matrix
8222 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8223 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8224 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8225                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8226                     always used.
8227 . n               - size of (possibly compressed) matrix
8228 . ia              - the row pointers
8229 - ja              - the column indices
8230 
8231   Output Parameter:
8232 . done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8233 
8234   Level: developer
8235 
8236   Note:
8237   This routine zeros out `n`, `ia`, and `ja`. This is to prevent accidental
8238   us of the array after it has been restored. If you pass `NULL`, it will
8239   not zero the pointers.  Use of ia or ja after `MatRestoreRowIJ()` is invalid.
8240 
8241 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8242 @*/
8243 PetscErrorCode MatRestoreRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8244 {
8245   PetscFunctionBegin;
8246   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8247   PetscValidType(mat, 1);
8248   if (ia) PetscAssertPointer(ia, 6);
8249   if (ja) PetscAssertPointer(ja, 7);
8250   if (done) PetscAssertPointer(done, 8);
8251   MatCheckPreallocated(mat, 1);
8252 
8253   if (!mat->ops->restorerowij && done) *done = PETSC_FALSE;
8254   else {
8255     if (done) *done = PETSC_TRUE;
8256     PetscUseTypeMethod(mat, restorerowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8257     if (n) *n = 0;
8258     if (ia) *ia = NULL;
8259     if (ja) *ja = NULL;
8260   }
8261   PetscFunctionReturn(PETSC_SUCCESS);
8262 }
8263 
8264 /*@C
8265   MatRestoreColumnIJ - Call after you are completed with the ia,ja indices obtained with `MatGetColumnIJ()`.
8266 
8267   Collective
8268 
8269   Input Parameters:
8270 + mat             - the matrix
8271 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8272 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8273 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8274                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8275                     always used.
8276 
8277   Output Parameters:
8278 + n    - size of (possibly compressed) matrix
8279 . ia   - the column pointers
8280 . ja   - the row indices
8281 - done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8282 
8283   Level: developer
8284 
8285 .seealso: [](ch_matrices), `Mat`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`
8286 @*/
8287 PetscErrorCode MatRestoreColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8288 {
8289   PetscFunctionBegin;
8290   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8291   PetscValidType(mat, 1);
8292   if (ia) PetscAssertPointer(ia, 6);
8293   if (ja) PetscAssertPointer(ja, 7);
8294   PetscAssertPointer(done, 8);
8295   MatCheckPreallocated(mat, 1);
8296 
8297   if (!mat->ops->restorecolumnij) *done = PETSC_FALSE;
8298   else {
8299     *done = PETSC_TRUE;
8300     PetscUseTypeMethod(mat, restorecolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8301     if (n) *n = 0;
8302     if (ia) *ia = NULL;
8303     if (ja) *ja = NULL;
8304   }
8305   PetscFunctionReturn(PETSC_SUCCESS);
8306 }
8307 
8308 /*@
8309   MatColoringPatch - Used inside matrix coloring routines that use `MatGetRowIJ()` and/or
8310   `MatGetColumnIJ()`.
8311 
8312   Collective
8313 
8314   Input Parameters:
8315 + mat        - the matrix
8316 . ncolors    - maximum color value
8317 . n          - number of entries in colorarray
8318 - colorarray - array indicating color for each column
8319 
8320   Output Parameter:
8321 . iscoloring - coloring generated using colorarray information
8322 
8323   Level: developer
8324 
8325 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatGetColumnIJ()`
8326 @*/
8327 PetscErrorCode MatColoringPatch(Mat mat, PetscInt ncolors, PetscInt n, ISColoringValue colorarray[], ISColoring *iscoloring)
8328 {
8329   PetscFunctionBegin;
8330   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8331   PetscValidType(mat, 1);
8332   PetscAssertPointer(colorarray, 4);
8333   PetscAssertPointer(iscoloring, 5);
8334   MatCheckPreallocated(mat, 1);
8335 
8336   if (!mat->ops->coloringpatch) {
8337     PetscCall(ISColoringCreate(PetscObjectComm((PetscObject)mat), ncolors, n, colorarray, PETSC_OWN_POINTER, iscoloring));
8338   } else {
8339     PetscUseTypeMethod(mat, coloringpatch, ncolors, n, colorarray, iscoloring);
8340   }
8341   PetscFunctionReturn(PETSC_SUCCESS);
8342 }
8343 
8344 /*@
8345   MatSetUnfactored - Resets a factored matrix to be treated as unfactored.
8346 
8347   Logically Collective
8348 
8349   Input Parameter:
8350 . mat - the factored matrix to be reset
8351 
8352   Level: developer
8353 
8354   Notes:
8355   This routine should be used only with factored matrices formed by in-place
8356   factorization via ILU(0) (or by in-place LU factorization for the `MATSEQDENSE`
8357   format).  This option can save memory, for example, when solving nonlinear
8358   systems with a matrix-free Newton-Krylov method and a matrix-based, in-place
8359   ILU(0) preconditioner.
8360 
8361   One can specify in-place ILU(0) factorization by calling
8362 .vb
8363      PCType(pc,PCILU);
8364      PCFactorSeUseInPlace(pc);
8365 .ve
8366   or by using the options -pc_type ilu -pc_factor_in_place
8367 
8368   In-place factorization ILU(0) can also be used as a local
8369   solver for the blocks within the block Jacobi or additive Schwarz
8370   methods (runtime option: -sub_pc_factor_in_place).  See Users-Manual: ch_pc
8371   for details on setting local solver options.
8372 
8373   Most users should employ the `KSP` interface for linear solvers
8374   instead of working directly with matrix algebra routines such as this.
8375   See, e.g., `KSPCreate()`.
8376 
8377 .seealso: [](ch_matrices), `Mat`, `PCFactorSetUseInPlace()`, `PCFactorGetUseInPlace()`
8378 @*/
8379 PetscErrorCode MatSetUnfactored(Mat mat)
8380 {
8381   PetscFunctionBegin;
8382   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8383   PetscValidType(mat, 1);
8384   MatCheckPreallocated(mat, 1);
8385   mat->factortype = MAT_FACTOR_NONE;
8386   if (!mat->ops->setunfactored) PetscFunctionReturn(PETSC_SUCCESS);
8387   PetscUseTypeMethod(mat, setunfactored);
8388   PetscFunctionReturn(PETSC_SUCCESS);
8389 }
8390 
8391 /*@
8392   MatCreateSubMatrix - Gets a single submatrix on the same number of processors
8393   as the original matrix.
8394 
8395   Collective
8396 
8397   Input Parameters:
8398 + mat   - the original matrix
8399 . isrow - parallel `IS` containing the rows this processor should obtain
8400 . 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.
8401 - cll   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
8402 
8403   Output Parameter:
8404 . newmat - the new submatrix, of the same type as the original matrix
8405 
8406   Level: advanced
8407 
8408   Notes:
8409   The submatrix will be able to be multiplied with vectors using the same layout as `iscol`.
8410 
8411   Some matrix types place restrictions on the row and column indices, such
8412   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;
8413   for example, if the block size is 3 one cannot select the 0 and 2 rows without selecting the 1 row.
8414 
8415   The index sets may not have duplicate entries.
8416 
8417   The first time this is called you should use a cll of `MAT_INITIAL_MATRIX`,
8418   the `MatCreateSubMatrix()` routine will create the newmat for you. Any additional calls
8419   to this routine with a mat of the same nonzero structure and with a call of `MAT_REUSE_MATRIX`
8420   will reuse the matrix generated the first time.  You should call `MatDestroy()` on `newmat` when
8421   you are finished using it.
8422 
8423   The communicator of the newly obtained matrix is ALWAYS the same as the communicator of
8424   the input matrix.
8425 
8426   If `iscol` is `NULL` then all columns are obtained (not supported in Fortran).
8427 
8428   If `isrow` and `iscol` have a nontrivial block-size, then the resulting matrix has this block-size as well. This feature
8429   is used by `PCFIELDSPLIT` to allow easy nesting of its use.
8430 
8431   Example usage:
8432   Consider the following 8x8 matrix with 34 non-zero values, that is
8433   assembled across 3 processors. Let's assume that proc0 owns 3 rows,
8434   proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
8435   as follows
8436 .vb
8437             1  2  0  |  0  3  0  |  0  4
8438     Proc0   0  5  6  |  7  0  0  |  8  0
8439             9  0 10  | 11  0  0  | 12  0
8440     -------------------------------------
8441            13  0 14  | 15 16 17  |  0  0
8442     Proc1   0 18  0  | 19 20 21  |  0  0
8443             0  0  0  | 22 23  0  | 24  0
8444     -------------------------------------
8445     Proc2  25 26 27  |  0  0 28  | 29  0
8446            30  0  0  | 31 32 33  |  0 34
8447 .ve
8448 
8449   Suppose `isrow` = [0 1 | 4 | 6 7] and `iscol` = [1 2 | 3 4 5 | 6].  The resulting submatrix is
8450 
8451 .vb
8452             2  0  |  0  3  0  |  0
8453     Proc0   5  6  |  7  0  0  |  8
8454     -------------------------------
8455     Proc1  18  0  | 19 20 21  |  0
8456     -------------------------------
8457     Proc2  26 27  |  0  0 28  | 29
8458             0  0  | 31 32 33  |  0
8459 .ve
8460 
8461 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatCreateSubMatricesMPI()`, `MatCreateSubMatrixVirtual()`, `MatSubMatrixVirtualUpdate()`
8462 @*/
8463 PetscErrorCode MatCreateSubMatrix(Mat mat, IS isrow, IS iscol, MatReuse cll, Mat *newmat)
8464 {
8465   PetscMPIInt size;
8466   Mat        *local;
8467   IS          iscoltmp;
8468   PetscBool   flg;
8469 
8470   PetscFunctionBegin;
8471   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8472   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
8473   if (iscol) PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
8474   PetscAssertPointer(newmat, 5);
8475   if (cll == MAT_REUSE_MATRIX) PetscValidHeaderSpecific(*newmat, MAT_CLASSID, 5);
8476   PetscValidType(mat, 1);
8477   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
8478   PetscCheck(cll != MAT_IGNORE_MATRIX, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot use MAT_IGNORE_MATRIX");
8479 
8480   MatCheckPreallocated(mat, 1);
8481   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
8482 
8483   if (!iscol || isrow == iscol) {
8484     PetscBool   stride;
8485     PetscMPIInt grabentirematrix = 0, grab;
8486     PetscCall(PetscObjectTypeCompare((PetscObject)isrow, ISSTRIDE, &stride));
8487     if (stride) {
8488       PetscInt first, step, n, rstart, rend;
8489       PetscCall(ISStrideGetInfo(isrow, &first, &step));
8490       if (step == 1) {
8491         PetscCall(MatGetOwnershipRange(mat, &rstart, &rend));
8492         if (rstart == first) {
8493           PetscCall(ISGetLocalSize(isrow, &n));
8494           if (n == rend - rstart) grabentirematrix = 1;
8495         }
8496       }
8497     }
8498     PetscCallMPI(MPIU_Allreduce(&grabentirematrix, &grab, 1, MPI_INT, MPI_MIN, PetscObjectComm((PetscObject)mat)));
8499     if (grab) {
8500       PetscCall(PetscInfo(mat, "Getting entire matrix as submatrix\n"));
8501       if (cll == MAT_INITIAL_MATRIX) {
8502         *newmat = mat;
8503         PetscCall(PetscObjectReference((PetscObject)mat));
8504       }
8505       PetscFunctionReturn(PETSC_SUCCESS);
8506     }
8507   }
8508 
8509   if (!iscol) {
8510     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)mat), mat->cmap->n, mat->cmap->rstart, 1, &iscoltmp));
8511   } else {
8512     iscoltmp = iscol;
8513   }
8514 
8515   /* if original matrix is on just one processor then use submatrix generated */
8516   if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1 && cll == MAT_REUSE_MATRIX) {
8517     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_REUSE_MATRIX, &newmat));
8518     goto setproperties;
8519   } else if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1) {
8520     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_INITIAL_MATRIX, &local));
8521     *newmat = *local;
8522     PetscCall(PetscFree(local));
8523     goto setproperties;
8524   } else if (!mat->ops->createsubmatrix) {
8525     /* Create a new matrix type that implements the operation using the full matrix */
8526     PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8527     switch (cll) {
8528     case MAT_INITIAL_MATRIX:
8529       PetscCall(MatCreateSubMatrixVirtual(mat, isrow, iscoltmp, newmat));
8530       break;
8531     case MAT_REUSE_MATRIX:
8532       PetscCall(MatSubMatrixVirtualUpdate(*newmat, mat, isrow, iscoltmp));
8533       break;
8534     default:
8535       SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Invalid MatReuse, must be either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX");
8536     }
8537     PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8538     goto setproperties;
8539   }
8540 
8541   PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8542   PetscUseTypeMethod(mat, createsubmatrix, isrow, iscoltmp, cll, newmat);
8543   PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8544 
8545 setproperties:
8546   if ((*newmat)->symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->structurally_symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->spd == PETSC_BOOL3_UNKNOWN && (*newmat)->hermitian == PETSC_BOOL3_UNKNOWN) {
8547     PetscCall(ISEqualUnsorted(isrow, iscoltmp, &flg));
8548     if (flg) PetscCall(MatPropagateSymmetryOptions(mat, *newmat));
8549   }
8550   if (!iscol) PetscCall(ISDestroy(&iscoltmp));
8551   if (*newmat && cll == MAT_INITIAL_MATRIX) PetscCall(PetscObjectStateIncrease((PetscObject)*newmat));
8552   if (!iscol || isrow == iscol) PetscCall(MatSelectVariableBlockSizes(*newmat, mat, isrow));
8553   PetscFunctionReturn(PETSC_SUCCESS);
8554 }
8555 
8556 /*@
8557   MatPropagateSymmetryOptions - Propagates symmetry options set on a matrix to another matrix
8558 
8559   Not Collective
8560 
8561   Input Parameters:
8562 + A - the matrix we wish to propagate options from
8563 - B - the matrix we wish to propagate options to
8564 
8565   Level: beginner
8566 
8567   Note:
8568   Propagates the options associated to `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_HERMITIAN`, `MAT_SPD`, `MAT_SYMMETRIC`, and `MAT_STRUCTURAL_SYMMETRY_ETERNAL`
8569 
8570 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatIsSymmetricKnown()`, `MatIsSPDKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
8571 @*/
8572 PetscErrorCode MatPropagateSymmetryOptions(Mat A, Mat B)
8573 {
8574   PetscFunctionBegin;
8575   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8576   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
8577   B->symmetry_eternal            = A->symmetry_eternal;
8578   B->structural_symmetry_eternal = A->structural_symmetry_eternal;
8579   B->symmetric                   = A->symmetric;
8580   B->structurally_symmetric      = A->structurally_symmetric;
8581   B->spd                         = A->spd;
8582   B->hermitian                   = A->hermitian;
8583   PetscFunctionReturn(PETSC_SUCCESS);
8584 }
8585 
8586 /*@
8587   MatStashSetInitialSize - sets the sizes of the matrix stash, that is
8588   used during the assembly process to store values that belong to
8589   other processors.
8590 
8591   Not Collective
8592 
8593   Input Parameters:
8594 + mat   - the matrix
8595 . size  - the initial size of the stash.
8596 - bsize - the initial size of the block-stash(if used).
8597 
8598   Options Database Keys:
8599 + -matstash_initial_size <size> or <size0,size1,...sizep-1>            - set initial size
8600 - -matstash_block_initial_size <bsize>  or <bsize0,bsize1,...bsizep-1> - set initial block size
8601 
8602   Level: intermediate
8603 
8604   Notes:
8605   The block-stash is used for values set with `MatSetValuesBlocked()` while
8606   the stash is used for values set with `MatSetValues()`
8607 
8608   Run with the option -info and look for output of the form
8609   MatAssemblyBegin_MPIXXX:Stash has MM entries, uses nn mallocs.
8610   to determine the appropriate value, MM, to use for size and
8611   MatAssemblyBegin_MPIXXX:Block-Stash has BMM entries, uses nn mallocs.
8612   to determine the value, BMM to use for bsize
8613 
8614 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashGetInfo()`
8615 @*/
8616 PetscErrorCode MatStashSetInitialSize(Mat mat, PetscInt size, PetscInt bsize)
8617 {
8618   PetscFunctionBegin;
8619   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8620   PetscValidType(mat, 1);
8621   PetscCall(MatStashSetInitialSize_Private(&mat->stash, size));
8622   PetscCall(MatStashSetInitialSize_Private(&mat->bstash, bsize));
8623   PetscFunctionReturn(PETSC_SUCCESS);
8624 }
8625 
8626 /*@
8627   MatInterpolateAdd - $w = y + A*x$ or $A^T*x$ depending on the shape of
8628   the matrix
8629 
8630   Neighbor-wise Collective
8631 
8632   Input Parameters:
8633 + A - the matrix
8634 . x - the vector to be multiplied by the interpolation operator
8635 - y - the vector to be added to the result
8636 
8637   Output Parameter:
8638 . w - the resulting vector
8639 
8640   Level: intermediate
8641 
8642   Notes:
8643   `w` may be the same vector as `y`.
8644 
8645   This allows one to use either the restriction or interpolation (its transpose)
8646   matrix to do the interpolation
8647 
8648 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8649 @*/
8650 PetscErrorCode MatInterpolateAdd(Mat A, Vec x, Vec y, Vec w)
8651 {
8652   PetscInt M, N, Ny;
8653 
8654   PetscFunctionBegin;
8655   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8656   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8657   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8658   PetscValidHeaderSpecific(w, VEC_CLASSID, 4);
8659   PetscCall(MatGetSize(A, &M, &N));
8660   PetscCall(VecGetSize(y, &Ny));
8661   if (M == Ny) {
8662     PetscCall(MatMultAdd(A, x, y, w));
8663   } else {
8664     PetscCall(MatMultTransposeAdd(A, x, y, w));
8665   }
8666   PetscFunctionReturn(PETSC_SUCCESS);
8667 }
8668 
8669 /*@
8670   MatInterpolate - $y = A*x$ or $A^T*x$ depending on the shape of
8671   the matrix
8672 
8673   Neighbor-wise Collective
8674 
8675   Input Parameters:
8676 + A - the matrix
8677 - x - the vector to be interpolated
8678 
8679   Output Parameter:
8680 . y - the resulting vector
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
8687 
8688 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8689 @*/
8690 PetscErrorCode MatInterpolate(Mat A, Vec x, Vec y)
8691 {
8692   PetscInt M, N, Ny;
8693 
8694   PetscFunctionBegin;
8695   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8696   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8697   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8698   PetscCall(MatGetSize(A, &M, &N));
8699   PetscCall(VecGetSize(y, &Ny));
8700   if (M == Ny) {
8701     PetscCall(MatMult(A, x, y));
8702   } else {
8703     PetscCall(MatMultTranspose(A, x, y));
8704   }
8705   PetscFunctionReturn(PETSC_SUCCESS);
8706 }
8707 
8708 /*@
8709   MatRestrict - $y = A*x$ or $A^T*x$
8710 
8711   Neighbor-wise Collective
8712 
8713   Input Parameters:
8714 + A - the matrix
8715 - x - the vector to be restricted
8716 
8717   Output Parameter:
8718 . y - the resulting vector
8719 
8720   Level: intermediate
8721 
8722   Note:
8723   This allows one to use either the restriction or interpolation (its transpose)
8724   matrix to do the restriction
8725 
8726 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatInterpolate()`, `PCMG`
8727 @*/
8728 PetscErrorCode MatRestrict(Mat A, Vec x, Vec y)
8729 {
8730   PetscInt M, N, Nx;
8731 
8732   PetscFunctionBegin;
8733   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8734   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8735   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8736   PetscCall(MatGetSize(A, &M, &N));
8737   PetscCall(VecGetSize(x, &Nx));
8738   if (M == Nx) {
8739     PetscCall(MatMultTranspose(A, x, y));
8740   } else {
8741     PetscCall(MatMult(A, x, y));
8742   }
8743   PetscFunctionReturn(PETSC_SUCCESS);
8744 }
8745 
8746 /*@
8747   MatMatInterpolateAdd - $Y = W + A*X$ or $W + A^T*X$ depending on the shape of `A`
8748 
8749   Neighbor-wise Collective
8750 
8751   Input Parameters:
8752 + A - the matrix
8753 . x - the input dense matrix to be multiplied
8754 - w - the input dense matrix to be added to the result
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`, `MatInterpolateAdd()`, `MatMatInterpolate()`, `MatMatRestrict()`, `PCMG`
8767 @*/
8768 PetscErrorCode MatMatInterpolateAdd(Mat A, Mat x, Mat w, Mat *y)
8769 {
8770   PetscInt  M, N, Mx, Nx, Mo, My = 0, Ny = 0;
8771   PetscBool trans = PETSC_TRUE;
8772   MatReuse  reuse = MAT_INITIAL_MATRIX;
8773 
8774   PetscFunctionBegin;
8775   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8776   PetscValidHeaderSpecific(x, MAT_CLASSID, 2);
8777   PetscValidType(x, 2);
8778   if (w) PetscValidHeaderSpecific(w, MAT_CLASSID, 3);
8779   if (*y) PetscValidHeaderSpecific(*y, MAT_CLASSID, 4);
8780   PetscCall(MatGetSize(A, &M, &N));
8781   PetscCall(MatGetSize(x, &Mx, &Nx));
8782   if (N == Mx) trans = PETSC_FALSE;
8783   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);
8784   Mo = trans ? N : M;
8785   if (*y) {
8786     PetscCall(MatGetSize(*y, &My, &Ny));
8787     if (Mo == My && Nx == Ny) {
8788       reuse = MAT_REUSE_MATRIX;
8789     } else {
8790       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);
8791       PetscCall(MatDestroy(y));
8792     }
8793   }
8794 
8795   if (w && *y == w) { /* this is to minimize changes in PCMG */
8796     PetscBool flg;
8797 
8798     PetscCall(PetscObjectQuery((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject *)&w));
8799     if (w) {
8800       PetscInt My, Ny, Mw, Nw;
8801 
8802       PetscCall(PetscObjectTypeCompare((PetscObject)*y, ((PetscObject)w)->type_name, &flg));
8803       PetscCall(MatGetSize(*y, &My, &Ny));
8804       PetscCall(MatGetSize(w, &Mw, &Nw));
8805       if (!flg || My != Mw || Ny != Nw) w = NULL;
8806     }
8807     if (!w) {
8808       PetscCall(MatDuplicate(*y, MAT_COPY_VALUES, &w));
8809       PetscCall(PetscObjectCompose((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject)w));
8810       PetscCall(PetscObjectDereference((PetscObject)w));
8811     } else {
8812       PetscCall(MatCopy(*y, w, UNKNOWN_NONZERO_PATTERN));
8813     }
8814   }
8815   if (!trans) {
8816     PetscCall(MatMatMult(A, x, reuse, PETSC_DETERMINE, y));
8817   } else {
8818     PetscCall(MatTransposeMatMult(A, x, reuse, PETSC_DETERMINE, y));
8819   }
8820   if (w) PetscCall(MatAXPY(*y, 1.0, w, UNKNOWN_NONZERO_PATTERN));
8821   PetscFunctionReturn(PETSC_SUCCESS);
8822 }
8823 
8824 /*@
8825   MatMatInterpolate - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8826 
8827   Neighbor-wise Collective
8828 
8829   Input Parameters:
8830 + A - the matrix
8831 - x - the input dense matrix
8832 
8833   Output Parameter:
8834 . y - the output dense matrix
8835 
8836   Level: intermediate
8837 
8838   Note:
8839   This allows one to use either the restriction or interpolation (its transpose)
8840   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8841   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8842 
8843 .seealso: [](ch_matrices), `Mat`, `MatInterpolate()`, `MatRestrict()`, `MatMatRestrict()`, `PCMG`
8844 @*/
8845 PetscErrorCode MatMatInterpolate(Mat A, Mat x, Mat *y)
8846 {
8847   PetscFunctionBegin;
8848   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8849   PetscFunctionReturn(PETSC_SUCCESS);
8850 }
8851 
8852 /*@
8853   MatMatRestrict - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8854 
8855   Neighbor-wise Collective
8856 
8857   Input Parameters:
8858 + A - the matrix
8859 - x - the input dense matrix
8860 
8861   Output Parameter:
8862 . y - the output dense matrix
8863 
8864   Level: intermediate
8865 
8866   Note:
8867   This allows one to use either the restriction or interpolation (its transpose)
8868   matrix to do the restriction. `y` matrix can be reused if already created with the proper sizes,
8869   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8870 
8871 .seealso: [](ch_matrices), `Mat`, `MatRestrict()`, `MatInterpolate()`, `MatMatInterpolate()`, `PCMG`
8872 @*/
8873 PetscErrorCode MatMatRestrict(Mat A, Mat x, Mat *y)
8874 {
8875   PetscFunctionBegin;
8876   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8877   PetscFunctionReturn(PETSC_SUCCESS);
8878 }
8879 
8880 /*@
8881   MatGetNullSpace - retrieves the null space of a matrix.
8882 
8883   Logically Collective
8884 
8885   Input Parameters:
8886 + mat    - the matrix
8887 - nullsp - the null space object
8888 
8889   Level: developer
8890 
8891 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetNullSpace()`, `MatNullSpace`
8892 @*/
8893 PetscErrorCode MatGetNullSpace(Mat mat, MatNullSpace *nullsp)
8894 {
8895   PetscFunctionBegin;
8896   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8897   PetscAssertPointer(nullsp, 2);
8898   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->nullsp) ? mat->transnullsp : mat->nullsp;
8899   PetscFunctionReturn(PETSC_SUCCESS);
8900 }
8901 
8902 /*@C
8903   MatGetNullSpaces - gets the null spaces, transpose null spaces, and near null spaces from an array of matrices
8904 
8905   Logically Collective
8906 
8907   Input Parameters:
8908 + n   - the number of matrices
8909 - mat - the array of matrices
8910 
8911   Output Parameters:
8912 . nullsp - an array of null spaces, `NULL` for each matrix that does not have a null space, length 3 * `n`
8913 
8914   Level: developer
8915 
8916   Note:
8917   Call `MatRestoreNullspaces()` to provide these to another array of matrices
8918 
8919 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
8920           `MatNullSpaceRemove()`, `MatRestoreNullSpaces()`
8921 @*/
8922 PetscErrorCode MatGetNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
8923 {
8924   PetscFunctionBegin;
8925   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
8926   PetscAssertPointer(mat, 2);
8927   PetscAssertPointer(nullsp, 3);
8928 
8929   PetscCall(PetscCalloc1(3 * n, nullsp));
8930   for (PetscInt i = 0; i < n; i++) {
8931     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
8932     (*nullsp)[i] = mat[i]->nullsp;
8933     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[i]));
8934     (*nullsp)[n + i] = mat[i]->nearnullsp;
8935     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[n + i]));
8936     (*nullsp)[2 * n + i] = mat[i]->transnullsp;
8937     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[2 * n + i]));
8938   }
8939   PetscFunctionReturn(PETSC_SUCCESS);
8940 }
8941 
8942 /*@C
8943   MatRestoreNullSpaces - sets the null spaces, transpose null spaces, and near null spaces obtained with `MatGetNullSpaces()` for an array of matrices
8944 
8945   Logically Collective
8946 
8947   Input Parameters:
8948 + n      - the number of matrices
8949 . mat    - the array of matrices
8950 - nullsp - an array of null spaces
8951 
8952   Level: developer
8953 
8954   Note:
8955   Call `MatGetNullSpaces()` to create `nullsp`
8956 
8957 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
8958           `MatNullSpaceRemove()`, `MatGetNullSpaces()`
8959 @*/
8960 PetscErrorCode MatRestoreNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
8961 {
8962   PetscFunctionBegin;
8963   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
8964   PetscAssertPointer(mat, 2);
8965   PetscAssertPointer(nullsp, 3);
8966   PetscAssertPointer(*nullsp, 3);
8967 
8968   for (PetscInt i = 0; i < n; i++) {
8969     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
8970     PetscCall(MatSetNullSpace(mat[i], (*nullsp)[i]));
8971     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[i]));
8972     PetscCall(MatSetNearNullSpace(mat[i], (*nullsp)[n + i]));
8973     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[n + i]));
8974     PetscCall(MatSetTransposeNullSpace(mat[i], (*nullsp)[2 * n + i]));
8975     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[2 * n + i]));
8976   }
8977   PetscCall(PetscFree(*nullsp));
8978   PetscFunctionReturn(PETSC_SUCCESS);
8979 }
8980 
8981 /*@
8982   MatSetNullSpace - attaches a null space to a matrix.
8983 
8984   Logically Collective
8985 
8986   Input Parameters:
8987 + mat    - the matrix
8988 - nullsp - the null space object
8989 
8990   Level: advanced
8991 
8992   Notes:
8993   This null space is used by the `KSP` linear solvers to solve singular systems.
8994 
8995   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`
8996 
8997   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
8998   to zero but the linear system will still be solved in a least squares sense.
8999 
9000   The fundamental theorem of linear algebra (Gilbert Strang, Introduction to Applied Mathematics, page 72) states that
9001   the domain of a matrix $A$ (from $R^n$ to $R^m$ ($m$ rows, $n$ columns) $R^n$ = the direct sum of the null space of $A$, $n(A)$, plus the range of $A^T$, $R(A^T)$.
9002   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
9003   $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
9004   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)$.
9005   This  $\hat{b}$ can be obtained by calling `MatNullSpaceRemove()` with the null space of the transpose of the matrix.
9006 
9007   If the matrix is known to be symmetric because it is an `MATSBAIJ` matrix or one has called
9008   `MatSetOption`(mat,`MAT_SYMMETRIC` or possibly `MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`); this
9009   routine also automatically calls `MatSetTransposeNullSpace()`.
9010 
9011   The user should call `MatNullSpaceDestroy()`.
9012 
9013 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`,
9014           `KSPSetPCSide()`
9015 @*/
9016 PetscErrorCode MatSetNullSpace(Mat mat, MatNullSpace nullsp)
9017 {
9018   PetscFunctionBegin;
9019   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9020   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9021   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9022   PetscCall(MatNullSpaceDestroy(&mat->nullsp));
9023   mat->nullsp = nullsp;
9024   if (mat->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetTransposeNullSpace(mat, nullsp));
9025   PetscFunctionReturn(PETSC_SUCCESS);
9026 }
9027 
9028 /*@
9029   MatGetTransposeNullSpace - retrieves the null space of the transpose of a matrix.
9030 
9031   Logically Collective
9032 
9033   Input Parameters:
9034 + mat    - the matrix
9035 - nullsp - the null space object
9036 
9037   Level: developer
9038 
9039 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetTransposeNullSpace()`, `MatSetNullSpace()`, `MatGetNullSpace()`
9040 @*/
9041 PetscErrorCode MatGetTransposeNullSpace(Mat mat, MatNullSpace *nullsp)
9042 {
9043   PetscFunctionBegin;
9044   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9045   PetscValidType(mat, 1);
9046   PetscAssertPointer(nullsp, 2);
9047   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->transnullsp) ? mat->nullsp : mat->transnullsp;
9048   PetscFunctionReturn(PETSC_SUCCESS);
9049 }
9050 
9051 /*@
9052   MatSetTransposeNullSpace - attaches the null space of a transpose of a matrix to the matrix
9053 
9054   Logically Collective
9055 
9056   Input Parameters:
9057 + mat    - the matrix
9058 - nullsp - the null space object
9059 
9060   Level: advanced
9061 
9062   Notes:
9063   This allows solving singular linear systems defined by the transpose of the matrix using `KSP` solvers with left preconditioning.
9064 
9065   See `MatSetNullSpace()`
9066 
9067 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`, `KSPSetPCSide()`
9068 @*/
9069 PetscErrorCode MatSetTransposeNullSpace(Mat mat, MatNullSpace nullsp)
9070 {
9071   PetscFunctionBegin;
9072   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9073   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9074   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9075   PetscCall(MatNullSpaceDestroy(&mat->transnullsp));
9076   mat->transnullsp = nullsp;
9077   PetscFunctionReturn(PETSC_SUCCESS);
9078 }
9079 
9080 /*@
9081   MatSetNearNullSpace - attaches a null space to a matrix, which is often the null space (rigid body modes) of the operator without boundary conditions
9082   This null space will be used to provide near null space vectors to a multigrid preconditioner built from this matrix.
9083 
9084   Logically Collective
9085 
9086   Input Parameters:
9087 + mat    - the matrix
9088 - nullsp - the null space object
9089 
9090   Level: advanced
9091 
9092   Notes:
9093   Overwrites any previous near null space that may have been attached
9094 
9095   You can remove the null space by calling this routine with an `nullsp` of `NULL`
9096 
9097 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNullSpace()`, `MatNullSpaceCreateRigidBody()`, `MatGetNearNullSpace()`
9098 @*/
9099 PetscErrorCode MatSetNearNullSpace(Mat mat, MatNullSpace nullsp)
9100 {
9101   PetscFunctionBegin;
9102   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9103   PetscValidType(mat, 1);
9104   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9105   MatCheckPreallocated(mat, 1);
9106   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9107   PetscCall(MatNullSpaceDestroy(&mat->nearnullsp));
9108   mat->nearnullsp = nullsp;
9109   PetscFunctionReturn(PETSC_SUCCESS);
9110 }
9111 
9112 /*@
9113   MatGetNearNullSpace - Get null space attached with `MatSetNearNullSpace()`
9114 
9115   Not Collective
9116 
9117   Input Parameter:
9118 . mat - the matrix
9119 
9120   Output Parameter:
9121 . nullsp - the null space object, `NULL` if not set
9122 
9123   Level: advanced
9124 
9125 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatNullSpaceCreate()`
9126 @*/
9127 PetscErrorCode MatGetNearNullSpace(Mat mat, MatNullSpace *nullsp)
9128 {
9129   PetscFunctionBegin;
9130   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9131   PetscValidType(mat, 1);
9132   PetscAssertPointer(nullsp, 2);
9133   MatCheckPreallocated(mat, 1);
9134   *nullsp = mat->nearnullsp;
9135   PetscFunctionReturn(PETSC_SUCCESS);
9136 }
9137 
9138 /*@
9139   MatICCFactor - Performs in-place incomplete Cholesky factorization of matrix.
9140 
9141   Collective
9142 
9143   Input Parameters:
9144 + mat  - the matrix
9145 . row  - row/column permutation
9146 - info - information on desired factorization process
9147 
9148   Level: developer
9149 
9150   Notes:
9151   Probably really in-place only when level of fill is zero, otherwise allocates
9152   new space to store factored matrix and deletes previous memory.
9153 
9154   Most users should employ the `KSP` interface for linear solvers
9155   instead of working directly with matrix algebra routines such as this.
9156   See, e.g., `KSPCreate()`.
9157 
9158   Fortran Note:
9159   A valid (non-null) `info` argument must be provided
9160 
9161 .seealso: [](ch_matrices), `Mat`, `MatFactorInfo`, `MatGetFactor()`, `MatICCFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
9162 @*/
9163 PetscErrorCode MatICCFactor(Mat mat, IS row, const MatFactorInfo *info)
9164 {
9165   PetscFunctionBegin;
9166   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9167   PetscValidType(mat, 1);
9168   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
9169   PetscAssertPointer(info, 3);
9170   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
9171   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
9172   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9173   MatCheckPreallocated(mat, 1);
9174   PetscUseTypeMethod(mat, iccfactor, row, info);
9175   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9176   PetscFunctionReturn(PETSC_SUCCESS);
9177 }
9178 
9179 /*@
9180   MatDiagonalScaleLocal - Scales columns of a matrix given the scaling values including the
9181   ghosted ones.
9182 
9183   Not Collective
9184 
9185   Input Parameters:
9186 + mat  - the matrix
9187 - diag - the diagonal values, including ghost ones
9188 
9189   Level: developer
9190 
9191   Notes:
9192   Works only for `MATMPIAIJ` and `MATMPIBAIJ` matrices
9193 
9194   This allows one to avoid during communication to perform the scaling that must be done with `MatDiagonalScale()`
9195 
9196 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
9197 @*/
9198 PetscErrorCode MatDiagonalScaleLocal(Mat mat, Vec diag)
9199 {
9200   PetscMPIInt size;
9201 
9202   PetscFunctionBegin;
9203   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9204   PetscValidHeaderSpecific(diag, VEC_CLASSID, 2);
9205   PetscValidType(mat, 1);
9206 
9207   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must be already assembled");
9208   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
9209   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
9210   if (size == 1) {
9211     PetscInt n, m;
9212     PetscCall(VecGetSize(diag, &n));
9213     PetscCall(MatGetSize(mat, NULL, &m));
9214     PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supported for sequential matrices when no ghost points/periodic conditions");
9215     PetscCall(MatDiagonalScale(mat, NULL, diag));
9216   } else {
9217     PetscUseMethod(mat, "MatDiagonalScaleLocal_C", (Mat, Vec), (mat, diag));
9218   }
9219   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
9220   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9221   PetscFunctionReturn(PETSC_SUCCESS);
9222 }
9223 
9224 /*@
9225   MatGetInertia - Gets the inertia from a factored matrix
9226 
9227   Collective
9228 
9229   Input Parameter:
9230 . mat - the matrix
9231 
9232   Output Parameters:
9233 + nneg  - number of negative eigenvalues
9234 . nzero - number of zero eigenvalues
9235 - npos  - number of positive eigenvalues
9236 
9237   Level: advanced
9238 
9239   Note:
9240   Matrix must have been factored by `MatCholeskyFactor()`
9241 
9242 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactor()`
9243 @*/
9244 PetscErrorCode MatGetInertia(Mat mat, PetscInt *nneg, PetscInt *nzero, PetscInt *npos)
9245 {
9246   PetscFunctionBegin;
9247   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9248   PetscValidType(mat, 1);
9249   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9250   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Numeric factor mat is not assembled");
9251   PetscUseTypeMethod(mat, getinertia, nneg, nzero, npos);
9252   PetscFunctionReturn(PETSC_SUCCESS);
9253 }
9254 
9255 /*@C
9256   MatSolves - Solves $A x = b$, given a factored matrix, for a collection of vectors
9257 
9258   Neighbor-wise Collective
9259 
9260   Input Parameters:
9261 + mat - the factored matrix obtained with `MatGetFactor()`
9262 - b   - the right-hand-side vectors
9263 
9264   Output Parameter:
9265 . x - the result vectors
9266 
9267   Level: developer
9268 
9269   Note:
9270   The vectors `b` and `x` cannot be the same.  I.e., one cannot
9271   call `MatSolves`(A,x,x).
9272 
9273 .seealso: [](ch_matrices), `Mat`, `Vecs`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`, `MatSolve()`
9274 @*/
9275 PetscErrorCode MatSolves(Mat mat, Vecs b, Vecs x)
9276 {
9277   PetscFunctionBegin;
9278   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9279   PetscValidType(mat, 1);
9280   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
9281   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9282   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
9283 
9284   MatCheckPreallocated(mat, 1);
9285   PetscCall(PetscLogEventBegin(MAT_Solves, mat, 0, 0, 0));
9286   PetscUseTypeMethod(mat, solves, b, x);
9287   PetscCall(PetscLogEventEnd(MAT_Solves, mat, 0, 0, 0));
9288   PetscFunctionReturn(PETSC_SUCCESS);
9289 }
9290 
9291 /*@
9292   MatIsSymmetric - Test whether a matrix is symmetric
9293 
9294   Collective
9295 
9296   Input Parameters:
9297 + A   - the matrix to test
9298 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact transpose)
9299 
9300   Output Parameter:
9301 . flg - the result
9302 
9303   Level: intermediate
9304 
9305   Notes:
9306   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9307 
9308   If the matrix does not yet know if it is symmetric or not this can be an expensive operation, also available `MatIsSymmetricKnown()`
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`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetricKnown()`,
9314           `MAT_SYMMETRIC`, `MAT_SYMMETRY_ETERNAL`
9315 @*/
9316 PetscErrorCode MatIsSymmetric(Mat A, PetscReal tol, PetscBool *flg)
9317 {
9318   PetscFunctionBegin;
9319   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9320   PetscAssertPointer(flg, 3);
9321   if (A->symmetric != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->symmetric);
9322   else {
9323     if (A->ops->issymmetric) PetscUseTypeMethod(A, issymmetric, tol, flg);
9324     else PetscCall(MatIsTranspose(A, A, tol, flg));
9325     if (!tol) PetscCall(MatSetOption(A, MAT_SYMMETRIC, *flg));
9326   }
9327   PetscFunctionReturn(PETSC_SUCCESS);
9328 }
9329 
9330 /*@
9331   MatIsHermitian - Test whether a matrix is Hermitian
9332 
9333   Collective
9334 
9335   Input Parameters:
9336 + A   - the matrix to test
9337 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact Hermitian)
9338 
9339   Output Parameter:
9340 . flg - the result
9341 
9342   Level: intermediate
9343 
9344   Notes:
9345   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9346 
9347   If the matrix does not yet know if it is Hermitian or not this can be an expensive operation, also available `MatIsHermitianKnown()`
9348 
9349   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9350   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMEMTRY_ETERNAL`,`PETSC_TRUE`)
9351 
9352 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetric()`, `MatSetOption()`,
9353           `MatIsSymmetricKnown()`, `MatIsSymmetric()`, `MAT_HERMITIAN`, `MAT_SYMMETRY_ETERNAL`
9354 @*/
9355 PetscErrorCode MatIsHermitian(Mat A, PetscReal tol, PetscBool *flg)
9356 {
9357   PetscFunctionBegin;
9358   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9359   PetscAssertPointer(flg, 3);
9360   if (A->hermitian != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->hermitian);
9361   else {
9362     if (A->ops->ishermitian) PetscUseTypeMethod(A, ishermitian, tol, flg);
9363     else PetscCall(MatIsHermitianTranspose(A, A, tol, flg));
9364     if (!tol) PetscCall(MatSetOption(A, MAT_HERMITIAN, *flg));
9365   }
9366   PetscFunctionReturn(PETSC_SUCCESS);
9367 }
9368 
9369 /*@
9370   MatIsSymmetricKnown - Checks if a matrix knows if it is symmetric or not and its symmetric state
9371 
9372   Not Collective
9373 
9374   Input Parameter:
9375 . A - the matrix to check
9376 
9377   Output Parameters:
9378 + set - `PETSC_TRUE` if the matrix knows its symmetry state (this tells you if the next flag is valid)
9379 - flg - the result (only valid if set is `PETSC_TRUE`)
9380 
9381   Level: advanced
9382 
9383   Notes:
9384   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsSymmetric()`
9385   if you want it explicitly checked
9386 
9387   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9388   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9389 
9390 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9391 @*/
9392 PetscErrorCode MatIsSymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9393 {
9394   PetscFunctionBegin;
9395   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9396   PetscAssertPointer(set, 2);
9397   PetscAssertPointer(flg, 3);
9398   if (A->symmetric != PETSC_BOOL3_UNKNOWN) {
9399     *set = PETSC_TRUE;
9400     *flg = PetscBool3ToBool(A->symmetric);
9401   } else {
9402     *set = PETSC_FALSE;
9403   }
9404   PetscFunctionReturn(PETSC_SUCCESS);
9405 }
9406 
9407 /*@
9408   MatIsSPDKnown - Checks if a matrix knows if it is symmetric positive definite or not and its symmetric positive definite state
9409 
9410   Not Collective
9411 
9412   Input Parameter:
9413 . A - the matrix to check
9414 
9415   Output Parameters:
9416 + set - `PETSC_TRUE` if the matrix knows its symmetric positive definite state (this tells you if the next flag is valid)
9417 - flg - the result (only valid if set is `PETSC_TRUE`)
9418 
9419   Level: advanced
9420 
9421   Notes:
9422   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`).
9423 
9424   One can declare that a matrix is SPD with `MatSetOption`(mat,`MAT_SPD`,`PETSC_TRUE`) and if it is known to remain SPD
9425   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SPD_ETERNAL`,`PETSC_TRUE`)
9426 
9427 .seealso: [](ch_matrices), `Mat`, `MAT_SPD_ETERNAL`, `MAT_SPD`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9428 @*/
9429 PetscErrorCode MatIsSPDKnown(Mat A, PetscBool *set, PetscBool *flg)
9430 {
9431   PetscFunctionBegin;
9432   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9433   PetscAssertPointer(set, 2);
9434   PetscAssertPointer(flg, 3);
9435   if (A->spd != PETSC_BOOL3_UNKNOWN) {
9436     *set = PETSC_TRUE;
9437     *flg = PetscBool3ToBool(A->spd);
9438   } else {
9439     *set = PETSC_FALSE;
9440   }
9441   PetscFunctionReturn(PETSC_SUCCESS);
9442 }
9443 
9444 /*@
9445   MatIsHermitianKnown - Checks if a matrix knows if it is Hermitian or not and its Hermitian state
9446 
9447   Not Collective
9448 
9449   Input Parameter:
9450 . A - the matrix to check
9451 
9452   Output Parameters:
9453 + set - `PETSC_TRUE` if the matrix knows its Hermitian state (this tells you if the next flag is valid)
9454 - flg - the result (only valid if set is `PETSC_TRUE`)
9455 
9456   Level: advanced
9457 
9458   Notes:
9459   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsHermitian()`
9460   if you want it explicitly checked
9461 
9462   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9463   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9464 
9465 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MAT_HERMITIAN`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`
9466 @*/
9467 PetscErrorCode MatIsHermitianKnown(Mat A, PetscBool *set, PetscBool *flg)
9468 {
9469   PetscFunctionBegin;
9470   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9471   PetscAssertPointer(set, 2);
9472   PetscAssertPointer(flg, 3);
9473   if (A->hermitian != PETSC_BOOL3_UNKNOWN) {
9474     *set = PETSC_TRUE;
9475     *flg = PetscBool3ToBool(A->hermitian);
9476   } else {
9477     *set = PETSC_FALSE;
9478   }
9479   PetscFunctionReturn(PETSC_SUCCESS);
9480 }
9481 
9482 /*@
9483   MatIsStructurallySymmetric - Test whether a matrix is structurally symmetric
9484 
9485   Collective
9486 
9487   Input Parameter:
9488 . A - the matrix to test
9489 
9490   Output Parameter:
9491 . flg - the result
9492 
9493   Level: intermediate
9494 
9495   Notes:
9496   If the matrix does yet know it is structurally symmetric this can be an expensive operation, also available `MatIsStructurallySymmetricKnown()`
9497 
9498   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
9499   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9500 
9501 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsSymmetric()`, `MatSetOption()`, `MatIsStructurallySymmetricKnown()`
9502 @*/
9503 PetscErrorCode MatIsStructurallySymmetric(Mat A, PetscBool *flg)
9504 {
9505   PetscFunctionBegin;
9506   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9507   PetscAssertPointer(flg, 2);
9508   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9509     *flg = PetscBool3ToBool(A->structurally_symmetric);
9510   } else {
9511     PetscUseTypeMethod(A, isstructurallysymmetric, flg);
9512     PetscCall(MatSetOption(A, MAT_STRUCTURALLY_SYMMETRIC, *flg));
9513   }
9514   PetscFunctionReturn(PETSC_SUCCESS);
9515 }
9516 
9517 /*@
9518   MatIsStructurallySymmetricKnown - Checks if a matrix knows if it is structurally symmetric or not and its structurally symmetric state
9519 
9520   Not Collective
9521 
9522   Input Parameter:
9523 . A - the matrix to check
9524 
9525   Output Parameters:
9526 + set - PETSC_TRUE if the matrix knows its structurally symmetric state (this tells you if the next flag is valid)
9527 - flg - the result (only valid if set is PETSC_TRUE)
9528 
9529   Level: advanced
9530 
9531   Notes:
9532   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
9533   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9534 
9535   Use `MatIsStructurallySymmetric()` to explicitly check if a matrix is structurally symmetric (this is an expensive operation)
9536 
9537 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9538 @*/
9539 PetscErrorCode MatIsStructurallySymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9540 {
9541   PetscFunctionBegin;
9542   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9543   PetscAssertPointer(set, 2);
9544   PetscAssertPointer(flg, 3);
9545   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9546     *set = PETSC_TRUE;
9547     *flg = PetscBool3ToBool(A->structurally_symmetric);
9548   } else {
9549     *set = PETSC_FALSE;
9550   }
9551   PetscFunctionReturn(PETSC_SUCCESS);
9552 }
9553 
9554 /*@
9555   MatStashGetInfo - Gets how many values are currently in the matrix stash, i.e. need
9556   to be communicated to other processors during the `MatAssemblyBegin()`/`MatAssemblyEnd()` process
9557 
9558   Not Collective
9559 
9560   Input Parameter:
9561 . mat - the matrix
9562 
9563   Output Parameters:
9564 + nstash    - the size of the stash
9565 . reallocs  - the number of additional mallocs incurred.
9566 . bnstash   - the size of the block stash
9567 - breallocs - the number of additional mallocs incurred.in the block stash
9568 
9569   Level: advanced
9570 
9571 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashSetInitialSize()`
9572 @*/
9573 PetscErrorCode MatStashGetInfo(Mat mat, PetscInt *nstash, PetscInt *reallocs, PetscInt *bnstash, PetscInt *breallocs)
9574 {
9575   PetscFunctionBegin;
9576   PetscCall(MatStashGetInfo_Private(&mat->stash, nstash, reallocs));
9577   PetscCall(MatStashGetInfo_Private(&mat->bstash, bnstash, breallocs));
9578   PetscFunctionReturn(PETSC_SUCCESS);
9579 }
9580 
9581 /*@
9582   MatCreateVecs - Get vector(s) compatible with the matrix, i.e. with the same
9583   parallel layout, `PetscLayout` for rows and columns
9584 
9585   Collective
9586 
9587   Input Parameter:
9588 . mat - the matrix
9589 
9590   Output Parameters:
9591 + right - (optional) vector that the matrix can be multiplied against
9592 - left  - (optional) vector that the matrix vector product can be stored in
9593 
9594   Level: advanced
9595 
9596   Notes:
9597   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()`.
9598 
9599   These are new vectors which are not owned by the mat, they should be destroyed in `VecDestroy()` when no longer needed
9600 
9601 .seealso: [](ch_matrices), `Mat`, `Vec`, `VecCreate()`, `VecDestroy()`, `DMCreateGlobalVector()`
9602 @*/
9603 PetscErrorCode MatCreateVecs(Mat mat, Vec *right, Vec *left)
9604 {
9605   PetscFunctionBegin;
9606   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9607   PetscValidType(mat, 1);
9608   if (mat->ops->getvecs) {
9609     PetscUseTypeMethod(mat, getvecs, right, left);
9610   } else {
9611     if (right) {
9612       PetscCheck(mat->cmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for columns not yet setup");
9613       PetscCall(VecCreateWithLayout_Private(mat->cmap, right));
9614       PetscCall(VecSetType(*right, mat->defaultvectype));
9615 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9616       if (mat->boundtocpu && mat->bindingpropagates) {
9617         PetscCall(VecSetBindingPropagates(*right, PETSC_TRUE));
9618         PetscCall(VecBindToCPU(*right, PETSC_TRUE));
9619       }
9620 #endif
9621     }
9622     if (left) {
9623       PetscCheck(mat->rmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for rows not yet setup");
9624       PetscCall(VecCreateWithLayout_Private(mat->rmap, left));
9625       PetscCall(VecSetType(*left, mat->defaultvectype));
9626 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9627       if (mat->boundtocpu && mat->bindingpropagates) {
9628         PetscCall(VecSetBindingPropagates(*left, PETSC_TRUE));
9629         PetscCall(VecBindToCPU(*left, PETSC_TRUE));
9630       }
9631 #endif
9632     }
9633   }
9634   PetscFunctionReturn(PETSC_SUCCESS);
9635 }
9636 
9637 /*@
9638   MatFactorInfoInitialize - Initializes a `MatFactorInfo` data structure
9639   with default values.
9640 
9641   Not Collective
9642 
9643   Input Parameter:
9644 . info - the `MatFactorInfo` data structure
9645 
9646   Level: developer
9647 
9648   Notes:
9649   The solvers are generally used through the `KSP` and `PC` objects, for example
9650   `PCLU`, `PCILU`, `PCCHOLESKY`, `PCICC`
9651 
9652   Once the data structure is initialized one may change certain entries as desired for the particular factorization to be performed
9653 
9654 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorInfo`
9655 @*/
9656 PetscErrorCode MatFactorInfoInitialize(MatFactorInfo *info)
9657 {
9658   PetscFunctionBegin;
9659   PetscCall(PetscMemzero(info, sizeof(MatFactorInfo)));
9660   PetscFunctionReturn(PETSC_SUCCESS);
9661 }
9662 
9663 /*@
9664   MatFactorSetSchurIS - Set indices corresponding to the Schur complement you wish to have computed
9665 
9666   Collective
9667 
9668   Input Parameters:
9669 + mat - the factored matrix
9670 - is  - the index set defining the Schur indices (0-based)
9671 
9672   Level: advanced
9673 
9674   Notes:
9675   Call `MatFactorSolveSchurComplement()` or `MatFactorSolveSchurComplementTranspose()` after this call to solve a Schur complement system.
9676 
9677   You can call `MatFactorGetSchurComplement()` or `MatFactorCreateSchurComplement()` after this call.
9678 
9679   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9680 
9681 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorGetSchurComplement()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSolveSchurComplement()`,
9682           `MatFactorSolveSchurComplementTranspose()`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9683 @*/
9684 PetscErrorCode MatFactorSetSchurIS(Mat mat, IS is)
9685 {
9686   PetscErrorCode (*f)(Mat, IS);
9687 
9688   PetscFunctionBegin;
9689   PetscValidType(mat, 1);
9690   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9691   PetscValidType(is, 2);
9692   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
9693   PetscCheckSameComm(mat, 1, is, 2);
9694   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
9695   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorSetSchurIS_C", &f));
9696   PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "The selected MatSolverType does not support Schur complement computation. You should use MATSOLVERMUMPS or MATSOLVERMKL_PARDISO");
9697   PetscCall(MatDestroy(&mat->schur));
9698   PetscCall((*f)(mat, is));
9699   PetscCheck(mat->schur, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Schur complement has not been created");
9700   PetscFunctionReturn(PETSC_SUCCESS);
9701 }
9702 
9703 /*@
9704   MatFactorCreateSchurComplement - Create a Schur complement matrix object using Schur data computed during the factorization step
9705 
9706   Logically Collective
9707 
9708   Input Parameters:
9709 + F      - the factored matrix obtained by calling `MatGetFactor()`
9710 . S      - location where to return the Schur complement, can be `NULL`
9711 - status - the status of the Schur complement matrix, can be `NULL`
9712 
9713   Level: advanced
9714 
9715   Notes:
9716   You must call `MatFactorSetSchurIS()` before calling this routine.
9717 
9718   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9719 
9720   The routine provides a copy of the Schur matrix stored within the solver data structures.
9721   The caller must destroy the object when it is no longer needed.
9722   If `MatFactorInvertSchurComplement()` has been called, the routine gets back the inverse.
9723 
9724   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)
9725 
9726   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9727 
9728   Developer Note:
9729   The reason this routine exists is because the representation of the Schur complement within the factor matrix may be different than a standard PETSc
9730   matrix representation and we normally do not want to use the time or memory to make a copy as a regular PETSc matrix.
9731 
9732 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorSchurStatus`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9733 @*/
9734 PetscErrorCode MatFactorCreateSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9735 {
9736   PetscFunctionBegin;
9737   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9738   if (S) PetscAssertPointer(S, 2);
9739   if (status) PetscAssertPointer(status, 3);
9740   if (S) {
9741     PetscErrorCode (*f)(Mat, Mat *);
9742 
9743     PetscCall(PetscObjectQueryFunction((PetscObject)F, "MatFactorCreateSchurComplement_C", &f));
9744     if (f) {
9745       PetscCall((*f)(F, S));
9746     } else {
9747       PetscCall(MatDuplicate(F->schur, MAT_COPY_VALUES, S));
9748     }
9749   }
9750   if (status) *status = F->schur_status;
9751   PetscFunctionReturn(PETSC_SUCCESS);
9752 }
9753 
9754 /*@
9755   MatFactorGetSchurComplement - Gets access to a Schur complement matrix using the current Schur data within a factored matrix
9756 
9757   Logically Collective
9758 
9759   Input Parameters:
9760 + F      - the factored matrix obtained by calling `MatGetFactor()`
9761 . S      - location where to return the Schur complement, can be `NULL`
9762 - status - the status of the Schur complement matrix, can be `NULL`
9763 
9764   Level: advanced
9765 
9766   Notes:
9767   You must call `MatFactorSetSchurIS()` before calling this routine.
9768 
9769   Schur complement mode is currently implemented for sequential matrices with factor type of `MATSOLVERMUMPS`
9770 
9771   The routine returns a the Schur Complement stored within the data structures of the solver.
9772 
9773   If `MatFactorInvertSchurComplement()` has previously been called, the returned matrix is actually the inverse of the Schur complement.
9774 
9775   The returned matrix should not be destroyed; the caller should call `MatFactorRestoreSchurComplement()` when the object is no longer needed.
9776 
9777   Use `MatFactorCreateSchurComplement()` to create a copy of the Schur complement matrix that is within a factored matrix
9778 
9779   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9780 
9781 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9782 @*/
9783 PetscErrorCode MatFactorGetSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9784 {
9785   PetscFunctionBegin;
9786   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9787   if (S) {
9788     PetscAssertPointer(S, 2);
9789     *S = F->schur;
9790   }
9791   if (status) {
9792     PetscAssertPointer(status, 3);
9793     *status = F->schur_status;
9794   }
9795   PetscFunctionReturn(PETSC_SUCCESS);
9796 }
9797 
9798 static PetscErrorCode MatFactorUpdateSchurStatus_Private(Mat F)
9799 {
9800   Mat S = F->schur;
9801 
9802   PetscFunctionBegin;
9803   switch (F->schur_status) {
9804   case MAT_FACTOR_SCHUR_UNFACTORED: // fall-through
9805   case MAT_FACTOR_SCHUR_INVERTED:
9806     if (S) {
9807       S->ops->solve             = NULL;
9808       S->ops->matsolve          = NULL;
9809       S->ops->solvetranspose    = NULL;
9810       S->ops->matsolvetranspose = NULL;
9811       S->ops->solveadd          = NULL;
9812       S->ops->solvetransposeadd = NULL;
9813       S->factortype             = MAT_FACTOR_NONE;
9814       PetscCall(PetscFree(S->solvertype));
9815     }
9816   case MAT_FACTOR_SCHUR_FACTORED: // fall-through
9817     break;
9818   default:
9819     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9820   }
9821   PetscFunctionReturn(PETSC_SUCCESS);
9822 }
9823 
9824 /*@
9825   MatFactorRestoreSchurComplement - Restore the Schur complement matrix object obtained from a call to `MatFactorGetSchurComplement()`
9826 
9827   Logically Collective
9828 
9829   Input Parameters:
9830 + F      - the factored matrix obtained by calling `MatGetFactor()`
9831 . S      - location where the Schur complement is stored
9832 - status - the status of the Schur complement matrix (see `MatFactorSchurStatus`)
9833 
9834   Level: advanced
9835 
9836 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9837 @*/
9838 PetscErrorCode MatFactorRestoreSchurComplement(Mat F, Mat *S, MatFactorSchurStatus status)
9839 {
9840   PetscFunctionBegin;
9841   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9842   if (S) {
9843     PetscValidHeaderSpecific(*S, MAT_CLASSID, 2);
9844     *S = NULL;
9845   }
9846   F->schur_status = status;
9847   PetscCall(MatFactorUpdateSchurStatus_Private(F));
9848   PetscFunctionReturn(PETSC_SUCCESS);
9849 }
9850 
9851 /*@
9852   MatFactorSolveSchurComplementTranspose - Solve the transpose of the Schur complement system computed during the factorization step
9853 
9854   Logically Collective
9855 
9856   Input Parameters:
9857 + F   - the factored matrix obtained by calling `MatGetFactor()`
9858 . rhs - location where the right-hand side of the Schur complement system is stored
9859 - sol - location where the solution of the Schur complement system has to be returned
9860 
9861   Level: advanced
9862 
9863   Notes:
9864   The sizes of the vectors should match the size of the Schur complement
9865 
9866   Must be called after `MatFactorSetSchurIS()`
9867 
9868 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplement()`
9869 @*/
9870 PetscErrorCode MatFactorSolveSchurComplementTranspose(Mat F, Vec rhs, Vec sol)
9871 {
9872   PetscFunctionBegin;
9873   PetscValidType(F, 1);
9874   PetscValidType(rhs, 2);
9875   PetscValidType(sol, 3);
9876   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9877   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
9878   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
9879   PetscCheckSameComm(F, 1, rhs, 2);
9880   PetscCheckSameComm(F, 1, sol, 3);
9881   PetscCall(MatFactorFactorizeSchurComplement(F));
9882   switch (F->schur_status) {
9883   case MAT_FACTOR_SCHUR_FACTORED:
9884     PetscCall(MatSolveTranspose(F->schur, rhs, sol));
9885     break;
9886   case MAT_FACTOR_SCHUR_INVERTED:
9887     PetscCall(MatMultTranspose(F->schur, rhs, sol));
9888     break;
9889   default:
9890     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9891   }
9892   PetscFunctionReturn(PETSC_SUCCESS);
9893 }
9894 
9895 /*@
9896   MatFactorSolveSchurComplement - Solve the Schur complement system computed during the factorization step
9897 
9898   Logically Collective
9899 
9900   Input Parameters:
9901 + F   - the factored matrix obtained by calling `MatGetFactor()`
9902 . rhs - location where the right-hand side of the Schur complement system is stored
9903 - sol - location where the solution of the Schur complement system has to be returned
9904 
9905   Level: advanced
9906 
9907   Notes:
9908   The sizes of the vectors should match the size of the Schur complement
9909 
9910   Must be called after `MatFactorSetSchurIS()`
9911 
9912 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplementTranspose()`
9913 @*/
9914 PetscErrorCode MatFactorSolveSchurComplement(Mat F, Vec rhs, Vec sol)
9915 {
9916   PetscFunctionBegin;
9917   PetscValidType(F, 1);
9918   PetscValidType(rhs, 2);
9919   PetscValidType(sol, 3);
9920   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9921   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
9922   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
9923   PetscCheckSameComm(F, 1, rhs, 2);
9924   PetscCheckSameComm(F, 1, sol, 3);
9925   PetscCall(MatFactorFactorizeSchurComplement(F));
9926   switch (F->schur_status) {
9927   case MAT_FACTOR_SCHUR_FACTORED:
9928     PetscCall(MatSolve(F->schur, rhs, sol));
9929     break;
9930   case MAT_FACTOR_SCHUR_INVERTED:
9931     PetscCall(MatMult(F->schur, rhs, sol));
9932     break;
9933   default:
9934     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9935   }
9936   PetscFunctionReturn(PETSC_SUCCESS);
9937 }
9938 
9939 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode MatSeqDenseInvertFactors_Private(Mat);
9940 #if PetscDefined(HAVE_CUDA)
9941 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode MatSeqDenseCUDAInvertFactors_Internal(Mat);
9942 #endif
9943 
9944 /* Schur status updated in the interface */
9945 static PetscErrorCode MatFactorInvertSchurComplement_Private(Mat F)
9946 {
9947   Mat S = F->schur;
9948 
9949   PetscFunctionBegin;
9950   if (S) {
9951     PetscMPIInt size;
9952     PetscBool   isdense, isdensecuda;
9953 
9954     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)S), &size));
9955     PetscCheck(size <= 1, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not yet implemented");
9956     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSE, &isdense));
9957     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSECUDA, &isdensecuda));
9958     PetscCheck(isdense || isdensecuda, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not implemented for type %s", ((PetscObject)S)->type_name);
9959     PetscCall(PetscLogEventBegin(MAT_FactorInvS, F, 0, 0, 0));
9960     if (isdense) {
9961       PetscCall(MatSeqDenseInvertFactors_Private(S));
9962     } else if (isdensecuda) {
9963 #if defined(PETSC_HAVE_CUDA)
9964       PetscCall(MatSeqDenseCUDAInvertFactors_Internal(S));
9965 #endif
9966     }
9967     // HIP??????????????
9968     PetscCall(PetscLogEventEnd(MAT_FactorInvS, F, 0, 0, 0));
9969   }
9970   PetscFunctionReturn(PETSC_SUCCESS);
9971 }
9972 
9973 /*@
9974   MatFactorInvertSchurComplement - Invert the Schur complement matrix computed during the factorization step
9975 
9976   Logically Collective
9977 
9978   Input Parameter:
9979 . F - the factored matrix obtained by calling `MatGetFactor()`
9980 
9981   Level: advanced
9982 
9983   Notes:
9984   Must be called after `MatFactorSetSchurIS()`.
9985 
9986   Call `MatFactorGetSchurComplement()` or  `MatFactorCreateSchurComplement()` AFTER this call to actually compute the inverse and get access to it.
9987 
9988 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorCreateSchurComplement()`
9989 @*/
9990 PetscErrorCode MatFactorInvertSchurComplement(Mat F)
9991 {
9992   PetscFunctionBegin;
9993   PetscValidType(F, 1);
9994   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9995   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED) PetscFunctionReturn(PETSC_SUCCESS);
9996   PetscCall(MatFactorFactorizeSchurComplement(F));
9997   PetscCall(MatFactorInvertSchurComplement_Private(F));
9998   F->schur_status = MAT_FACTOR_SCHUR_INVERTED;
9999   PetscFunctionReturn(PETSC_SUCCESS);
10000 }
10001 
10002 /*@
10003   MatFactorFactorizeSchurComplement - Factorize the Schur complement matrix computed during the factorization step
10004 
10005   Logically Collective
10006 
10007   Input Parameter:
10008 . F - the factored matrix obtained by calling `MatGetFactor()`
10009 
10010   Level: advanced
10011 
10012   Note:
10013   Must be called after `MatFactorSetSchurIS()`
10014 
10015 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorInvertSchurComplement()`
10016 @*/
10017 PetscErrorCode MatFactorFactorizeSchurComplement(Mat F)
10018 {
10019   MatFactorInfo info;
10020 
10021   PetscFunctionBegin;
10022   PetscValidType(F, 1);
10023   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
10024   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED || F->schur_status == MAT_FACTOR_SCHUR_FACTORED) PetscFunctionReturn(PETSC_SUCCESS);
10025   PetscCall(PetscLogEventBegin(MAT_FactorFactS, F, 0, 0, 0));
10026   PetscCall(PetscMemzero(&info, sizeof(MatFactorInfo)));
10027   if (F->factortype == MAT_FACTOR_CHOLESKY) { /* LDL^t regarded as Cholesky */
10028     PetscCall(MatCholeskyFactor(F->schur, NULL, &info));
10029   } else {
10030     PetscCall(MatLUFactor(F->schur, NULL, NULL, &info));
10031   }
10032   PetscCall(PetscLogEventEnd(MAT_FactorFactS, F, 0, 0, 0));
10033   F->schur_status = MAT_FACTOR_SCHUR_FACTORED;
10034   PetscFunctionReturn(PETSC_SUCCESS);
10035 }
10036 
10037 /*@
10038   MatPtAP - Creates the matrix product $C = P^T * A * P$
10039 
10040   Neighbor-wise Collective
10041 
10042   Input Parameters:
10043 + A     - the matrix
10044 . P     - the projection matrix
10045 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10046 - 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
10047           if the result is a dense matrix this is irrelevant
10048 
10049   Output Parameter:
10050 . C - the product matrix
10051 
10052   Level: intermediate
10053 
10054   Notes:
10055   C will be created and must be destroyed by the user with `MatDestroy()`.
10056 
10057   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
10058 
10059   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10060 
10061   Developer Note:
10062   For matrix types without special implementation the function fallbacks to `MatMatMult()` followed by `MatTransposeMatMult()`.
10063 
10064 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatRARt()`
10065 @*/
10066 PetscErrorCode MatPtAP(Mat A, Mat P, MatReuse scall, PetscReal fill, Mat *C)
10067 {
10068   PetscFunctionBegin;
10069   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10070   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10071 
10072   if (scall == MAT_INITIAL_MATRIX) {
10073     PetscCall(MatProductCreate(A, P, NULL, C));
10074     PetscCall(MatProductSetType(*C, MATPRODUCT_PtAP));
10075     PetscCall(MatProductSetAlgorithm(*C, "default"));
10076     PetscCall(MatProductSetFill(*C, fill));
10077 
10078     (*C)->product->api_user = PETSC_TRUE;
10079     PetscCall(MatProductSetFromOptions(*C));
10080     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);
10081     PetscCall(MatProductSymbolic(*C));
10082   } else { /* scall == MAT_REUSE_MATRIX */
10083     PetscCall(MatProductReplaceMats(A, P, NULL, *C));
10084   }
10085 
10086   PetscCall(MatProductNumeric(*C));
10087   (*C)->symmetric = A->symmetric;
10088   (*C)->spd       = A->spd;
10089   PetscFunctionReturn(PETSC_SUCCESS);
10090 }
10091 
10092 /*@
10093   MatRARt - Creates the matrix product $C = R * A * R^T$
10094 
10095   Neighbor-wise Collective
10096 
10097   Input Parameters:
10098 + A     - the matrix
10099 . R     - the projection matrix
10100 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10101 - fill  - expected fill as ratio of nnz(C)/nnz(A), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10102           if the result is a dense matrix this is irrelevant
10103 
10104   Output Parameter:
10105 . C - the product matrix
10106 
10107   Level: intermediate
10108 
10109   Notes:
10110   `C` will be created and must be destroyed by the user with `MatDestroy()`.
10111 
10112   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
10113 
10114   This routine is currently only implemented for pairs of `MATAIJ` matrices and classes
10115   which inherit from `MATAIJ`. Due to PETSc sparse matrix block row distribution among processes,
10116   the parallel `MatRARt()` is implemented computing the explicit transpose of `R`, which can be very expensive.
10117   We recommend using `MatPtAP()` when possible.
10118 
10119   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10120 
10121 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatPtAP()`
10122 @*/
10123 PetscErrorCode MatRARt(Mat A, Mat R, MatReuse scall, PetscReal fill, Mat *C)
10124 {
10125   PetscFunctionBegin;
10126   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10127   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10128 
10129   if (scall == MAT_INITIAL_MATRIX) {
10130     PetscCall(MatProductCreate(A, R, NULL, C));
10131     PetscCall(MatProductSetType(*C, MATPRODUCT_RARt));
10132     PetscCall(MatProductSetAlgorithm(*C, "default"));
10133     PetscCall(MatProductSetFill(*C, fill));
10134 
10135     (*C)->product->api_user = PETSC_TRUE;
10136     PetscCall(MatProductSetFromOptions(*C));
10137     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);
10138     PetscCall(MatProductSymbolic(*C));
10139   } else { /* scall == MAT_REUSE_MATRIX */
10140     PetscCall(MatProductReplaceMats(A, R, NULL, *C));
10141   }
10142 
10143   PetscCall(MatProductNumeric(*C));
10144   if (A->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10145   PetscFunctionReturn(PETSC_SUCCESS);
10146 }
10147 
10148 static PetscErrorCode MatProduct_Private(Mat A, Mat B, MatReuse scall, PetscReal fill, MatProductType ptype, Mat *C)
10149 {
10150   PetscBool flg = PETSC_TRUE;
10151 
10152   PetscFunctionBegin;
10153   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX product not supported");
10154   if (scall == MAT_INITIAL_MATRIX) {
10155     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_INITIAL_MATRIX and product type %s\n", MatProductTypes[ptype]));
10156     PetscCall(MatProductCreate(A, B, NULL, C));
10157     PetscCall(MatProductSetAlgorithm(*C, MATPRODUCTALGORITHMDEFAULT));
10158     PetscCall(MatProductSetFill(*C, fill));
10159   } else { /* scall == MAT_REUSE_MATRIX */
10160     Mat_Product *product = (*C)->product;
10161 
10162     PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)*C, &flg, MATSEQDENSE, MATMPIDENSE, ""));
10163     if (flg && product && product->type != ptype) {
10164       PetscCall(MatProductClear(*C));
10165       product = NULL;
10166     }
10167     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_REUSE_MATRIX %s product present and product type %s\n", product ? "with" : "without", MatProductTypes[ptype]));
10168     if (!product) { /* user provide the dense matrix *C without calling MatProductCreate() or reusing it from previous calls */
10169       PetscCheck(flg, PetscObjectComm((PetscObject)*C), PETSC_ERR_SUP, "Call MatProductCreate() first");
10170       PetscCall(MatProductCreate_Private(A, B, NULL, *C));
10171       product        = (*C)->product;
10172       product->fill  = fill;
10173       product->clear = PETSC_TRUE;
10174     } else { /* user may change input matrices A or B when MAT_REUSE_MATRIX */
10175       flg = PETSC_FALSE;
10176       PetscCall(MatProductReplaceMats(A, B, NULL, *C));
10177     }
10178   }
10179   if (flg) {
10180     (*C)->product->api_user = PETSC_TRUE;
10181     PetscCall(MatProductSetType(*C, ptype));
10182     PetscCall(MatProductSetFromOptions(*C));
10183     PetscCall(MatProductSymbolic(*C));
10184   }
10185   PetscCall(MatProductNumeric(*C));
10186   PetscFunctionReturn(PETSC_SUCCESS);
10187 }
10188 
10189 /*@
10190   MatMatMult - Performs matrix-matrix multiplication C=A*B.
10191 
10192   Neighbor-wise Collective
10193 
10194   Input Parameters:
10195 + A     - the left matrix
10196 . B     - the right matrix
10197 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10198 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10199           if the result is a dense matrix this is irrelevant
10200 
10201   Output Parameter:
10202 . C - the product matrix
10203 
10204   Notes:
10205   Unless scall is `MAT_REUSE_MATRIX` C will be created.
10206 
10207   `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
10208   call to this function with `MAT_INITIAL_MATRIX`.
10209 
10210   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value actually needed.
10211 
10212   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`,
10213   rather than first having `MatMatMult()` create it for you. You can NEVER do this if the matrix `C` is sparse.
10214 
10215   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10216 
10217   Example of Usage:
10218 .vb
10219      MatProductCreate(A,B,NULL,&C);
10220      MatProductSetType(C,MATPRODUCT_AB);
10221      MatProductSymbolic(C);
10222      MatProductNumeric(C); // compute C=A * B
10223      MatProductReplaceMats(A1,B1,NULL,C); // compute C=A1 * B1
10224      MatProductNumeric(C);
10225      MatProductReplaceMats(A2,NULL,NULL,C); // compute C=A2 * B1
10226      MatProductNumeric(C);
10227 .ve
10228 
10229   Level: intermediate
10230 
10231 .seealso: [](ch_matrices), `Mat`, `MatProductType`, `MATPRODUCT_AB`, `MatTransposeMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`, `MatProductCreate()`, `MatProductSymbolic()`, `MatProductReplaceMats()`, `MatProductNumeric()`
10232 @*/
10233 PetscErrorCode MatMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10234 {
10235   PetscFunctionBegin;
10236   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AB, C));
10237   PetscFunctionReturn(PETSC_SUCCESS);
10238 }
10239 
10240 /*@
10241   MatMatTransposeMult - Performs matrix-matrix multiplication $C = A*B^T$.
10242 
10243   Neighbor-wise Collective
10244 
10245   Input Parameters:
10246 + A     - the left matrix
10247 . B     - the right matrix
10248 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10249 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10250 
10251   Output Parameter:
10252 . C - the product matrix
10253 
10254   Options Database Key:
10255 . -matmattransmult_mpidense_mpidense_via {allgatherv,cyclic} - Choose between algorithms for `MATMPIDENSE` matrices: the
10256               first redundantly copies the transposed `B` matrix on each process and requires O(log P) communication complexity;
10257               the second never stores more than one portion of the `B` matrix at a time but requires O(P) communication complexity.
10258 
10259   Level: intermediate
10260 
10261   Notes:
10262   C will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10263 
10264   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call
10265 
10266   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10267   actually needed.
10268 
10269   This routine is currently only implemented for pairs of `MATSEQAIJ` matrices, for the `MATSEQDENSE` class,
10270   and for pairs of `MATMPIDENSE` matrices.
10271 
10272   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABt`
10273 
10274   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10275 
10276 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABt`, `MatMatMult()`, `MatTransposeMatMult()` `MatPtAP()`, `MatProductAlgorithm`, `MatProductType`
10277 @*/
10278 PetscErrorCode MatMatTransposeMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10279 {
10280   PetscFunctionBegin;
10281   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_ABt, C));
10282   if (A == B) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10283   PetscFunctionReturn(PETSC_SUCCESS);
10284 }
10285 
10286 /*@
10287   MatTransposeMatMult - Performs matrix-matrix multiplication $C = A^T*B$.
10288 
10289   Neighbor-wise Collective
10290 
10291   Input Parameters:
10292 + A     - the left matrix
10293 . B     - the right matrix
10294 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10295 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10296 
10297   Output Parameter:
10298 . C - the product matrix
10299 
10300   Level: intermediate
10301 
10302   Notes:
10303   `C` will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10304 
10305   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call.
10306 
10307   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_AtB`
10308 
10309   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10310   actually needed.
10311 
10312   This routine is currently implemented for pairs of `MATAIJ` matrices and pairs of `MATSEQDENSE` matrices and classes
10313   which inherit from `MATSEQAIJ`.  `C` will be of the same type as the input matrices.
10314 
10315   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10316 
10317 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_AtB`, `MatMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`
10318 @*/
10319 PetscErrorCode MatTransposeMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10320 {
10321   PetscFunctionBegin;
10322   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AtB, C));
10323   PetscFunctionReturn(PETSC_SUCCESS);
10324 }
10325 
10326 /*@
10327   MatMatMatMult - Performs matrix-matrix-matrix multiplication D=A*B*C.
10328 
10329   Neighbor-wise Collective
10330 
10331   Input Parameters:
10332 + A     - the left matrix
10333 . B     - the middle matrix
10334 . C     - the right matrix
10335 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10336 - 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
10337           if the result is a dense matrix this is irrelevant
10338 
10339   Output Parameter:
10340 . D - the product matrix
10341 
10342   Level: intermediate
10343 
10344   Notes:
10345   Unless `scall` is `MAT_REUSE_MATRIX` `D` will be created.
10346 
10347   `MAT_REUSE_MATRIX` can only be used if the matrices `A`, `B`, and `C` have the same nonzero pattern as in the previous call
10348 
10349   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABC`
10350 
10351   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value
10352   actually needed.
10353 
10354   If you have many matrices with the same non-zero structure to multiply, you
10355   should use `MAT_REUSE_MATRIX` in all calls but the first
10356 
10357   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10358 
10359 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABC`, `MatMatMult`, `MatPtAP()`, `MatMatTransposeMult()`, `MatTransposeMatMult()`
10360 @*/
10361 PetscErrorCode MatMatMatMult(Mat A, Mat B, Mat C, MatReuse scall, PetscReal fill, Mat *D)
10362 {
10363   PetscFunctionBegin;
10364   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*D, 6);
10365   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10366 
10367   if (scall == MAT_INITIAL_MATRIX) {
10368     PetscCall(MatProductCreate(A, B, C, D));
10369     PetscCall(MatProductSetType(*D, MATPRODUCT_ABC));
10370     PetscCall(MatProductSetAlgorithm(*D, "default"));
10371     PetscCall(MatProductSetFill(*D, fill));
10372 
10373     (*D)->product->api_user = PETSC_TRUE;
10374     PetscCall(MatProductSetFromOptions(*D));
10375     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,
10376                ((PetscObject)C)->type_name);
10377     PetscCall(MatProductSymbolic(*D));
10378   } else { /* user may change input matrices when REUSE */
10379     PetscCall(MatProductReplaceMats(A, B, C, *D));
10380   }
10381   PetscCall(MatProductNumeric(*D));
10382   PetscFunctionReturn(PETSC_SUCCESS);
10383 }
10384 
10385 /*@
10386   MatCreateRedundantMatrix - Create redundant matrices and put them into processors of subcommunicators.
10387 
10388   Collective
10389 
10390   Input Parameters:
10391 + mat      - the matrix
10392 . nsubcomm - the number of subcommunicators (= number of redundant parallel or sequential matrices)
10393 . subcomm  - MPI communicator split from the communicator where mat resides in (or `MPI_COMM_NULL` if nsubcomm is used)
10394 - reuse    - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10395 
10396   Output Parameter:
10397 . matredundant - redundant matrix
10398 
10399   Level: advanced
10400 
10401   Notes:
10402   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
10403   original matrix has not changed from that last call to `MatCreateRedundantMatrix()`.
10404 
10405   This routine creates the duplicated matrices in the subcommunicators; you should NOT create them before
10406   calling it.
10407 
10408   `PetscSubcommCreate()` can be used to manage the creation of the subcomm but need not be.
10409 
10410 .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `PetscSubcommCreate()`, `PetscSubcomm`
10411 @*/
10412 PetscErrorCode MatCreateRedundantMatrix(Mat mat, PetscInt nsubcomm, MPI_Comm subcomm, MatReuse reuse, Mat *matredundant)
10413 {
10414   MPI_Comm       comm;
10415   PetscMPIInt    size;
10416   PetscInt       mloc_sub, nloc_sub, rstart, rend, M = mat->rmap->N, N = mat->cmap->N, bs = mat->rmap->bs;
10417   Mat_Redundant *redund     = NULL;
10418   PetscSubcomm   psubcomm   = NULL;
10419   MPI_Comm       subcomm_in = subcomm;
10420   Mat           *matseq;
10421   IS             isrow, iscol;
10422   PetscBool      newsubcomm = PETSC_FALSE;
10423 
10424   PetscFunctionBegin;
10425   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10426   if (nsubcomm && reuse == MAT_REUSE_MATRIX) {
10427     PetscAssertPointer(*matredundant, 5);
10428     PetscValidHeaderSpecific(*matredundant, MAT_CLASSID, 5);
10429   }
10430 
10431   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
10432   if (size == 1 || nsubcomm == 1) {
10433     if (reuse == MAT_INITIAL_MATRIX) {
10434       PetscCall(MatDuplicate(mat, MAT_COPY_VALUES, matredundant));
10435     } else {
10436       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");
10437       PetscCall(MatCopy(mat, *matredundant, SAME_NONZERO_PATTERN));
10438     }
10439     PetscFunctionReturn(PETSC_SUCCESS);
10440   }
10441 
10442   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10443   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10444   MatCheckPreallocated(mat, 1);
10445 
10446   PetscCall(PetscLogEventBegin(MAT_RedundantMat, mat, 0, 0, 0));
10447   if (subcomm_in == MPI_COMM_NULL && reuse == MAT_INITIAL_MATRIX) { /* get subcomm if user does not provide subcomm */
10448     /* create psubcomm, then get subcomm */
10449     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10450     PetscCallMPI(MPI_Comm_size(comm, &size));
10451     PetscCheck(nsubcomm >= 1 && nsubcomm <= size, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "nsubcomm must between 1 and %d", size);
10452 
10453     PetscCall(PetscSubcommCreate(comm, &psubcomm));
10454     PetscCall(PetscSubcommSetNumber(psubcomm, nsubcomm));
10455     PetscCall(PetscSubcommSetType(psubcomm, PETSC_SUBCOMM_CONTIGUOUS));
10456     PetscCall(PetscSubcommSetFromOptions(psubcomm));
10457     PetscCall(PetscCommDuplicate(PetscSubcommChild(psubcomm), &subcomm, NULL));
10458     newsubcomm = PETSC_TRUE;
10459     PetscCall(PetscSubcommDestroy(&psubcomm));
10460   }
10461 
10462   /* get isrow, iscol and a local sequential matrix matseq[0] */
10463   if (reuse == MAT_INITIAL_MATRIX) {
10464     mloc_sub = PETSC_DECIDE;
10465     nloc_sub = PETSC_DECIDE;
10466     if (bs < 1) {
10467       PetscCall(PetscSplitOwnership(subcomm, &mloc_sub, &M));
10468       PetscCall(PetscSplitOwnership(subcomm, &nloc_sub, &N));
10469     } else {
10470       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &mloc_sub, &M));
10471       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &nloc_sub, &N));
10472     }
10473     PetscCallMPI(MPI_Scan(&mloc_sub, &rend, 1, MPIU_INT, MPI_SUM, subcomm));
10474     rstart = rend - mloc_sub;
10475     PetscCall(ISCreateStride(PETSC_COMM_SELF, mloc_sub, rstart, 1, &isrow));
10476     PetscCall(ISCreateStride(PETSC_COMM_SELF, N, 0, 1, &iscol));
10477     PetscCall(ISSetIdentity(iscol));
10478   } else { /* reuse == MAT_REUSE_MATRIX */
10479     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");
10480     /* retrieve subcomm */
10481     PetscCall(PetscObjectGetComm((PetscObject)*matredundant, &subcomm));
10482     redund = (*matredundant)->redundant;
10483     isrow  = redund->isrow;
10484     iscol  = redund->iscol;
10485     matseq = redund->matseq;
10486   }
10487   PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscol, reuse, &matseq));
10488 
10489   /* get matredundant over subcomm */
10490   if (reuse == MAT_INITIAL_MATRIX) {
10491     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], nloc_sub, reuse, matredundant));
10492 
10493     /* create a supporting struct and attach it to C for reuse */
10494     PetscCall(PetscNew(&redund));
10495     (*matredundant)->redundant = redund;
10496     redund->isrow              = isrow;
10497     redund->iscol              = iscol;
10498     redund->matseq             = matseq;
10499     if (newsubcomm) {
10500       redund->subcomm = subcomm;
10501     } else {
10502       redund->subcomm = MPI_COMM_NULL;
10503     }
10504   } else {
10505     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], PETSC_DECIDE, reuse, matredundant));
10506   }
10507 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
10508   if (matseq[0]->boundtocpu && matseq[0]->bindingpropagates) {
10509     PetscCall(MatBindToCPU(*matredundant, PETSC_TRUE));
10510     PetscCall(MatSetBindingPropagates(*matredundant, PETSC_TRUE));
10511   }
10512 #endif
10513   PetscCall(PetscLogEventEnd(MAT_RedundantMat, mat, 0, 0, 0));
10514   PetscFunctionReturn(PETSC_SUCCESS);
10515 }
10516 
10517 /*@C
10518   MatGetMultiProcBlock - Create multiple 'parallel submatrices' from
10519   a given `Mat`. Each submatrix can span multiple procs.
10520 
10521   Collective
10522 
10523   Input Parameters:
10524 + mat     - the matrix
10525 . subComm - the sub communicator obtained as if by `MPI_Comm_split(PetscObjectComm((PetscObject)mat))`
10526 - scall   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10527 
10528   Output Parameter:
10529 . subMat - parallel sub-matrices each spanning a given `subcomm`
10530 
10531   Level: advanced
10532 
10533   Notes:
10534   The submatrix partition across processors is dictated by `subComm` a
10535   communicator obtained by `MPI_comm_split()` or via `PetscSubcommCreate()`. The `subComm`
10536   is not restricted to be grouped with consecutive original MPI processes.
10537 
10538   Due the `MPI_Comm_split()` usage, the parallel layout of the submatrices
10539   map directly to the layout of the original matrix [wrt the local
10540   row,col partitioning]. So the original 'DiagonalMat' naturally maps
10541   into the 'DiagonalMat' of the `subMat`, hence it is used directly from
10542   the `subMat`. However the offDiagMat looses some columns - and this is
10543   reconstructed with `MatSetValues()`
10544 
10545   This is used by `PCBJACOBI` when a single block spans multiple MPI processes.
10546 
10547 .seealso: [](ch_matrices), `Mat`, `MatCreateRedundantMatrix()`, `MatCreateSubMatrices()`, `PCBJACOBI`
10548 @*/
10549 PetscErrorCode MatGetMultiProcBlock(Mat mat, MPI_Comm subComm, MatReuse scall, Mat *subMat)
10550 {
10551   PetscMPIInt commsize, subCommSize;
10552 
10553   PetscFunctionBegin;
10554   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &commsize));
10555   PetscCallMPI(MPI_Comm_size(subComm, &subCommSize));
10556   PetscCheck(subCommSize <= commsize, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "CommSize %d < SubCommZize %d", commsize, subCommSize);
10557 
10558   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");
10559   PetscCall(PetscLogEventBegin(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10560   PetscUseTypeMethod(mat, getmultiprocblock, subComm, scall, subMat);
10561   PetscCall(PetscLogEventEnd(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10562   PetscFunctionReturn(PETSC_SUCCESS);
10563 }
10564 
10565 /*@
10566   MatGetLocalSubMatrix - Gets a reference to a submatrix specified in local numbering
10567 
10568   Not Collective
10569 
10570   Input Parameters:
10571 + mat   - matrix to extract local submatrix from
10572 . isrow - local row indices for submatrix
10573 - iscol - local column indices for submatrix
10574 
10575   Output Parameter:
10576 . submat - the submatrix
10577 
10578   Level: intermediate
10579 
10580   Notes:
10581   `submat` should be disposed of with `MatRestoreLocalSubMatrix()`.
10582 
10583   Depending on the format of `mat`, the returned `submat` may not implement `MatMult()`.  Its communicator may be
10584   the same as `mat`, it may be `PETSC_COMM_SELF`, or some other sub-communictor of `mat`'s.
10585 
10586   `submat` always implements `MatSetValuesLocal()`.  If `isrow` and `iscol` have the same block size, then
10587   `MatSetValuesBlockedLocal()` will also be implemented.
10588 
10589   `mat` must have had a `ISLocalToGlobalMapping` provided to it with `MatSetLocalToGlobalMapping()`.
10590   Matrices obtained with `DMCreateMatrix()` generally already have the local to global mapping provided.
10591 
10592 .seealso: [](ch_matrices), `Mat`, `MatRestoreLocalSubMatrix()`, `MatCreateLocalRef()`, `MatSetLocalToGlobalMapping()`
10593 @*/
10594 PetscErrorCode MatGetLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10595 {
10596   PetscFunctionBegin;
10597   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10598   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10599   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10600   PetscCheckSameComm(isrow, 2, iscol, 3);
10601   PetscAssertPointer(submat, 4);
10602   PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must have local to global mapping provided before this call");
10603 
10604   if (mat->ops->getlocalsubmatrix) {
10605     PetscUseTypeMethod(mat, getlocalsubmatrix, isrow, iscol, submat);
10606   } else {
10607     PetscCall(MatCreateLocalRef(mat, isrow, iscol, submat));
10608   }
10609   PetscFunctionReturn(PETSC_SUCCESS);
10610 }
10611 
10612 /*@
10613   MatRestoreLocalSubMatrix - Restores a reference to a submatrix specified in local numbering obtained with `MatGetLocalSubMatrix()`
10614 
10615   Not Collective
10616 
10617   Input Parameters:
10618 + mat    - matrix to extract local submatrix from
10619 . isrow  - local row indices for submatrix
10620 . iscol  - local column indices for submatrix
10621 - submat - the submatrix
10622 
10623   Level: intermediate
10624 
10625 .seealso: [](ch_matrices), `Mat`, `MatGetLocalSubMatrix()`
10626 @*/
10627 PetscErrorCode MatRestoreLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10628 {
10629   PetscFunctionBegin;
10630   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10631   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10632   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10633   PetscCheckSameComm(isrow, 2, iscol, 3);
10634   PetscAssertPointer(submat, 4);
10635   if (*submat) PetscValidHeaderSpecific(*submat, MAT_CLASSID, 4);
10636 
10637   if (mat->ops->restorelocalsubmatrix) {
10638     PetscUseTypeMethod(mat, restorelocalsubmatrix, isrow, iscol, submat);
10639   } else {
10640     PetscCall(MatDestroy(submat));
10641   }
10642   *submat = NULL;
10643   PetscFunctionReturn(PETSC_SUCCESS);
10644 }
10645 
10646 /*@
10647   MatFindZeroDiagonals - Finds all the rows of a matrix that have zero or no diagonal entry in the matrix
10648 
10649   Collective
10650 
10651   Input Parameter:
10652 . mat - the matrix
10653 
10654   Output Parameter:
10655 . is - if any rows have zero diagonals this contains the list of them
10656 
10657   Level: developer
10658 
10659 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10660 @*/
10661 PetscErrorCode MatFindZeroDiagonals(Mat mat, IS *is)
10662 {
10663   PetscFunctionBegin;
10664   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10665   PetscValidType(mat, 1);
10666   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10667   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10668 
10669   if (!mat->ops->findzerodiagonals) {
10670     Vec                diag;
10671     const PetscScalar *a;
10672     PetscInt          *rows;
10673     PetscInt           rStart, rEnd, r, nrow = 0;
10674 
10675     PetscCall(MatCreateVecs(mat, &diag, NULL));
10676     PetscCall(MatGetDiagonal(mat, diag));
10677     PetscCall(MatGetOwnershipRange(mat, &rStart, &rEnd));
10678     PetscCall(VecGetArrayRead(diag, &a));
10679     for (r = 0; r < rEnd - rStart; ++r)
10680       if (a[r] == 0.0) ++nrow;
10681     PetscCall(PetscMalloc1(nrow, &rows));
10682     nrow = 0;
10683     for (r = 0; r < rEnd - rStart; ++r)
10684       if (a[r] == 0.0) rows[nrow++] = r + rStart;
10685     PetscCall(VecRestoreArrayRead(diag, &a));
10686     PetscCall(VecDestroy(&diag));
10687     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nrow, rows, PETSC_OWN_POINTER, is));
10688   } else {
10689     PetscUseTypeMethod(mat, findzerodiagonals, is);
10690   }
10691   PetscFunctionReturn(PETSC_SUCCESS);
10692 }
10693 
10694 /*@
10695   MatFindOffBlockDiagonalEntries - Finds all the rows of a matrix that have entries outside of the main diagonal block (defined by the matrix block size)
10696 
10697   Collective
10698 
10699   Input Parameter:
10700 . mat - the matrix
10701 
10702   Output Parameter:
10703 . is - contains the list of rows with off block diagonal entries
10704 
10705   Level: developer
10706 
10707 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10708 @*/
10709 PetscErrorCode MatFindOffBlockDiagonalEntries(Mat mat, IS *is)
10710 {
10711   PetscFunctionBegin;
10712   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10713   PetscValidType(mat, 1);
10714   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10715   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10716 
10717   PetscUseTypeMethod(mat, findoffblockdiagonalentries, is);
10718   PetscFunctionReturn(PETSC_SUCCESS);
10719 }
10720 
10721 /*@C
10722   MatInvertBlockDiagonal - Inverts the block diagonal entries.
10723 
10724   Collective; No Fortran Support
10725 
10726   Input Parameter:
10727 . mat - the matrix
10728 
10729   Output Parameter:
10730 . values - the block inverses in column major order (FORTRAN-like)
10731 
10732   Level: advanced
10733 
10734   Notes:
10735   The size of the blocks is determined by the block size of the matrix.
10736 
10737   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10738 
10739   The blocks all have the same size, use `MatInvertVariableBlockDiagonal()` for variable block size
10740 
10741 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatInvertBlockDiagonalMat()`
10742 @*/
10743 PetscErrorCode MatInvertBlockDiagonal(Mat mat, const PetscScalar *values[])
10744 {
10745   PetscFunctionBegin;
10746   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10747   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10748   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10749   PetscUseTypeMethod(mat, invertblockdiagonal, values);
10750   PetscFunctionReturn(PETSC_SUCCESS);
10751 }
10752 
10753 /*@
10754   MatInvertVariableBlockDiagonal - Inverts the point block diagonal entries.
10755 
10756   Collective; No Fortran Support
10757 
10758   Input Parameters:
10759 + mat     - the matrix
10760 . nblocks - the number of blocks on the process, set with `MatSetVariableBlockSizes()`
10761 - bsizes  - the size of each block on the process, set with `MatSetVariableBlockSizes()`
10762 
10763   Output Parameter:
10764 . values - the block inverses in column major order (FORTRAN-like)
10765 
10766   Level: advanced
10767 
10768   Notes:
10769   Use `MatInvertBlockDiagonal()` if all blocks have the same size
10770 
10771   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10772 
10773 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatSetVariableBlockSizes()`, `MatInvertVariableBlockEnvelope()`
10774 @*/
10775 PetscErrorCode MatInvertVariableBlockDiagonal(Mat mat, PetscInt nblocks, const PetscInt bsizes[], PetscScalar values[])
10776 {
10777   PetscFunctionBegin;
10778   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10779   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10780   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10781   PetscUseTypeMethod(mat, invertvariableblockdiagonal, nblocks, bsizes, values);
10782   PetscFunctionReturn(PETSC_SUCCESS);
10783 }
10784 
10785 /*@
10786   MatInvertBlockDiagonalMat - set the values of matrix C to be the inverted block diagonal of matrix A
10787 
10788   Collective
10789 
10790   Input Parameters:
10791 + A - the matrix
10792 - C - matrix with inverted block diagonal of `A`.  This matrix should be created and may have its type set.
10793 
10794   Level: advanced
10795 
10796   Note:
10797   The blocksize of the matrix is used to determine the blocks on the diagonal of `C`
10798 
10799 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`
10800 @*/
10801 PetscErrorCode MatInvertBlockDiagonalMat(Mat A, Mat C)
10802 {
10803   const PetscScalar *vals;
10804   PetscInt          *dnnz;
10805   PetscInt           m, rstart, rend, bs, i, j;
10806 
10807   PetscFunctionBegin;
10808   PetscCall(MatInvertBlockDiagonal(A, &vals));
10809   PetscCall(MatGetBlockSize(A, &bs));
10810   PetscCall(MatGetLocalSize(A, &m, NULL));
10811   PetscCall(MatSetLayouts(C, A->rmap, A->cmap));
10812   PetscCall(MatSetBlockSizes(C, A->rmap->bs, A->cmap->bs));
10813   PetscCall(PetscMalloc1(m / bs, &dnnz));
10814   for (j = 0; j < m / bs; j++) dnnz[j] = 1;
10815   PetscCall(MatXAIJSetPreallocation(C, bs, dnnz, NULL, NULL, NULL));
10816   PetscCall(PetscFree(dnnz));
10817   PetscCall(MatGetOwnershipRange(C, &rstart, &rend));
10818   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_FALSE));
10819   for (i = rstart / bs; i < rend / bs; i++) PetscCall(MatSetValuesBlocked(C, 1, &i, 1, &i, &vals[(i - rstart / bs) * bs * bs], INSERT_VALUES));
10820   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
10821   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
10822   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_TRUE));
10823   PetscFunctionReturn(PETSC_SUCCESS);
10824 }
10825 
10826 /*@
10827   MatTransposeColoringDestroy - Destroys a coloring context for matrix product $C = A*B^T$ that was created
10828   via `MatTransposeColoringCreate()`.
10829 
10830   Collective
10831 
10832   Input Parameter:
10833 . c - coloring context
10834 
10835   Level: intermediate
10836 
10837 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`
10838 @*/
10839 PetscErrorCode MatTransposeColoringDestroy(MatTransposeColoring *c)
10840 {
10841   MatTransposeColoring matcolor = *c;
10842 
10843   PetscFunctionBegin;
10844   if (!matcolor) PetscFunctionReturn(PETSC_SUCCESS);
10845   if (--((PetscObject)matcolor)->refct > 0) {
10846     matcolor = NULL;
10847     PetscFunctionReturn(PETSC_SUCCESS);
10848   }
10849 
10850   PetscCall(PetscFree3(matcolor->ncolumns, matcolor->nrows, matcolor->colorforrow));
10851   PetscCall(PetscFree(matcolor->rows));
10852   PetscCall(PetscFree(matcolor->den2sp));
10853   PetscCall(PetscFree(matcolor->colorforcol));
10854   PetscCall(PetscFree(matcolor->columns));
10855   if (matcolor->brows > 0) PetscCall(PetscFree(matcolor->lstart));
10856   PetscCall(PetscHeaderDestroy(c));
10857   PetscFunctionReturn(PETSC_SUCCESS);
10858 }
10859 
10860 /*@
10861   MatTransColoringApplySpToDen - Given a symbolic matrix product $C = A*B^T$ for which
10862   a `MatTransposeColoring` context has been created, computes a dense $B^T$ by applying
10863   `MatTransposeColoring` to sparse `B`.
10864 
10865   Collective
10866 
10867   Input Parameters:
10868 + coloring - coloring context created with `MatTransposeColoringCreate()`
10869 - B        - sparse matrix
10870 
10871   Output Parameter:
10872 . Btdense - dense matrix $B^T$
10873 
10874   Level: developer
10875 
10876   Note:
10877   These are used internally for some implementations of `MatRARt()`
10878 
10879 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplyDenToSp()`
10880 @*/
10881 PetscErrorCode MatTransColoringApplySpToDen(MatTransposeColoring coloring, Mat B, Mat Btdense)
10882 {
10883   PetscFunctionBegin;
10884   PetscValidHeaderSpecific(coloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
10885   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
10886   PetscValidHeaderSpecific(Btdense, MAT_CLASSID, 3);
10887 
10888   PetscCall((*B->ops->transcoloringapplysptoden)(coloring, B, Btdense));
10889   PetscFunctionReturn(PETSC_SUCCESS);
10890 }
10891 
10892 /*@
10893   MatTransColoringApplyDenToSp - Given a symbolic matrix product $C_{sp} = A*B^T$ for which
10894   a `MatTransposeColoring` context has been created and a dense matrix $C_{den} = A*B^T_{dense}$
10895   in which `B^T_{dens}` is obtained from `MatTransColoringApplySpToDen()`, recover sparse matrix
10896   $C_{sp}$ from $C_{den}$.
10897 
10898   Collective
10899 
10900   Input Parameters:
10901 + matcoloring - coloring context created with `MatTransposeColoringCreate()`
10902 - Cden        - matrix product of a sparse matrix and a dense matrix Btdense
10903 
10904   Output Parameter:
10905 . Csp - sparse matrix
10906 
10907   Level: developer
10908 
10909   Note:
10910   These are used internally for some implementations of `MatRARt()`
10911 
10912 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`
10913 @*/
10914 PetscErrorCode MatTransColoringApplyDenToSp(MatTransposeColoring matcoloring, Mat Cden, Mat Csp)
10915 {
10916   PetscFunctionBegin;
10917   PetscValidHeaderSpecific(matcoloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
10918   PetscValidHeaderSpecific(Cden, MAT_CLASSID, 2);
10919   PetscValidHeaderSpecific(Csp, MAT_CLASSID, 3);
10920 
10921   PetscCall((*Csp->ops->transcoloringapplydentosp)(matcoloring, Cden, Csp));
10922   PetscCall(MatAssemblyBegin(Csp, MAT_FINAL_ASSEMBLY));
10923   PetscCall(MatAssemblyEnd(Csp, MAT_FINAL_ASSEMBLY));
10924   PetscFunctionReturn(PETSC_SUCCESS);
10925 }
10926 
10927 /*@
10928   MatTransposeColoringCreate - Creates a matrix coloring context for the matrix product $C = A*B^T$.
10929 
10930   Collective
10931 
10932   Input Parameters:
10933 + mat        - the matrix product C
10934 - iscoloring - the coloring of the matrix; usually obtained with `MatColoringCreate()` or `DMCreateColoring()`
10935 
10936   Output Parameter:
10937 . color - the new coloring context
10938 
10939   Level: intermediate
10940 
10941 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`,
10942           `MatTransColoringApplyDenToSp()`
10943 @*/
10944 PetscErrorCode MatTransposeColoringCreate(Mat mat, ISColoring iscoloring, MatTransposeColoring *color)
10945 {
10946   MatTransposeColoring c;
10947   MPI_Comm             comm;
10948 
10949   PetscFunctionBegin;
10950   PetscAssertPointer(color, 3);
10951 
10952   PetscCall(PetscLogEventBegin(MAT_TransposeColoringCreate, mat, 0, 0, 0));
10953   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10954   PetscCall(PetscHeaderCreate(c, MAT_TRANSPOSECOLORING_CLASSID, "MatTransposeColoring", "Matrix product C=A*B^T via coloring", "Mat", comm, MatTransposeColoringDestroy, NULL));
10955   c->ctype = iscoloring->ctype;
10956   PetscUseTypeMethod(mat, transposecoloringcreate, iscoloring, c);
10957   *color = c;
10958   PetscCall(PetscLogEventEnd(MAT_TransposeColoringCreate, mat, 0, 0, 0));
10959   PetscFunctionReturn(PETSC_SUCCESS);
10960 }
10961 
10962 /*@
10963   MatGetNonzeroState - Returns a 64-bit integer representing the current state of nonzeros in the matrix. If the
10964   matrix has had new nonzero locations added to (or removed from) the matrix since the previous call, the value will be larger.
10965 
10966   Not Collective
10967 
10968   Input Parameter:
10969 . mat - the matrix
10970 
10971   Output Parameter:
10972 . state - the current state
10973 
10974   Level: intermediate
10975 
10976   Notes:
10977   You can only compare states from two different calls to the SAME matrix, you cannot compare calls between
10978   different matrices
10979 
10980   Use `PetscObjectStateGet()` to check for changes to the numerical values in a matrix
10981 
10982   Use the result of `PetscObjectGetId()` to compare if a previously checked matrix is the same as the current matrix, do not compare object pointers.
10983 
10984 .seealso: [](ch_matrices), `Mat`, `PetscObjectStateGet()`, `PetscObjectGetId()`
10985 @*/
10986 PetscErrorCode MatGetNonzeroState(Mat mat, PetscObjectState *state)
10987 {
10988   PetscFunctionBegin;
10989   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10990   *state = mat->nonzerostate;
10991   PetscFunctionReturn(PETSC_SUCCESS);
10992 }
10993 
10994 /*@
10995   MatCreateMPIMatConcatenateSeqMat - Creates a single large PETSc matrix by concatenating sequential
10996   matrices from each processor
10997 
10998   Collective
10999 
11000   Input Parameters:
11001 + comm   - the communicators the parallel matrix will live on
11002 . seqmat - the input sequential matrices
11003 . n      - number of local columns (or `PETSC_DECIDE`)
11004 - reuse  - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
11005 
11006   Output Parameter:
11007 . mpimat - the parallel matrix generated
11008 
11009   Level: developer
11010 
11011   Note:
11012   The number of columns of the matrix in EACH processor MUST be the same.
11013 
11014 .seealso: [](ch_matrices), `Mat`
11015 @*/
11016 PetscErrorCode MatCreateMPIMatConcatenateSeqMat(MPI_Comm comm, Mat seqmat, PetscInt n, MatReuse reuse, Mat *mpimat)
11017 {
11018   PetscMPIInt size;
11019 
11020   PetscFunctionBegin;
11021   PetscCallMPI(MPI_Comm_size(comm, &size));
11022   if (size == 1) {
11023     if (reuse == MAT_INITIAL_MATRIX) {
11024       PetscCall(MatDuplicate(seqmat, MAT_COPY_VALUES, mpimat));
11025     } else {
11026       PetscCall(MatCopy(seqmat, *mpimat, SAME_NONZERO_PATTERN));
11027     }
11028     PetscFunctionReturn(PETSC_SUCCESS);
11029   }
11030 
11031   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");
11032 
11033   PetscCall(PetscLogEventBegin(MAT_Merge, seqmat, 0, 0, 0));
11034   PetscCall((*seqmat->ops->creatempimatconcatenateseqmat)(comm, seqmat, n, reuse, mpimat));
11035   PetscCall(PetscLogEventEnd(MAT_Merge, seqmat, 0, 0, 0));
11036   PetscFunctionReturn(PETSC_SUCCESS);
11037 }
11038 
11039 /*@
11040   MatSubdomainsCreateCoalesce - Creates index subdomains by coalescing adjacent MPI processes' ownership ranges.
11041 
11042   Collective
11043 
11044   Input Parameters:
11045 + A - the matrix to create subdomains from
11046 - N - requested number of subdomains
11047 
11048   Output Parameters:
11049 + n   - number of subdomains resulting on this MPI process
11050 - iss - `IS` list with indices of subdomains on this MPI process
11051 
11052   Level: advanced
11053 
11054   Note:
11055   The number of subdomains must be smaller than the communicator size
11056 
11057 .seealso: [](ch_matrices), `Mat`, `IS`
11058 @*/
11059 PetscErrorCode MatSubdomainsCreateCoalesce(Mat A, PetscInt N, PetscInt *n, IS *iss[])
11060 {
11061   MPI_Comm    comm, subcomm;
11062   PetscMPIInt size, rank, color;
11063   PetscInt    rstart, rend, k;
11064 
11065   PetscFunctionBegin;
11066   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
11067   PetscCallMPI(MPI_Comm_size(comm, &size));
11068   PetscCallMPI(MPI_Comm_rank(comm, &rank));
11069   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);
11070   *n    = 1;
11071   k     = size / N + (size % N > 0); /* There are up to k ranks to a color */
11072   color = rank / k;
11073   PetscCallMPI(MPI_Comm_split(comm, color, rank, &subcomm));
11074   PetscCall(PetscMalloc1(1, iss));
11075   PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
11076   PetscCall(ISCreateStride(subcomm, rend - rstart, rstart, 1, iss[0]));
11077   PetscCallMPI(MPI_Comm_free(&subcomm));
11078   PetscFunctionReturn(PETSC_SUCCESS);
11079 }
11080 
11081 /*@
11082   MatGalerkin - Constructs the coarse grid problem matrix via Galerkin projection.
11083 
11084   If the interpolation and restriction operators are the same, uses `MatPtAP()`.
11085   If they are not the same, uses `MatMatMatMult()`.
11086 
11087   Once the coarse grid problem is constructed, correct for interpolation operators
11088   that are not of full rank, which can legitimately happen in the case of non-nested
11089   geometric multigrid.
11090 
11091   Input Parameters:
11092 + restrct     - restriction operator
11093 . dA          - fine grid matrix
11094 . interpolate - interpolation operator
11095 . reuse       - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
11096 - fill        - expected fill, use `PETSC_DETERMINE` or `PETSC_DETERMINE` if you do not have a good estimate
11097 
11098   Output Parameter:
11099 . A - the Galerkin coarse matrix
11100 
11101   Options Database Key:
11102 . -pc_mg_galerkin <both,pmat,mat,none> - for what matrices the Galerkin process should be used
11103 
11104   Level: developer
11105 
11106   Note:
11107   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
11108 
11109 .seealso: [](ch_matrices), `Mat`, `MatPtAP()`, `MatMatMatMult()`
11110 @*/
11111 PetscErrorCode MatGalerkin(Mat restrct, Mat dA, Mat interpolate, MatReuse reuse, PetscReal fill, Mat *A)
11112 {
11113   IS  zerorows;
11114   Vec diag;
11115 
11116   PetscFunctionBegin;
11117   PetscCheck(reuse != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
11118   /* Construct the coarse grid matrix */
11119   if (interpolate == restrct) {
11120     PetscCall(MatPtAP(dA, interpolate, reuse, fill, A));
11121   } else {
11122     PetscCall(MatMatMatMult(restrct, dA, interpolate, reuse, fill, A));
11123   }
11124 
11125   /* If the interpolation matrix is not of full rank, A will have zero rows.
11126      This can legitimately happen in the case of non-nested geometric multigrid.
11127      In that event, we set the rows of the matrix to the rows of the identity,
11128      ignoring the equations (as the RHS will also be zero). */
11129 
11130   PetscCall(MatFindZeroRows(*A, &zerorows));
11131 
11132   if (zerorows != NULL) { /* if there are any zero rows */
11133     PetscCall(MatCreateVecs(*A, &diag, NULL));
11134     PetscCall(MatGetDiagonal(*A, diag));
11135     PetscCall(VecISSet(diag, zerorows, 1.0));
11136     PetscCall(MatDiagonalSet(*A, diag, INSERT_VALUES));
11137     PetscCall(VecDestroy(&diag));
11138     PetscCall(ISDestroy(&zerorows));
11139   }
11140   PetscFunctionReturn(PETSC_SUCCESS);
11141 }
11142 
11143 /*@C
11144   MatSetOperation - Allows user to set a matrix operation for any matrix type
11145 
11146   Logically Collective
11147 
11148   Input Parameters:
11149 + mat - the matrix
11150 . op  - the name of the operation
11151 - f   - the function that provides the operation
11152 
11153   Level: developer
11154 
11155   Example Usage:
11156 .vb
11157   extern PetscErrorCode usermult(Mat, Vec, Vec);
11158 
11159   PetscCall(MatCreateXXX(comm, ..., &A));
11160   PetscCall(MatSetOperation(A, MATOP_MULT, (PetscVoidFn *)usermult));
11161 .ve
11162 
11163   Notes:
11164   See the file `include/petscmat.h` for a complete list of matrix
11165   operations, which all have the form MATOP_<OPERATION>, where
11166   <OPERATION> is the name (in all capital letters) of the
11167   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11168 
11169   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
11170   sequence as the usual matrix interface routines, since they
11171   are intended to be accessed via the usual matrix interface
11172   routines, e.g.,
11173 .vb
11174   MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
11175 .ve
11176 
11177   In particular each function MUST return `PETSC_SUCCESS` on success and
11178   nonzero on failure.
11179 
11180   This routine is distinct from `MatShellSetOperation()` in that it can be called on any matrix type.
11181 
11182 .seealso: [](ch_matrices), `Mat`, `MatGetOperation()`, `MatCreateShell()`, `MatShellSetContext()`, `MatShellSetOperation()`
11183 @*/
11184 PetscErrorCode MatSetOperation(Mat mat, MatOperation op, void (*f)(void))
11185 {
11186   PetscFunctionBegin;
11187   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11188   if (op == MATOP_VIEW && !mat->ops->viewnative && f != (void (*)(void))mat->ops->view) mat->ops->viewnative = mat->ops->view;
11189   (((void (**)(void))mat->ops)[op]) = f;
11190   PetscFunctionReturn(PETSC_SUCCESS);
11191 }
11192 
11193 /*@C
11194   MatGetOperation - Gets a matrix operation for any matrix type.
11195 
11196   Not Collective
11197 
11198   Input Parameters:
11199 + mat - the matrix
11200 - op  - the name of the operation
11201 
11202   Output Parameter:
11203 . f - the function that provides the operation
11204 
11205   Level: developer
11206 
11207   Example Usage:
11208 .vb
11209   PetscErrorCode (*usermult)(Mat, Vec, Vec);
11210 
11211   MatGetOperation(A, MATOP_MULT, (void (**)(void))&usermult);
11212 .ve
11213 
11214   Notes:
11215   See the file include/petscmat.h for a complete list of matrix
11216   operations, which all have the form MATOP_<OPERATION>, where
11217   <OPERATION> is the name (in all capital letters) of the
11218   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11219 
11220   This routine is distinct from `MatShellGetOperation()` in that it can be called on any matrix type.
11221 
11222 .seealso: [](ch_matrices), `Mat`, `MatSetOperation()`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
11223 @*/
11224 PetscErrorCode MatGetOperation(Mat mat, MatOperation op, void (**f)(void))
11225 {
11226   PetscFunctionBegin;
11227   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11228   *f = (((void (**)(void))mat->ops)[op]);
11229   PetscFunctionReturn(PETSC_SUCCESS);
11230 }
11231 
11232 /*@
11233   MatHasOperation - Determines whether the given matrix supports the particular operation.
11234 
11235   Not Collective
11236 
11237   Input Parameters:
11238 + mat - the matrix
11239 - op  - the operation, for example, `MATOP_GET_DIAGONAL`
11240 
11241   Output Parameter:
11242 . has - either `PETSC_TRUE` or `PETSC_FALSE`
11243 
11244   Level: advanced
11245 
11246   Note:
11247   See `MatSetOperation()` for additional discussion on naming convention and usage of `op`.
11248 
11249 .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`, `MatGetOperation()`, `MatSetOperation()`
11250 @*/
11251 PetscErrorCode MatHasOperation(Mat mat, MatOperation op, PetscBool *has)
11252 {
11253   PetscFunctionBegin;
11254   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11255   PetscAssertPointer(has, 3);
11256   if (mat->ops->hasoperation) {
11257     PetscUseTypeMethod(mat, hasoperation, op, has);
11258   } else {
11259     if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
11260     else {
11261       *has = PETSC_FALSE;
11262       if (op == MATOP_CREATE_SUBMATRIX) {
11263         PetscMPIInt size;
11264 
11265         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
11266         if (size == 1) PetscCall(MatHasOperation(mat, MATOP_CREATE_SUBMATRICES, has));
11267       }
11268     }
11269   }
11270   PetscFunctionReturn(PETSC_SUCCESS);
11271 }
11272 
11273 /*@
11274   MatHasCongruentLayouts - Determines whether the rows and columns layouts of the matrix are congruent
11275 
11276   Collective
11277 
11278   Input Parameter:
11279 . mat - the matrix
11280 
11281   Output Parameter:
11282 . cong - either `PETSC_TRUE` or `PETSC_FALSE`
11283 
11284   Level: beginner
11285 
11286 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatSetSizes()`, `PetscLayout`
11287 @*/
11288 PetscErrorCode MatHasCongruentLayouts(Mat mat, PetscBool *cong)
11289 {
11290   PetscFunctionBegin;
11291   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11292   PetscValidType(mat, 1);
11293   PetscAssertPointer(cong, 2);
11294   if (!mat->rmap || !mat->cmap) {
11295     *cong = mat->rmap == mat->cmap ? PETSC_TRUE : PETSC_FALSE;
11296     PetscFunctionReturn(PETSC_SUCCESS);
11297   }
11298   if (mat->congruentlayouts == PETSC_DECIDE) { /* first time we compare rows and cols layouts */
11299     PetscCall(PetscLayoutSetUp(mat->rmap));
11300     PetscCall(PetscLayoutSetUp(mat->cmap));
11301     PetscCall(PetscLayoutCompare(mat->rmap, mat->cmap, cong));
11302     if (*cong) mat->congruentlayouts = 1;
11303     else mat->congruentlayouts = 0;
11304   } else *cong = mat->congruentlayouts ? PETSC_TRUE : PETSC_FALSE;
11305   PetscFunctionReturn(PETSC_SUCCESS);
11306 }
11307 
11308 PetscErrorCode MatSetInf(Mat A)
11309 {
11310   PetscFunctionBegin;
11311   PetscUseTypeMethod(A, setinf);
11312   PetscFunctionReturn(PETSC_SUCCESS);
11313 }
11314 
11315 /*@
11316   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
11317   and possibly removes small values from the graph structure.
11318 
11319   Collective
11320 
11321   Input Parameters:
11322 + A       - the matrix
11323 . sym     - `PETSC_TRUE` indicates that the graph should be symmetrized
11324 . scale   - `PETSC_TRUE` indicates that the graph edge weights should be symmetrically scaled with the diagonal entry
11325 . filter  - filter value - < 0: does nothing; == 0: removes only 0.0 entries; otherwise: removes entries with abs(entries) <= value
11326 . num_idx - size of 'index' array
11327 - index   - array of block indices to use for graph strength of connection weight
11328 
11329   Output Parameter:
11330 . graph - the resulting graph
11331 
11332   Level: advanced
11333 
11334 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PCGAMG`
11335 @*/
11336 PetscErrorCode MatCreateGraph(Mat A, PetscBool sym, PetscBool scale, PetscReal filter, PetscInt num_idx, PetscInt index[], Mat *graph)
11337 {
11338   PetscFunctionBegin;
11339   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11340   PetscValidType(A, 1);
11341   PetscValidLogicalCollectiveBool(A, scale, 3);
11342   PetscAssertPointer(graph, 7);
11343   PetscCall(PetscLogEventBegin(MAT_CreateGraph, A, 0, 0, 0));
11344   PetscUseTypeMethod(A, creategraph, sym, scale, filter, num_idx, index, graph);
11345   PetscCall(PetscLogEventEnd(MAT_CreateGraph, A, 0, 0, 0));
11346   PetscFunctionReturn(PETSC_SUCCESS);
11347 }
11348 
11349 /*@
11350   MatEliminateZeros - eliminate the nondiagonal zero entries in place from the nonzero structure of a sparse `Mat` in place,
11351   meaning the same memory is used for the matrix, and no new memory is allocated.
11352 
11353   Collective
11354 
11355   Input Parameters:
11356 + A    - the matrix
11357 - 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
11358 
11359   Level: intermediate
11360 
11361   Developer Note:
11362   The entries in the sparse matrix data structure are shifted to fill in the unneeded locations in the data. Thus the end
11363   of the arrays in the data structure are unneeded.
11364 
11365 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateGraph()`, `MatFilter()`
11366 @*/
11367 PetscErrorCode MatEliminateZeros(Mat A, PetscBool keep)
11368 {
11369   PetscFunctionBegin;
11370   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11371   PetscUseTypeMethod(A, eliminatezeros, keep);
11372   PetscFunctionReturn(PETSC_SUCCESS);
11373 }
11374