xref: /petsc/src/mat/interface/matrix.c (revision d7d2d1d2babbf975e9544da80073779625dd96d9)
1 /*
2    This is where the abstract matrix operations are defined
3    Portions of this code are under:
4    Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
5 */
6 
7 #include <petsc/private/matimpl.h> /*I "petscmat.h" I*/
8 #include <petsc/private/isimpl.h>
9 #include <petsc/private/vecimpl.h>
10 
11 /* Logging support */
12 PetscClassId MAT_CLASSID;
13 PetscClassId MAT_COLORING_CLASSID;
14 PetscClassId MAT_FDCOLORING_CLASSID;
15 PetscClassId MAT_TRANSPOSECOLORING_CLASSID;
16 
17 PetscLogEvent MAT_Mult, MAT_MultAdd, MAT_MultTranspose;
18 PetscLogEvent MAT_MultTransposeAdd, MAT_Solve, MAT_Solves, MAT_SolveAdd, MAT_SolveTranspose, MAT_MatSolve, MAT_MatTrSolve;
19 PetscLogEvent MAT_SolveTransposeAdd, MAT_SOR, MAT_ForwardSolve, MAT_BackwardSolve, MAT_LUFactor, MAT_LUFactorSymbolic;
20 PetscLogEvent MAT_LUFactorNumeric, MAT_CholeskyFactor, MAT_CholeskyFactorSymbolic, MAT_CholeskyFactorNumeric, MAT_ILUFactor;
21 PetscLogEvent MAT_ILUFactorSymbolic, MAT_ICCFactorSymbolic, MAT_Copy, MAT_Convert, MAT_Scale, MAT_AssemblyBegin;
22 PetscLogEvent MAT_QRFactorNumeric, MAT_QRFactorSymbolic, MAT_QRFactor;
23 PetscLogEvent MAT_AssemblyEnd, MAT_SetValues, MAT_GetValues, MAT_GetRow, MAT_GetRowIJ, MAT_CreateSubMats, MAT_GetOrdering, MAT_RedundantMat, MAT_GetSeqNonzeroStructure;
24 PetscLogEvent MAT_IncreaseOverlap, MAT_Partitioning, MAT_PartitioningND, MAT_Coarsen, MAT_ZeroEntries, MAT_Load, MAT_View, MAT_AXPY, MAT_FDColoringCreate;
25 PetscLogEvent MAT_FDColoringSetUp, MAT_FDColoringApply, MAT_Transpose, MAT_FDColoringFunction, MAT_CreateSubMat;
26 PetscLogEvent MAT_TransposeColoringCreate;
27 PetscLogEvent MAT_MatMult, MAT_MatMultSymbolic, MAT_MatMultNumeric;
28 PetscLogEvent MAT_PtAP, MAT_PtAPSymbolic, MAT_PtAPNumeric, MAT_RARt, MAT_RARtSymbolic, MAT_RARtNumeric;
29 PetscLogEvent MAT_MatTransposeMult, MAT_MatTransposeMultSymbolic, MAT_MatTransposeMultNumeric;
30 PetscLogEvent MAT_TransposeMatMult, MAT_TransposeMatMultSymbolic, MAT_TransposeMatMultNumeric;
31 PetscLogEvent MAT_MatMatMult, MAT_MatMatMultSymbolic, MAT_MatMatMultNumeric;
32 PetscLogEvent MAT_MultHermitianTranspose, MAT_MultHermitianTransposeAdd;
33 PetscLogEvent MAT_Getsymtransreduced, MAT_GetBrowsOfAcols;
34 PetscLogEvent MAT_GetBrowsOfAocols, MAT_Getlocalmat, MAT_Getlocalmatcondensed, MAT_Seqstompi, MAT_Seqstompinum, MAT_Seqstompisym;
35 PetscLogEvent MAT_GetMultiProcBlock;
36 PetscLogEvent MAT_CUSPARSECopyToGPU, MAT_CUSPARSECopyFromGPU, MAT_CUSPARSEGenerateTranspose, MAT_CUSPARSESolveAnalysis;
37 PetscLogEvent MAT_HIPSPARSECopyToGPU, MAT_HIPSPARSECopyFromGPU, MAT_HIPSPARSEGenerateTranspose, MAT_HIPSPARSESolveAnalysis;
38 PetscLogEvent MAT_PreallCOO, MAT_SetVCOO;
39 PetscLogEvent MAT_CreateGraph;
40 PetscLogEvent MAT_SetValuesBatch;
41 PetscLogEvent MAT_ViennaCLCopyToGPU;
42 PetscLogEvent MAT_CUDACopyToGPU, MAT_HIPCopyToGPU;
43 PetscLogEvent MAT_DenseCopyToGPU, MAT_DenseCopyFromGPU;
44 PetscLogEvent MAT_Merge, MAT_Residual, MAT_SetRandom;
45 PetscLogEvent MAT_FactorFactS, MAT_FactorInvS;
46 PetscLogEvent MATCOLORING_Apply, MATCOLORING_Comm, MATCOLORING_Local, MATCOLORING_ISCreate, MATCOLORING_SetUp, MATCOLORING_Weights;
47 PetscLogEvent MAT_H2Opus_Build, MAT_H2Opus_Compress, MAT_H2Opus_Orthog, MAT_H2Opus_LR;
48 
49 const char *const MatFactorTypes[] = {"NONE", "LU", "CHOLESKY", "ILU", "ICC", "ILUDT", "QR", "MatFactorType", "MAT_FACTOR_", NULL};
50 
51 /*@
52   MatSetRandom - Sets all components of a matrix to random numbers.
53 
54   Logically Collective
55 
56   Input Parameters:
57 + x    - the matrix
58 - rctx - the `PetscRandom` object, formed by `PetscRandomCreate()`, or `NULL` and
59           it will create one internally.
60 
61   Example:
62 .vb
63      PetscRandomCreate(PETSC_COMM_WORLD,&rctx);
64      MatSetRandom(x,rctx);
65      PetscRandomDestroy(rctx);
66 .ve
67 
68   Level: intermediate
69 
70   Notes:
71   For sparse matrices that have been preallocated but not been assembled, it randomly selects appropriate locations,
72 
73   for sparse matrices that already have nonzero locations, it fills the locations with random numbers.
74 
75   It generates an error if used on unassembled sparse matrices that have not been preallocated.
76 
77 .seealso: [](ch_matrices), `Mat`, `PetscRandom`, `PetscRandomCreate()`, `MatZeroEntries()`, `MatSetValues()`, `PetscRandomDestroy()`
78 @*/
79 PetscErrorCode MatSetRandom(Mat x, PetscRandom rctx)
80 {
81   PetscRandom randObj = NULL;
82 
83   PetscFunctionBegin;
84   PetscValidHeaderSpecific(x, MAT_CLASSID, 1);
85   if (rctx) PetscValidHeaderSpecific(rctx, PETSC_RANDOM_CLASSID, 2);
86   PetscValidType(x, 1);
87   MatCheckPreallocated(x, 1);
88 
89   if (!rctx) {
90     MPI_Comm comm;
91     PetscCall(PetscObjectGetComm((PetscObject)x, &comm));
92     PetscCall(PetscRandomCreate(comm, &randObj));
93     PetscCall(PetscRandomSetType(randObj, x->defaultrandtype));
94     PetscCall(PetscRandomSetFromOptions(randObj));
95     rctx = randObj;
96   }
97   PetscCall(PetscLogEventBegin(MAT_SetRandom, x, rctx, 0, 0));
98   PetscUseTypeMethod(x, setrandom, rctx);
99   PetscCall(PetscLogEventEnd(MAT_SetRandom, x, rctx, 0, 0));
100 
101   PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
102   PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
103   PetscCall(PetscRandomDestroy(&randObj));
104   PetscFunctionReturn(PETSC_SUCCESS);
105 }
106 
107 /*@
108   MatCopyHashToXAIJ - copy hash table entries into an XAIJ matrix type
109 
110   Logically Collective
111 
112   Input Parameter:
113 . A - A matrix in unassembled, hash table form
114 
115   Output Parameter:
116 . B - The XAIJ matrix. This can either be `A` or some matrix of equivalent size, e.g. obtained from `A` via `MatDuplicate()`
117 
118   Example:
119 .vb
120      PetscCall(MatDuplicate(A, MAT_DO_NOT_COPY_VALUES, &B));
121      PetscCall(MatCopyHashToXAIJ(A, B));
122 .ve
123 
124   Level: advanced
125 
126   Notes:
127   If `B` is `A`, then the hash table data structure will be destroyed. `B` is assembled
128 
129 .seealso: [](ch_matrices), `Mat`, `MAT_USE_HASH_TABLE`
130 @*/
131 PetscErrorCode MatCopyHashToXAIJ(Mat A, Mat B)
132 {
133   PetscFunctionBegin;
134   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
135   PetscUseTypeMethod(A, copyhashtoxaij, B);
136   PetscFunctionReturn(PETSC_SUCCESS);
137 }
138 
139 /*@
140   MatFactorGetErrorZeroPivot - returns the pivot value that was determined to be zero and the row it occurred in
141 
142   Logically Collective
143 
144   Input Parameter:
145 . mat - the factored matrix
146 
147   Output Parameters:
148 + pivot - the pivot value computed
149 - row   - the row that the zero pivot occurred. This row value must be interpreted carefully due to row reorderings and which processes
150          the share the matrix
151 
152   Level: advanced
153 
154   Notes:
155   This routine does not work for factorizations done with external packages.
156 
157   This routine should only be called if `MatGetFactorError()` returns a value of `MAT_FACTOR_NUMERIC_ZEROPIVOT`
158 
159   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
160 
161 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`,
162 `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`, `MatFactorClearError()`,
163 `MAT_FACTOR_NUMERIC_ZEROPIVOT`
164 @*/
165 PetscErrorCode MatFactorGetErrorZeroPivot(Mat mat, PetscReal *pivot, PetscInt *row)
166 {
167   PetscFunctionBegin;
168   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
169   PetscAssertPointer(pivot, 2);
170   PetscAssertPointer(row, 3);
171   *pivot = mat->factorerror_zeropivot_value;
172   *row   = mat->factorerror_zeropivot_row;
173   PetscFunctionReturn(PETSC_SUCCESS);
174 }
175 
176 /*@
177   MatFactorGetError - gets the error code from a factorization
178 
179   Logically Collective
180 
181   Input Parameter:
182 . mat - the factored matrix
183 
184   Output Parameter:
185 . err - the error code
186 
187   Level: advanced
188 
189   Note:
190   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
191 
192 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`,
193           `MatFactorClearError()`, `MatFactorGetErrorZeroPivot()`, `MatFactorError`
194 @*/
195 PetscErrorCode MatFactorGetError(Mat mat, MatFactorError *err)
196 {
197   PetscFunctionBegin;
198   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
199   PetscAssertPointer(err, 2);
200   *err = mat->factorerrortype;
201   PetscFunctionReturn(PETSC_SUCCESS);
202 }
203 
204 /*@
205   MatFactorClearError - clears the error code in a factorization
206 
207   Logically Collective
208 
209   Input Parameter:
210 . mat - the factored matrix
211 
212   Level: developer
213 
214   Note:
215   This can also be called on non-factored matrices that come from, for example, matrices used in SOR.
216 
217 .seealso: [](ch_matrices), `Mat`, `MatZeroEntries()`, `MatFactor()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`, `MatFactorGetError()`, `MatFactorGetErrorZeroPivot()`,
218           `MatGetErrorCode()`, `MatFactorError`
219 @*/
220 PetscErrorCode MatFactorClearError(Mat mat)
221 {
222   PetscFunctionBegin;
223   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
224   mat->factorerrortype             = MAT_FACTOR_NOERROR;
225   mat->factorerror_zeropivot_value = 0.0;
226   mat->factorerror_zeropivot_row   = 0;
227   PetscFunctionReturn(PETSC_SUCCESS);
228 }
229 
230 PetscErrorCode MatFindNonzeroRowsOrCols_Basic(Mat mat, PetscBool cols, PetscReal tol, IS *nonzero)
231 {
232   Vec                r, l;
233   const PetscScalar *al;
234   PetscInt           i, nz, gnz, N, n, st;
235 
236   PetscFunctionBegin;
237   PetscCall(MatCreateVecs(mat, &r, &l));
238   if (!cols) { /* nonzero rows */
239     PetscCall(MatGetOwnershipRange(mat, &st, NULL));
240     PetscCall(MatGetSize(mat, &N, NULL));
241     PetscCall(MatGetLocalSize(mat, &n, NULL));
242     PetscCall(VecSet(l, 0.0));
243     PetscCall(VecSetRandom(r, NULL));
244     PetscCall(MatMult(mat, r, l));
245     PetscCall(VecGetArrayRead(l, &al));
246   } else { /* nonzero columns */
247     PetscCall(MatGetOwnershipRangeColumn(mat, &st, NULL));
248     PetscCall(MatGetSize(mat, NULL, &N));
249     PetscCall(MatGetLocalSize(mat, NULL, &n));
250     PetscCall(VecSet(r, 0.0));
251     PetscCall(VecSetRandom(l, NULL));
252     PetscCall(MatMultTranspose(mat, l, r));
253     PetscCall(VecGetArrayRead(r, &al));
254   }
255   if (tol <= 0.0) {
256     for (i = 0, nz = 0; i < n; i++)
257       if (al[i] != 0.0) nz++;
258   } else {
259     for (i = 0, nz = 0; i < n; i++)
260       if (PetscAbsScalar(al[i]) > tol) nz++;
261   }
262   PetscCallMPI(MPIU_Allreduce(&nz, &gnz, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
263   if (gnz != N) {
264     PetscInt *nzr;
265     PetscCall(PetscMalloc1(nz, &nzr));
266     if (nz) {
267       if (tol < 0) {
268         for (i = 0, nz = 0; i < n; i++)
269           if (al[i] != 0.0) nzr[nz++] = i + st;
270       } else {
271         for (i = 0, nz = 0; i < n; i++)
272           if (PetscAbsScalar(al[i]) > tol) nzr[nz++] = i + st;
273       }
274     }
275     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nz, nzr, PETSC_OWN_POINTER, nonzero));
276   } else *nonzero = NULL;
277   if (!cols) { /* nonzero rows */
278     PetscCall(VecRestoreArrayRead(l, &al));
279   } else {
280     PetscCall(VecRestoreArrayRead(r, &al));
281   }
282   PetscCall(VecDestroy(&l));
283   PetscCall(VecDestroy(&r));
284   PetscFunctionReturn(PETSC_SUCCESS);
285 }
286 
287 /*@
288   MatFindNonzeroRows - Locate all rows that are not completely zero in the matrix
289 
290   Input Parameter:
291 . mat - the matrix
292 
293   Output Parameter:
294 . keptrows - the rows that are not completely zero
295 
296   Level: intermediate
297 
298   Note:
299   `keptrows` is set to `NULL` if all rows are nonzero.
300 
301   Developer Note:
302   If `keptrows` is not `NULL`, it must be sorted.
303 
304 .seealso: [](ch_matrices), `Mat`, `MatFindZeroRows()`
305  @*/
306 PetscErrorCode MatFindNonzeroRows(Mat mat, IS *keptrows)
307 {
308   PetscFunctionBegin;
309   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
310   PetscValidType(mat, 1);
311   PetscAssertPointer(keptrows, 2);
312   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
313   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
314   if (mat->ops->findnonzerorows) PetscUseTypeMethod(mat, findnonzerorows, keptrows);
315   else PetscCall(MatFindNonzeroRowsOrCols_Basic(mat, PETSC_FALSE, 0.0, keptrows));
316   if (keptrows && *keptrows) PetscCall(ISSetInfo(*keptrows, IS_SORTED, IS_GLOBAL, PETSC_FALSE, PETSC_TRUE));
317   PetscFunctionReturn(PETSC_SUCCESS);
318 }
319 
320 /*@
321   MatFindZeroRows - Locate all rows that are completely zero in the matrix
322 
323   Input Parameter:
324 . mat - the matrix
325 
326   Output Parameter:
327 . zerorows - the rows that are completely zero
328 
329   Level: intermediate
330 
331   Note:
332   `zerorows` is set to `NULL` if no rows are zero.
333 
334 .seealso: [](ch_matrices), `Mat`, `MatFindNonzeroRows()`
335  @*/
336 PetscErrorCode MatFindZeroRows(Mat mat, IS *zerorows)
337 {
338   IS       keptrows;
339   PetscInt m, n;
340 
341   PetscFunctionBegin;
342   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
343   PetscValidType(mat, 1);
344   PetscAssertPointer(zerorows, 2);
345   PetscCall(MatFindNonzeroRows(mat, &keptrows));
346   /* MatFindNonzeroRows sets keptrows to NULL if there are no zero rows.
347      In keeping with this convention, we set zerorows to NULL if there are no zero
348      rows. */
349   if (keptrows == NULL) {
350     *zerorows = NULL;
351   } else {
352     PetscCall(MatGetOwnershipRange(mat, &m, &n));
353     PetscCall(ISComplement(keptrows, m, n, zerorows));
354     PetscCall(ISDestroy(&keptrows));
355   }
356   PetscFunctionReturn(PETSC_SUCCESS);
357 }
358 
359 /*@
360   MatGetDiagonalBlock - Returns the part of the matrix associated with the on-process coupling
361 
362   Not Collective
363 
364   Input Parameter:
365 . A - the matrix
366 
367   Output Parameter:
368 . a - the diagonal part (which is a SEQUENTIAL matrix)
369 
370   Level: advanced
371 
372   Notes:
373   See `MatCreateAIJ()` for more information on the "diagonal part" of the matrix.
374 
375   Use caution, as the reference count on the returned matrix is not incremented and it is used as part of `A`'s normal operation.
376 
377 .seealso: [](ch_matrices), `Mat`, `MatCreateAIJ()`, `MATAIJ`, `MATBAIJ`, `MATSBAIJ`
378 @*/
379 PetscErrorCode MatGetDiagonalBlock(Mat A, Mat *a)
380 {
381   PetscFunctionBegin;
382   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
383   PetscValidType(A, 1);
384   PetscAssertPointer(a, 2);
385   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
386   if (A->ops->getdiagonalblock) PetscUseTypeMethod(A, getdiagonalblock, a);
387   else {
388     PetscMPIInt size;
389 
390     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
391     PetscCheck(size == 1, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for parallel matrix type %s", ((PetscObject)A)->type_name);
392     *a = A;
393   }
394   PetscFunctionReturn(PETSC_SUCCESS);
395 }
396 
397 /*@
398   MatGetTrace - Gets the trace of a matrix. The sum of the diagonal entries.
399 
400   Collective
401 
402   Input Parameter:
403 . mat - the matrix
404 
405   Output Parameter:
406 . trace - the sum of the diagonal entries
407 
408   Level: advanced
409 
410 .seealso: [](ch_matrices), `Mat`
411 @*/
412 PetscErrorCode MatGetTrace(Mat mat, PetscScalar *trace)
413 {
414   Vec diag;
415 
416   PetscFunctionBegin;
417   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
418   PetscAssertPointer(trace, 2);
419   PetscCall(MatCreateVecs(mat, &diag, NULL));
420   PetscCall(MatGetDiagonal(mat, diag));
421   PetscCall(VecSum(diag, trace));
422   PetscCall(VecDestroy(&diag));
423   PetscFunctionReturn(PETSC_SUCCESS);
424 }
425 
426 /*@
427   MatRealPart - Zeros out the imaginary part of the matrix
428 
429   Logically Collective
430 
431   Input Parameter:
432 . mat - the matrix
433 
434   Level: advanced
435 
436 .seealso: [](ch_matrices), `Mat`, `MatImaginaryPart()`
437 @*/
438 PetscErrorCode MatRealPart(Mat mat)
439 {
440   PetscFunctionBegin;
441   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
442   PetscValidType(mat, 1);
443   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
444   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
445   MatCheckPreallocated(mat, 1);
446   PetscUseTypeMethod(mat, realpart);
447   PetscFunctionReturn(PETSC_SUCCESS);
448 }
449 
450 /*@C
451   MatGetGhosts - Get the global indices of all ghost nodes defined by the sparse matrix
452 
453   Collective
454 
455   Input Parameter:
456 . mat - the matrix
457 
458   Output Parameters:
459 + nghosts - number of ghosts (for `MATBAIJ` and `MATSBAIJ` matrices there is one ghost for each matrix block)
460 - ghosts  - the global indices of the ghost points
461 
462   Level: advanced
463 
464   Note:
465   `nghosts` and `ghosts` are suitable to pass into `VecCreateGhost()` or `VecCreateGhostBlock()`
466 
467 .seealso: [](ch_matrices), `Mat`, `VecCreateGhost()`, `VecCreateGhostBlock()`
468 @*/
469 PetscErrorCode MatGetGhosts(Mat mat, PetscInt *nghosts, const PetscInt *ghosts[])
470 {
471   PetscFunctionBegin;
472   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
473   PetscValidType(mat, 1);
474   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
475   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
476   if (mat->ops->getghosts) PetscUseTypeMethod(mat, getghosts, nghosts, ghosts);
477   else {
478     if (nghosts) *nghosts = 0;
479     if (ghosts) *ghosts = NULL;
480   }
481   PetscFunctionReturn(PETSC_SUCCESS);
482 }
483 
484 /*@
485   MatImaginaryPart - Moves the imaginary part of the matrix to the real part and zeros the imaginary part
486 
487   Logically Collective
488 
489   Input Parameter:
490 . mat - the matrix
491 
492   Level: advanced
493 
494 .seealso: [](ch_matrices), `Mat`, `MatRealPart()`
495 @*/
496 PetscErrorCode MatImaginaryPart(Mat mat)
497 {
498   PetscFunctionBegin;
499   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
500   PetscValidType(mat, 1);
501   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
502   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
503   MatCheckPreallocated(mat, 1);
504   PetscUseTypeMethod(mat, imaginarypart);
505   PetscFunctionReturn(PETSC_SUCCESS);
506 }
507 
508 /*@
509   MatMissingDiagonal - Determine if sparse matrix is missing a diagonal entry (or block entry for `MATBAIJ` and `MATSBAIJ` matrices) in the nonzero structure
510 
511   Not Collective
512 
513   Input Parameter:
514 . mat - the matrix
515 
516   Output Parameters:
517 + missing - is any diagonal entry missing
518 - dd      - first diagonal entry that is missing (optional) on this process
519 
520   Level: advanced
521 
522   Note:
523   This does not return diagonal entries that are in the nonzero structure but happen to have a zero numerical value
524 
525 .seealso: [](ch_matrices), `Mat`
526 @*/
527 PetscErrorCode MatMissingDiagonal(Mat mat, PetscBool *missing, PetscInt *dd)
528 {
529   PetscFunctionBegin;
530   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
531   PetscValidType(mat, 1);
532   PetscAssertPointer(missing, 2);
533   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix %s", ((PetscObject)mat)->type_name);
534   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
535   PetscUseTypeMethod(mat, missingdiagonal, missing, dd);
536   PetscFunctionReturn(PETSC_SUCCESS);
537 }
538 
539 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
540 /*@C
541   MatGetRow - Gets a row of a matrix.  You MUST call `MatRestoreRow()`
542   for each row that you get to ensure that your application does
543   not bleed memory.
544 
545   Not Collective
546 
547   Input Parameters:
548 + mat - the matrix
549 - row - the row to get
550 
551   Output Parameters:
552 + ncols - if not `NULL`, the number of nonzeros in `row`
553 . cols  - if not `NULL`, the column numbers
554 - vals  - if not `NULL`, the numerical values
555 
556   Level: advanced
557 
558   Notes:
559   This routine is provided for people who need to have direct access
560   to the structure of a matrix.  We hope that we provide enough
561   high-level matrix routines that few users will need it.
562 
563   `MatGetRow()` always returns 0-based column indices, regardless of
564   whether the internal representation is 0-based (default) or 1-based.
565 
566   For better efficiency, set `cols` and/or `vals` to `NULL` if you do
567   not wish to extract these quantities.
568 
569   The user can only examine the values extracted with `MatGetRow()`;
570   the values CANNOT be altered.  To change the matrix entries, one
571   must use `MatSetValues()`.
572 
573   You can only have one call to `MatGetRow()` outstanding for a particular
574   matrix at a time, per processor. `MatGetRow()` can only obtain rows
575   associated with the given processor, it cannot get rows from the
576   other processors; for that we suggest using `MatCreateSubMatrices()`, then
577   `MatGetRow()` on the submatrix. The row index passed to `MatGetRow()`
578   is in the global number of rows.
579 
580   Use `MatGetRowIJ()` and `MatRestoreRowIJ()` to access all the local indices of the sparse matrix.
581 
582   Use `MatSeqAIJGetArray()` and similar functions to access the numerical values for certain matrix types directly.
583 
584   Fortran Note:
585   The calling sequence is
586 .vb
587    MatGetRow(matrix,row,ncols,cols,values,ierr)
588          Mat         matrix (input)
589          PetscInt    row    (input)
590          PetscInt    ncols  (output)
591          PetscInt    cols(maxcols) (output)
592          PetscScalar values(maxcols) output
593 .ve
594   where maxcols >= maximum nonzeros in any row of the matrix.
595 
596 .seealso: [](ch_matrices), `Mat`, `MatRestoreRow()`, `MatSetValues()`, `MatGetValues()`, `MatCreateSubMatrices()`, `MatGetDiagonal()`, `MatGetRowIJ()`, `MatRestoreRowIJ()`
597 @*/
598 PetscErrorCode MatGetRow(Mat mat, PetscInt row, PetscInt *ncols, const PetscInt *cols[], const PetscScalar *vals[])
599 {
600   PetscInt incols;
601 
602   PetscFunctionBegin;
603   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
604   PetscValidType(mat, 1);
605   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
606   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
607   MatCheckPreallocated(mat, 1);
608   PetscCheck(row >= mat->rmap->rstart && row < mat->rmap->rend, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Only for local rows, %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ")", row, mat->rmap->rstart, mat->rmap->rend);
609   PetscCall(PetscLogEventBegin(MAT_GetRow, mat, 0, 0, 0));
610   PetscUseTypeMethod(mat, getrow, row, &incols, (PetscInt **)cols, (PetscScalar **)vals);
611   if (ncols) *ncols = incols;
612   PetscCall(PetscLogEventEnd(MAT_GetRow, mat, 0, 0, 0));
613   PetscFunctionReturn(PETSC_SUCCESS);
614 }
615 
616 /*@
617   MatConjugate - replaces the matrix values with their complex conjugates
618 
619   Logically Collective
620 
621   Input Parameter:
622 . mat - the matrix
623 
624   Level: advanced
625 
626 .seealso: [](ch_matrices), `Mat`, `MatRealPart()`, `MatImaginaryPart()`, `VecConjugate()`, `MatTranspose()`
627 @*/
628 PetscErrorCode MatConjugate(Mat mat)
629 {
630   PetscFunctionBegin;
631   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
632   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
633   if (PetscDefined(USE_COMPLEX) && mat->hermitian != PETSC_BOOL3_TRUE) {
634     PetscUseTypeMethod(mat, conjugate);
635     PetscCall(PetscObjectStateIncrease((PetscObject)mat));
636   }
637   PetscFunctionReturn(PETSC_SUCCESS);
638 }
639 
640 /*@C
641   MatRestoreRow - Frees any temporary space allocated by `MatGetRow()`.
642 
643   Not Collective
644 
645   Input Parameters:
646 + mat   - the matrix
647 . row   - the row to get
648 . ncols - the number of nonzeros
649 . cols  - the columns of the nonzeros
650 - vals  - if nonzero the column values
651 
652   Level: advanced
653 
654   Notes:
655   This routine should be called after you have finished examining the entries.
656 
657   This routine zeros out `ncols`, `cols`, and `vals`. This is to prevent accidental
658   us of the array after it has been restored. If you pass `NULL`, it will
659   not zero the pointers.  Use of `cols` or `vals` after `MatRestoreRow()` is invalid.
660 
661   Fortran Note:
662   `MatRestoreRow()` MUST be called after `MatGetRow()`
663   before another call to `MatGetRow()` can be made.
664 
665 .seealso: [](ch_matrices), `Mat`, `MatGetRow()`
666 @*/
667 PetscErrorCode MatRestoreRow(Mat mat, PetscInt row, PetscInt *ncols, const PetscInt *cols[], const PetscScalar *vals[])
668 {
669   PetscFunctionBegin;
670   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
671   if (ncols) PetscAssertPointer(ncols, 3);
672   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
673   if (!mat->ops->restorerow) PetscFunctionReturn(PETSC_SUCCESS);
674   PetscUseTypeMethod(mat, restorerow, row, ncols, (PetscInt **)cols, (PetscScalar **)vals);
675   if (ncols) *ncols = 0;
676   if (cols) *cols = NULL;
677   if (vals) *vals = NULL;
678   PetscFunctionReturn(PETSC_SUCCESS);
679 }
680 
681 /*@
682   MatGetRowUpperTriangular - Sets a flag to enable calls to `MatGetRow()` for matrix in `MATSBAIJ` format.
683   You should call `MatRestoreRowUpperTriangular()` after calling` MatGetRow()` and `MatRestoreRow()` to disable the flag.
684 
685   Not Collective
686 
687   Input Parameter:
688 . mat - the matrix
689 
690   Level: advanced
691 
692   Note:
693   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.
694 
695 .seealso: [](ch_matrices), `Mat`, `MATSBAIJ`, `MatRestoreRowUpperTriangular()`
696 @*/
697 PetscErrorCode MatGetRowUpperTriangular(Mat mat)
698 {
699   PetscFunctionBegin;
700   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
701   PetscValidType(mat, 1);
702   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
703   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
704   MatCheckPreallocated(mat, 1);
705   if (!mat->ops->getrowuppertriangular) PetscFunctionReturn(PETSC_SUCCESS);
706   PetscUseTypeMethod(mat, getrowuppertriangular);
707   PetscFunctionReturn(PETSC_SUCCESS);
708 }
709 
710 /*@
711   MatRestoreRowUpperTriangular - Disable calls to `MatGetRow()` for matrix in `MATSBAIJ` format.
712 
713   Not Collective
714 
715   Input Parameter:
716 . mat - the matrix
717 
718   Level: advanced
719 
720   Note:
721   This routine should be called after you have finished calls to `MatGetRow()` and `MatRestoreRow()`.
722 
723 .seealso: [](ch_matrices), `Mat`, `MATSBAIJ`, `MatGetRowUpperTriangular()`
724 @*/
725 PetscErrorCode MatRestoreRowUpperTriangular(Mat mat)
726 {
727   PetscFunctionBegin;
728   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
729   PetscValidType(mat, 1);
730   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
731   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
732   MatCheckPreallocated(mat, 1);
733   if (!mat->ops->restorerowuppertriangular) PetscFunctionReturn(PETSC_SUCCESS);
734   PetscUseTypeMethod(mat, restorerowuppertriangular);
735   PetscFunctionReturn(PETSC_SUCCESS);
736 }
737 
738 /*@
739   MatSetOptionsPrefix - Sets the prefix used for searching for all
740   `Mat` options in the database.
741 
742   Logically Collective
743 
744   Input Parameters:
745 + A      - the matrix
746 - prefix - the prefix to prepend to all option names
747 
748   Level: advanced
749 
750   Notes:
751   A hyphen (-) must NOT be given at the beginning of the prefix name.
752   The first character of all runtime options is AUTOMATICALLY the hyphen.
753 
754   This is NOT used for options for the factorization of the matrix. Normally the
755   prefix is automatically passed in from the PC calling the factorization. To set
756   it directly use  `MatSetOptionsPrefixFactor()`
757 
758 .seealso: [](ch_matrices), `Mat`, `MatSetFromOptions()`, `MatSetOptionsPrefixFactor()`
759 @*/
760 PetscErrorCode MatSetOptionsPrefix(Mat A, const char prefix[])
761 {
762   PetscFunctionBegin;
763   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
764   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)A, prefix));
765   PetscFunctionReturn(PETSC_SUCCESS);
766 }
767 
768 /*@
769   MatSetOptionsPrefixFactor - Sets the prefix used for searching for all matrix factor options in the database for
770   for matrices created with `MatGetFactor()`
771 
772   Logically Collective
773 
774   Input Parameters:
775 + A      - the matrix
776 - prefix - the prefix to prepend to all option names for the factored matrix
777 
778   Level: developer
779 
780   Notes:
781   A hyphen (-) must NOT be given at the beginning of the prefix name.
782   The first character of all runtime options is AUTOMATICALLY the hyphen.
783 
784   Normally the prefix is automatically passed in from the `PC` calling the factorization. To set
785   it directly when not using `KSP`/`PC` use  `MatSetOptionsPrefixFactor()`
786 
787 .seealso: [](ch_matrices), `Mat`,   [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSetFromOptions()`, `MatSetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`
788 @*/
789 PetscErrorCode MatSetOptionsPrefixFactor(Mat A, const char prefix[])
790 {
791   PetscFunctionBegin;
792   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
793   if (prefix) {
794     PetscAssertPointer(prefix, 2);
795     PetscCheck(prefix[0] != '-', PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
796     if (prefix != A->factorprefix) {
797       PetscCall(PetscFree(A->factorprefix));
798       PetscCall(PetscStrallocpy(prefix, &A->factorprefix));
799     }
800   } else PetscCall(PetscFree(A->factorprefix));
801   PetscFunctionReturn(PETSC_SUCCESS);
802 }
803 
804 /*@
805   MatAppendOptionsPrefixFactor - Appends to the prefix used for searching for all matrix factor options in the database for
806   for matrices created with `MatGetFactor()`
807 
808   Logically Collective
809 
810   Input Parameters:
811 + A      - the matrix
812 - prefix - the prefix to prepend to all option names for the factored matrix
813 
814   Level: developer
815 
816   Notes:
817   A hyphen (-) must NOT be given at the beginning of the prefix name.
818   The first character of all runtime options is AUTOMATICALLY the hyphen.
819 
820   Normally the prefix is automatically passed in from the `PC` calling the factorization. To set
821   it directly when not using `KSP`/`PC` use  `MatAppendOptionsPrefixFactor()`
822 
823 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `PetscOptionsCreate()`, `PetscOptionsDestroy()`, `PetscObjectSetOptionsPrefix()`, `PetscObjectPrependOptionsPrefix()`,
824           `PetscObjectGetOptionsPrefix()`, `TSAppendOptionsPrefix()`, `SNESAppendOptionsPrefix()`, `KSPAppendOptionsPrefix()`, `MatSetOptionsPrefixFactor()`,
825           `MatSetOptionsPrefix()`
826 @*/
827 PetscErrorCode MatAppendOptionsPrefixFactor(Mat A, const char prefix[])
828 {
829   size_t len1, len2, new_len;
830 
831   PetscFunctionBegin;
832   PetscValidHeader(A, 1);
833   if (!prefix) PetscFunctionReturn(PETSC_SUCCESS);
834   if (!A->factorprefix) {
835     PetscCall(MatSetOptionsPrefixFactor(A, prefix));
836     PetscFunctionReturn(PETSC_SUCCESS);
837   }
838   PetscCheck(prefix[0] != '-', PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
839 
840   PetscCall(PetscStrlen(A->factorprefix, &len1));
841   PetscCall(PetscStrlen(prefix, &len2));
842   new_len = len1 + len2 + 1;
843   PetscCall(PetscRealloc(new_len * sizeof(*A->factorprefix), &A->factorprefix));
844   PetscCall(PetscStrncpy(A->factorprefix + len1, prefix, len2 + 1));
845   PetscFunctionReturn(PETSC_SUCCESS);
846 }
847 
848 /*@
849   MatAppendOptionsPrefix - Appends to the prefix used for searching for all
850   matrix options in the database.
851 
852   Logically Collective
853 
854   Input Parameters:
855 + A      - the matrix
856 - prefix - the prefix to prepend to all option names
857 
858   Level: advanced
859 
860   Note:
861   A hyphen (-) must NOT be given at the beginning of the prefix name.
862   The first character of all runtime options is AUTOMATICALLY the hyphen.
863 
864 .seealso: [](ch_matrices), `Mat`, `MatGetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`, `MatSetOptionsPrefix()`
865 @*/
866 PetscErrorCode MatAppendOptionsPrefix(Mat A, const char prefix[])
867 {
868   PetscFunctionBegin;
869   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
870   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)A, prefix));
871   PetscFunctionReturn(PETSC_SUCCESS);
872 }
873 
874 /*@
875   MatGetOptionsPrefix - Gets the prefix used for searching for all
876   matrix options in the database.
877 
878   Not Collective
879 
880   Input Parameter:
881 . A - the matrix
882 
883   Output Parameter:
884 . prefix - pointer to the prefix string used
885 
886   Level: advanced
887 
888   Fortran Note:
889   The user should pass in a string `prefix` of
890   sufficient length to hold the prefix.
891 
892 .seealso: [](ch_matrices), `Mat`, `MatAppendOptionsPrefix()`, `MatSetOptionsPrefix()`, `MatAppendOptionsPrefixFactor()`, `MatSetOptionsPrefixFactor()`
893 @*/
894 PetscErrorCode MatGetOptionsPrefix(Mat A, const char *prefix[])
895 {
896   PetscFunctionBegin;
897   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
898   PetscAssertPointer(prefix, 2);
899   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)A, prefix));
900   PetscFunctionReturn(PETSC_SUCCESS);
901 }
902 
903 /*@
904   MatGetState - Gets the state of a `Mat`. Same value as returned by `PetscObjectStateGet()`
905 
906   Not Collective
907 
908   Input Parameter:
909 . A - the matrix
910 
911   Output Parameter:
912 . state - the object state
913 
914   Level: advanced
915 
916   Note:
917   Object state is an integer which gets increased every time
918   the object is changed. By saving and later querying the object state
919   one can determine whether information about the object is still current.
920 
921   See `MatGetNonzeroState()` to determine if the nonzero structure of the matrix has changed.
922 
923 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PetscObjectStateGet()`, `MatGetNonzeroState()`
924 @*/
925 PetscErrorCode MatGetState(Mat A, PetscObjectState *state)
926 {
927   PetscFunctionBegin;
928   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
929   PetscAssertPointer(state, 2);
930   PetscCall(PetscObjectStateGet((PetscObject)A, state));
931   PetscFunctionReturn(PETSC_SUCCESS);
932 }
933 
934 /*@
935   MatResetPreallocation - Reset matrix to use the original nonzero pattern provided by the user.
936 
937   Collective
938 
939   Input Parameter:
940 . A - the matrix
941 
942   Level: beginner
943 
944   Notes:
945   The allocated memory will be shrunk after calling `MatAssemblyBegin()` and `MatAssemblyEnd()` with `MAT_FINAL_ASSEMBLY`.
946 
947   Users can reset the preallocation to access the original memory.
948 
949   Currently only supported for  `MATAIJ` matrices.
950 
951 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatXAIJSetPreallocation()`
952 @*/
953 PetscErrorCode MatResetPreallocation(Mat A)
954 {
955   PetscFunctionBegin;
956   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
957   PetscValidType(A, 1);
958   PetscCheck(A->insertmode == NOT_SET_VALUES, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot reset preallocation after setting some values but not yet calling MatAssemblyBegin()/MatAssemblyEnd()");
959   if (A->num_ass == 0) PetscFunctionReturn(PETSC_SUCCESS);
960   PetscUseMethod(A, "MatResetPreallocation_C", (Mat), (A));
961   PetscFunctionReturn(PETSC_SUCCESS);
962 }
963 
964 /*@
965   MatSetUp - Sets up the internal matrix data structures for later use.
966 
967   Collective
968 
969   Input Parameter:
970 . A - the matrix
971 
972   Level: intermediate
973 
974   Notes:
975   If the user has not set preallocation for this matrix then an efficient algorithm will be used for the first round of
976   setting values in the matrix.
977 
978   This routine is called internally by other matrix functions when needed so rarely needs to be called by users
979 
980 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatCreate()`, `MatDestroy()`, `MatXAIJSetPreallocation()`
981 @*/
982 PetscErrorCode MatSetUp(Mat A)
983 {
984   PetscFunctionBegin;
985   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
986   if (!((PetscObject)A)->type_name) {
987     PetscMPIInt size;
988 
989     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
990     PetscCall(MatSetType(A, size == 1 ? MATSEQAIJ : MATMPIAIJ));
991   }
992   if (!A->preallocated) PetscTryTypeMethod(A, setup);
993   PetscCall(PetscLayoutSetUp(A->rmap));
994   PetscCall(PetscLayoutSetUp(A->cmap));
995   A->preallocated = PETSC_TRUE;
996   PetscFunctionReturn(PETSC_SUCCESS);
997 }
998 
999 #if defined(PETSC_HAVE_SAWS)
1000   #include <petscviewersaws.h>
1001 #endif
1002 
1003 /*
1004    If threadsafety is on extraneous matrices may be printed
1005 
1006    This flag cannot be stored in the matrix because the original matrix in MatView() may assemble a new matrix which is passed into MatViewFromOptions()
1007 */
1008 #if !defined(PETSC_HAVE_THREADSAFETY)
1009 static PetscInt insidematview = 0;
1010 #endif
1011 
1012 /*@
1013   MatViewFromOptions - View properties of the matrix based on options set in the options database
1014 
1015   Collective
1016 
1017   Input Parameters:
1018 + A    - the matrix
1019 . obj  - optional additional object that provides the options prefix to use
1020 - name - command line option
1021 
1022   Options Database Key:
1023 . -mat_view [viewertype]:... - the viewer and its options
1024 
1025   Level: intermediate
1026 
1027   Note:
1028 .vb
1029     If no value is provided ascii:stdout is used
1030        ascii[:[filename][:[format][:append]]]    defaults to stdout - format can be one of ascii_info, ascii_info_detail, or ascii_matlab,
1031                                                   for example ascii::ascii_info prints just the information about the object not all details
1032                                                   unless :append is given filename opens in write mode, overwriting what was already there
1033        binary[:[filename][:[format][:append]]]   defaults to the file binaryoutput
1034        draw[:drawtype[:filename]]                for example, draw:tikz, draw:tikz:figure.tex  or draw:x
1035        socket[:port]                             defaults to the standard output port
1036        saws[:communicatorname]                    publishes object to the Scientific Application Webserver (SAWs)
1037 .ve
1038 
1039 .seealso: [](ch_matrices), `Mat`, `MatView()`, `PetscObjectViewFromOptions()`, `MatCreate()`
1040 @*/
1041 PetscErrorCode MatViewFromOptions(Mat A, PetscObject obj, const char name[])
1042 {
1043   PetscFunctionBegin;
1044   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
1045 #if !defined(PETSC_HAVE_THREADSAFETY)
1046   if (insidematview) PetscFunctionReturn(PETSC_SUCCESS);
1047 #endif
1048   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
1049   PetscFunctionReturn(PETSC_SUCCESS);
1050 }
1051 
1052 /*@
1053   MatView - display information about a matrix in a variety ways
1054 
1055   Collective on viewer
1056 
1057   Input Parameters:
1058 + mat    - the matrix
1059 - viewer - visualization context
1060 
1061   Options Database Keys:
1062 + -mat_view ::ascii_info           - Prints info on matrix at conclusion of `MatAssemblyEnd()`
1063 . -mat_view ::ascii_info_detail    - Prints more detailed info
1064 . -mat_view                        - Prints matrix in ASCII format
1065 . -mat_view ::ascii_matlab         - Prints matrix in MATLAB format
1066 . -mat_view draw                   - PetscDraws nonzero structure of matrix, using `MatView()` and `PetscDrawOpenX()`.
1067 . -display <name>                  - Sets display name (default is host)
1068 . -draw_pause <sec>                - Sets number of seconds to pause after display
1069 . -mat_view socket                 - Sends matrix to socket, can be accessed from MATLAB (see Users-Manual: ch_matlab for details)
1070 . -viewer_socket_machine <machine> - -
1071 . -viewer_socket_port <port>       - -
1072 . -mat_view binary                 - save matrix to file in binary format
1073 - -viewer_binary_filename <name>   - -
1074 
1075   Level: beginner
1076 
1077   Notes:
1078   The available visualization contexts include
1079 +    `PETSC_VIEWER_STDOUT_SELF` - for sequential matrices
1080 .    `PETSC_VIEWER_STDOUT_WORLD` - for parallel matrices created on `PETSC_COMM_WORLD`
1081 .    `PETSC_VIEWER_STDOUT_`(comm) - for matrices created on MPI communicator comm
1082 -     `PETSC_VIEWER_DRAW_WORLD` - graphical display of nonzero structure
1083 
1084   The user can open alternative visualization contexts with
1085 +    `PetscViewerASCIIOpen()` - Outputs matrix to a specified file
1086 .    `PetscViewerBinaryOpen()` - Outputs matrix in binary to a
1087   specified file; corresponding input uses `MatLoad()`
1088 .    `PetscViewerDrawOpen()` - Outputs nonzero matrix structure to
1089   an X window display
1090 -    `PetscViewerSocketOpen()` - Outputs matrix to Socket viewer.
1091   Currently only the `MATSEQDENSE` and `MATAIJ`
1092   matrix types support the Socket viewer.
1093 
1094   The user can call `PetscViewerPushFormat()` to specify the output
1095   format of ASCII printed objects (when using `PETSC_VIEWER_STDOUT_SELF`,
1096   `PETSC_VIEWER_STDOUT_WORLD` and `PetscViewerASCIIOpen()`).  Available formats include
1097 +    `PETSC_VIEWER_DEFAULT` - default, prints matrix contents
1098 .    `PETSC_VIEWER_ASCII_MATLAB` - prints matrix contents in MATLAB format
1099 .    `PETSC_VIEWER_ASCII_DENSE` - prints entire matrix including zeros
1100 .    `PETSC_VIEWER_ASCII_COMMON` - prints matrix contents, using a sparse
1101   format common among all matrix types
1102 .    `PETSC_VIEWER_ASCII_IMPL` - prints matrix contents, using an implementation-specific
1103   format (which is in many cases the same as the default)
1104 .    `PETSC_VIEWER_ASCII_INFO` - prints basic information about the matrix
1105   size and structure (not the matrix entries)
1106 -    `PETSC_VIEWER_ASCII_INFO_DETAIL` - prints more detailed information about
1107   the matrix structure (still not vector or matrix entries)
1108 
1109   The ASCII viewers are only recommended for small matrices on at most a moderate number of processes,
1110   the program will seemingly hang and take hours for larger matrices, for larger matrices one should use the binary format.
1111 
1112   In the debugger you can do "call MatView(mat,0)" to display the matrix. (The same holds for any PETSc object viewer).
1113 
1114   See the manual page for `MatLoad()` for the exact format of the binary file when the binary
1115   viewer is used.
1116 
1117   See share/petsc/matlab/PetscBinaryRead.m for a MATLAB code that can read in the binary file when the binary
1118   viewer is used and lib/petsc/bin/PetscBinaryIO.py for loading them into Python.
1119 
1120   One can use '-mat_view draw -draw_pause -1' to pause the graphical display of matrix nonzero structure,
1121   and then use the following mouse functions.
1122 .vb
1123   left mouse: zoom in
1124   middle mouse: zoom out
1125   right mouse: continue with the simulation
1126 .ve
1127 
1128 .seealso: [](ch_matrices), `Mat`, `PetscViewerPushFormat()`, `PetscViewerASCIIOpen()`, `PetscViewerDrawOpen()`, `PetscViewer`,
1129           `PetscViewerSocketOpen()`, `PetscViewerBinaryOpen()`, `MatLoad()`, `MatViewFromOptions()`
1130 @*/
1131 PetscErrorCode MatView(Mat mat, PetscViewer viewer)
1132 {
1133   PetscInt          rows, cols, rbs, cbs;
1134   PetscBool         isascii, isstring, issaws;
1135   PetscViewerFormat format;
1136   PetscMPIInt       size;
1137 
1138   PetscFunctionBegin;
1139   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1140   PetscValidType(mat, 1);
1141   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)mat), &viewer));
1142   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1143 
1144   PetscCall(PetscViewerGetFormat(viewer, &format));
1145   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size));
1146   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
1147 
1148 #if !defined(PETSC_HAVE_THREADSAFETY)
1149   insidematview++;
1150 #endif
1151   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
1152   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1153   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSAWS, &issaws));
1154   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");
1155 
1156   PetscCall(PetscLogEventBegin(MAT_View, mat, viewer, 0, 0));
1157   if (isascii) {
1158     if (!mat->preallocated) {
1159       PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix has not been preallocated yet\n"));
1160 #if !defined(PETSC_HAVE_THREADSAFETY)
1161       insidematview--;
1162 #endif
1163       PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1164       PetscFunctionReturn(PETSC_SUCCESS);
1165     }
1166     if (!mat->assembled) {
1167       PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix has not been assembled yet\n"));
1168 #if !defined(PETSC_HAVE_THREADSAFETY)
1169       insidematview--;
1170 #endif
1171       PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1172       PetscFunctionReturn(PETSC_SUCCESS);
1173     }
1174     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)mat, viewer));
1175     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1176       MatNullSpace nullsp, transnullsp;
1177 
1178       PetscCall(PetscViewerASCIIPushTab(viewer));
1179       PetscCall(MatGetSize(mat, &rows, &cols));
1180       PetscCall(MatGetBlockSizes(mat, &rbs, &cbs));
1181       if (rbs != 1 || cbs != 1) {
1182         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" : ""));
1183         else PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT ", bs=%" PetscInt_FMT "%s\n", rows, cols, rbs, mat->bsizes ? " variable blocks set" : ""));
1184       } else PetscCall(PetscViewerASCIIPrintf(viewer, "rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", rows, cols));
1185       if (mat->factortype) {
1186         MatSolverType solver;
1187         PetscCall(MatFactorGetSolverType(mat, &solver));
1188         PetscCall(PetscViewerASCIIPrintf(viewer, "package used to perform factorization: %s\n", solver));
1189       }
1190       if (mat->ops->getinfo) {
1191         MatInfo info;
1192         PetscCall(MatGetInfo(mat, MAT_GLOBAL_SUM, &info));
1193         PetscCall(PetscViewerASCIIPrintf(viewer, "total: nonzeros=%.f, allocated nonzeros=%.f\n", info.nz_used, info.nz_allocated));
1194         if (!mat->factortype) PetscCall(PetscViewerASCIIPrintf(viewer, "total number of mallocs used during MatSetValues calls=%" PetscInt_FMT "\n", (PetscInt)info.mallocs));
1195       }
1196       PetscCall(MatGetNullSpace(mat, &nullsp));
1197       PetscCall(MatGetTransposeNullSpace(mat, &transnullsp));
1198       if (nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached null space\n"));
1199       if (transnullsp && transnullsp != nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached transposed null space\n"));
1200       PetscCall(MatGetNearNullSpace(mat, &nullsp));
1201       if (nullsp) PetscCall(PetscViewerASCIIPrintf(viewer, "  has attached near null space\n"));
1202       PetscCall(PetscViewerASCIIPushTab(viewer));
1203       PetscCall(MatProductView(mat, viewer));
1204       PetscCall(PetscViewerASCIIPopTab(viewer));
1205       if (mat->bsizes && format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
1206         IS tmp;
1207 
1208         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), mat->nblocks, mat->bsizes, PETSC_USE_POINTER, &tmp));
1209         PetscCall(PetscObjectSetName((PetscObject)tmp, "Block Sizes"));
1210         PetscCall(PetscViewerASCIIPushTab(viewer));
1211         PetscCall(ISView(tmp, viewer));
1212         PetscCall(PetscViewerASCIIPopTab(viewer));
1213         PetscCall(ISDestroy(&tmp));
1214       }
1215     }
1216   } else if (issaws) {
1217 #if defined(PETSC_HAVE_SAWS)
1218     PetscMPIInt rank;
1219 
1220     PetscCall(PetscObjectName((PetscObject)mat));
1221     PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1222     if (!((PetscObject)mat)->amsmem && rank == 0) PetscCall(PetscObjectViewSAWs((PetscObject)mat, viewer));
1223 #endif
1224   } else if (isstring) {
1225     const char *type;
1226     PetscCall(MatGetType(mat, &type));
1227     PetscCall(PetscViewerStringSPrintf(viewer, " MatType: %-7.7s", type));
1228     PetscTryTypeMethod(mat, view, viewer);
1229   }
1230   if ((format == PETSC_VIEWER_NATIVE || format == PETSC_VIEWER_LOAD_BALANCE) && mat->ops->viewnative) {
1231     PetscCall(PetscViewerASCIIPushTab(viewer));
1232     PetscUseTypeMethod(mat, viewnative, viewer);
1233     PetscCall(PetscViewerASCIIPopTab(viewer));
1234   } else if (mat->ops->view) {
1235     PetscCall(PetscViewerASCIIPushTab(viewer));
1236     PetscUseTypeMethod(mat, view, viewer);
1237     PetscCall(PetscViewerASCIIPopTab(viewer));
1238   }
1239   if (isascii) {
1240     PetscCall(PetscViewerGetFormat(viewer, &format));
1241     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscCall(PetscViewerASCIIPopTab(viewer));
1242   }
1243   PetscCall(PetscLogEventEnd(MAT_View, mat, viewer, 0, 0));
1244 #if !defined(PETSC_HAVE_THREADSAFETY)
1245   insidematview--;
1246 #endif
1247   PetscFunctionReturn(PETSC_SUCCESS);
1248 }
1249 
1250 #if defined(PETSC_USE_DEBUG)
1251   #include <../src/sys/totalview/tv_data_display.h>
1252 PETSC_UNUSED static int TV_display_type(const struct _p_Mat *mat)
1253 {
1254   TV_add_row("Local rows", "int", &mat->rmap->n);
1255   TV_add_row("Local columns", "int", &mat->cmap->n);
1256   TV_add_row("Global rows", "int", &mat->rmap->N);
1257   TV_add_row("Global columns", "int", &mat->cmap->N);
1258   TV_add_row("Typename", TV_ascii_string_type, ((PetscObject)mat)->type_name);
1259   return TV_format_OK;
1260 }
1261 #endif
1262 
1263 /*@
1264   MatLoad - Loads a matrix that has been stored in binary/HDF5 format
1265   with `MatView()`.  The matrix format is determined from the options database.
1266   Generates a parallel MPI matrix if the communicator has more than one
1267   processor.  The default matrix type is `MATAIJ`.
1268 
1269   Collective
1270 
1271   Input Parameters:
1272 + mat    - the newly loaded matrix, this needs to have been created with `MatCreate()`
1273             or some related function before a call to `MatLoad()`
1274 - viewer - `PETSCVIEWERBINARY`/`PETSCVIEWERHDF5` file viewer
1275 
1276   Options Database Key:
1277 . -matload_block_size <bs> - set block size
1278 
1279   Level: beginner
1280 
1281   Notes:
1282   If the `Mat` type has not yet been given then `MATAIJ` is used, call `MatSetFromOptions()` on the
1283   `Mat` before calling this routine if you wish to set it from the options database.
1284 
1285   `MatLoad()` automatically loads into the options database any options
1286   given in the file filename.info where filename is the name of the file
1287   that was passed to the `PetscViewerBinaryOpen()`. The options in the info
1288   file will be ignored if you use the -viewer_binary_skip_info option.
1289 
1290   If the type or size of mat is not set before a call to `MatLoad()`, PETSc
1291   sets the default matrix type AIJ and sets the local and global sizes.
1292   If type and/or size is already set, then the same are used.
1293 
1294   In parallel, each processor can load a subset of rows (or the
1295   entire matrix).  This routine is especially useful when a large
1296   matrix is stored on disk and only part of it is desired on each
1297   processor.  For example, a parallel solver may access only some of
1298   the rows from each processor.  The algorithm used here reads
1299   relatively small blocks of data rather than reading the entire
1300   matrix and then subsetting it.
1301 
1302   Viewer's `PetscViewerType` must be either `PETSCVIEWERBINARY` or `PETSCVIEWERHDF5`.
1303   Such viewer can be created using `PetscViewerBinaryOpen()` or `PetscViewerHDF5Open()`,
1304   or the sequence like
1305 .vb
1306     `PetscViewer` v;
1307     `PetscViewerCreate`(`PETSC_COMM_WORLD`,&v);
1308     `PetscViewerSetType`(v,`PETSCVIEWERBINARY`);
1309     `PetscViewerSetFromOptions`(v);
1310     `PetscViewerFileSetMode`(v,`FILE_MODE_READ`);
1311     `PetscViewerFileSetName`(v,"datafile");
1312 .ve
1313   The optional `PetscViewerSetFromOptions()` call allows overriding `PetscViewerSetType()` using the option
1314 $ -viewer_type {binary, hdf5}
1315 
1316   See the example src/ksp/ksp/tutorials/ex27.c with the first approach,
1317   and src/mat/tutorials/ex10.c with the second approach.
1318 
1319   In case of `PETSCVIEWERBINARY`, a native PETSc binary format is used. Each of the blocks
1320   is read onto MPI rank 0 and then shipped to its destination MPI rank, one after another.
1321   Multiple objects, both matrices and vectors, can be stored within the same file.
1322   Their `PetscObject` name is ignored; they are loaded in the order of their storage.
1323 
1324   Most users should not need to know the details of the binary storage
1325   format, since `MatLoad()` and `MatView()` completely hide these details.
1326   But for anyone who is interested, the standard binary matrix storage
1327   format is
1328 
1329 .vb
1330     PetscInt    MAT_FILE_CLASSID
1331     PetscInt    number of rows
1332     PetscInt    number of columns
1333     PetscInt    total number of nonzeros
1334     PetscInt    *number nonzeros in each row
1335     PetscInt    *column indices of all nonzeros (starting index is zero)
1336     PetscScalar *values of all nonzeros
1337 .ve
1338   If PETSc was not configured with `--with-64-bit-indices` then only `MATMPIAIJ` matrices with more than `PETSC_INT_MAX` non-zeros can be
1339   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
1340   case will not fit in a (32-bit) `PetscInt` the value `PETSC_INT_MAX` is used for the header entry `total number of nonzeros`.
1341 
1342   PETSc automatically does the byte swapping for
1343   machines that store the bytes reversed. Thus if you write your own binary
1344   read/write routines you have to swap the bytes; see `PetscBinaryRead()`
1345   and `PetscBinaryWrite()` to see how this may be done.
1346 
1347   In case of `PETSCVIEWERHDF5`, a parallel HDF5 reader is used.
1348   Each processor's chunk is loaded independently by its owning MPI process.
1349   Multiple objects, both matrices and vectors, can be stored within the same file.
1350   They are looked up by their PetscObject name.
1351 
1352   As the MATLAB MAT-File Version 7.3 format is also a HDF5 flavor, we decided to use
1353   by default the same structure and naming of the AIJ arrays and column count
1354   within the HDF5 file. This means that a MAT file saved with -v7.3 flag, e.g.
1355 $    save example.mat A b -v7.3
1356   can be directly read by this routine (see Reference 1 for details).
1357 
1358   Depending on your MATLAB version, this format might be a default,
1359   otherwise you can set it as default in Preferences.
1360 
1361   Unless -nocompression flag is used to save the file in MATLAB,
1362   PETSc must be configured with ZLIB package.
1363 
1364   See also examples src/mat/tutorials/ex10.c and src/ksp/ksp/tutorials/ex27.c
1365 
1366   This reader currently supports only real `MATSEQAIJ`, `MATMPIAIJ`, `MATSEQDENSE` and `MATMPIDENSE` matrices for `PETSCVIEWERHDF5`
1367 
1368   Corresponding `MatView()` is not yet implemented.
1369 
1370   The loaded matrix is actually a transpose of the original one in MATLAB,
1371   unless you push `PETSC_VIEWER_HDF5_MAT` format (see examples above).
1372   With this format, matrix is automatically transposed by PETSc,
1373   unless the matrix is marked as SPD or symmetric
1374   (see `MatSetOption()`, `MAT_SPD`, `MAT_SYMMETRIC`).
1375 
1376   See MATLAB Documentation on `save()`, <https://www.mathworks.com/help/matlab/ref/save.html#btox10b-1-version>
1377 
1378 .seealso: [](ch_matrices), `Mat`, `PetscViewerBinaryOpen()`, `PetscViewerSetType()`, `MatView()`, `VecLoad()`
1379  @*/
1380 PetscErrorCode MatLoad(Mat mat, PetscViewer viewer)
1381 {
1382   PetscBool flg;
1383 
1384   PetscFunctionBegin;
1385   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1386   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1387 
1388   if (!((PetscObject)mat)->type_name) PetscCall(MatSetType(mat, MATAIJ));
1389 
1390   flg = PETSC_FALSE;
1391   PetscCall(PetscOptionsGetBool(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matload_symmetric", &flg, NULL));
1392   if (flg) {
1393     PetscCall(MatSetOption(mat, MAT_SYMMETRIC, PETSC_TRUE));
1394     PetscCall(MatSetOption(mat, MAT_SYMMETRY_ETERNAL, PETSC_TRUE));
1395   }
1396   flg = PETSC_FALSE;
1397   PetscCall(PetscOptionsGetBool(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matload_spd", &flg, NULL));
1398   if (flg) PetscCall(MatSetOption(mat, MAT_SPD, PETSC_TRUE));
1399 
1400   PetscCall(PetscLogEventBegin(MAT_Load, mat, viewer, 0, 0));
1401   PetscUseTypeMethod(mat, load, viewer);
1402   PetscCall(PetscLogEventEnd(MAT_Load, mat, viewer, 0, 0));
1403   PetscFunctionReturn(PETSC_SUCCESS);
1404 }
1405 
1406 static PetscErrorCode MatDestroy_Redundant(Mat_Redundant **redundant)
1407 {
1408   Mat_Redundant *redund = *redundant;
1409 
1410   PetscFunctionBegin;
1411   if (redund) {
1412     if (redund->matseq) { /* via MatCreateSubMatrices()  */
1413       PetscCall(ISDestroy(&redund->isrow));
1414       PetscCall(ISDestroy(&redund->iscol));
1415       PetscCall(MatDestroySubMatrices(1, &redund->matseq));
1416     } else {
1417       PetscCall(PetscFree2(redund->send_rank, redund->recv_rank));
1418       PetscCall(PetscFree(redund->sbuf_j));
1419       PetscCall(PetscFree(redund->sbuf_a));
1420       for (PetscInt i = 0; i < redund->nrecvs; i++) {
1421         PetscCall(PetscFree(redund->rbuf_j[i]));
1422         PetscCall(PetscFree(redund->rbuf_a[i]));
1423       }
1424       PetscCall(PetscFree4(redund->sbuf_nz, redund->rbuf_nz, redund->rbuf_j, redund->rbuf_a));
1425     }
1426 
1427     if (redund->subcomm) PetscCall(PetscCommDestroy(&redund->subcomm));
1428     PetscCall(PetscFree(redund));
1429   }
1430   PetscFunctionReturn(PETSC_SUCCESS);
1431 }
1432 
1433 /*@
1434   MatDestroy - Frees space taken by a matrix.
1435 
1436   Collective
1437 
1438   Input Parameter:
1439 . A - the matrix
1440 
1441   Level: beginner
1442 
1443   Developer Note:
1444   Some special arrays of matrices are not destroyed in this routine but instead by the routines called by
1445   `MatDestroySubMatrices()`. Thus one must be sure that any changes here must also be made in those routines.
1446   `MatHeaderMerge()` and `MatHeaderReplace()` also manipulate the data in the `Mat` object and likely need changes
1447   if changes are needed here.
1448 
1449 .seealso: [](ch_matrices), `Mat`, `MatCreate()`
1450 @*/
1451 PetscErrorCode MatDestroy(Mat *A)
1452 {
1453   PetscFunctionBegin;
1454   if (!*A) PetscFunctionReturn(PETSC_SUCCESS);
1455   PetscValidHeaderSpecific(*A, MAT_CLASSID, 1);
1456   if (--((PetscObject)*A)->refct > 0) {
1457     *A = NULL;
1458     PetscFunctionReturn(PETSC_SUCCESS);
1459   }
1460 
1461   /* if memory was published with SAWs then destroy it */
1462   PetscCall(PetscObjectSAWsViewOff((PetscObject)*A));
1463   PetscTryTypeMethod(*A, destroy);
1464 
1465   PetscCall(PetscFree((*A)->factorprefix));
1466   PetscCall(PetscFree((*A)->defaultvectype));
1467   PetscCall(PetscFree((*A)->defaultrandtype));
1468   PetscCall(PetscFree((*A)->bsizes));
1469   PetscCall(PetscFree((*A)->solvertype));
1470   for (PetscInt i = 0; i < MAT_FACTOR_NUM_TYPES; i++) PetscCall(PetscFree((*A)->preferredordering[i]));
1471   if ((*A)->redundant && (*A)->redundant->matseq[0] == *A) (*A)->redundant->matseq[0] = NULL;
1472   PetscCall(MatDestroy_Redundant(&(*A)->redundant));
1473   PetscCall(MatProductClear(*A));
1474   PetscCall(MatNullSpaceDestroy(&(*A)->nullsp));
1475   PetscCall(MatNullSpaceDestroy(&(*A)->transnullsp));
1476   PetscCall(MatNullSpaceDestroy(&(*A)->nearnullsp));
1477   PetscCall(MatDestroy(&(*A)->schur));
1478   PetscCall(PetscLayoutDestroy(&(*A)->rmap));
1479   PetscCall(PetscLayoutDestroy(&(*A)->cmap));
1480   PetscCall(PetscHeaderDestroy(A));
1481   PetscFunctionReturn(PETSC_SUCCESS);
1482 }
1483 
1484 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1485 /*@
1486   MatSetValues - Inserts or adds a block of values into a matrix.
1487   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
1488   MUST be called after all calls to `MatSetValues()` have been completed.
1489 
1490   Not Collective
1491 
1492   Input Parameters:
1493 + mat  - the matrix
1494 . v    - a logically two-dimensional array of values
1495 . m    - the number of rows
1496 . idxm - the global indices of the rows
1497 . n    - the number of columns
1498 . idxn - the global indices of the columns
1499 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
1500 
1501   Level: beginner
1502 
1503   Notes:
1504   By default the values, `v`, are stored row-oriented. See `MatSetOption()` for other options.
1505 
1506   Calls to `MatSetValues()` with the `INSERT_VALUES` and `ADD_VALUES`
1507   options cannot be mixed without intervening calls to the assembly
1508   routines.
1509 
1510   `MatSetValues()` uses 0-based row and column numbers in Fortran
1511   as well as in C.
1512 
1513   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
1514   simply ignored. This allows easily inserting element stiffness matrices
1515   with homogeneous Dirichlet boundary conditions that you don't want represented
1516   in the matrix.
1517 
1518   Efficiency Alert:
1519   The routine `MatSetValuesBlocked()` may offer much better efficiency
1520   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1521 
1522   Fortran Notes:
1523   If any of `idxm`, `idxn`, and `v` are scalars pass them using, for example,
1524 .vb
1525   MatSetValues(mat, one, [idxm], one, [idxn], [v], INSERT_VALUES)
1526 .ve
1527 
1528   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
1529 
1530   Developer Note:
1531   This is labeled with C so does not automatically generate Fortran stubs and interfaces
1532   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
1533 
1534 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1535           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1536 @*/
1537 PetscErrorCode MatSetValues(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar v[], InsertMode addv)
1538 {
1539   PetscFunctionBeginHot;
1540   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1541   PetscValidType(mat, 1);
1542   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1543   PetscAssertPointer(idxm, 3);
1544   PetscAssertPointer(idxn, 5);
1545   MatCheckPreallocated(mat, 1);
1546 
1547   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
1548   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
1549 
1550   if (PetscDefined(USE_DEBUG)) {
1551     PetscInt i, j;
1552 
1553     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1554     if (v) {
1555       for (i = 0; i < m; i++) {
1556         for (j = 0; j < n; j++) {
1557           if (mat->erroriffailure && PetscIsInfOrNanScalar(v[i * n + j]))
1558 #if defined(PETSC_USE_COMPLEX)
1559             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]);
1560 #else
1561             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]);
1562 #endif
1563         }
1564       }
1565     }
1566     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);
1567     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);
1568   }
1569 
1570   if (mat->assembled) {
1571     mat->was_assembled = PETSC_TRUE;
1572     mat->assembled     = PETSC_FALSE;
1573   }
1574   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
1575   PetscUseTypeMethod(mat, setvalues, m, idxm, n, idxn, v, addv);
1576   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
1577   PetscFunctionReturn(PETSC_SUCCESS);
1578 }
1579 
1580 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1581 /*@
1582   MatSetValuesIS - Inserts or adds a block of values into a matrix using an `IS` to indicate the rows and columns
1583   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
1584   MUST be called after all calls to `MatSetValues()` have been completed.
1585 
1586   Not Collective
1587 
1588   Input Parameters:
1589 + mat  - the matrix
1590 . v    - a logically two-dimensional array of values
1591 . ism  - the rows to provide
1592 . isn  - the columns to provide
1593 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
1594 
1595   Level: beginner
1596 
1597   Notes:
1598   By default the values, `v`, are stored row-oriented. See `MatSetOption()` for other options.
1599 
1600   Calls to `MatSetValues()` with the `INSERT_VALUES` and `ADD_VALUES`
1601   options cannot be mixed without intervening calls to the assembly
1602   routines.
1603 
1604   `MatSetValues()` uses 0-based row and column numbers in Fortran
1605   as well as in C.
1606 
1607   Negative indices may be passed in `ism` and `isn`, these rows and columns are
1608   simply ignored. This allows easily inserting element stiffness matrices
1609   with homogeneous Dirichlet boundary conditions that you don't want represented
1610   in the matrix.
1611 
1612   Efficiency Alert:
1613   The routine `MatSetValuesBlocked()` may offer much better efficiency
1614   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1615 
1616   This is currently not optimized for any particular `ISType`
1617 
1618   Developer Note:
1619   This is labeled with C so does not automatically generate Fortran stubs and interfaces
1620   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
1621 
1622 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatSetValues()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1623           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1624 @*/
1625 PetscErrorCode MatSetValuesIS(Mat mat, IS ism, IS isn, const PetscScalar v[], InsertMode addv)
1626 {
1627   PetscInt        m, n;
1628   const PetscInt *rows, *cols;
1629 
1630   PetscFunctionBeginHot;
1631   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1632   PetscCall(ISGetIndices(ism, &rows));
1633   PetscCall(ISGetIndices(isn, &cols));
1634   PetscCall(ISGetLocalSize(ism, &m));
1635   PetscCall(ISGetLocalSize(isn, &n));
1636   PetscCall(MatSetValues(mat, m, rows, n, cols, v, addv));
1637   PetscCall(ISRestoreIndices(ism, &rows));
1638   PetscCall(ISRestoreIndices(isn, &cols));
1639   PetscFunctionReturn(PETSC_SUCCESS);
1640 }
1641 
1642 /*@
1643   MatSetValuesRowLocal - Inserts a row (block row for `MATBAIJ` matrices) of nonzero
1644   values into a matrix
1645 
1646   Not Collective
1647 
1648   Input Parameters:
1649 + mat - the matrix
1650 . row - the (block) row to set
1651 - v   - a logically two-dimensional array of values
1652 
1653   Level: intermediate
1654 
1655   Notes:
1656   The values, `v`, are column-oriented (for the block version) and sorted
1657 
1658   All the nonzero values in `row` must be provided
1659 
1660   The matrix must have previously had its column indices set, likely by having been assembled.
1661 
1662   `row` must belong to this MPI process
1663 
1664 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1665           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`, `MatSetValues()`, `MatSetValuesRow()`, `MatSetLocalToGlobalMapping()`
1666 @*/
1667 PetscErrorCode MatSetValuesRowLocal(Mat mat, PetscInt row, const PetscScalar v[])
1668 {
1669   PetscInt globalrow;
1670 
1671   PetscFunctionBegin;
1672   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1673   PetscValidType(mat, 1);
1674   PetscAssertPointer(v, 3);
1675   PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, 1, &row, &globalrow));
1676   PetscCall(MatSetValuesRow(mat, globalrow, v));
1677   PetscFunctionReturn(PETSC_SUCCESS);
1678 }
1679 
1680 /*@
1681   MatSetValuesRow - Inserts a row (block row for `MATBAIJ` matrices) of nonzero
1682   values into a matrix
1683 
1684   Not Collective
1685 
1686   Input Parameters:
1687 + mat - the matrix
1688 . row - the (block) row to set
1689 - 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
1690 
1691   Level: advanced
1692 
1693   Notes:
1694   The values, `v`, are column-oriented for the block version.
1695 
1696   All the nonzeros in `row` must be provided
1697 
1698   THE MATRIX MUST HAVE PREVIOUSLY HAD ITS COLUMN INDICES SET. IT IS RARE THAT THIS ROUTINE IS USED, usually `MatSetValues()` is used.
1699 
1700   `row` must belong to this process
1701 
1702 .seealso: [](ch_matrices), `Mat`, `MatSetValues()`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
1703           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
1704 @*/
1705 PetscErrorCode MatSetValuesRow(Mat mat, PetscInt row, const PetscScalar v[])
1706 {
1707   PetscFunctionBeginHot;
1708   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1709   PetscValidType(mat, 1);
1710   MatCheckPreallocated(mat, 1);
1711   PetscAssertPointer(v, 3);
1712   PetscCheck(mat->insertmode != ADD_VALUES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add and insert values");
1713   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
1714   mat->insertmode = INSERT_VALUES;
1715 
1716   if (mat->assembled) {
1717     mat->was_assembled = PETSC_TRUE;
1718     mat->assembled     = PETSC_FALSE;
1719   }
1720   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
1721   PetscUseTypeMethod(mat, setvaluesrow, row, v);
1722   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
1723   PetscFunctionReturn(PETSC_SUCCESS);
1724 }
1725 
1726 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
1727 /*@
1728   MatSetValuesStencil - Inserts or adds a block of values into a matrix.
1729   Using structured grid indexing
1730 
1731   Not Collective
1732 
1733   Input Parameters:
1734 + mat  - the matrix
1735 . m    - number of rows being entered
1736 . idxm - grid coordinates (and component number when dof > 1) for matrix rows being entered
1737 . n    - number of columns being entered
1738 . idxn - grid coordinates (and component number when dof > 1) for matrix columns being entered
1739 . v    - a logically two-dimensional array of values
1740 - addv - either `ADD_VALUES` to add to existing entries at that location or `INSERT_VALUES` to replace existing entries with new values
1741 
1742   Level: beginner
1743 
1744   Notes:
1745   By default the values, `v`, are row-oriented.  See `MatSetOption()` for other options.
1746 
1747   Calls to `MatSetValuesStencil()` with the `INSERT_VALUES` and `ADD_VALUES`
1748   options cannot be mixed without intervening calls to the assembly
1749   routines.
1750 
1751   The grid coordinates are across the entire grid, not just the local portion
1752 
1753   `MatSetValuesStencil()` uses 0-based row and column numbers in Fortran
1754   as well as in C.
1755 
1756   For setting/accessing vector values via array coordinates you can use the `DMDAVecGetArray()` routine
1757 
1758   In order to use this routine you must either obtain the matrix with `DMCreateMatrix()`
1759   or call `MatSetLocalToGlobalMapping()` and `MatSetStencil()` first.
1760 
1761   The columns and rows in the stencil passed in MUST be contained within the
1762   ghost region of the given process as set with DMDACreateXXX() or `MatSetStencil()`. For example,
1763   if you create a `DMDA` with an overlap of one grid level and on a particular process its first
1764   local nonghost x logical coordinate is 6 (so its first ghost x logical coordinate is 5) the
1765   first i index you can use in your column and row indices in `MatSetStencil()` is 5.
1766 
1767   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
1768   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
1769   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
1770   `DM_BOUNDARY_PERIODIC` boundary type.
1771 
1772   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
1773   a single value per point) you can skip filling those indices.
1774 
1775   Inspired by the structured grid interface to the HYPRE package
1776   (https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods)
1777 
1778   Efficiency Alert:
1779   The routine `MatSetValuesBlockedStencil()` may offer much better efficiency
1780   for users of block sparse formats (`MATSEQBAIJ` and `MATMPIBAIJ`).
1781 
1782   Fortran Note:
1783   `idxm` and `idxn` should be declared as
1784 $     MatStencil idxm(4,m),idxn(4,n)
1785   and the values inserted using
1786 .vb
1787     idxm(MatStencil_i,1) = i
1788     idxm(MatStencil_j,1) = j
1789     idxm(MatStencil_k,1) = k
1790     idxm(MatStencil_c,1) = c
1791     etc
1792 .ve
1793 
1794 .seealso: [](ch_matrices), `Mat`, `DMDA`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1795           `MatSetValues()`, `MatSetValuesBlockedStencil()`, `MatSetStencil()`, `DMCreateMatrix()`, `DMDAVecGetArray()`, `MatStencil`
1796 @*/
1797 PetscErrorCode MatSetValuesStencil(Mat mat, PetscInt m, const MatStencil idxm[], PetscInt n, const MatStencil idxn[], const PetscScalar v[], InsertMode addv)
1798 {
1799   PetscInt  buf[8192], *bufm = NULL, *bufn = NULL, *jdxm, *jdxn;
1800   PetscInt  j, i, dim = mat->stencil.dim, *dims = mat->stencil.dims + 1, tmp;
1801   PetscInt *starts = mat->stencil.starts, *dxm = (PetscInt *)idxm, *dxn = (PetscInt *)idxn, sdim = dim - (1 - (PetscInt)mat->stencil.noc);
1802 
1803   PetscFunctionBegin;
1804   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1805   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1806   PetscValidType(mat, 1);
1807   PetscAssertPointer(idxm, 3);
1808   PetscAssertPointer(idxn, 5);
1809 
1810   if ((m + n) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
1811     jdxm = buf;
1812     jdxn = buf + m;
1813   } else {
1814     PetscCall(PetscMalloc2(m, &bufm, n, &bufn));
1815     jdxm = bufm;
1816     jdxn = bufn;
1817   }
1818   for (i = 0; i < m; i++) {
1819     for (j = 0; j < 3 - sdim; j++) dxm++;
1820     tmp = *dxm++ - starts[0];
1821     for (j = 0; j < dim - 1; j++) {
1822       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1823       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
1824     }
1825     if (mat->stencil.noc) dxm++;
1826     jdxm[i] = tmp;
1827   }
1828   for (i = 0; i < n; i++) {
1829     for (j = 0; j < 3 - sdim; j++) dxn++;
1830     tmp = *dxn++ - starts[0];
1831     for (j = 0; j < dim - 1; j++) {
1832       if ((*dxn++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1833       else tmp = tmp * dims[j] + *(dxn - 1) - starts[j + 1];
1834     }
1835     if (mat->stencil.noc) dxn++;
1836     jdxn[i] = tmp;
1837   }
1838   PetscCall(MatSetValuesLocal(mat, m, jdxm, n, jdxn, v, addv));
1839   PetscCall(PetscFree2(bufm, bufn));
1840   PetscFunctionReturn(PETSC_SUCCESS);
1841 }
1842 
1843 /*@
1844   MatSetValuesBlockedStencil - Inserts or adds a block of values into a matrix.
1845   Using structured grid indexing
1846 
1847   Not Collective
1848 
1849   Input Parameters:
1850 + mat  - the matrix
1851 . m    - number of rows being entered
1852 . idxm - grid coordinates for matrix rows being entered
1853 . n    - number of columns being entered
1854 . idxn - grid coordinates for matrix columns being entered
1855 . v    - a logically two-dimensional array of values
1856 - addv - either `ADD_VALUES` to add to existing entries or `INSERT_VALUES` to replace existing entries with new values
1857 
1858   Level: beginner
1859 
1860   Notes:
1861   By default the values, `v`, are row-oriented and unsorted.
1862   See `MatSetOption()` for other options.
1863 
1864   Calls to `MatSetValuesBlockedStencil()` with the `INSERT_VALUES` and `ADD_VALUES`
1865   options cannot be mixed without intervening calls to the assembly
1866   routines.
1867 
1868   The grid coordinates are across the entire grid, not just the local portion
1869 
1870   `MatSetValuesBlockedStencil()` uses 0-based row and column numbers in Fortran
1871   as well as in C.
1872 
1873   For setting/accessing vector values via array coordinates you can use the `DMDAVecGetArray()` routine
1874 
1875   In order to use this routine you must either obtain the matrix with `DMCreateMatrix()`
1876   or call `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()` and `MatSetStencil()` first.
1877 
1878   The columns and rows in the stencil passed in MUST be contained within the
1879   ghost region of the given process as set with DMDACreateXXX() or `MatSetStencil()`. For example,
1880   if you create a `DMDA` with an overlap of one grid level and on a particular process its first
1881   local nonghost x logical coordinate is 6 (so its first ghost x logical coordinate is 5) the
1882   first i index you can use in your column and row indices in `MatSetStencil()` is 5.
1883 
1884   Negative indices may be passed in idxm and idxn, these rows and columns are
1885   simply ignored. This allows easily inserting element stiffness matrices
1886   with homogeneous Dirichlet boundary conditions that you don't want represented
1887   in the matrix.
1888 
1889   Inspired by the structured grid interface to the HYPRE package
1890   (https://computation.llnl.gov/projects/hypre-scalable-linear-solvers-multigrid-methods)
1891 
1892   Fortran Note:
1893   `idxm` and `idxn` should be declared as
1894 $     MatStencil idxm(4,m),idxn(4,n)
1895   and the values inserted using
1896 .vb
1897     idxm(MatStencil_i,1) = i
1898     idxm(MatStencil_j,1) = j
1899     idxm(MatStencil_k,1) = k
1900    etc
1901 .ve
1902 
1903 .seealso: [](ch_matrices), `Mat`, `DMDA`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1904           `MatSetValues()`, `MatSetValuesStencil()`, `MatSetStencil()`, `DMCreateMatrix()`, `DMDAVecGetArray()`, `MatStencil`,
1905           `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()`
1906 @*/
1907 PetscErrorCode MatSetValuesBlockedStencil(Mat mat, PetscInt m, const MatStencil idxm[], PetscInt n, const MatStencil idxn[], const PetscScalar v[], InsertMode addv)
1908 {
1909   PetscInt  buf[8192], *bufm = NULL, *bufn = NULL, *jdxm, *jdxn;
1910   PetscInt  j, i, dim = mat->stencil.dim, *dims = mat->stencil.dims + 1, tmp;
1911   PetscInt *starts = mat->stencil.starts, *dxm = (PetscInt *)idxm, *dxn = (PetscInt *)idxn, sdim = dim - (1 - (PetscInt)mat->stencil.noc);
1912 
1913   PetscFunctionBegin;
1914   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
1915   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1916   PetscValidType(mat, 1);
1917   PetscAssertPointer(idxm, 3);
1918   PetscAssertPointer(idxn, 5);
1919   PetscAssertPointer(v, 6);
1920 
1921   if ((m + n) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
1922     jdxm = buf;
1923     jdxn = buf + m;
1924   } else {
1925     PetscCall(PetscMalloc2(m, &bufm, n, &bufn));
1926     jdxm = bufm;
1927     jdxn = bufn;
1928   }
1929   for (i = 0; i < m; i++) {
1930     for (j = 0; j < 3 - sdim; j++) dxm++;
1931     tmp = *dxm++ - starts[0];
1932     for (j = 0; j < sdim - 1; j++) {
1933       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1934       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
1935     }
1936     dxm++;
1937     jdxm[i] = tmp;
1938   }
1939   for (i = 0; i < n; i++) {
1940     for (j = 0; j < 3 - sdim; j++) dxn++;
1941     tmp = *dxn++ - starts[0];
1942     for (j = 0; j < sdim - 1; j++) {
1943       if ((*dxn++ - starts[j + 1]) < 0 || tmp < 0) tmp = -1;
1944       else tmp = tmp * dims[j] + *(dxn - 1) - starts[j + 1];
1945     }
1946     dxn++;
1947     jdxn[i] = tmp;
1948   }
1949   PetscCall(MatSetValuesBlockedLocal(mat, m, jdxm, n, jdxn, v, addv));
1950   PetscCall(PetscFree2(bufm, bufn));
1951   PetscFunctionReturn(PETSC_SUCCESS);
1952 }
1953 
1954 /*@
1955   MatSetStencil - Sets the grid information for setting values into a matrix via
1956   `MatSetValuesStencil()`
1957 
1958   Not Collective
1959 
1960   Input Parameters:
1961 + mat    - the matrix
1962 . dim    - dimension of the grid 1, 2, or 3
1963 . dims   - number of grid points in x, y, and z direction, including ghost points on your processor
1964 . starts - starting point of ghost nodes on your processor in x, y, and z direction
1965 - dof    - number of degrees of freedom per node
1966 
1967   Level: beginner
1968 
1969   Notes:
1970   Inspired by the structured grid interface to the HYPRE package
1971   (www.llnl.gov/CASC/hyper)
1972 
1973   For matrices generated with `DMCreateMatrix()` this routine is automatically called and so not needed by the
1974   user.
1975 
1976 .seealso: [](ch_matrices), `Mat`, `MatStencil`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`
1977           `MatSetValues()`, `MatSetValuesBlockedStencil()`, `MatSetValuesStencil()`
1978 @*/
1979 PetscErrorCode MatSetStencil(Mat mat, PetscInt dim, const PetscInt dims[], const PetscInt starts[], PetscInt dof)
1980 {
1981   PetscFunctionBegin;
1982   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
1983   PetscAssertPointer(dims, 3);
1984   PetscAssertPointer(starts, 4);
1985 
1986   mat->stencil.dim = dim + (dof > 1);
1987   for (PetscInt i = 0; i < dim; i++) {
1988     mat->stencil.dims[i]   = dims[dim - i - 1]; /* copy the values in backwards */
1989     mat->stencil.starts[i] = starts[dim - i - 1];
1990   }
1991   mat->stencil.dims[dim]   = dof;
1992   mat->stencil.starts[dim] = 0;
1993   mat->stencil.noc         = (PetscBool)(dof == 1);
1994   PetscFunctionReturn(PETSC_SUCCESS);
1995 }
1996 
1997 /*@
1998   MatSetValuesBlocked - Inserts or adds a block of values into a matrix.
1999 
2000   Not Collective
2001 
2002   Input Parameters:
2003 + mat  - the matrix
2004 . v    - a logically two-dimensional array of values
2005 . m    - the number of block rows
2006 . idxm - the global block indices
2007 . n    - the number of block columns
2008 . idxn - the global block indices
2009 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` replaces existing entries with new values
2010 
2011   Level: intermediate
2012 
2013   Notes:
2014   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call
2015   MatXXXXSetPreallocation() or `MatSetUp()` before using this routine.
2016 
2017   The `m` and `n` count the NUMBER of blocks in the row direction and column direction,
2018   NOT the total number of rows/columns; for example, if the block size is 2 and
2019   you are passing in values for rows 2,3,4,5  then `m` would be 2 (not 4).
2020   The values in `idxm` would be 1 2; that is the first index for each block divided by
2021   the block size.
2022 
2023   You must call `MatSetBlockSize()` when constructing this matrix (before
2024   preallocating it).
2025 
2026   By default the values, `v`, are row-oriented, so the layout of
2027   `v` is the same as for `MatSetValues()`. See `MatSetOption()` for other options.
2028 
2029   Calls to `MatSetValuesBlocked()` with the `INSERT_VALUES` and `ADD_VALUES`
2030   options cannot be mixed without intervening calls to the assembly
2031   routines.
2032 
2033   `MatSetValuesBlocked()` uses 0-based row and column numbers in Fortran
2034   as well as in C.
2035 
2036   Negative indices may be passed in `idxm` and `idxn`, these rows and columns are
2037   simply ignored. This allows easily inserting element stiffness matrices
2038   with homogeneous Dirichlet boundary conditions that you don't want represented
2039   in the matrix.
2040 
2041   Each time an entry is set within a sparse matrix via `MatSetValues()`,
2042   internal searching must be done to determine where to place the
2043   data in the matrix storage space.  By instead inserting blocks of
2044   entries via `MatSetValuesBlocked()`, the overhead of matrix assembly is
2045   reduced.
2046 
2047   Example:
2048 .vb
2049    Suppose m=n=2 and block size(bs) = 2 The array is
2050 
2051    1  2  | 3  4
2052    5  6  | 7  8
2053    - - - | - - -
2054    9  10 | 11 12
2055    13 14 | 15 16
2056 
2057    v[] should be passed in like
2058    v[] = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
2059 
2060   If you are not using row-oriented storage of v (that is you called MatSetOption(mat,MAT_ROW_ORIENTED,PETSC_FALSE)) then
2061    v[] = [1,5,9,13,2,6,10,14,3,7,11,15,4,8,12,16]
2062 .ve
2063 
2064   Fortran Notes:
2065   If any of `idmx`, `idxn`, and `v` are scalars pass them using, for example,
2066 .vb
2067   MatSetValuesBlocked(mat, one, [idxm], one, [idxn], [v], INSERT_VALUES)
2068 .ve
2069 
2070   If `v` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2071 
2072 .seealso: [](ch_matrices), `Mat`, `MatSetBlockSize()`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetValuesBlockedLocal()`
2073 @*/
2074 PetscErrorCode MatSetValuesBlocked(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar v[], InsertMode addv)
2075 {
2076   PetscFunctionBeginHot;
2077   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2078   PetscValidType(mat, 1);
2079   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2080   PetscAssertPointer(idxm, 3);
2081   PetscAssertPointer(idxn, 5);
2082   MatCheckPreallocated(mat, 1);
2083   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2084   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2085   if (PetscDefined(USE_DEBUG)) {
2086     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2087     PetscCheck(mat->ops->setvaluesblocked || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2088   }
2089   if (PetscDefined(USE_DEBUG)) {
2090     PetscInt rbs, cbs, M, N, i;
2091     PetscCall(MatGetBlockSizes(mat, &rbs, &cbs));
2092     PetscCall(MatGetSize(mat, &M, &N));
2093     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);
2094     for (i = 0; i < n; i++)
2095       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);
2096   }
2097   if (mat->assembled) {
2098     mat->was_assembled = PETSC_TRUE;
2099     mat->assembled     = PETSC_FALSE;
2100   }
2101   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2102   if (mat->ops->setvaluesblocked) {
2103     PetscUseTypeMethod(mat, setvaluesblocked, m, idxm, n, idxn, v, addv);
2104   } else {
2105     PetscInt buf[8192], *bufr = NULL, *bufc = NULL, *iidxm, *iidxn;
2106     PetscInt i, j, bs, cbs;
2107 
2108     PetscCall(MatGetBlockSizes(mat, &bs, &cbs));
2109     if ((m * bs + n * cbs) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2110       iidxm = buf;
2111       iidxn = buf + m * bs;
2112     } else {
2113       PetscCall(PetscMalloc2(m * bs, &bufr, n * cbs, &bufc));
2114       iidxm = bufr;
2115       iidxn = bufc;
2116     }
2117     for (i = 0; i < m; i++) {
2118       for (j = 0; j < bs; j++) iidxm[i * bs + j] = bs * idxm[i] + j;
2119     }
2120     if (m != n || bs != cbs || idxm != idxn) {
2121       for (i = 0; i < n; i++) {
2122         for (j = 0; j < cbs; j++) iidxn[i * cbs + j] = cbs * idxn[i] + j;
2123       }
2124     } else iidxn = iidxm;
2125     PetscCall(MatSetValues(mat, m * bs, iidxm, n * cbs, iidxn, v, addv));
2126     PetscCall(PetscFree2(bufr, bufc));
2127   }
2128   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2129   PetscFunctionReturn(PETSC_SUCCESS);
2130 }
2131 
2132 /*@
2133   MatGetValues - Gets a block of local values from a matrix.
2134 
2135   Not Collective; can only return values that are owned by the give process
2136 
2137   Input Parameters:
2138 + mat  - the matrix
2139 . v    - a logically two-dimensional array for storing the values
2140 . m    - the number of rows
2141 . idxm - the  global indices of the rows
2142 . n    - the number of columns
2143 - idxn - the global indices of the columns
2144 
2145   Level: advanced
2146 
2147   Notes:
2148   The user must allocate space (m*n `PetscScalar`s) for the values, `v`.
2149   The values, `v`, are then returned in a row-oriented format,
2150   analogous to that used by default in `MatSetValues()`.
2151 
2152   `MatGetValues()` uses 0-based row and column numbers in
2153   Fortran as well as in C.
2154 
2155   `MatGetValues()` requires that the matrix has been assembled
2156   with `MatAssemblyBegin()`/`MatAssemblyEnd()`.  Thus, calls to
2157   `MatSetValues()` and `MatGetValues()` CANNOT be made in succession
2158   without intermediate matrix assembly.
2159 
2160   Negative row or column indices will be ignored and those locations in `v` will be
2161   left unchanged.
2162 
2163   For the standard row-based matrix formats, `idxm` can only contain rows owned by the requesting MPI process.
2164   That is, rows with global index greater than or equal to rstart and less than rend where rstart and rend are obtainable
2165   from `MatGetOwnershipRange`(mat,&rstart,&rend).
2166 
2167 .seealso: [](ch_matrices), `Mat`, `MatGetRow()`, `MatCreateSubMatrices()`, `MatSetValues()`, `MatGetOwnershipRange()`, `MatGetValuesLocal()`, `MatGetValue()`
2168 @*/
2169 PetscErrorCode MatGetValues(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], PetscScalar v[])
2170 {
2171   PetscFunctionBegin;
2172   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2173   PetscValidType(mat, 1);
2174   if (!m || !n) PetscFunctionReturn(PETSC_SUCCESS);
2175   PetscAssertPointer(idxm, 3);
2176   PetscAssertPointer(idxn, 5);
2177   PetscAssertPointer(v, 6);
2178   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2179   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2180   MatCheckPreallocated(mat, 1);
2181 
2182   PetscCall(PetscLogEventBegin(MAT_GetValues, mat, 0, 0, 0));
2183   PetscUseTypeMethod(mat, getvalues, m, idxm, n, idxn, v);
2184   PetscCall(PetscLogEventEnd(MAT_GetValues, mat, 0, 0, 0));
2185   PetscFunctionReturn(PETSC_SUCCESS);
2186 }
2187 
2188 /*@
2189   MatGetValuesLocal - retrieves values from certain locations in a matrix using the local numbering of the indices
2190   defined previously by `MatSetLocalToGlobalMapping()`
2191 
2192   Not Collective
2193 
2194   Input Parameters:
2195 + mat  - the matrix
2196 . nrow - number of rows
2197 . irow - the row local indices
2198 . ncol - number of columns
2199 - icol - the column local indices
2200 
2201   Output Parameter:
2202 . y - a logically two-dimensional array of values
2203 
2204   Level: advanced
2205 
2206   Notes:
2207   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetLocalToGlobalMapping()` before using this routine.
2208 
2209   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,
2210   are greater than or equal to rstart and less than rend where rstart and rend are obtainable from `MatGetOwnershipRange`(mat,&rstart,&rend). One can
2211   determine if the resulting global row associated with the local row r is owned by the requesting MPI process by applying the `ISLocalToGlobalMapping` set
2212   with `MatSetLocalToGlobalMapping()`.
2213 
2214   Developer Note:
2215   This is labelled with C so does not automatically generate Fortran stubs and interfaces
2216   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
2217 
2218 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetLocalToGlobalMapping()`,
2219           `MatSetValuesLocal()`, `MatGetValues()`
2220 @*/
2221 PetscErrorCode MatGetValuesLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], PetscScalar y[])
2222 {
2223   PetscFunctionBeginHot;
2224   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2225   PetscValidType(mat, 1);
2226   MatCheckPreallocated(mat, 1);
2227   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to retrieve */
2228   PetscAssertPointer(irow, 3);
2229   PetscAssertPointer(icol, 5);
2230   if (PetscDefined(USE_DEBUG)) {
2231     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2232     PetscCheck(mat->ops->getvalueslocal || mat->ops->getvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2233   }
2234   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2235   PetscCall(PetscLogEventBegin(MAT_GetValues, mat, 0, 0, 0));
2236   if (mat->ops->getvalueslocal) PetscUseTypeMethod(mat, getvalueslocal, nrow, irow, ncol, icol, y);
2237   else {
2238     PetscInt buf[8192], *bufr = NULL, *bufc = NULL, *irowm, *icolm;
2239     if ((nrow + ncol) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2240       irowm = buf;
2241       icolm = buf + nrow;
2242     } else {
2243       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2244       irowm = bufr;
2245       icolm = bufc;
2246     }
2247     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MatGetValuesLocal() cannot proceed without local-to-global row mapping (See MatSetLocalToGlobalMapping()).");
2248     PetscCheck(mat->cmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MatGetValuesLocal() cannot proceed without local-to-global column mapping (See MatSetLocalToGlobalMapping()).");
2249     PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, nrow, irow, irowm));
2250     PetscCall(ISLocalToGlobalMappingApply(mat->cmap->mapping, ncol, icol, icolm));
2251     PetscCall(MatGetValues(mat, nrow, irowm, ncol, icolm, y));
2252     PetscCall(PetscFree2(bufr, bufc));
2253   }
2254   PetscCall(PetscLogEventEnd(MAT_GetValues, mat, 0, 0, 0));
2255   PetscFunctionReturn(PETSC_SUCCESS);
2256 }
2257 
2258 /*@
2259   MatSetValuesBatch - Adds (`ADD_VALUES`) many blocks of values into a matrix at once. The blocks must all be square and
2260   the same size. Currently, this can only be called once and creates the given matrix.
2261 
2262   Not Collective
2263 
2264   Input Parameters:
2265 + mat  - the matrix
2266 . nb   - the number of blocks
2267 . bs   - the number of rows (and columns) in each block
2268 . rows - a concatenation of the rows for each block
2269 - v    - a concatenation of logically two-dimensional arrays of values
2270 
2271   Level: advanced
2272 
2273   Notes:
2274   `MatSetPreallocationCOO()` and `MatSetValuesCOO()` may be a better way to provide the values
2275 
2276   In the future, we will extend this routine to handle rectangular blocks, and to allow multiple calls for a given matrix.
2277 
2278 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValuesBlocked()`, `MatSetValuesLocal()`,
2279           `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`, `MatSetValues()`, `MatSetPreallocationCOO()`, `MatSetValuesCOO()`
2280 @*/
2281 PetscErrorCode MatSetValuesBatch(Mat mat, PetscInt nb, PetscInt bs, PetscInt rows[], const PetscScalar v[])
2282 {
2283   PetscFunctionBegin;
2284   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2285   PetscValidType(mat, 1);
2286   PetscAssertPointer(rows, 4);
2287   PetscAssertPointer(v, 5);
2288   PetscAssert(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2289 
2290   PetscCall(PetscLogEventBegin(MAT_SetValuesBatch, mat, 0, 0, 0));
2291   if (mat->ops->setvaluesbatch) PetscUseTypeMethod(mat, setvaluesbatch, nb, bs, rows, v);
2292   else {
2293     for (PetscInt b = 0; b < nb; ++b) PetscCall(MatSetValues(mat, bs, &rows[b * bs], bs, &rows[b * bs], &v[b * bs * bs], ADD_VALUES));
2294   }
2295   PetscCall(PetscLogEventEnd(MAT_SetValuesBatch, mat, 0, 0, 0));
2296   PetscFunctionReturn(PETSC_SUCCESS);
2297 }
2298 
2299 /*@
2300   MatSetLocalToGlobalMapping - Sets a local-to-global numbering for use by
2301   the routine `MatSetValuesLocal()` to allow users to insert matrix entries
2302   using a local (per-processor) numbering.
2303 
2304   Not Collective
2305 
2306   Input Parameters:
2307 + x        - the matrix
2308 . rmapping - row mapping created with `ISLocalToGlobalMappingCreate()` or `ISLocalToGlobalMappingCreateIS()`
2309 - cmapping - column mapping
2310 
2311   Level: intermediate
2312 
2313   Note:
2314   If the matrix is obtained with `DMCreateMatrix()` then this may already have been called on the matrix
2315 
2316 .seealso: [](ch_matrices), `Mat`, `DM`, `DMCreateMatrix()`, `MatGetLocalToGlobalMapping()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetValuesLocal()`, `MatGetValuesLocal()`
2317 @*/
2318 PetscErrorCode MatSetLocalToGlobalMapping(Mat x, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping)
2319 {
2320   PetscFunctionBegin;
2321   PetscValidHeaderSpecific(x, MAT_CLASSID, 1);
2322   PetscValidType(x, 1);
2323   if (rmapping) PetscValidHeaderSpecific(rmapping, IS_LTOGM_CLASSID, 2);
2324   if (cmapping) PetscValidHeaderSpecific(cmapping, IS_LTOGM_CLASSID, 3);
2325   if (x->ops->setlocaltoglobalmapping) PetscUseTypeMethod(x, setlocaltoglobalmapping, rmapping, cmapping);
2326   else {
2327     PetscCall(PetscLayoutSetISLocalToGlobalMapping(x->rmap, rmapping));
2328     PetscCall(PetscLayoutSetISLocalToGlobalMapping(x->cmap, cmapping));
2329   }
2330   PetscFunctionReturn(PETSC_SUCCESS);
2331 }
2332 
2333 /*@
2334   MatGetLocalToGlobalMapping - Gets the local-to-global numbering set by `MatSetLocalToGlobalMapping()`
2335 
2336   Not Collective
2337 
2338   Input Parameter:
2339 . A - the matrix
2340 
2341   Output Parameters:
2342 + rmapping - row mapping
2343 - cmapping - column mapping
2344 
2345   Level: advanced
2346 
2347 .seealso: [](ch_matrices), `Mat`, `MatSetLocalToGlobalMapping()`, `MatSetValuesLocal()`
2348 @*/
2349 PetscErrorCode MatGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping)
2350 {
2351   PetscFunctionBegin;
2352   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2353   PetscValidType(A, 1);
2354   if (rmapping) {
2355     PetscAssertPointer(rmapping, 2);
2356     *rmapping = A->rmap->mapping;
2357   }
2358   if (cmapping) {
2359     PetscAssertPointer(cmapping, 3);
2360     *cmapping = A->cmap->mapping;
2361   }
2362   PetscFunctionReturn(PETSC_SUCCESS);
2363 }
2364 
2365 /*@
2366   MatSetLayouts - Sets the `PetscLayout` objects for rows and columns of a matrix
2367 
2368   Logically Collective
2369 
2370   Input Parameters:
2371 + A    - the matrix
2372 . rmap - row layout
2373 - cmap - column layout
2374 
2375   Level: advanced
2376 
2377   Note:
2378   The `PetscLayout` objects are usually created automatically for the matrix so this routine rarely needs to be called.
2379 
2380 .seealso: [](ch_matrices), `Mat`, `PetscLayout`, `MatCreateVecs()`, `MatGetLocalToGlobalMapping()`, `MatGetLayouts()`
2381 @*/
2382 PetscErrorCode MatSetLayouts(Mat A, PetscLayout rmap, PetscLayout cmap)
2383 {
2384   PetscFunctionBegin;
2385   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2386   PetscCall(PetscLayoutReference(rmap, &A->rmap));
2387   PetscCall(PetscLayoutReference(cmap, &A->cmap));
2388   PetscFunctionReturn(PETSC_SUCCESS);
2389 }
2390 
2391 /*@
2392   MatGetLayouts - Gets the `PetscLayout` objects for rows and columns
2393 
2394   Not Collective
2395 
2396   Input Parameter:
2397 . A - the matrix
2398 
2399   Output Parameters:
2400 + rmap - row layout
2401 - cmap - column layout
2402 
2403   Level: advanced
2404 
2405 .seealso: [](ch_matrices), `Mat`, [Matrix Layouts](sec_matlayout), `PetscLayout`, `MatCreateVecs()`, `MatGetLocalToGlobalMapping()`, `MatSetLayouts()`
2406 @*/
2407 PetscErrorCode MatGetLayouts(Mat A, PetscLayout *rmap, PetscLayout *cmap)
2408 {
2409   PetscFunctionBegin;
2410   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
2411   PetscValidType(A, 1);
2412   if (rmap) {
2413     PetscAssertPointer(rmap, 2);
2414     *rmap = A->rmap;
2415   }
2416   if (cmap) {
2417     PetscAssertPointer(cmap, 3);
2418     *cmap = A->cmap;
2419   }
2420   PetscFunctionReturn(PETSC_SUCCESS);
2421 }
2422 
2423 /*@
2424   MatSetValuesLocal - Inserts or adds values into certain locations of a matrix,
2425   using a local numbering of the rows and columns.
2426 
2427   Not Collective
2428 
2429   Input Parameters:
2430 + mat  - the matrix
2431 . nrow - number of rows
2432 . irow - the row local indices
2433 . ncol - number of columns
2434 . icol - the column local indices
2435 . y    - a logically two-dimensional array of values
2436 - addv - either `INSERT_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
2437 
2438   Level: intermediate
2439 
2440   Notes:
2441   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetLocalToGlobalMapping()` before using this routine
2442 
2443   Calls to `MatSetValuesLocal()` with the `INSERT_VALUES` and `ADD_VALUES`
2444   options cannot be mixed without intervening calls to the assembly
2445   routines.
2446 
2447   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
2448   MUST be called after all calls to `MatSetValuesLocal()` have been completed.
2449 
2450   Fortran Notes:
2451   If any of `irow`, `icol`, and `y` are scalars pass them using, for example,
2452 .vb
2453   MatSetValuesLocal(mat, one, [irow], one, [icol], [y], INSERT_VALUES)
2454 .ve
2455 
2456   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2457 
2458   Developer Note:
2459   This is labeled with C so does not automatically generate Fortran stubs and interfaces
2460   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
2461 
2462 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatAssemblyEnd()`, `MatSetValues()`, `MatSetLocalToGlobalMapping()`,
2463           `MatGetValuesLocal()`
2464 @*/
2465 PetscErrorCode MatSetValuesLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv)
2466 {
2467   PetscFunctionBeginHot;
2468   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2469   PetscValidType(mat, 1);
2470   MatCheckPreallocated(mat, 1);
2471   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2472   PetscAssertPointer(irow, 3);
2473   PetscAssertPointer(icol, 5);
2474   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2475   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2476   if (PetscDefined(USE_DEBUG)) {
2477     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2478     PetscCheck(mat->ops->setvalueslocal || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2479   }
2480 
2481   if (mat->assembled) {
2482     mat->was_assembled = PETSC_TRUE;
2483     mat->assembled     = PETSC_FALSE;
2484   }
2485   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2486   if (mat->ops->setvalueslocal) PetscUseTypeMethod(mat, setvalueslocal, nrow, irow, ncol, icol, y, addv);
2487   else {
2488     PetscInt        buf[8192], *bufr = NULL, *bufc = NULL;
2489     const PetscInt *irowm, *icolm;
2490 
2491     if ((!mat->rmap->mapping && !mat->cmap->mapping) || (nrow + ncol) <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) {
2492       bufr  = buf;
2493       bufc  = buf + nrow;
2494       irowm = bufr;
2495       icolm = bufc;
2496     } else {
2497       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2498       irowm = bufr;
2499       icolm = bufc;
2500     }
2501     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingApply(mat->rmap->mapping, nrow, irow, bufr));
2502     else irowm = irow;
2503     if (mat->cmap->mapping) {
2504       if (mat->cmap->mapping != mat->rmap->mapping || ncol != nrow || icol != irow) {
2505         PetscCall(ISLocalToGlobalMappingApply(mat->cmap->mapping, ncol, icol, bufc));
2506       } else icolm = irowm;
2507     } else icolm = icol;
2508     PetscCall(MatSetValues(mat, nrow, irowm, ncol, icolm, y, addv));
2509     if (bufr != buf) PetscCall(PetscFree2(bufr, bufc));
2510   }
2511   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2512   PetscFunctionReturn(PETSC_SUCCESS);
2513 }
2514 
2515 /*@
2516   MatSetValuesBlockedLocal - Inserts or adds values into certain locations of a matrix,
2517   using a local ordering of the nodes a block at a time.
2518 
2519   Not Collective
2520 
2521   Input Parameters:
2522 + mat  - the matrix
2523 . nrow - number of rows
2524 . irow - the row local indices
2525 . ncol - number of columns
2526 . icol - the column local indices
2527 . y    - a logically two-dimensional array of values
2528 - addv - either `ADD_VALUES` to add values to any existing entries, or `INSERT_VALUES` to replace existing entries with new values
2529 
2530   Level: intermediate
2531 
2532   Notes:
2533   If you create the matrix yourself (that is not with a call to `DMCreateMatrix()`) then you MUST call `MatSetBlockSize()` and `MatSetLocalToGlobalMapping()`
2534   before using this routineBefore calling `MatSetValuesLocal()`, the user must first set the
2535 
2536   Calls to `MatSetValuesBlockedLocal()` with the `INSERT_VALUES` and `ADD_VALUES`
2537   options cannot be mixed without intervening calls to the assembly
2538   routines.
2539 
2540   These values may be cached, so `MatAssemblyBegin()` and `MatAssemblyEnd()`
2541   MUST be called after all calls to `MatSetValuesBlockedLocal()` have been completed.
2542 
2543   Fortran Notes:
2544   If any of `irow`, `icol`, and `y` are scalars pass them using, for example,
2545 .vb
2546   MatSetValuesBlockedLocal(mat, one, [irow], one, [icol], [y], INSERT_VALUES)
2547 .ve
2548 
2549   If `y` is a two-dimensional array use `reshape()` to pass it as a one dimensional array
2550 
2551   Developer Note:
2552   This is labeled with C so does not automatically generate Fortran stubs and interfaces
2553   because it requires multiple Fortran interfaces depending on which arguments are scalar or arrays.
2554 
2555 .seealso: [](ch_matrices), `Mat`, `MatSetBlockSize()`, `MatSetLocalToGlobalMapping()`, `MatAssemblyBegin()`, `MatAssemblyEnd()`,
2556           `MatSetValuesLocal()`, `MatSetValuesBlocked()`
2557 @*/
2558 PetscErrorCode MatSetValuesBlockedLocal(Mat mat, PetscInt nrow, const PetscInt irow[], PetscInt ncol, const PetscInt icol[], const PetscScalar y[], InsertMode addv)
2559 {
2560   PetscFunctionBeginHot;
2561   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2562   PetscValidType(mat, 1);
2563   MatCheckPreallocated(mat, 1);
2564   if (!nrow || !ncol) PetscFunctionReturn(PETSC_SUCCESS); /* no values to insert */
2565   PetscAssertPointer(irow, 3);
2566   PetscAssertPointer(icol, 5);
2567   if (mat->insertmode == NOT_SET_VALUES) mat->insertmode = addv;
2568   else PetscCheck(mat->insertmode == addv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot mix add values and insert values");
2569   if (PetscDefined(USE_DEBUG)) {
2570     PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2571     PetscCheck(mat->ops->setvaluesblockedlocal || mat->ops->setvaluesblocked || mat->ops->setvalueslocal || mat->ops->setvalues, PETSC_COMM_SELF, PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2572   }
2573 
2574   if (mat->assembled) {
2575     mat->was_assembled = PETSC_TRUE;
2576     mat->assembled     = PETSC_FALSE;
2577   }
2578   if (PetscUnlikelyDebug(mat->rmap->mapping)) { /* Condition on the mapping existing, because MatSetValuesBlockedLocal_IS does not require it to be set. */
2579     PetscInt irbs, rbs;
2580     PetscCall(MatGetBlockSizes(mat, &rbs, NULL));
2581     PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &irbs));
2582     PetscCheck(rbs == irbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Different row block sizes! mat %" PetscInt_FMT ", row l2g map %" PetscInt_FMT, rbs, irbs);
2583   }
2584   if (PetscUnlikelyDebug(mat->cmap->mapping)) {
2585     PetscInt icbs, cbs;
2586     PetscCall(MatGetBlockSizes(mat, NULL, &cbs));
2587     PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &icbs));
2588     PetscCheck(cbs == icbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Different col block sizes! mat %" PetscInt_FMT ", col l2g map %" PetscInt_FMT, cbs, icbs);
2589   }
2590   PetscCall(PetscLogEventBegin(MAT_SetValues, mat, 0, 0, 0));
2591   if (mat->ops->setvaluesblockedlocal) PetscUseTypeMethod(mat, setvaluesblockedlocal, nrow, irow, ncol, icol, y, addv);
2592   else {
2593     PetscInt        buf[8192], *bufr = NULL, *bufc = NULL;
2594     const PetscInt *irowm, *icolm;
2595 
2596     if ((!mat->rmap->mapping && !mat->cmap->mapping) || (nrow + ncol) <= ((PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf))) {
2597       bufr  = buf;
2598       bufc  = buf + nrow;
2599       irowm = bufr;
2600       icolm = bufc;
2601     } else {
2602       PetscCall(PetscMalloc2(nrow, &bufr, ncol, &bufc));
2603       irowm = bufr;
2604       icolm = bufc;
2605     }
2606     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingApplyBlock(mat->rmap->mapping, nrow, irow, bufr));
2607     else irowm = irow;
2608     if (mat->cmap->mapping) {
2609       if (mat->cmap->mapping != mat->rmap->mapping || ncol != nrow || icol != irow) {
2610         PetscCall(ISLocalToGlobalMappingApplyBlock(mat->cmap->mapping, ncol, icol, bufc));
2611       } else icolm = irowm;
2612     } else icolm = icol;
2613     PetscCall(MatSetValuesBlocked(mat, nrow, irowm, ncol, icolm, y, addv));
2614     if (bufr != buf) PetscCall(PetscFree2(bufr, bufc));
2615   }
2616   PetscCall(PetscLogEventEnd(MAT_SetValues, mat, 0, 0, 0));
2617   PetscFunctionReturn(PETSC_SUCCESS);
2618 }
2619 
2620 /*@
2621   MatMultDiagonalBlock - Computes the matrix-vector product, $y = Dx$. Where `D` is defined by the inode or block structure of the diagonal
2622 
2623   Collective
2624 
2625   Input Parameters:
2626 + mat - the matrix
2627 - x   - the vector to be multiplied
2628 
2629   Output Parameter:
2630 . y - the result
2631 
2632   Level: developer
2633 
2634   Note:
2635   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2636   call `MatMultDiagonalBlock`(A,y,y).
2637 
2638 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
2639 @*/
2640 PetscErrorCode MatMultDiagonalBlock(Mat mat, Vec x, Vec y)
2641 {
2642   PetscFunctionBegin;
2643   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2644   PetscValidType(mat, 1);
2645   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2646   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2647 
2648   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2649   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2650   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2651   MatCheckPreallocated(mat, 1);
2652 
2653   PetscUseTypeMethod(mat, multdiagonalblock, x, y);
2654   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2655   PetscFunctionReturn(PETSC_SUCCESS);
2656 }
2657 
2658 /*@
2659   MatMult - Computes the matrix-vector product, $y = Ax$.
2660 
2661   Neighbor-wise Collective
2662 
2663   Input Parameters:
2664 + mat - the matrix
2665 - x   - the vector to be multiplied
2666 
2667   Output Parameter:
2668 . y - the result
2669 
2670   Level: beginner
2671 
2672   Note:
2673   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2674   call `MatMult`(A,y,y).
2675 
2676 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
2677 @*/
2678 PetscErrorCode MatMult(Mat mat, Vec x, Vec y)
2679 {
2680   PetscFunctionBegin;
2681   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2682   PetscValidType(mat, 1);
2683   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2684   VecCheckAssembled(x);
2685   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2686   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2687   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2688   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2689   PetscCheck(mat->cmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, x->map->N);
2690   PetscCheck(mat->rmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, y->map->N);
2691   PetscCheck(mat->cmap->n == x->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->n, x->map->n);
2692   PetscCheck(mat->rmap->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, y->map->n);
2693   PetscCall(VecSetErrorIfLocked(y, 3));
2694   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2695   MatCheckPreallocated(mat, 1);
2696 
2697   PetscCall(VecLockReadPush(x));
2698   PetscCall(PetscLogEventBegin(MAT_Mult, mat, x, y, 0));
2699   PetscUseTypeMethod(mat, mult, x, y);
2700   PetscCall(PetscLogEventEnd(MAT_Mult, mat, x, y, 0));
2701   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(y, 3, PETSC_FALSE));
2702   PetscCall(VecLockReadPop(x));
2703   PetscFunctionReturn(PETSC_SUCCESS);
2704 }
2705 
2706 /*@
2707   MatMultTranspose - Computes matrix transpose times a vector $y = A^T * x$.
2708 
2709   Neighbor-wise Collective
2710 
2711   Input Parameters:
2712 + mat - the matrix
2713 - x   - the vector to be multiplied
2714 
2715   Output Parameter:
2716 . y - the result
2717 
2718   Level: beginner
2719 
2720   Notes:
2721   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2722   call `MatMultTranspose`(A,y,y).
2723 
2724   For complex numbers this does NOT compute the Hermitian (complex conjugate) transpose multiple,
2725   use `MatMultHermitianTranspose()`
2726 
2727 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatMultHermitianTranspose()`, `MatTranspose()`
2728 @*/
2729 PetscErrorCode MatMultTranspose(Mat mat, Vec x, Vec y)
2730 {
2731   PetscErrorCode (*op)(Mat, Vec, Vec) = NULL;
2732 
2733   PetscFunctionBegin;
2734   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2735   PetscValidType(mat, 1);
2736   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2737   VecCheckAssembled(x);
2738   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2739 
2740   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2741   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2742   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2743   PetscCheck(mat->cmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, y->map->N);
2744   PetscCheck(mat->rmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, x->map->N);
2745   PetscCheck(mat->cmap->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->n, y->map->n);
2746   PetscCheck(mat->rmap->n == x->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, x->map->n);
2747   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(x, 2, PETSC_TRUE));
2748   MatCheckPreallocated(mat, 1);
2749 
2750   if (!mat->ops->multtranspose) {
2751     if (mat->symmetric == PETSC_BOOL3_TRUE && mat->ops->mult) op = mat->ops->mult;
2752     PetscCheck(op, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Matrix type %s does not have a multiply transpose defined or is symmetric and does not have a multiply defined", ((PetscObject)mat)->type_name);
2753   } else op = mat->ops->multtranspose;
2754   PetscCall(PetscLogEventBegin(MAT_MultTranspose, mat, x, y, 0));
2755   PetscCall(VecLockReadPush(x));
2756   PetscCall((*op)(mat, x, y));
2757   PetscCall(VecLockReadPop(x));
2758   PetscCall(PetscLogEventEnd(MAT_MultTranspose, mat, x, y, 0));
2759   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2760   if (mat->erroriffailure) PetscCall(VecValidValues_Internal(y, 3, PETSC_FALSE));
2761   PetscFunctionReturn(PETSC_SUCCESS);
2762 }
2763 
2764 /*@
2765   MatMultHermitianTranspose - Computes matrix Hermitian-transpose times a vector $y = A^H * x$.
2766 
2767   Neighbor-wise Collective
2768 
2769   Input Parameters:
2770 + mat - the matrix
2771 - x   - the vector to be multiplied
2772 
2773   Output Parameter:
2774 . y - the result
2775 
2776   Level: beginner
2777 
2778   Notes:
2779   The vectors `x` and `y` cannot be the same.  I.e., one cannot
2780   call `MatMultHermitianTranspose`(A,y,y).
2781 
2782   Also called the conjugate transpose, complex conjugate transpose, or adjoint.
2783 
2784   For real numbers `MatMultTranspose()` and `MatMultHermitianTranspose()` are identical.
2785 
2786 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `MatMultHermitianTransposeAdd()`, `MatMultTranspose()`
2787 @*/
2788 PetscErrorCode MatMultHermitianTranspose(Mat mat, Vec x, Vec y)
2789 {
2790   PetscFunctionBegin;
2791   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2792   PetscValidType(mat, 1);
2793   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
2794   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
2795 
2796   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2797   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2798   PetscCheck(x != y, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "x and y must be different vectors");
2799   PetscCheck(mat->cmap->N == y->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, y->map->N);
2800   PetscCheck(mat->rmap->N == x->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, x->map->N);
2801   PetscCheck(mat->cmap->n == y->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec y: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->n, y->map->n);
2802   PetscCheck(mat->rmap->n == x->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec x: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, x->map->n);
2803   MatCheckPreallocated(mat, 1);
2804 
2805   PetscCall(PetscLogEventBegin(MAT_MultHermitianTranspose, mat, x, y, 0));
2806 #if defined(PETSC_USE_COMPLEX)
2807   if (mat->ops->multhermitiantranspose || (mat->hermitian == PETSC_BOOL3_TRUE && mat->ops->mult)) {
2808     PetscCall(VecLockReadPush(x));
2809     if (mat->ops->multhermitiantranspose) PetscUseTypeMethod(mat, multhermitiantranspose, x, y);
2810     else PetscUseTypeMethod(mat, mult, x, y);
2811     PetscCall(VecLockReadPop(x));
2812   } else {
2813     Vec w;
2814     PetscCall(VecDuplicate(x, &w));
2815     PetscCall(VecCopy(x, w));
2816     PetscCall(VecConjugate(w));
2817     PetscCall(MatMultTranspose(mat, w, y));
2818     PetscCall(VecDestroy(&w));
2819     PetscCall(VecConjugate(y));
2820   }
2821   PetscCall(PetscObjectStateIncrease((PetscObject)y));
2822 #else
2823   PetscCall(MatMultTranspose(mat, x, y));
2824 #endif
2825   PetscCall(PetscLogEventEnd(MAT_MultHermitianTranspose, mat, x, y, 0));
2826   PetscFunctionReturn(PETSC_SUCCESS);
2827 }
2828 
2829 /*@
2830   MatMultAdd -  Computes $v3 = v2 + A * v1$.
2831 
2832   Neighbor-wise Collective
2833 
2834   Input Parameters:
2835 + mat - the matrix
2836 . v1  - the vector to be multiplied by `mat`
2837 - v2  - the vector to be added to the result
2838 
2839   Output Parameter:
2840 . v3 - the result
2841 
2842   Level: beginner
2843 
2844   Note:
2845   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2846   call `MatMultAdd`(A,v1,v2,v1).
2847 
2848 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMult()`, `MatMultTransposeAdd()`
2849 @*/
2850 PetscErrorCode MatMultAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2851 {
2852   PetscFunctionBegin;
2853   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2854   PetscValidType(mat, 1);
2855   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2856   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2857   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2858 
2859   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2860   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2861   PetscCheck(mat->cmap->N == v1->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v1: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v1->map->N);
2862   /* PetscCheck(mat->rmap->N == v2->map->N,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Mat mat,Vec v2: global dim %" PetscInt_FMT " %" PetscInt_FMT,mat->rmap->N,v2->map->N);
2863      PetscCheck(mat->rmap->N == v3->map->N,PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Mat mat,Vec v3: global dim %" PetscInt_FMT " %" PetscInt_FMT,mat->rmap->N,v3->map->N); */
2864   PetscCheck(mat->rmap->n == v3->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec v3: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, v3->map->n);
2865   PetscCheck(mat->rmap->n == v2->map->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Mat mat,Vec v2: local dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->n, v2->map->n);
2866   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2867   MatCheckPreallocated(mat, 1);
2868 
2869   PetscCall(PetscLogEventBegin(MAT_MultAdd, mat, v1, v2, v3));
2870   PetscCall(VecLockReadPush(v1));
2871   PetscUseTypeMethod(mat, multadd, v1, v2, v3);
2872   PetscCall(VecLockReadPop(v1));
2873   PetscCall(PetscLogEventEnd(MAT_MultAdd, mat, v1, v2, v3));
2874   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2875   PetscFunctionReturn(PETSC_SUCCESS);
2876 }
2877 
2878 /*@
2879   MatMultTransposeAdd - Computes $v3 = v2 + A^T * v1$.
2880 
2881   Neighbor-wise Collective
2882 
2883   Input Parameters:
2884 + mat - the matrix
2885 . v1  - the vector to be multiplied by the transpose of the matrix
2886 - v2  - the vector to be added to the result
2887 
2888   Output Parameter:
2889 . v3 - the result
2890 
2891   Level: beginner
2892 
2893   Note:
2894   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2895   call `MatMultTransposeAdd`(A,v1,v2,v1).
2896 
2897 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMult()`
2898 @*/
2899 PetscErrorCode MatMultTransposeAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2900 {
2901   PetscErrorCode (*op)(Mat, Vec, Vec, Vec) = (!mat->ops->multtransposeadd && mat->symmetric) ? mat->ops->multadd : mat->ops->multtransposeadd;
2902 
2903   PetscFunctionBegin;
2904   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2905   PetscValidType(mat, 1);
2906   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2907   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2908   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2909 
2910   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2911   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2912   PetscCheck(mat->rmap->N == v1->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v1: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, v1->map->N);
2913   PetscCheck(mat->cmap->N == v2->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v2: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v2->map->N);
2914   PetscCheck(mat->cmap->N == v3->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v3: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v3->map->N);
2915   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2916   PetscCheck(op, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Mat type %s", ((PetscObject)mat)->type_name);
2917   MatCheckPreallocated(mat, 1);
2918 
2919   PetscCall(PetscLogEventBegin(MAT_MultTransposeAdd, mat, v1, v2, v3));
2920   PetscCall(VecLockReadPush(v1));
2921   PetscCall((*op)(mat, v1, v2, v3));
2922   PetscCall(VecLockReadPop(v1));
2923   PetscCall(PetscLogEventEnd(MAT_MultTransposeAdd, mat, v1, v2, v3));
2924   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2925   PetscFunctionReturn(PETSC_SUCCESS);
2926 }
2927 
2928 /*@
2929   MatMultHermitianTransposeAdd - Computes $v3 = v2 + A^H * v1$.
2930 
2931   Neighbor-wise Collective
2932 
2933   Input Parameters:
2934 + mat - the matrix
2935 . v1  - the vector to be multiplied by the Hermitian transpose
2936 - v2  - the vector to be added to the result
2937 
2938   Output Parameter:
2939 . v3 - the result
2940 
2941   Level: beginner
2942 
2943   Note:
2944   The vectors `v1` and `v3` cannot be the same.  I.e., one cannot
2945   call `MatMultHermitianTransposeAdd`(A,v1,v2,v1).
2946 
2947 .seealso: [](ch_matrices), `Mat`, `MatMultHermitianTranspose()`, `MatMultTranspose()`, `MatMultAdd()`, `MatMult()`
2948 @*/
2949 PetscErrorCode MatMultHermitianTransposeAdd(Mat mat, Vec v1, Vec v2, Vec v3)
2950 {
2951   PetscFunctionBegin;
2952   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
2953   PetscValidType(mat, 1);
2954   PetscValidHeaderSpecific(v1, VEC_CLASSID, 2);
2955   PetscValidHeaderSpecific(v2, VEC_CLASSID, 3);
2956   PetscValidHeaderSpecific(v3, VEC_CLASSID, 4);
2957 
2958   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
2959   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
2960   PetscCheck(v1 != v3, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "v1 and v3 must be different vectors");
2961   PetscCheck(mat->rmap->N == v1->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v1: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->rmap->N, v1->map->N);
2962   PetscCheck(mat->cmap->N == v2->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v2: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v2->map->N);
2963   PetscCheck(mat->cmap->N == v3->map->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_SIZ, "Mat mat,Vec v3: global dim %" PetscInt_FMT " %" PetscInt_FMT, mat->cmap->N, v3->map->N);
2964   MatCheckPreallocated(mat, 1);
2965 
2966   PetscCall(PetscLogEventBegin(MAT_MultHermitianTransposeAdd, mat, v1, v2, v3));
2967   PetscCall(VecLockReadPush(v1));
2968   if (mat->ops->multhermitiantransposeadd) PetscUseTypeMethod(mat, multhermitiantransposeadd, v1, v2, v3);
2969   else {
2970     Vec w, z;
2971     PetscCall(VecDuplicate(v1, &w));
2972     PetscCall(VecCopy(v1, w));
2973     PetscCall(VecConjugate(w));
2974     PetscCall(VecDuplicate(v3, &z));
2975     PetscCall(MatMultTranspose(mat, w, z));
2976     PetscCall(VecDestroy(&w));
2977     PetscCall(VecConjugate(z));
2978     if (v2 != v3) {
2979       PetscCall(VecWAXPY(v3, 1.0, v2, z));
2980     } else {
2981       PetscCall(VecAXPY(v3, 1.0, z));
2982     }
2983     PetscCall(VecDestroy(&z));
2984   }
2985   PetscCall(VecLockReadPop(v1));
2986   PetscCall(PetscLogEventEnd(MAT_MultHermitianTransposeAdd, mat, v1, v2, v3));
2987   PetscCall(PetscObjectStateIncrease((PetscObject)v3));
2988   PetscFunctionReturn(PETSC_SUCCESS);
2989 }
2990 
2991 /*@
2992   MatGetFactorType - gets the type of factorization a matrix is
2993 
2994   Not Collective
2995 
2996   Input Parameter:
2997 . mat - the matrix
2998 
2999   Output Parameter:
3000 . t - the type, one of `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`, `MAT_FACTOR_ICC,MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3001 
3002   Level: intermediate
3003 
3004 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatGetFactor()`, `MatSetFactorType()`, `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`,
3005           `MAT_FACTOR_ICC`,`MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3006 @*/
3007 PetscErrorCode MatGetFactorType(Mat mat, MatFactorType *t)
3008 {
3009   PetscFunctionBegin;
3010   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3011   PetscValidType(mat, 1);
3012   PetscAssertPointer(t, 2);
3013   *t = mat->factortype;
3014   PetscFunctionReturn(PETSC_SUCCESS);
3015 }
3016 
3017 /*@
3018   MatSetFactorType - sets the type of factorization a matrix is
3019 
3020   Logically Collective
3021 
3022   Input Parameters:
3023 + mat - the matrix
3024 - t   - the type, one of `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`, `MAT_FACTOR_ICC,MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3025 
3026   Level: intermediate
3027 
3028 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatGetFactor()`, `MatGetFactorType()`, `MAT_FACTOR_NONE`, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ILU`,
3029           `MAT_FACTOR_ICC`,`MAT_FACTOR_ILUDT`, `MAT_FACTOR_QR`
3030 @*/
3031 PetscErrorCode MatSetFactorType(Mat mat, MatFactorType t)
3032 {
3033   PetscFunctionBegin;
3034   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3035   PetscValidType(mat, 1);
3036   mat->factortype = t;
3037   PetscFunctionReturn(PETSC_SUCCESS);
3038 }
3039 
3040 /*@
3041   MatGetInfo - Returns information about matrix storage (number of
3042   nonzeros, memory, etc.).
3043 
3044   Collective if `MAT_GLOBAL_MAX` or `MAT_GLOBAL_SUM` is used as the flag
3045 
3046   Input Parameters:
3047 + mat  - the matrix
3048 - flag - flag indicating the type of parameters to be returned (`MAT_LOCAL` - local matrix, `MAT_GLOBAL_MAX` - maximum over all processors, `MAT_GLOBAL_SUM` - sum over all processors)
3049 
3050   Output Parameter:
3051 . info - matrix information context
3052 
3053   Options Database Key:
3054 . -mat_view ::ascii_info - print matrix info to `PETSC_STDOUT`
3055 
3056   Level: intermediate
3057 
3058   Notes:
3059   The `MatInfo` context contains a variety of matrix data, including
3060   number of nonzeros allocated and used, number of mallocs during
3061   matrix assembly, etc.  Additional information for factored matrices
3062   is provided (such as the fill ratio, number of mallocs during
3063   factorization, etc.).
3064 
3065   Example:
3066   See the file ${PETSC_DIR}/include/petscmat.h for a complete list of
3067   data within the `MatInfo` context.  For example,
3068 .vb
3069       MatInfo info;
3070       Mat     A;
3071       double  mal, nz_a, nz_u;
3072 
3073       MatGetInfo(A, MAT_LOCAL, &info);
3074       mal  = info.mallocs;
3075       nz_a = info.nz_allocated;
3076 .ve
3077 
3078   Fortran Note:
3079   Declare info as a `MatInfo` array of dimension `MAT_INFO_SIZE`, and then extract the parameters
3080   of interest.  See the file ${PETSC_DIR}/include/petsc/finclude/petscmat.h
3081   a complete list of parameter names.
3082 .vb
3083       MatInfo info(MAT_INFO_SIZE)
3084       double  precision mal, nz_a
3085       Mat     A
3086       integer ierr
3087 
3088       call MatGetInfo(A, MAT_LOCAL, info, ierr)
3089       mal = info(MAT_INFO_MALLOCS)
3090       nz_a = info(MAT_INFO_NZ_ALLOCATED)
3091 .ve
3092 
3093 .seealso: [](ch_matrices), `Mat`, `MatInfo`, `MatStashGetInfo()`
3094 @*/
3095 PetscErrorCode MatGetInfo(Mat mat, MatInfoType flag, MatInfo *info)
3096 {
3097   PetscFunctionBegin;
3098   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3099   PetscValidType(mat, 1);
3100   PetscAssertPointer(info, 3);
3101   MatCheckPreallocated(mat, 1);
3102   PetscUseTypeMethod(mat, getinfo, flag, info);
3103   PetscFunctionReturn(PETSC_SUCCESS);
3104 }
3105 
3106 /*
3107    This is used by external packages where it is not easy to get the info from the actual
3108    matrix factorization.
3109 */
3110 PetscErrorCode MatGetInfo_External(Mat A, MatInfoType flag, MatInfo *info)
3111 {
3112   PetscFunctionBegin;
3113   PetscCall(PetscMemzero(info, sizeof(MatInfo)));
3114   PetscFunctionReturn(PETSC_SUCCESS);
3115 }
3116 
3117 /*@
3118   MatLUFactor - Performs in-place LU factorization of matrix.
3119 
3120   Collective
3121 
3122   Input Parameters:
3123 + mat  - the matrix
3124 . row  - row permutation
3125 . col  - column permutation
3126 - info - options for factorization, includes
3127 .vb
3128           fill - expected fill as ratio of original fill.
3129           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3130                    Run with the option -info to determine an optimal value to use
3131 .ve
3132 
3133   Level: developer
3134 
3135   Notes:
3136   Most users should employ the `KSP` interface for linear solvers
3137   instead of working directly with matrix algebra routines such as this.
3138   See, e.g., `KSPCreate()`.
3139 
3140   This changes the state of the matrix to a factored matrix; it cannot be used
3141   for example with `MatSetValues()` unless one first calls `MatSetUnfactored()`.
3142 
3143   This is really in-place only for dense matrices, the preferred approach is to use `MatGetFactor()`, `MatLUFactorSymbolic()`, and `MatLUFactorNumeric()`
3144   when not using `KSP`.
3145 
3146   Developer Note:
3147   The Fortran interface is not autogenerated as the
3148   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3149 
3150 .seealso: [](ch_matrices), [Matrix Factorization](sec_matfactor), `Mat`, `MatFactorType`, `MatLUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`,
3151           `MatGetOrdering()`, `MatSetUnfactored()`, `MatFactorInfo`, `MatGetFactor()`
3152 @*/
3153 PetscErrorCode MatLUFactor(Mat mat, IS row, IS col, const MatFactorInfo *info)
3154 {
3155   MatFactorInfo tinfo;
3156 
3157   PetscFunctionBegin;
3158   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3159   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
3160   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3161   if (info) PetscAssertPointer(info, 4);
3162   PetscValidType(mat, 1);
3163   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3164   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3165   MatCheckPreallocated(mat, 1);
3166   if (!info) {
3167     PetscCall(MatFactorInfoInitialize(&tinfo));
3168     info = &tinfo;
3169   }
3170 
3171   PetscCall(PetscLogEventBegin(MAT_LUFactor, mat, row, col, 0));
3172   PetscUseTypeMethod(mat, lufactor, row, col, info);
3173   PetscCall(PetscLogEventEnd(MAT_LUFactor, mat, row, col, 0));
3174   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3175   PetscFunctionReturn(PETSC_SUCCESS);
3176 }
3177 
3178 /*@
3179   MatILUFactor - Performs in-place ILU factorization of matrix.
3180 
3181   Collective
3182 
3183   Input Parameters:
3184 + mat  - the matrix
3185 . row  - row permutation
3186 . col  - column permutation
3187 - info - structure containing
3188 .vb
3189       levels - number of levels of fill.
3190       expected fill - as ratio of original fill.
3191       1 or 0 - indicating force fill on diagonal (improves robustness for matrices
3192                 missing diagonal entries)
3193 .ve
3194 
3195   Level: developer
3196 
3197   Notes:
3198   Most users should employ the `KSP` interface for linear solvers
3199   instead of working directly with matrix algebra routines such as this.
3200   See, e.g., `KSPCreate()`.
3201 
3202   Probably really in-place only when level of fill is zero, otherwise allocates
3203   new space to store factored matrix and deletes previous memory. The preferred approach is to use `MatGetFactor()`, `MatILUFactorSymbolic()`, and `MatILUFactorNumeric()`
3204   when not using `KSP`.
3205 
3206   Developer Note:
3207   The Fortran interface is not autogenerated as the
3208   interface definition cannot be generated correctly [due to MatFactorInfo]
3209 
3210 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatILUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`
3211 @*/
3212 PetscErrorCode MatILUFactor(Mat mat, IS row, IS col, const MatFactorInfo *info)
3213 {
3214   PetscFunctionBegin;
3215   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3216   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
3217   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3218   PetscAssertPointer(info, 4);
3219   PetscValidType(mat, 1);
3220   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
3221   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3222   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3223   MatCheckPreallocated(mat, 1);
3224 
3225   PetscCall(PetscLogEventBegin(MAT_ILUFactor, mat, row, col, 0));
3226   PetscUseTypeMethod(mat, ilufactor, row, col, info);
3227   PetscCall(PetscLogEventEnd(MAT_ILUFactor, mat, row, col, 0));
3228   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3229   PetscFunctionReturn(PETSC_SUCCESS);
3230 }
3231 
3232 /*@
3233   MatLUFactorSymbolic - Performs symbolic LU factorization of matrix.
3234   Call this routine before calling `MatLUFactorNumeric()` and after `MatGetFactor()`.
3235 
3236   Collective
3237 
3238   Input Parameters:
3239 + fact - the factor matrix obtained with `MatGetFactor()`
3240 . mat  - the matrix
3241 . row  - the row permutation
3242 . col  - the column permutation
3243 - info - options for factorization, includes
3244 .vb
3245           fill - expected fill as ratio of original fill. Run with the option -info to determine an optimal value to use
3246           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3247 .ve
3248 
3249   Level: developer
3250 
3251   Notes:
3252   See [Matrix Factorization](sec_matfactor) for additional information about factorizations
3253 
3254   Most users should employ the simplified `KSP` interface for linear solvers
3255   instead of working directly with matrix algebra routines such as this.
3256   See, e.g., `KSPCreate()`.
3257 
3258   Developer Note:
3259   The Fortran interface is not autogenerated as the
3260   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3261 
3262 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactor()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`, `MatFactorInfoInitialize()`
3263 @*/
3264 PetscErrorCode MatLUFactorSymbolic(Mat fact, Mat mat, IS row, IS col, const MatFactorInfo *info)
3265 {
3266   MatFactorInfo tinfo;
3267 
3268   PetscFunctionBegin;
3269   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3270   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3271   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 3);
3272   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 4);
3273   if (info) PetscAssertPointer(info, 5);
3274   PetscValidType(fact, 1);
3275   PetscValidType(mat, 2);
3276   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3277   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3278   MatCheckPreallocated(mat, 2);
3279   if (!info) {
3280     PetscCall(MatFactorInfoInitialize(&tinfo));
3281     info = &tinfo;
3282   }
3283 
3284   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_LUFactorSymbolic, mat, row, col, 0));
3285   PetscUseTypeMethod(fact, lufactorsymbolic, mat, row, col, info);
3286   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_LUFactorSymbolic, mat, row, col, 0));
3287   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3288   PetscFunctionReturn(PETSC_SUCCESS);
3289 }
3290 
3291 /*@
3292   MatLUFactorNumeric - Performs numeric LU factorization of a matrix.
3293   Call this routine after first calling `MatLUFactorSymbolic()` and `MatGetFactor()`.
3294 
3295   Collective
3296 
3297   Input Parameters:
3298 + fact - the factor matrix obtained with `MatGetFactor()`
3299 . mat  - the matrix
3300 - info - options for factorization
3301 
3302   Level: developer
3303 
3304   Notes:
3305   See `MatLUFactor()` for in-place factorization.  See
3306   `MatCholeskyFactorNumeric()` for the symmetric, positive definite case.
3307 
3308   Most users should employ the `KSP` interface for linear solvers
3309   instead of working directly with matrix algebra routines such as this.
3310   See, e.g., `KSPCreate()`.
3311 
3312   Developer Note:
3313   The Fortran interface is not autogenerated as the
3314   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3315 
3316 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatLUFactorSymbolic()`, `MatLUFactor()`, `MatCholeskyFactor()`
3317 @*/
3318 PetscErrorCode MatLUFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3319 {
3320   MatFactorInfo tinfo;
3321 
3322   PetscFunctionBegin;
3323   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3324   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3325   PetscValidType(fact, 1);
3326   PetscValidType(mat, 2);
3327   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3328   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,
3329              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3330 
3331   MatCheckPreallocated(mat, 2);
3332   if (!info) {
3333     PetscCall(MatFactorInfoInitialize(&tinfo));
3334     info = &tinfo;
3335   }
3336 
3337   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_LUFactorNumeric, mat, fact, 0, 0));
3338   else PetscCall(PetscLogEventBegin(MAT_LUFactor, mat, fact, 0, 0));
3339   PetscUseTypeMethod(fact, lufactornumeric, mat, info);
3340   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_LUFactorNumeric, mat, fact, 0, 0));
3341   else PetscCall(PetscLogEventEnd(MAT_LUFactor, mat, fact, 0, 0));
3342   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3343   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3344   PetscFunctionReturn(PETSC_SUCCESS);
3345 }
3346 
3347 /*@
3348   MatCholeskyFactor - Performs in-place Cholesky factorization of a
3349   symmetric matrix.
3350 
3351   Collective
3352 
3353   Input Parameters:
3354 + mat  - the matrix
3355 . perm - row and column permutations
3356 - info - expected fill as ratio of original fill
3357 
3358   Level: developer
3359 
3360   Notes:
3361   See `MatLUFactor()` for the nonsymmetric case.  See also `MatGetFactor()`,
3362   `MatCholeskyFactorSymbolic()`, and `MatCholeskyFactorNumeric()`.
3363 
3364   Most users should employ the `KSP` interface for linear solvers
3365   instead of working directly with matrix algebra routines such as this.
3366   See, e.g., `KSPCreate()`.
3367 
3368   Developer Note:
3369   The Fortran interface is not autogenerated as the
3370   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3371 
3372 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatLUFactor()`, `MatCholeskyFactorSymbolic()`, `MatCholeskyFactorNumeric()`
3373           `MatGetOrdering()`
3374 @*/
3375 PetscErrorCode MatCholeskyFactor(Mat mat, IS perm, const MatFactorInfo *info)
3376 {
3377   MatFactorInfo tinfo;
3378 
3379   PetscFunctionBegin;
3380   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3381   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 2);
3382   if (info) PetscAssertPointer(info, 3);
3383   PetscValidType(mat, 1);
3384   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Matrix must be square");
3385   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3386   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3387   MatCheckPreallocated(mat, 1);
3388   if (!info) {
3389     PetscCall(MatFactorInfoInitialize(&tinfo));
3390     info = &tinfo;
3391   }
3392 
3393   PetscCall(PetscLogEventBegin(MAT_CholeskyFactor, mat, perm, 0, 0));
3394   PetscUseTypeMethod(mat, choleskyfactor, perm, info);
3395   PetscCall(PetscLogEventEnd(MAT_CholeskyFactor, mat, perm, 0, 0));
3396   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3397   PetscFunctionReturn(PETSC_SUCCESS);
3398 }
3399 
3400 /*@
3401   MatCholeskyFactorSymbolic - Performs symbolic Cholesky factorization
3402   of a symmetric matrix.
3403 
3404   Collective
3405 
3406   Input Parameters:
3407 + fact - the factor matrix obtained with `MatGetFactor()`
3408 . mat  - the matrix
3409 . perm - row and column permutations
3410 - info - options for factorization, includes
3411 .vb
3412           fill - expected fill as ratio of original fill.
3413           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3414                    Run with the option -info to determine an optimal value to use
3415 .ve
3416 
3417   Level: developer
3418 
3419   Notes:
3420   See `MatLUFactorSymbolic()` for the nonsymmetric case.  See also
3421   `MatCholeskyFactor()` and `MatCholeskyFactorNumeric()`.
3422 
3423   Most users should employ the `KSP` interface for linear solvers
3424   instead of working directly with matrix algebra routines such as this.
3425   See, e.g., `KSPCreate()`.
3426 
3427   Developer Note:
3428   The Fortran interface is not autogenerated as the
3429   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3430 
3431 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactor()`, `MatCholeskyFactorNumeric()`
3432           `MatGetOrdering()`
3433 @*/
3434 PetscErrorCode MatCholeskyFactorSymbolic(Mat fact, Mat mat, IS perm, const MatFactorInfo *info)
3435 {
3436   MatFactorInfo tinfo;
3437 
3438   PetscFunctionBegin;
3439   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3440   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3441   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 3);
3442   if (info) PetscAssertPointer(info, 4);
3443   PetscValidType(fact, 1);
3444   PetscValidType(mat, 2);
3445   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Matrix must be square");
3446   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3447   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3448   MatCheckPreallocated(mat, 2);
3449   if (!info) {
3450     PetscCall(MatFactorInfoInitialize(&tinfo));
3451     info = &tinfo;
3452   }
3453 
3454   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_CholeskyFactorSymbolic, mat, perm, 0, 0));
3455   PetscUseTypeMethod(fact, choleskyfactorsymbolic, mat, perm, info);
3456   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_CholeskyFactorSymbolic, mat, perm, 0, 0));
3457   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3458   PetscFunctionReturn(PETSC_SUCCESS);
3459 }
3460 
3461 /*@
3462   MatCholeskyFactorNumeric - Performs numeric Cholesky factorization
3463   of a symmetric matrix. Call this routine after first calling `MatGetFactor()` and
3464   `MatCholeskyFactorSymbolic()`.
3465 
3466   Collective
3467 
3468   Input Parameters:
3469 + fact - the factor matrix obtained with `MatGetFactor()`, where the factored values are stored
3470 . mat  - the initial matrix that is to be factored
3471 - info - options for factorization
3472 
3473   Level: developer
3474 
3475   Note:
3476   Most users should employ the `KSP` interface for linear solvers
3477   instead of working directly with matrix algebra routines such as this.
3478   See, e.g., `KSPCreate()`.
3479 
3480   Developer Note:
3481   The Fortran interface is not autogenerated as the
3482   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3483 
3484 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatCholeskyFactorSymbolic()`, `MatCholeskyFactor()`, `MatLUFactorNumeric()`
3485 @*/
3486 PetscErrorCode MatCholeskyFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3487 {
3488   MatFactorInfo tinfo;
3489 
3490   PetscFunctionBegin;
3491   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3492   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3493   PetscValidType(fact, 1);
3494   PetscValidType(mat, 2);
3495   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3496   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,
3497              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3498   MatCheckPreallocated(mat, 2);
3499   if (!info) {
3500     PetscCall(MatFactorInfoInitialize(&tinfo));
3501     info = &tinfo;
3502   }
3503 
3504   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_CholeskyFactorNumeric, mat, fact, 0, 0));
3505   else PetscCall(PetscLogEventBegin(MAT_CholeskyFactor, mat, fact, 0, 0));
3506   PetscUseTypeMethod(fact, choleskyfactornumeric, mat, info);
3507   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_CholeskyFactorNumeric, mat, fact, 0, 0));
3508   else PetscCall(PetscLogEventEnd(MAT_CholeskyFactor, mat, fact, 0, 0));
3509   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3510   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3511   PetscFunctionReturn(PETSC_SUCCESS);
3512 }
3513 
3514 /*@
3515   MatQRFactor - Performs in-place QR factorization of matrix.
3516 
3517   Collective
3518 
3519   Input Parameters:
3520 + mat  - the matrix
3521 . col  - column permutation
3522 - info - options for factorization, includes
3523 .vb
3524           fill - expected fill as ratio of original fill.
3525           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3526                    Run with the option -info to determine an optimal value to use
3527 .ve
3528 
3529   Level: developer
3530 
3531   Notes:
3532   Most users should employ the `KSP` interface for linear solvers
3533   instead of working directly with matrix algebra routines such as this.
3534   See, e.g., `KSPCreate()`.
3535 
3536   This changes the state of the matrix to a factored matrix; it cannot be used
3537   for example with `MatSetValues()` unless one first calls `MatSetUnfactored()`.
3538 
3539   Developer Note:
3540   The Fortran interface is not autogenerated as the
3541   interface definition cannot be generated correctly [due to MatFactorInfo]
3542 
3543 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatQRFactorSymbolic()`, `MatQRFactorNumeric()`, `MatLUFactor()`,
3544           `MatSetUnfactored()`
3545 @*/
3546 PetscErrorCode MatQRFactor(Mat mat, IS col, const MatFactorInfo *info)
3547 {
3548   PetscFunctionBegin;
3549   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3550   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 2);
3551   if (info) PetscAssertPointer(info, 3);
3552   PetscValidType(mat, 1);
3553   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3554   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3555   MatCheckPreallocated(mat, 1);
3556   PetscCall(PetscLogEventBegin(MAT_QRFactor, mat, col, 0, 0));
3557   PetscUseMethod(mat, "MatQRFactor_C", (Mat, IS, const MatFactorInfo *), (mat, col, info));
3558   PetscCall(PetscLogEventEnd(MAT_QRFactor, mat, col, 0, 0));
3559   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
3560   PetscFunctionReturn(PETSC_SUCCESS);
3561 }
3562 
3563 /*@
3564   MatQRFactorSymbolic - Performs symbolic QR factorization of matrix.
3565   Call this routine after `MatGetFactor()` but before calling `MatQRFactorNumeric()`.
3566 
3567   Collective
3568 
3569   Input Parameters:
3570 + fact - the factor matrix obtained with `MatGetFactor()`
3571 . mat  - the matrix
3572 . col  - column permutation
3573 - info - options for factorization, includes
3574 .vb
3575           fill - expected fill as ratio of original fill.
3576           dtcol - pivot tolerance (0 no pivot, 1 full column pivoting)
3577                    Run with the option -info to determine an optimal value to use
3578 .ve
3579 
3580   Level: developer
3581 
3582   Note:
3583   Most users should employ the `KSP` interface for linear solvers
3584   instead of working directly with matrix algebra routines such as this.
3585   See, e.g., `KSPCreate()`.
3586 
3587   Developer Note:
3588   The Fortran interface is not autogenerated as the
3589   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3590 
3591 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatFactorInfo`, `MatQRFactor()`, `MatQRFactorNumeric()`, `MatLUFactor()`, `MatFactorInfoInitialize()`
3592 @*/
3593 PetscErrorCode MatQRFactorSymbolic(Mat fact, Mat mat, IS col, const MatFactorInfo *info)
3594 {
3595   MatFactorInfo tinfo;
3596 
3597   PetscFunctionBegin;
3598   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3599   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3600   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 3);
3601   if (info) PetscAssertPointer(info, 4);
3602   PetscValidType(fact, 1);
3603   PetscValidType(mat, 2);
3604   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3605   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
3606   MatCheckPreallocated(mat, 2);
3607   if (!info) {
3608     PetscCall(MatFactorInfoInitialize(&tinfo));
3609     info = &tinfo;
3610   }
3611 
3612   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_QRFactorSymbolic, fact, mat, col, 0));
3613   PetscUseMethod(fact, "MatQRFactorSymbolic_C", (Mat, Mat, IS, const MatFactorInfo *), (fact, mat, col, info));
3614   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_QRFactorSymbolic, fact, mat, col, 0));
3615   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3616   PetscFunctionReturn(PETSC_SUCCESS);
3617 }
3618 
3619 /*@
3620   MatQRFactorNumeric - Performs numeric QR factorization of a matrix.
3621   Call this routine after first calling `MatGetFactor()`, and `MatQRFactorSymbolic()`.
3622 
3623   Collective
3624 
3625   Input Parameters:
3626 + fact - the factor matrix obtained with `MatGetFactor()`
3627 . mat  - the matrix
3628 - info - options for factorization
3629 
3630   Level: developer
3631 
3632   Notes:
3633   See `MatQRFactor()` for in-place factorization.
3634 
3635   Most users should employ the `KSP` interface for linear solvers
3636   instead of working directly with matrix algebra routines such as this.
3637   See, e.g., `KSPCreate()`.
3638 
3639   Developer Note:
3640   The Fortran interface is not autogenerated as the
3641   interface definition cannot be generated correctly [due to `MatFactorInfo`]
3642 
3643 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorInfo`, `MatGetFactor()`, `MatQRFactor()`, `MatQRFactorSymbolic()`, `MatLUFactor()`
3644 @*/
3645 PetscErrorCode MatQRFactorNumeric(Mat fact, Mat mat, const MatFactorInfo *info)
3646 {
3647   MatFactorInfo tinfo;
3648 
3649   PetscFunctionBegin;
3650   PetscValidHeaderSpecific(fact, MAT_CLASSID, 1);
3651   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
3652   PetscValidType(fact, 1);
3653   PetscValidType(mat, 2);
3654   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
3655   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,
3656              mat->rmap->N, (fact)->rmap->N, mat->cmap->N, (fact)->cmap->N);
3657 
3658   MatCheckPreallocated(mat, 2);
3659   if (!info) {
3660     PetscCall(MatFactorInfoInitialize(&tinfo));
3661     info = &tinfo;
3662   }
3663 
3664   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_QRFactorNumeric, mat, fact, 0, 0));
3665   else PetscCall(PetscLogEventBegin(MAT_QRFactor, mat, fact, 0, 0));
3666   PetscUseMethod(fact, "MatQRFactorNumeric_C", (Mat, Mat, const MatFactorInfo *), (fact, mat, info));
3667   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_QRFactorNumeric, mat, fact, 0, 0));
3668   else PetscCall(PetscLogEventEnd(MAT_QRFactor, mat, fact, 0, 0));
3669   PetscCall(MatViewFromOptions(fact, NULL, "-mat_factor_view"));
3670   PetscCall(PetscObjectStateIncrease((PetscObject)fact));
3671   PetscFunctionReturn(PETSC_SUCCESS);
3672 }
3673 
3674 /*@
3675   MatSolve - Solves $A x = b$, given a factored matrix.
3676 
3677   Neighbor-wise Collective
3678 
3679   Input Parameters:
3680 + mat - the factored matrix
3681 - b   - the right-hand-side vector
3682 
3683   Output Parameter:
3684 . x - the result vector
3685 
3686   Level: developer
3687 
3688   Notes:
3689   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3690   call `MatSolve`(A,x,x).
3691 
3692   Most users should employ the `KSP` interface for linear solvers
3693   instead of working directly with matrix algebra routines such as this.
3694   See, e.g., `KSPCreate()`.
3695 
3696 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactor()`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`
3697 @*/
3698 PetscErrorCode MatSolve(Mat mat, Vec b, Vec x)
3699 {
3700   PetscFunctionBegin;
3701   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3702   PetscValidType(mat, 1);
3703   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3704   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3705   PetscCheckSameComm(mat, 1, b, 2);
3706   PetscCheckSameComm(mat, 1, x, 3);
3707   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3708   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);
3709   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);
3710   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);
3711   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3712   MatCheckPreallocated(mat, 1);
3713 
3714   PetscCall(PetscLogEventBegin(MAT_Solve, mat, b, x, 0));
3715   PetscCall(VecFlag(x, mat->factorerrortype));
3716   if (mat->factorerrortype) {
3717     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
3718   } else PetscUseTypeMethod(mat, solve, b, x);
3719   PetscCall(PetscLogEventEnd(MAT_Solve, mat, b, x, 0));
3720   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3721   PetscFunctionReturn(PETSC_SUCCESS);
3722 }
3723 
3724 static PetscErrorCode MatMatSolve_Basic(Mat A, Mat B, Mat X, PetscBool trans)
3725 {
3726   Vec      b, x;
3727   PetscInt N, i;
3728   PetscErrorCode (*f)(Mat, Vec, Vec);
3729   PetscBool Abound, Bneedconv = PETSC_FALSE, Xneedconv = PETSC_FALSE;
3730 
3731   PetscFunctionBegin;
3732   if (A->factorerrortype) {
3733     PetscCall(PetscInfo(A, "MatFactorError %d\n", A->factorerrortype));
3734     PetscCall(MatSetInf(X));
3735     PetscFunctionReturn(PETSC_SUCCESS);
3736   }
3737   f = (!trans || (!A->ops->solvetranspose && A->symmetric)) ? A->ops->solve : A->ops->solvetranspose;
3738   PetscCheck(f, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Mat type %s", ((PetscObject)A)->type_name);
3739   PetscCall(MatBoundToCPU(A, &Abound));
3740   if (!Abound) {
3741     PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &Bneedconv, MATSEQDENSE, MATMPIDENSE, ""));
3742     PetscCall(PetscObjectTypeCompareAny((PetscObject)X, &Xneedconv, MATSEQDENSE, MATMPIDENSE, ""));
3743   }
3744 #if PetscDefined(HAVE_CUDA)
3745   if (Bneedconv) PetscCall(MatConvert(B, MATDENSECUDA, MAT_INPLACE_MATRIX, &B));
3746   if (Xneedconv) PetscCall(MatConvert(X, MATDENSECUDA, MAT_INPLACE_MATRIX, &X));
3747 #elif PetscDefined(HAVE_HIP)
3748   if (Bneedconv) PetscCall(MatConvert(B, MATDENSEHIP, MAT_INPLACE_MATRIX, &B));
3749   if (Xneedconv) PetscCall(MatConvert(X, MATDENSEHIP, MAT_INPLACE_MATRIX, &X));
3750 #endif
3751   PetscCall(MatGetSize(B, NULL, &N));
3752   for (i = 0; i < N; i++) {
3753     PetscCall(MatDenseGetColumnVecRead(B, i, &b));
3754     PetscCall(MatDenseGetColumnVecWrite(X, i, &x));
3755     PetscCall((*f)(A, b, x));
3756     PetscCall(MatDenseRestoreColumnVecWrite(X, i, &x));
3757     PetscCall(MatDenseRestoreColumnVecRead(B, i, &b));
3758   }
3759   if (Bneedconv) PetscCall(MatConvert(B, MATDENSE, MAT_INPLACE_MATRIX, &B));
3760   if (Xneedconv) PetscCall(MatConvert(X, MATDENSE, MAT_INPLACE_MATRIX, &X));
3761   PetscFunctionReturn(PETSC_SUCCESS);
3762 }
3763 
3764 /*@
3765   MatMatSolve - Solves $A X = B$, given a factored matrix.
3766 
3767   Neighbor-wise Collective
3768 
3769   Input Parameters:
3770 + A - the factored matrix
3771 - B - the right-hand-side matrix `MATDENSE` (or sparse `MATAIJ`-- when using MUMPS)
3772 
3773   Output Parameter:
3774 . X - the result matrix (dense matrix)
3775 
3776   Level: developer
3777 
3778   Note:
3779   If `B` is a `MATDENSE` matrix then one can call `MatMatSolve`(A,B,B) except with `MATSOLVERMKL_CPARDISO`;
3780   otherwise, `B` and `X` cannot be the same.
3781 
3782 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolve()`, `MatMatSolveTranspose()`, `MatLUFactor()`, `MatCholeskyFactor()`
3783 @*/
3784 PetscErrorCode MatMatSolve(Mat A, Mat B, Mat X)
3785 {
3786   PetscFunctionBegin;
3787   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3788   PetscValidType(A, 1);
3789   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
3790   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3791   PetscCheckSameComm(A, 1, B, 2);
3792   PetscCheckSameComm(A, 1, X, 3);
3793   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);
3794   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);
3795   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");
3796   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3797   MatCheckPreallocated(A, 1);
3798 
3799   PetscCall(PetscLogEventBegin(MAT_MatSolve, A, B, X, 0));
3800   if (!A->ops->matsolve) {
3801     PetscCall(PetscInfo(A, "Mat type %s using basic MatMatSolve\n", ((PetscObject)A)->type_name));
3802     PetscCall(MatMatSolve_Basic(A, B, X, PETSC_FALSE));
3803   } else PetscUseTypeMethod(A, matsolve, B, X);
3804   PetscCall(PetscLogEventEnd(MAT_MatSolve, A, B, X, 0));
3805   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3806   PetscFunctionReturn(PETSC_SUCCESS);
3807 }
3808 
3809 /*@
3810   MatMatSolveTranspose - Solves $A^T X = B $, given a factored matrix.
3811 
3812   Neighbor-wise Collective
3813 
3814   Input Parameters:
3815 + A - the factored matrix
3816 - B - the right-hand-side matrix  (`MATDENSE` matrix)
3817 
3818   Output Parameter:
3819 . X - the result matrix (dense matrix)
3820 
3821   Level: developer
3822 
3823   Note:
3824   The matrices `B` and `X` cannot be the same.  I.e., one cannot
3825   call `MatMatSolveTranspose`(A,X,X).
3826 
3827 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolveTranspose()`, `MatMatSolve()`, `MatLUFactor()`, `MatCholeskyFactor()`
3828 @*/
3829 PetscErrorCode MatMatSolveTranspose(Mat A, Mat B, Mat X)
3830 {
3831   PetscFunctionBegin;
3832   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3833   PetscValidType(A, 1);
3834   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
3835   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3836   PetscCheckSameComm(A, 1, B, 2);
3837   PetscCheckSameComm(A, 1, X, 3);
3838   PetscCheck(X != B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_IDN, "X and B must be different matrices");
3839   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);
3840   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);
3841   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);
3842   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");
3843   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3844   MatCheckPreallocated(A, 1);
3845 
3846   PetscCall(PetscLogEventBegin(MAT_MatSolve, A, B, X, 0));
3847   if (!A->ops->matsolvetranspose) {
3848     PetscCall(PetscInfo(A, "Mat type %s using basic MatMatSolveTranspose\n", ((PetscObject)A)->type_name));
3849     PetscCall(MatMatSolve_Basic(A, B, X, PETSC_TRUE));
3850   } else PetscUseTypeMethod(A, matsolvetranspose, B, X);
3851   PetscCall(PetscLogEventEnd(MAT_MatSolve, A, B, X, 0));
3852   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3853   PetscFunctionReturn(PETSC_SUCCESS);
3854 }
3855 
3856 /*@
3857   MatMatTransposeSolve - Solves $A X = B^T$, given a factored matrix.
3858 
3859   Neighbor-wise Collective
3860 
3861   Input Parameters:
3862 + A  - the factored matrix
3863 - Bt - the transpose of right-hand-side matrix as a `MATDENSE`
3864 
3865   Output Parameter:
3866 . X - the result matrix (dense matrix)
3867 
3868   Level: developer
3869 
3870   Note:
3871   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
3872   format on the host processor and call `MatMatTransposeSolve()` to implement MUMPS' `MatMatSolve()`.
3873 
3874 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatMatSolve()`, `MatMatSolveTranspose()`, `MatLUFactor()`, `MatCholeskyFactor()`
3875 @*/
3876 PetscErrorCode MatMatTransposeSolve(Mat A, Mat Bt, Mat X)
3877 {
3878   PetscFunctionBegin;
3879   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
3880   PetscValidType(A, 1);
3881   PetscValidHeaderSpecific(Bt, MAT_CLASSID, 2);
3882   PetscValidHeaderSpecific(X, MAT_CLASSID, 3);
3883   PetscCheckSameComm(A, 1, Bt, 2);
3884   PetscCheckSameComm(A, 1, X, 3);
3885 
3886   PetscCheck(X != Bt, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_IDN, "X and B must be different matrices");
3887   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);
3888   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);
3889   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");
3890   if (!A->rmap->N && !A->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3891   PetscCheck(A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
3892   MatCheckPreallocated(A, 1);
3893 
3894   PetscCall(PetscLogEventBegin(MAT_MatTrSolve, A, Bt, X, 0));
3895   PetscUseTypeMethod(A, mattransposesolve, Bt, X);
3896   PetscCall(PetscLogEventEnd(MAT_MatTrSolve, A, Bt, X, 0));
3897   PetscCall(PetscObjectStateIncrease((PetscObject)X));
3898   PetscFunctionReturn(PETSC_SUCCESS);
3899 }
3900 
3901 /*@
3902   MatForwardSolve - Solves $ L x = b $, given a factored matrix, $A = LU $, or
3903   $U^T*D^(1/2) x = b$, given a factored symmetric matrix, $A = U^T*D*U$,
3904 
3905   Neighbor-wise Collective
3906 
3907   Input Parameters:
3908 + mat - the factored matrix
3909 - b   - the right-hand-side vector
3910 
3911   Output Parameter:
3912 . x - the result vector
3913 
3914   Level: developer
3915 
3916   Notes:
3917   `MatSolve()` should be used for most applications, as it performs
3918   a forward solve followed by a backward solve.
3919 
3920   The vectors `b` and `x` cannot be the same,  i.e., one cannot
3921   call `MatForwardSolve`(A,x,x).
3922 
3923   For matrix in `MATSEQBAIJ` format with block size larger than 1,
3924   the diagonal blocks are not implemented as $D = D^(1/2) * D^(1/2)$ yet.
3925   `MatForwardSolve()` solves $U^T*D y = b$, and
3926   `MatBackwardSolve()` solves $U x = y$.
3927   Thus they do not provide a symmetric preconditioner.
3928 
3929 .seealso: [](ch_matrices), `Mat`, `MatBackwardSolve()`, `MatGetFactor()`, `MatSolve()`
3930 @*/
3931 PetscErrorCode MatForwardSolve(Mat mat, Vec b, Vec x)
3932 {
3933   PetscFunctionBegin;
3934   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3935   PetscValidType(mat, 1);
3936   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3937   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3938   PetscCheckSameComm(mat, 1, b, 2);
3939   PetscCheckSameComm(mat, 1, x, 3);
3940   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3941   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);
3942   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);
3943   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);
3944   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3945   MatCheckPreallocated(mat, 1);
3946 
3947   PetscCall(PetscLogEventBegin(MAT_ForwardSolve, mat, b, x, 0));
3948   PetscUseTypeMethod(mat, forwardsolve, b, x);
3949   PetscCall(PetscLogEventEnd(MAT_ForwardSolve, mat, b, x, 0));
3950   PetscCall(PetscObjectStateIncrease((PetscObject)x));
3951   PetscFunctionReturn(PETSC_SUCCESS);
3952 }
3953 
3954 /*@
3955   MatBackwardSolve - Solves $U x = b$, given a factored matrix, $A = LU$.
3956   $D^(1/2) U x = b$, given a factored symmetric matrix, $A = U^T*D*U$,
3957 
3958   Neighbor-wise Collective
3959 
3960   Input Parameters:
3961 + mat - the factored matrix
3962 - b   - the right-hand-side vector
3963 
3964   Output Parameter:
3965 . x - the result vector
3966 
3967   Level: developer
3968 
3969   Notes:
3970   `MatSolve()` should be used for most applications, as it performs
3971   a forward solve followed by a backward solve.
3972 
3973   The vectors `b` and `x` cannot be the same.  I.e., one cannot
3974   call `MatBackwardSolve`(A,x,x).
3975 
3976   For matrix in `MATSEQBAIJ` format with block size larger than 1,
3977   the diagonal blocks are not implemented as $D = D^(1/2) * D^(1/2)$ yet.
3978   `MatForwardSolve()` solves $U^T*D y = b$, and
3979   `MatBackwardSolve()` solves $U x = y$.
3980   Thus they do not provide a symmetric preconditioner.
3981 
3982 .seealso: [](ch_matrices), `Mat`, `MatForwardSolve()`, `MatGetFactor()`, `MatSolve()`
3983 @*/
3984 PetscErrorCode MatBackwardSolve(Mat mat, Vec b, Vec x)
3985 {
3986   PetscFunctionBegin;
3987   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
3988   PetscValidType(mat, 1);
3989   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
3990   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
3991   PetscCheckSameComm(mat, 1, b, 2);
3992   PetscCheckSameComm(mat, 1, x, 3);
3993   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
3994   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);
3995   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);
3996   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);
3997   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
3998   MatCheckPreallocated(mat, 1);
3999 
4000   PetscCall(PetscLogEventBegin(MAT_BackwardSolve, mat, b, x, 0));
4001   PetscUseTypeMethod(mat, backwardsolve, b, x);
4002   PetscCall(PetscLogEventEnd(MAT_BackwardSolve, mat, b, x, 0));
4003   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4004   PetscFunctionReturn(PETSC_SUCCESS);
4005 }
4006 
4007 /*@
4008   MatSolveAdd - Computes $x = y + A^{-1}*b$, given a factored matrix.
4009 
4010   Neighbor-wise Collective
4011 
4012   Input Parameters:
4013 + mat - the factored matrix
4014 . b   - the right-hand-side vector
4015 - y   - the vector to be added to
4016 
4017   Output Parameter:
4018 . x - the result vector
4019 
4020   Level: developer
4021 
4022   Note:
4023   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4024   call `MatSolveAdd`(A,x,y,x).
4025 
4026 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatSolve()`, `MatGetFactor()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`
4027 @*/
4028 PetscErrorCode MatSolveAdd(Mat mat, Vec b, Vec y, Vec x)
4029 {
4030   PetscScalar one = 1.0;
4031   Vec         tmp;
4032 
4033   PetscFunctionBegin;
4034   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4035   PetscValidType(mat, 1);
4036   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
4037   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4038   PetscValidHeaderSpecific(x, VEC_CLASSID, 4);
4039   PetscCheckSameComm(mat, 1, b, 2);
4040   PetscCheckSameComm(mat, 1, y, 3);
4041   PetscCheckSameComm(mat, 1, x, 4);
4042   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4043   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);
4044   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);
4045   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);
4046   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);
4047   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);
4048   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4049   MatCheckPreallocated(mat, 1);
4050 
4051   PetscCall(PetscLogEventBegin(MAT_SolveAdd, mat, b, x, y));
4052   PetscCall(VecFlag(x, mat->factorerrortype));
4053   if (mat->factorerrortype) {
4054     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4055   } else if (mat->ops->solveadd) {
4056     PetscUseTypeMethod(mat, solveadd, b, y, x);
4057   } else {
4058     /* do the solve then the add manually */
4059     if (x != y) {
4060       PetscCall(MatSolve(mat, b, x));
4061       PetscCall(VecAXPY(x, one, y));
4062     } else {
4063       PetscCall(VecDuplicate(x, &tmp));
4064       PetscCall(VecCopy(x, tmp));
4065       PetscCall(MatSolve(mat, b, x));
4066       PetscCall(VecAXPY(x, one, tmp));
4067       PetscCall(VecDestroy(&tmp));
4068     }
4069   }
4070   PetscCall(PetscLogEventEnd(MAT_SolveAdd, mat, b, x, y));
4071   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4072   PetscFunctionReturn(PETSC_SUCCESS);
4073 }
4074 
4075 /*@
4076   MatSolveTranspose - Solves $A^T x = b$, given a factored matrix.
4077 
4078   Neighbor-wise Collective
4079 
4080   Input Parameters:
4081 + mat - the factored matrix
4082 - b   - the right-hand-side vector
4083 
4084   Output Parameter:
4085 . x - the result vector
4086 
4087   Level: developer
4088 
4089   Notes:
4090   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4091   call `MatSolveTranspose`(A,x,x).
4092 
4093   Most users should employ the `KSP` interface for linear solvers
4094   instead of working directly with matrix algebra routines such as this.
4095   See, e.g., `KSPCreate()`.
4096 
4097 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `KSP`, `MatSolve()`, `MatSolveAdd()`, `MatSolveTransposeAdd()`
4098 @*/
4099 PetscErrorCode MatSolveTranspose(Mat mat, Vec b, Vec x)
4100 {
4101   PetscErrorCode (*f)(Mat, Vec, Vec) = (!mat->ops->solvetranspose && mat->symmetric) ? mat->ops->solve : mat->ops->solvetranspose;
4102 
4103   PetscFunctionBegin;
4104   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4105   PetscValidType(mat, 1);
4106   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4107   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
4108   PetscCheckSameComm(mat, 1, b, 2);
4109   PetscCheckSameComm(mat, 1, x, 3);
4110   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4111   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);
4112   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);
4113   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4114   MatCheckPreallocated(mat, 1);
4115   PetscCall(PetscLogEventBegin(MAT_SolveTranspose, mat, b, x, 0));
4116   PetscCall(VecFlag(x, mat->factorerrortype));
4117   if (mat->factorerrortype) {
4118     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4119   } else {
4120     PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Matrix type %s", ((PetscObject)mat)->type_name);
4121     PetscCall((*f)(mat, b, x));
4122   }
4123   PetscCall(PetscLogEventEnd(MAT_SolveTranspose, mat, b, x, 0));
4124   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4125   PetscFunctionReturn(PETSC_SUCCESS);
4126 }
4127 
4128 /*@
4129   MatSolveTransposeAdd - Computes $x = y + A^{-T} b$
4130   factored matrix.
4131 
4132   Neighbor-wise Collective
4133 
4134   Input Parameters:
4135 + mat - the factored matrix
4136 . b   - the right-hand-side vector
4137 - y   - the vector to be added to
4138 
4139   Output Parameter:
4140 . x - the result vector
4141 
4142   Level: developer
4143 
4144   Note:
4145   The vectors `b` and `x` cannot be the same.  I.e., one cannot
4146   call `MatSolveTransposeAdd`(A,x,y,x).
4147 
4148 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatSolve()`, `MatSolveAdd()`, `MatSolveTranspose()`
4149 @*/
4150 PetscErrorCode MatSolveTransposeAdd(Mat mat, Vec b, Vec y, Vec x)
4151 {
4152   PetscScalar one = 1.0;
4153   Vec         tmp;
4154   PetscErrorCode (*f)(Mat, Vec, Vec, Vec) = (!mat->ops->solvetransposeadd && mat->symmetric) ? mat->ops->solveadd : mat->ops->solvetransposeadd;
4155 
4156   PetscFunctionBegin;
4157   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4158   PetscValidType(mat, 1);
4159   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
4160   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4161   PetscValidHeaderSpecific(x, VEC_CLASSID, 4);
4162   PetscCheckSameComm(mat, 1, b, 2);
4163   PetscCheckSameComm(mat, 1, y, 3);
4164   PetscCheckSameComm(mat, 1, x, 4);
4165   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
4166   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);
4167   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);
4168   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);
4169   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);
4170   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
4171   MatCheckPreallocated(mat, 1);
4172 
4173   PetscCall(PetscLogEventBegin(MAT_SolveTransposeAdd, mat, b, x, y));
4174   PetscCall(VecFlag(x, mat->factorerrortype));
4175   if (mat->factorerrortype) {
4176     PetscCall(PetscInfo(mat, "MatFactorError %d\n", mat->factorerrortype));
4177   } else if (f) {
4178     PetscCall((*f)(mat, b, y, x));
4179   } else {
4180     /* do the solve then the add manually */
4181     if (x != y) {
4182       PetscCall(MatSolveTranspose(mat, b, x));
4183       PetscCall(VecAXPY(x, one, y));
4184     } else {
4185       PetscCall(VecDuplicate(x, &tmp));
4186       PetscCall(VecCopy(x, tmp));
4187       PetscCall(MatSolveTranspose(mat, b, x));
4188       PetscCall(VecAXPY(x, one, tmp));
4189       PetscCall(VecDestroy(&tmp));
4190     }
4191   }
4192   PetscCall(PetscLogEventEnd(MAT_SolveTransposeAdd, mat, b, x, y));
4193   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4194   PetscFunctionReturn(PETSC_SUCCESS);
4195 }
4196 
4197 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
4198 /*@
4199   MatSOR - Computes relaxation (SOR, Gauss-Seidel) sweeps.
4200 
4201   Neighbor-wise Collective
4202 
4203   Input Parameters:
4204 + mat   - the matrix
4205 . b     - the right-hand side
4206 . omega - the relaxation factor
4207 . flag  - flag indicating the type of SOR (see below)
4208 . shift - diagonal shift
4209 . its   - the number of iterations
4210 - lits  - the number of local iterations
4211 
4212   Output Parameter:
4213 . x - the solution (can contain an initial guess, use option `SOR_ZERO_INITIAL_GUESS` to indicate no guess)
4214 
4215   SOR Flags:
4216 +     `SOR_FORWARD_SWEEP` - forward SOR
4217 .     `SOR_BACKWARD_SWEEP` - backward SOR
4218 .     `SOR_SYMMETRIC_SWEEP` - SSOR (symmetric SOR)
4219 .     `SOR_LOCAL_FORWARD_SWEEP` - local forward SOR
4220 .     `SOR_LOCAL_BACKWARD_SWEEP` - local forward SOR
4221 .     `SOR_LOCAL_SYMMETRIC_SWEEP` - local SSOR
4222 .     `SOR_EISENSTAT` - SOR with Eisenstat trick
4223 .     `SOR_APPLY_UPPER`, `SOR_APPLY_LOWER` - applies
4224   upper/lower triangular part of matrix to
4225   vector (with omega)
4226 -     `SOR_ZERO_INITIAL_GUESS` - zero initial guess
4227 
4228   Level: developer
4229 
4230   Notes:
4231   `SOR_LOCAL_FORWARD_SWEEP`, `SOR_LOCAL_BACKWARD_SWEEP`, and
4232   `SOR_LOCAL_SYMMETRIC_SWEEP` perform separate independent smoothings
4233   on each processor.
4234 
4235   Application programmers will not generally use `MatSOR()` directly,
4236   but instead will employ the `KSP`/`PC` interface.
4237 
4238   For `MATBAIJ`, `MATSBAIJ`, and `MATAIJ` matrices with Inodes this does a block SOR smoothing, otherwise it does a pointwise smoothing
4239 
4240   Most users should employ the `KSP` interface for linear solvers
4241   instead of working directly with matrix algebra routines such as this.
4242   See, e.g., `KSPCreate()`.
4243 
4244   Vectors `x` and `b` CANNOT be the same
4245 
4246   The flags are implemented as bitwise inclusive or operations.
4247   For example, use (`SOR_ZERO_INITIAL_GUESS` | `SOR_SYMMETRIC_SWEEP`)
4248   to specify a zero initial guess for SSOR.
4249 
4250   Developer Note:
4251   We should add block SOR support for `MATAIJ` matrices with block size set to great than one and no inodes
4252 
4253 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `KSP`, `PC`, `MatGetFactor()`
4254 @*/
4255 PetscErrorCode MatSOR(Mat mat, Vec b, PetscReal omega, MatSORType flag, PetscReal shift, PetscInt its, PetscInt lits, Vec x)
4256 {
4257   PetscFunctionBegin;
4258   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4259   PetscValidType(mat, 1);
4260   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
4261   PetscValidHeaderSpecific(x, VEC_CLASSID, 8);
4262   PetscCheckSameComm(mat, 1, b, 2);
4263   PetscCheckSameComm(mat, 1, x, 8);
4264   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4265   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4266   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);
4267   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);
4268   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);
4269   PetscCheck(its > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires global its %" PetscInt_FMT " positive", its);
4270   PetscCheck(lits > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Relaxation requires local its %" PetscInt_FMT " positive", lits);
4271   PetscCheck(b != x, PETSC_COMM_SELF, PETSC_ERR_ARG_IDN, "b and x vector cannot be the same");
4272 
4273   MatCheckPreallocated(mat, 1);
4274   PetscCall(PetscLogEventBegin(MAT_SOR, mat, b, x, 0));
4275   PetscUseTypeMethod(mat, sor, b, omega, flag, shift, its, lits, x);
4276   PetscCall(PetscLogEventEnd(MAT_SOR, mat, b, x, 0));
4277   PetscCall(PetscObjectStateIncrease((PetscObject)x));
4278   PetscFunctionReturn(PETSC_SUCCESS);
4279 }
4280 
4281 /*
4282       Default matrix copy routine.
4283 */
4284 PetscErrorCode MatCopy_Basic(Mat A, Mat B, MatStructure str)
4285 {
4286   PetscInt           i, rstart = 0, rend = 0, nz;
4287   const PetscInt    *cwork;
4288   const PetscScalar *vwork;
4289 
4290   PetscFunctionBegin;
4291   if (B->assembled) PetscCall(MatZeroEntries(B));
4292   if (str == SAME_NONZERO_PATTERN) {
4293     PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
4294     for (i = rstart; i < rend; i++) {
4295       PetscCall(MatGetRow(A, i, &nz, &cwork, &vwork));
4296       PetscCall(MatSetValues(B, 1, &i, nz, cwork, vwork, INSERT_VALUES));
4297       PetscCall(MatRestoreRow(A, i, &nz, &cwork, &vwork));
4298     }
4299   } else {
4300     PetscCall(MatAYPX(B, 0.0, A, str));
4301   }
4302   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
4303   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
4304   PetscFunctionReturn(PETSC_SUCCESS);
4305 }
4306 
4307 /*@
4308   MatCopy - Copies a matrix to another matrix.
4309 
4310   Collective
4311 
4312   Input Parameters:
4313 + A   - the matrix
4314 - str - `SAME_NONZERO_PATTERN` or `DIFFERENT_NONZERO_PATTERN`
4315 
4316   Output Parameter:
4317 . B - where the copy is put
4318 
4319   Level: intermediate
4320 
4321   Notes:
4322   If you use `SAME_NONZERO_PATTERN`, then the two matrices must have the same nonzero pattern or the routine will crash.
4323 
4324   `MatCopy()` copies the matrix entries of a matrix to another existing
4325   matrix (after first zeroing the second matrix).  A related routine is
4326   `MatConvert()`, which first creates a new matrix and then copies the data.
4327 
4328 .seealso: [](ch_matrices), `Mat`, `MatConvert()`, `MatDuplicate()`
4329 @*/
4330 PetscErrorCode MatCopy(Mat A, Mat B, MatStructure str)
4331 {
4332   PetscInt i;
4333 
4334   PetscFunctionBegin;
4335   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
4336   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
4337   PetscValidType(A, 1);
4338   PetscValidType(B, 2);
4339   PetscCheckSameComm(A, 1, B, 2);
4340   MatCheckPreallocated(B, 2);
4341   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4342   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4343   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,
4344              A->cmap->N, B->cmap->N);
4345   MatCheckPreallocated(A, 1);
4346   if (A == B) PetscFunctionReturn(PETSC_SUCCESS);
4347 
4348   PetscCall(PetscLogEventBegin(MAT_Copy, A, B, 0, 0));
4349   if (A->ops->copy) PetscUseTypeMethod(A, copy, B, str);
4350   else PetscCall(MatCopy_Basic(A, B, str));
4351 
4352   B->stencil.dim = A->stencil.dim;
4353   B->stencil.noc = A->stencil.noc;
4354   for (i = 0; i <= A->stencil.dim + (A->stencil.noc ? 0 : -1); i++) {
4355     B->stencil.dims[i]   = A->stencil.dims[i];
4356     B->stencil.starts[i] = A->stencil.starts[i];
4357   }
4358 
4359   PetscCall(PetscLogEventEnd(MAT_Copy, A, B, 0, 0));
4360   PetscCall(PetscObjectStateIncrease((PetscObject)B));
4361   PetscFunctionReturn(PETSC_SUCCESS);
4362 }
4363 
4364 /*@
4365   MatConvert - Converts a matrix to another matrix, either of the same
4366   or different type.
4367 
4368   Collective
4369 
4370   Input Parameters:
4371 + mat     - the matrix
4372 . newtype - new matrix type.  Use `MATSAME` to create a new matrix of the
4373             same type as the original matrix.
4374 - reuse   - denotes if the destination matrix is to be created or reused.
4375             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
4376             `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).
4377 
4378   Output Parameter:
4379 . M - pointer to place new matrix
4380 
4381   Level: intermediate
4382 
4383   Notes:
4384   `MatConvert()` first creates a new matrix and then copies the data from
4385   the first matrix.  A related routine is `MatCopy()`, which copies the matrix
4386   entries of one matrix to another already existing matrix context.
4387 
4388   Cannot be used to convert a sequential matrix to parallel or parallel to sequential,
4389   the MPI communicator of the generated matrix is always the same as the communicator
4390   of the input matrix.
4391 
4392 .seealso: [](ch_matrices), `Mat`, `MatCopy()`, `MatDuplicate()`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
4393 @*/
4394 PetscErrorCode MatConvert(Mat mat, MatType newtype, MatReuse reuse, Mat *M)
4395 {
4396   PetscBool  sametype, issame, flg;
4397   PetscBool3 issymmetric, ishermitian;
4398   char       convname[256], mtype[256];
4399   Mat        B;
4400 
4401   PetscFunctionBegin;
4402   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4403   PetscValidType(mat, 1);
4404   PetscAssertPointer(M, 4);
4405   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
4406   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4407   MatCheckPreallocated(mat, 1);
4408 
4409   PetscCall(PetscOptionsGetString(((PetscObject)mat)->options, ((PetscObject)mat)->prefix, "-matconvert_type", mtype, sizeof(mtype), &flg));
4410   if (flg) newtype = mtype;
4411 
4412   PetscCall(PetscObjectTypeCompare((PetscObject)mat, newtype, &sametype));
4413   PetscCall(PetscStrcmp(newtype, "same", &issame));
4414   PetscCheck(!(reuse == MAT_INPLACE_MATRIX) || !(mat != *M), PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX requires same input and output matrix");
4415   if (reuse == MAT_REUSE_MATRIX) {
4416     PetscValidHeaderSpecific(*M, MAT_CLASSID, 4);
4417     PetscCheck(mat != *M, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_REUSE_MATRIX means reuse matrix in final argument, perhaps you mean MAT_INPLACE_MATRIX");
4418   }
4419 
4420   if ((reuse == MAT_INPLACE_MATRIX) && (issame || sametype)) {
4421     PetscCall(PetscInfo(mat, "Early return for inplace %s %d %d\n", ((PetscObject)mat)->type_name, sametype, issame));
4422     PetscFunctionReturn(PETSC_SUCCESS);
4423   }
4424 
4425   /* Cache Mat options because some converters use MatHeaderReplace  */
4426   issymmetric = mat->symmetric;
4427   ishermitian = mat->hermitian;
4428 
4429   if ((sametype || issame) && (reuse == MAT_INITIAL_MATRIX) && mat->ops->duplicate) {
4430     PetscCall(PetscInfo(mat, "Calling duplicate for initial matrix %s %d %d\n", ((PetscObject)mat)->type_name, sametype, issame));
4431     PetscUseTypeMethod(mat, duplicate, MAT_COPY_VALUES, M);
4432   } else {
4433     PetscErrorCode (*conv)(Mat, MatType, MatReuse, Mat *) = NULL;
4434     const char *prefix[3]                                 = {"seq", "mpi", ""};
4435     PetscInt    i;
4436     /*
4437        Order of precedence:
4438        0) See if newtype is a superclass of the current matrix.
4439        1) See if a specialized converter is known to the current matrix.
4440        2) See if a specialized converter is known to the desired matrix class.
4441        3) See if a good general converter is registered for the desired class
4442           (as of 6/27/03 only MATMPIADJ falls into this category).
4443        4) See if a good general converter is known for the current matrix.
4444        5) Use a really basic converter.
4445     */
4446 
4447     /* 0) See if newtype is a superclass of the current matrix.
4448           i.e mat is mpiaij and newtype is aij */
4449     for (i = 0; i < 2; i++) {
4450       PetscCall(PetscStrncpy(convname, prefix[i], sizeof(convname)));
4451       PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4452       PetscCall(PetscStrcmp(convname, ((PetscObject)mat)->type_name, &flg));
4453       PetscCall(PetscInfo(mat, "Check superclass %s %s -> %d\n", convname, ((PetscObject)mat)->type_name, flg));
4454       if (flg) {
4455         if (reuse == MAT_INPLACE_MATRIX) {
4456           PetscCall(PetscInfo(mat, "Early return\n"));
4457           PetscFunctionReturn(PETSC_SUCCESS);
4458         } else if (reuse == MAT_INITIAL_MATRIX && mat->ops->duplicate) {
4459           PetscCall(PetscInfo(mat, "Calling MatDuplicate\n"));
4460           PetscUseTypeMethod(mat, duplicate, MAT_COPY_VALUES, M);
4461           PetscFunctionReturn(PETSC_SUCCESS);
4462         } else if (reuse == MAT_REUSE_MATRIX && mat->ops->copy) {
4463           PetscCall(PetscInfo(mat, "Calling MatCopy\n"));
4464           PetscCall(MatCopy(mat, *M, SAME_NONZERO_PATTERN));
4465           PetscFunctionReturn(PETSC_SUCCESS);
4466         }
4467       }
4468     }
4469     /* 1) See if a specialized converter is known to the current matrix and the desired class */
4470     for (i = 0; i < 3; i++) {
4471       PetscCall(PetscStrncpy(convname, "MatConvert_", sizeof(convname)));
4472       PetscCall(PetscStrlcat(convname, ((PetscObject)mat)->type_name, sizeof(convname)));
4473       PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4474       PetscCall(PetscStrlcat(convname, prefix[i], sizeof(convname)));
4475       PetscCall(PetscStrlcat(convname, issame ? ((PetscObject)mat)->type_name : newtype, sizeof(convname)));
4476       PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4477       PetscCall(PetscObjectQueryFunction((PetscObject)mat, convname, &conv));
4478       PetscCall(PetscInfo(mat, "Check specialized (1) %s (%s) -> %d\n", convname, ((PetscObject)mat)->type_name, !!conv));
4479       if (conv) goto foundconv;
4480     }
4481 
4482     /* 2)  See if a specialized converter is known to the desired matrix class. */
4483     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B));
4484     PetscCall(MatSetSizes(B, mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N));
4485     PetscCall(MatSetType(B, newtype));
4486     for (i = 0; i < 3; i++) {
4487       PetscCall(PetscStrncpy(convname, "MatConvert_", sizeof(convname)));
4488       PetscCall(PetscStrlcat(convname, ((PetscObject)mat)->type_name, sizeof(convname)));
4489       PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4490       PetscCall(PetscStrlcat(convname, prefix[i], sizeof(convname)));
4491       PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4492       PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4493       PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4494       PetscCall(PetscInfo(mat, "Check specialized (2) %s (%s) -> %d\n", convname, ((PetscObject)B)->type_name, !!conv));
4495       if (conv) {
4496         PetscCall(MatDestroy(&B));
4497         goto foundconv;
4498       }
4499     }
4500 
4501     /* 3) See if a good general converter is registered for the desired class */
4502     conv = B->ops->convertfrom;
4503     PetscCall(PetscInfo(mat, "Check convertfrom (%s) -> %d\n", ((PetscObject)B)->type_name, !!conv));
4504     PetscCall(MatDestroy(&B));
4505     if (conv) goto foundconv;
4506 
4507     /* 4) See if a good general converter is known for the current matrix */
4508     if (mat->ops->convert) conv = mat->ops->convert;
4509     PetscCall(PetscInfo(mat, "Check general convert (%s) -> %d\n", ((PetscObject)mat)->type_name, !!conv));
4510     if (conv) goto foundconv;
4511 
4512     /* 5) Use a really basic converter. */
4513     PetscCall(PetscInfo(mat, "Using MatConvert_Basic\n"));
4514     conv = MatConvert_Basic;
4515 
4516   foundconv:
4517     PetscCall(PetscLogEventBegin(MAT_Convert, mat, 0, 0, 0));
4518     PetscCall((*conv)(mat, newtype, reuse, M));
4519     if (mat->rmap->mapping && mat->cmap->mapping && !(*M)->rmap->mapping && !(*M)->cmap->mapping) {
4520       /* the block sizes must be same if the mappings are copied over */
4521       (*M)->rmap->bs = mat->rmap->bs;
4522       (*M)->cmap->bs = mat->cmap->bs;
4523       PetscCall(PetscObjectReference((PetscObject)mat->rmap->mapping));
4524       PetscCall(PetscObjectReference((PetscObject)mat->cmap->mapping));
4525       (*M)->rmap->mapping = mat->rmap->mapping;
4526       (*M)->cmap->mapping = mat->cmap->mapping;
4527     }
4528     (*M)->stencil.dim = mat->stencil.dim;
4529     (*M)->stencil.noc = mat->stencil.noc;
4530     for (i = 0; i <= mat->stencil.dim + (mat->stencil.noc ? 0 : -1); i++) {
4531       (*M)->stencil.dims[i]   = mat->stencil.dims[i];
4532       (*M)->stencil.starts[i] = mat->stencil.starts[i];
4533     }
4534     PetscCall(PetscLogEventEnd(MAT_Convert, mat, 0, 0, 0));
4535   }
4536   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4537 
4538   /* Copy Mat options */
4539   if (issymmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*M, MAT_SYMMETRIC, PETSC_TRUE));
4540   else if (issymmetric == PETSC_BOOL3_FALSE) PetscCall(MatSetOption(*M, MAT_SYMMETRIC, PETSC_FALSE));
4541   if (ishermitian == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*M, MAT_HERMITIAN, PETSC_TRUE));
4542   else if (ishermitian == PETSC_BOOL3_FALSE) PetscCall(MatSetOption(*M, MAT_HERMITIAN, PETSC_FALSE));
4543   PetscFunctionReturn(PETSC_SUCCESS);
4544 }
4545 
4546 /*@
4547   MatFactorGetSolverType - Returns name of the package providing the factorization routines
4548 
4549   Not Collective
4550 
4551   Input Parameter:
4552 . mat - the matrix, must be a factored matrix
4553 
4554   Output Parameter:
4555 . type - the string name of the package (do not free this string)
4556 
4557   Level: intermediate
4558 
4559   Fortran Note:
4560   Pass in an empty string that is long enough and the package name will be copied into it.
4561 
4562 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatSolverType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`
4563 @*/
4564 PetscErrorCode MatFactorGetSolverType(Mat mat, MatSolverType *type)
4565 {
4566   PetscErrorCode (*conv)(Mat, MatSolverType *);
4567 
4568   PetscFunctionBegin;
4569   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4570   PetscValidType(mat, 1);
4571   PetscAssertPointer(type, 2);
4572   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
4573   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorGetSolverType_C", &conv));
4574   if (conv) PetscCall((*conv)(mat, type));
4575   else *type = MATSOLVERPETSC;
4576   PetscFunctionReturn(PETSC_SUCCESS);
4577 }
4578 
4579 typedef struct _MatSolverTypeForSpecifcType *MatSolverTypeForSpecifcType;
4580 struct _MatSolverTypeForSpecifcType {
4581   MatType mtype;
4582   /* no entry for MAT_FACTOR_NONE */
4583   PetscErrorCode (*createfactor[MAT_FACTOR_NUM_TYPES - 1])(Mat, MatFactorType, Mat *);
4584   MatSolverTypeForSpecifcType next;
4585 };
4586 
4587 typedef struct _MatSolverTypeHolder *MatSolverTypeHolder;
4588 struct _MatSolverTypeHolder {
4589   char                       *name;
4590   MatSolverTypeForSpecifcType handlers;
4591   MatSolverTypeHolder         next;
4592 };
4593 
4594 static MatSolverTypeHolder MatSolverTypeHolders = NULL;
4595 
4596 /*@C
4597   MatSolverTypeRegister - Registers a `MatSolverType` that works for a particular matrix type
4598 
4599   Logically Collective, No Fortran Support
4600 
4601   Input Parameters:
4602 + package      - name of the package, for example petsc or superlu
4603 . mtype        - the matrix type that works with this package
4604 . ftype        - the type of factorization supported by the package
4605 - createfactor - routine that will create the factored matrix ready to be used
4606 
4607   Level: developer
4608 
4609 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorGetSolverType()`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`,
4610   `MatGetFactor()`
4611 @*/
4612 PetscErrorCode MatSolverTypeRegister(MatSolverType package, MatType mtype, MatFactorType ftype, PetscErrorCode (*createfactor)(Mat, MatFactorType, Mat *))
4613 {
4614   MatSolverTypeHolder         next = MatSolverTypeHolders, prev = NULL;
4615   PetscBool                   flg;
4616   MatSolverTypeForSpecifcType inext, iprev = NULL;
4617 
4618   PetscFunctionBegin;
4619   PetscCall(MatInitializePackage());
4620   if (!next) {
4621     PetscCall(PetscNew(&MatSolverTypeHolders));
4622     PetscCall(PetscStrallocpy(package, &MatSolverTypeHolders->name));
4623     PetscCall(PetscNew(&MatSolverTypeHolders->handlers));
4624     PetscCall(PetscStrallocpy(mtype, (char **)&MatSolverTypeHolders->handlers->mtype));
4625     MatSolverTypeHolders->handlers->createfactor[(int)ftype - 1] = createfactor;
4626     PetscFunctionReturn(PETSC_SUCCESS);
4627   }
4628   while (next) {
4629     PetscCall(PetscStrcasecmp(package, next->name, &flg));
4630     if (flg) {
4631       PetscCheck(next->handlers, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatSolverTypeHolder is missing handlers");
4632       inext = next->handlers;
4633       while (inext) {
4634         PetscCall(PetscStrcasecmp(mtype, inext->mtype, &flg));
4635         if (flg) {
4636           inext->createfactor[(int)ftype - 1] = createfactor;
4637           PetscFunctionReturn(PETSC_SUCCESS);
4638         }
4639         iprev = inext;
4640         inext = inext->next;
4641       }
4642       PetscCall(PetscNew(&iprev->next));
4643       PetscCall(PetscStrallocpy(mtype, (char **)&iprev->next->mtype));
4644       iprev->next->createfactor[(int)ftype - 1] = createfactor;
4645       PetscFunctionReturn(PETSC_SUCCESS);
4646     }
4647     prev = next;
4648     next = next->next;
4649   }
4650   PetscCall(PetscNew(&prev->next));
4651   PetscCall(PetscStrallocpy(package, &prev->next->name));
4652   PetscCall(PetscNew(&prev->next->handlers));
4653   PetscCall(PetscStrallocpy(mtype, (char **)&prev->next->handlers->mtype));
4654   prev->next->handlers->createfactor[(int)ftype - 1] = createfactor;
4655   PetscFunctionReturn(PETSC_SUCCESS);
4656 }
4657 
4658 /*@C
4659   MatSolverTypeGet - Gets the function that creates the factor matrix if it exist
4660 
4661   Input Parameters:
4662 + 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
4663 . ftype - the type of factorization supported by the type
4664 - mtype - the matrix type that works with this type
4665 
4666   Output Parameters:
4667 + foundtype    - `PETSC_TRUE` if the type was registered
4668 . foundmtype   - `PETSC_TRUE` if the type supports the requested mtype
4669 - createfactor - routine that will create the factored matrix ready to be used or `NULL` if not found
4670 
4671   Calling sequence of `createfactor`:
4672 + A     - the matrix providing the factor matrix
4673 . ftype - the `MatFactorType` of the factor requested
4674 - B     - the new factor matrix that responds to MatXXFactorSymbolic,Numeric() functions, such as `MatLUFactorSymbolic()`
4675 
4676   Level: developer
4677 
4678   Note:
4679   When `type` is `NULL` the available functions are searched for based on the order of the calls to `MatSolverTypeRegister()` in `MatInitializePackage()`.
4680   Since different PETSc configurations may have different external solvers, seemingly identical runs with different PETSc configurations may use a different solver.
4681   For example if one configuration had `--download-mumps` while a different one had `--download-superlu_dist`.
4682 
4683 .seealso: [](ch_matrices), `Mat`, `MatFactorType`, `MatType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatSolverTypeRegister()`, `MatGetFactor()`,
4684           `MatInitializePackage()`
4685 @*/
4686 PetscErrorCode MatSolverTypeGet(MatSolverType type, MatType mtype, MatFactorType ftype, PetscBool *foundtype, PetscBool *foundmtype, PetscErrorCode (**createfactor)(Mat A, MatFactorType ftype, Mat *B))
4687 {
4688   MatSolverTypeHolder         next = MatSolverTypeHolders;
4689   PetscBool                   flg;
4690   MatSolverTypeForSpecifcType inext;
4691 
4692   PetscFunctionBegin;
4693   if (foundtype) *foundtype = PETSC_FALSE;
4694   if (foundmtype) *foundmtype = PETSC_FALSE;
4695   if (createfactor) *createfactor = NULL;
4696 
4697   if (type) {
4698     while (next) {
4699       PetscCall(PetscStrcasecmp(type, next->name, &flg));
4700       if (flg) {
4701         if (foundtype) *foundtype = PETSC_TRUE;
4702         inext = next->handlers;
4703         while (inext) {
4704           PetscCall(PetscStrbeginswith(mtype, inext->mtype, &flg));
4705           if (flg) {
4706             if (foundmtype) *foundmtype = PETSC_TRUE;
4707             if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4708             PetscFunctionReturn(PETSC_SUCCESS);
4709           }
4710           inext = inext->next;
4711         }
4712       }
4713       next = next->next;
4714     }
4715   } else {
4716     while (next) {
4717       inext = next->handlers;
4718       while (inext) {
4719         PetscCall(PetscStrcmp(mtype, inext->mtype, &flg));
4720         if (flg && inext->createfactor[(int)ftype - 1]) {
4721           if (foundtype) *foundtype = PETSC_TRUE;
4722           if (foundmtype) *foundmtype = PETSC_TRUE;
4723           if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4724           PetscFunctionReturn(PETSC_SUCCESS);
4725         }
4726         inext = inext->next;
4727       }
4728       next = next->next;
4729     }
4730     /* try with base classes inext->mtype */
4731     next = MatSolverTypeHolders;
4732     while (next) {
4733       inext = next->handlers;
4734       while (inext) {
4735         PetscCall(PetscStrbeginswith(mtype, inext->mtype, &flg));
4736         if (flg && inext->createfactor[(int)ftype - 1]) {
4737           if (foundtype) *foundtype = PETSC_TRUE;
4738           if (foundmtype) *foundmtype = PETSC_TRUE;
4739           if (createfactor) *createfactor = inext->createfactor[(int)ftype - 1];
4740           PetscFunctionReturn(PETSC_SUCCESS);
4741         }
4742         inext = inext->next;
4743       }
4744       next = next->next;
4745     }
4746   }
4747   PetscFunctionReturn(PETSC_SUCCESS);
4748 }
4749 
4750 PetscErrorCode MatSolverTypeDestroy(void)
4751 {
4752   MatSolverTypeHolder         next = MatSolverTypeHolders, prev;
4753   MatSolverTypeForSpecifcType inext, iprev;
4754 
4755   PetscFunctionBegin;
4756   while (next) {
4757     PetscCall(PetscFree(next->name));
4758     inext = next->handlers;
4759     while (inext) {
4760       PetscCall(PetscFree(inext->mtype));
4761       iprev = inext;
4762       inext = inext->next;
4763       PetscCall(PetscFree(iprev));
4764     }
4765     prev = next;
4766     next = next->next;
4767     PetscCall(PetscFree(prev));
4768   }
4769   MatSolverTypeHolders = NULL;
4770   PetscFunctionReturn(PETSC_SUCCESS);
4771 }
4772 
4773 /*@
4774   MatFactorGetCanUseOrdering - Indicates if the factorization can use the ordering provided in `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4775 
4776   Logically Collective
4777 
4778   Input Parameter:
4779 . mat - the matrix
4780 
4781   Output Parameter:
4782 . flg - `PETSC_TRUE` if uses the ordering
4783 
4784   Level: developer
4785 
4786   Note:
4787   Most internal PETSc factorizations use the ordering passed to the factorization routine but external
4788   packages do not, thus we want to skip generating the ordering when it is not needed or used.
4789 
4790 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4791 @*/
4792 PetscErrorCode MatFactorGetCanUseOrdering(Mat mat, PetscBool *flg)
4793 {
4794   PetscFunctionBegin;
4795   *flg = mat->canuseordering;
4796   PetscFunctionReturn(PETSC_SUCCESS);
4797 }
4798 
4799 /*@
4800   MatFactorGetPreferredOrdering - The preferred ordering for a particular matrix factor object
4801 
4802   Logically Collective
4803 
4804   Input Parameters:
4805 + mat   - the matrix obtained with `MatGetFactor()`
4806 - ftype - the factorization type to be used
4807 
4808   Output Parameter:
4809 . otype - the preferred ordering type
4810 
4811   Level: developer
4812 
4813 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatFactorType`, `MatOrderingType`, `MatCopy()`, `MatDuplicate()`, `MatGetFactorAvailable()`, `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatCholeskyFactorSymbolic()`
4814 @*/
4815 PetscErrorCode MatFactorGetPreferredOrdering(Mat mat, MatFactorType ftype, MatOrderingType *otype)
4816 {
4817   PetscFunctionBegin;
4818   *otype = mat->preferredordering[ftype];
4819   PetscCheck(*otype, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatFactor did not have a preferred ordering");
4820   PetscFunctionReturn(PETSC_SUCCESS);
4821 }
4822 
4823 /*@
4824   MatGetFactor - Returns a matrix suitable to calls to MatXXFactorSymbolic,Numeric()
4825 
4826   Collective
4827 
4828   Input Parameters:
4829 + mat   - the matrix
4830 . 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
4831           the other criteria is returned
4832 - ftype - factor type, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`
4833 
4834   Output Parameter:
4835 . f - the factor matrix used with MatXXFactorSymbolic,Numeric() calls. Can be `NULL` in some cases, see notes below.
4836 
4837   Options Database Keys:
4838 + -pc_factor_mat_solver_type <type>             - choose the type at run time. When using `KSP` solvers
4839 - -mat_factor_bind_factorization <host, device> - Where to do matrix factorization? Default is device (might consume more device memory.
4840                                                   One can choose host to save device memory). Currently only supported with `MATSEQAIJCUSPARSE` matrices.
4841 
4842   Level: intermediate
4843 
4844   Notes:
4845   The return matrix can be `NULL` if the requested factorization is not available, since some combinations of matrix types and factorization
4846   types registered with `MatSolverTypeRegister()` cannot be fully tested if not at runtime.
4847 
4848   Users usually access the factorization solvers via `KSP`
4849 
4850   Some PETSc matrix formats have alternative solvers available that are contained in alternative packages
4851   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
4852 
4853   When `type` is `NULL` the available results are searched for based on the order of the calls to `MatSolverTypeRegister()` in `MatInitializePackage()`.
4854   Since different PETSc configurations may have different external solvers, seemingly identical runs with different PETSc configurations may use a different solver.
4855   For example if one configuration had --download-mumps while a different one had --download-superlu_dist.
4856 
4857   Some of the packages have options for controlling the factorization, these are in the form -prefix_mat_packagename_packageoption
4858   where prefix is normally obtained from the calling `KSP`/`PC`. If `MatGetFactor()` is called directly one can set
4859   call `MatSetOptionsPrefixFactor()` on the originating matrix or  `MatSetOptionsPrefix()` on the resulting factor matrix.
4860 
4861   Developer Note:
4862   This should actually be called `MatCreateFactor()` since it creates a new factor object
4863 
4864 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `KSP`, `MatSolverType`, `MatFactorType`, `MatCopy()`, `MatDuplicate()`,
4865           `MatGetFactorAvailable()`, `MatFactorGetCanUseOrdering()`, `MatSolverTypeRegister()`, `MatSolverTypeGet()`
4866           `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`, `MatInitializePackage()`
4867 @*/
4868 PetscErrorCode MatGetFactor(Mat mat, MatSolverType type, MatFactorType ftype, Mat *f)
4869 {
4870   PetscBool foundtype, foundmtype, shell, hasop = PETSC_FALSE;
4871   PetscErrorCode (*conv)(Mat, MatFactorType, Mat *);
4872 
4873   PetscFunctionBegin;
4874   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4875   PetscValidType(mat, 1);
4876 
4877   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4878   MatCheckPreallocated(mat, 1);
4879 
4880   PetscCall(MatIsShell(mat, &shell));
4881   if (shell) PetscCall(MatHasOperation(mat, MATOP_GET_FACTOR, &hasop));
4882   if (hasop) {
4883     PetscUseTypeMethod(mat, getfactor, type, ftype, f);
4884     PetscFunctionReturn(PETSC_SUCCESS);
4885   }
4886 
4887   PetscCall(MatSolverTypeGet(type, ((PetscObject)mat)->type_name, ftype, &foundtype, &foundmtype, &conv));
4888   if (!foundtype) {
4889     if (type) {
4890       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],
4891               ((PetscObject)mat)->type_name, type);
4892     } else {
4893       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);
4894     }
4895   }
4896   PetscCheck(foundmtype, PetscObjectComm((PetscObject)mat), PETSC_ERR_MISSING_FACTOR, "MatSolverType %s does not support matrix type %s", type, ((PetscObject)mat)->type_name);
4897   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);
4898 
4899   PetscCall((*conv)(mat, ftype, f));
4900   if (mat->factorprefix) PetscCall(MatSetOptionsPrefix(*f, mat->factorprefix));
4901   PetscFunctionReturn(PETSC_SUCCESS);
4902 }
4903 
4904 /*@
4905   MatGetFactorAvailable - Returns a flag if matrix supports particular type and factor type
4906 
4907   Not Collective
4908 
4909   Input Parameters:
4910 + mat   - the matrix
4911 . type  - name of solver type, for example, superlu, petsc (to use PETSc's default)
4912 - ftype - factor type, `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`
4913 
4914   Output Parameter:
4915 . flg - PETSC_TRUE if the factorization is available
4916 
4917   Level: intermediate
4918 
4919   Notes:
4920   Some PETSc matrix formats have alternative solvers available that are contained in alternative packages
4921   such as pastix, superlu, mumps etc.
4922 
4923   PETSc must have been ./configure to use the external solver, using the option --download-package
4924 
4925   Developer Note:
4926   This should actually be called `MatCreateFactorAvailable()` since `MatGetFactor()` creates a new factor object
4927 
4928 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatSolverType`, `MatFactorType`, `MatGetFactor()`, `MatCopy()`, `MatDuplicate()`, `MatSolverTypeRegister()`,
4929           `MAT_FACTOR_LU`, `MAT_FACTOR_CHOLESKY`, `MAT_FACTOR_ICC`, `MAT_FACTOR_ILU`, `MAT_FACTOR_QR`, `MatSolverTypeGet()`
4930 @*/
4931 PetscErrorCode MatGetFactorAvailable(Mat mat, MatSolverType type, MatFactorType ftype, PetscBool *flg)
4932 {
4933   PetscErrorCode (*gconv)(Mat, MatFactorType, Mat *);
4934 
4935   PetscFunctionBegin;
4936   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4937   PetscAssertPointer(flg, 4);
4938 
4939   *flg = PETSC_FALSE;
4940   if (!((PetscObject)mat)->type_name) PetscFunctionReturn(PETSC_SUCCESS);
4941 
4942   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4943   MatCheckPreallocated(mat, 1);
4944 
4945   PetscCall(MatSolverTypeGet(type, ((PetscObject)mat)->type_name, ftype, NULL, NULL, &gconv));
4946   *flg = gconv ? PETSC_TRUE : PETSC_FALSE;
4947   PetscFunctionReturn(PETSC_SUCCESS);
4948 }
4949 
4950 /*@
4951   MatDuplicate - Duplicates a matrix including the non-zero structure.
4952 
4953   Collective
4954 
4955   Input Parameters:
4956 + mat - the matrix
4957 - op  - One of `MAT_DO_NOT_COPY_VALUES`, `MAT_COPY_VALUES`, or `MAT_SHARE_NONZERO_PATTERN`.
4958         See the manual page for `MatDuplicateOption()` for an explanation of these options.
4959 
4960   Output Parameter:
4961 . M - pointer to place new matrix
4962 
4963   Level: intermediate
4964 
4965   Notes:
4966   You cannot change the nonzero pattern for the parent or child matrix later if you use `MAT_SHARE_NONZERO_PATTERN`.
4967 
4968   If `op` is not `MAT_COPY_VALUES` the numerical values in the new matrix are zeroed.
4969 
4970   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.
4971 
4972   When original mat is a product of matrix operation, e.g., an output of `MatMatMult()` or `MatCreateSubMatrix()`, only the matrix data structure of `mat`
4973   is duplicated and the internal data structures created for the reuse of previous matrix operations are not duplicated.
4974   User should not use `MatDuplicate()` to create new matrix `M` if `M` is intended to be reused as the product of matrix operation.
4975 
4976 .seealso: [](ch_matrices), `Mat`, `MatCopy()`, `MatConvert()`, `MatDuplicateOption`
4977 @*/
4978 PetscErrorCode MatDuplicate(Mat mat, MatDuplicateOption op, Mat *M)
4979 {
4980   Mat         B;
4981   VecType     vtype;
4982   PetscInt    i;
4983   PetscObject dm, container_h, container_d;
4984   void (*viewf)(void);
4985 
4986   PetscFunctionBegin;
4987   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
4988   PetscValidType(mat, 1);
4989   PetscAssertPointer(M, 3);
4990   PetscCheck(op != MAT_COPY_VALUES || mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "MAT_COPY_VALUES not allowed for unassembled matrix");
4991   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
4992   MatCheckPreallocated(mat, 1);
4993 
4994   *M = NULL;
4995   PetscCall(PetscLogEventBegin(MAT_Convert, mat, 0, 0, 0));
4996   PetscUseTypeMethod(mat, duplicate, op, M);
4997   PetscCall(PetscLogEventEnd(MAT_Convert, mat, 0, 0, 0));
4998   B = *M;
4999 
5000   PetscCall(MatGetOperation(mat, MATOP_VIEW, &viewf));
5001   if (viewf) PetscCall(MatSetOperation(B, MATOP_VIEW, viewf));
5002   PetscCall(MatGetVecType(mat, &vtype));
5003   PetscCall(MatSetVecType(B, vtype));
5004 
5005   B->stencil.dim = mat->stencil.dim;
5006   B->stencil.noc = mat->stencil.noc;
5007   for (i = 0; i <= mat->stencil.dim + (mat->stencil.noc ? 0 : -1); i++) {
5008     B->stencil.dims[i]   = mat->stencil.dims[i];
5009     B->stencil.starts[i] = mat->stencil.starts[i];
5010   }
5011 
5012   B->nooffproczerorows = mat->nooffproczerorows;
5013   B->nooffprocentries  = mat->nooffprocentries;
5014 
5015   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_dm", &dm));
5016   if (dm) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_dm", dm));
5017   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_MatCOOStruct_Host", &container_h));
5018   if (container_h) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_MatCOOStruct_Host", container_h));
5019   PetscCall(PetscObjectQuery((PetscObject)mat, "__PETSc_MatCOOStruct_Device", &container_d));
5020   if (container_d) PetscCall(PetscObjectCompose((PetscObject)B, "__PETSc_MatCOOStruct_Device", container_d));
5021   if (op == MAT_COPY_VALUES) PetscCall(MatPropagateSymmetryOptions(mat, B));
5022   PetscCall(PetscObjectStateIncrease((PetscObject)B));
5023   PetscFunctionReturn(PETSC_SUCCESS);
5024 }
5025 
5026 /*@
5027   MatGetDiagonal - Gets the diagonal of a matrix as a `Vec`
5028 
5029   Logically Collective
5030 
5031   Input Parameter:
5032 . mat - the matrix
5033 
5034   Output Parameter:
5035 . v - the diagonal of the matrix
5036 
5037   Level: intermediate
5038 
5039   Note:
5040   If `mat` has local sizes `n` x `m`, this routine fills the first `ndiag = min(n, m)` entries
5041   of `v` with the diagonal values. Thus `v` must have local size of at least `ndiag`. If `v`
5042   is larger than `ndiag`, the values of the remaining entries are unspecified.
5043 
5044   Currently only correct in parallel for square matrices.
5045 
5046 .seealso: [](ch_matrices), `Mat`, `Vec`, `MatGetRow()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`
5047 @*/
5048 PetscErrorCode MatGetDiagonal(Mat mat, Vec v)
5049 {
5050   PetscFunctionBegin;
5051   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5052   PetscValidType(mat, 1);
5053   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5054   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5055   MatCheckPreallocated(mat, 1);
5056   if (PetscDefined(USE_DEBUG)) {
5057     PetscInt nv, row, col, ndiag;
5058 
5059     PetscCall(VecGetLocalSize(v, &nv));
5060     PetscCall(MatGetLocalSize(mat, &row, &col));
5061     ndiag = PetscMin(row, col);
5062     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);
5063   }
5064 
5065   PetscUseTypeMethod(mat, getdiagonal, v);
5066   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5067   PetscFunctionReturn(PETSC_SUCCESS);
5068 }
5069 
5070 /*@
5071   MatGetRowMin - Gets the minimum value (of the real part) of each
5072   row of the matrix
5073 
5074   Logically Collective
5075 
5076   Input Parameter:
5077 . mat - the matrix
5078 
5079   Output Parameters:
5080 + v   - the vector for storing the maximums
5081 - idx - the indices of the column found for each row (optional, pass `NULL` if not needed)
5082 
5083   Level: intermediate
5084 
5085   Note:
5086   The result of this call are the same as if one converted the matrix to dense format
5087   and found the minimum value in each row (i.e. the implicit zeros are counted as zeros).
5088 
5089   This code is only implemented for a couple of matrix formats.
5090 
5091 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`, `MatGetRowMinAbs()`,
5092           `MatGetRowMax()`
5093 @*/
5094 PetscErrorCode MatGetRowMin(Mat mat, Vec v, PetscInt idx[])
5095 {
5096   PetscFunctionBegin;
5097   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5098   PetscValidType(mat, 1);
5099   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5100   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5101 
5102   if (!mat->cmap->N) {
5103     PetscCall(VecSet(v, PETSC_MAX_REAL));
5104     if (idx) {
5105       PetscInt i, m = mat->rmap->n;
5106       for (i = 0; i < m; i++) idx[i] = -1;
5107     }
5108   } else {
5109     MatCheckPreallocated(mat, 1);
5110   }
5111   PetscUseTypeMethod(mat, getrowmin, v, idx);
5112   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5113   PetscFunctionReturn(PETSC_SUCCESS);
5114 }
5115 
5116 /*@
5117   MatGetRowMinAbs - Gets the minimum value (in absolute value) of each
5118   row of the matrix
5119 
5120   Logically Collective
5121 
5122   Input Parameter:
5123 . mat - the matrix
5124 
5125   Output Parameters:
5126 + v   - the vector for storing the minimums
5127 - idx - the indices of the column found for each row (or `NULL` if not needed)
5128 
5129   Level: intermediate
5130 
5131   Notes:
5132   if a row is completely empty or has only 0.0 values, then the `idx` value for that
5133   row is 0 (the first column).
5134 
5135   This code is only implemented for a couple of matrix formats.
5136 
5137 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMaxAbs()`, `MatGetRowMin()`
5138 @*/
5139 PetscErrorCode MatGetRowMinAbs(Mat mat, Vec v, PetscInt idx[])
5140 {
5141   PetscFunctionBegin;
5142   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5143   PetscValidType(mat, 1);
5144   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5145   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5146   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5147 
5148   if (!mat->cmap->N) {
5149     PetscCall(VecSet(v, 0.0));
5150     if (idx) {
5151       PetscInt i, m = mat->rmap->n;
5152       for (i = 0; i < m; i++) idx[i] = -1;
5153     }
5154   } else {
5155     MatCheckPreallocated(mat, 1);
5156     if (idx) PetscCall(PetscArrayzero(idx, mat->rmap->n));
5157     PetscUseTypeMethod(mat, getrowminabs, v, idx);
5158   }
5159   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5160   PetscFunctionReturn(PETSC_SUCCESS);
5161 }
5162 
5163 /*@
5164   MatGetRowMax - Gets the maximum value (of the real part) of each
5165   row of the matrix
5166 
5167   Logically Collective
5168 
5169   Input Parameter:
5170 . mat - the matrix
5171 
5172   Output Parameters:
5173 + v   - the vector for storing the maximums
5174 - idx - the indices of the column found for each row (optional, otherwise pass `NULL`)
5175 
5176   Level: intermediate
5177 
5178   Notes:
5179   The result of this call are the same as if one converted the matrix to dense format
5180   and found the minimum value in each row (i.e. the implicit zeros are counted as zeros).
5181 
5182   This code is only implemented for a couple of matrix formats.
5183 
5184 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMaxAbs()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5185 @*/
5186 PetscErrorCode MatGetRowMax(Mat mat, Vec v, PetscInt idx[])
5187 {
5188   PetscFunctionBegin;
5189   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5190   PetscValidType(mat, 1);
5191   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5192   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5193 
5194   if (!mat->cmap->N) {
5195     PetscCall(VecSet(v, PETSC_MIN_REAL));
5196     if (idx) {
5197       PetscInt i, m = mat->rmap->n;
5198       for (i = 0; i < m; i++) idx[i] = -1;
5199     }
5200   } else {
5201     MatCheckPreallocated(mat, 1);
5202     PetscUseTypeMethod(mat, getrowmax, v, idx);
5203   }
5204   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5205   PetscFunctionReturn(PETSC_SUCCESS);
5206 }
5207 
5208 /*@
5209   MatGetRowMaxAbs - Gets the maximum value (in absolute value) of each
5210   row of the matrix
5211 
5212   Logically Collective
5213 
5214   Input Parameter:
5215 . mat - the matrix
5216 
5217   Output Parameters:
5218 + v   - the vector for storing the maximums
5219 - idx - the indices of the column found for each row (or `NULL` if not needed)
5220 
5221   Level: intermediate
5222 
5223   Notes:
5224   if a row is completely empty or has only 0.0 values, then the `idx` value for that
5225   row is 0 (the first column).
5226 
5227   This code is only implemented for a couple of matrix formats.
5228 
5229 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowSum()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5230 @*/
5231 PetscErrorCode MatGetRowMaxAbs(Mat mat, Vec v, PetscInt idx[])
5232 {
5233   PetscFunctionBegin;
5234   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5235   PetscValidType(mat, 1);
5236   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5237   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5238 
5239   if (!mat->cmap->N) {
5240     PetscCall(VecSet(v, 0.0));
5241     if (idx) {
5242       PetscInt i, m = mat->rmap->n;
5243       for (i = 0; i < m; i++) idx[i] = -1;
5244     }
5245   } else {
5246     MatCheckPreallocated(mat, 1);
5247     if (idx) PetscCall(PetscArrayzero(idx, mat->rmap->n));
5248     PetscUseTypeMethod(mat, getrowmaxabs, v, idx);
5249   }
5250   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5251   PetscFunctionReturn(PETSC_SUCCESS);
5252 }
5253 
5254 /*@
5255   MatGetRowSumAbs - Gets the sum value (in absolute value) of each row of the matrix
5256 
5257   Logically Collective
5258 
5259   Input Parameter:
5260 . mat - the matrix
5261 
5262   Output Parameter:
5263 . v - the vector for storing the sum
5264 
5265   Level: intermediate
5266 
5267   This code is only implemented for a couple of matrix formats.
5268 
5269 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMin()`, `MatGetRowMinAbs()`
5270 @*/
5271 PetscErrorCode MatGetRowSumAbs(Mat mat, Vec v)
5272 {
5273   PetscFunctionBegin;
5274   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5275   PetscValidType(mat, 1);
5276   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5277   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5278 
5279   if (!mat->cmap->N) {
5280     PetscCall(VecSet(v, 0.0));
5281   } else {
5282     MatCheckPreallocated(mat, 1);
5283     PetscUseTypeMethod(mat, getrowsumabs, v);
5284   }
5285   PetscCall(PetscObjectStateIncrease((PetscObject)v));
5286   PetscFunctionReturn(PETSC_SUCCESS);
5287 }
5288 
5289 /*@
5290   MatGetRowSum - Gets the sum of each row of the matrix
5291 
5292   Logically or Neighborhood Collective
5293 
5294   Input Parameter:
5295 . mat - the matrix
5296 
5297   Output Parameter:
5298 . v - the vector for storing the sum of rows
5299 
5300   Level: intermediate
5301 
5302   Note:
5303   This code is slow since it is not currently specialized for different formats
5304 
5305 .seealso: [](ch_matrices), `Mat`, `MatGetDiagonal()`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRowMax()`, `MatGetRowMin()`, `MatGetRowMaxAbs()`, `MatGetRowMinAbs()`, `MatGetRowSumAbs()`
5306 @*/
5307 PetscErrorCode MatGetRowSum(Mat mat, Vec v)
5308 {
5309   Vec ones;
5310 
5311   PetscFunctionBegin;
5312   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5313   PetscValidType(mat, 1);
5314   PetscValidHeaderSpecific(v, VEC_CLASSID, 2);
5315   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5316   MatCheckPreallocated(mat, 1);
5317   PetscCall(MatCreateVecs(mat, &ones, NULL));
5318   PetscCall(VecSet(ones, 1.));
5319   PetscCall(MatMult(mat, ones, v));
5320   PetscCall(VecDestroy(&ones));
5321   PetscFunctionReturn(PETSC_SUCCESS);
5322 }
5323 
5324 /*@
5325   MatTransposeSetPrecursor - Set the matrix from which the second matrix will receive numerical transpose data with a call to `MatTranspose`(A,`MAT_REUSE_MATRIX`,&B)
5326   when B was not obtained with `MatTranspose`(A,`MAT_INITIAL_MATRIX`,&B)
5327 
5328   Collective
5329 
5330   Input Parameter:
5331 . mat - the matrix to provide the transpose
5332 
5333   Output Parameter:
5334 . 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
5335 
5336   Level: advanced
5337 
5338   Note:
5339   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
5340   routine allows bypassing that call.
5341 
5342 .seealso: [](ch_matrices), `Mat`, `MatTransposeSymbolic()`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
5343 @*/
5344 PetscErrorCode MatTransposeSetPrecursor(Mat mat, Mat B)
5345 {
5346   MatParentState *rb = NULL;
5347 
5348   PetscFunctionBegin;
5349   PetscCall(PetscNew(&rb));
5350   rb->id    = ((PetscObject)mat)->id;
5351   rb->state = 0;
5352   PetscCall(MatGetNonzeroState(mat, &rb->nonzerostate));
5353   PetscCall(PetscObjectContainerCompose((PetscObject)B, "MatTransposeParent", rb, PetscCtxDestroyDefault));
5354   PetscFunctionReturn(PETSC_SUCCESS);
5355 }
5356 
5357 /*@
5358   MatTranspose - Computes an in-place or out-of-place transpose of a matrix.
5359 
5360   Collective
5361 
5362   Input Parameters:
5363 + mat   - the matrix to transpose
5364 - reuse - either `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, or `MAT_INPLACE_MATRIX`
5365 
5366   Output Parameter:
5367 . B - the transpose
5368 
5369   Level: intermediate
5370 
5371   Notes:
5372   If you use `MAT_INPLACE_MATRIX` then you must pass in `&mat` for `B`
5373 
5374   `MAT_REUSE_MATRIX` uses the `B` matrix obtained from a previous call to this function with `MAT_INITIAL_MATRIX`. If you already have a matrix to contain the
5375   transpose, call `MatTransposeSetPrecursor(mat, B)` before calling this routine.
5376 
5377   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.
5378 
5379   Consider using `MatCreateTranspose()` instead if you only need a matrix that behaves like the transpose, but don't need the storage to be changed.
5380 
5381   If mat is unchanged from the last call this function returns immediately without recomputing the result
5382 
5383   If you only need the symbolic transpose, and not the numerical values, use `MatTransposeSymbolic()`
5384 
5385 .seealso: [](ch_matrices), `Mat`, `MatTransposeSetPrecursor()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`,
5386           `MatTransposeSymbolic()`, `MatCreateTranspose()`
5387 @*/
5388 PetscErrorCode MatTranspose(Mat mat, MatReuse reuse, Mat *B)
5389 {
5390   PetscContainer  rB = NULL;
5391   MatParentState *rb = NULL;
5392 
5393   PetscFunctionBegin;
5394   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5395   PetscValidType(mat, 1);
5396   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5397   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5398   PetscCheck(reuse != MAT_INPLACE_MATRIX || mat == *B, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX requires last matrix to match first");
5399   PetscCheck(reuse != MAT_REUSE_MATRIX || mat != *B, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Perhaps you mean MAT_INPLACE_MATRIX");
5400   MatCheckPreallocated(mat, 1);
5401   if (reuse == MAT_REUSE_MATRIX) {
5402     PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
5403     PetscCheck(rB, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose(). Suggest MatTransposeSetPrecursor().");
5404     PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5405     PetscCheck(rb->id == ((PetscObject)mat)->id, PetscObjectComm((PetscObject)*B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from input matrix");
5406     if (rb->state == ((PetscObject)mat)->state) PetscFunctionReturn(PETSC_SUCCESS);
5407   }
5408 
5409   PetscCall(PetscLogEventBegin(MAT_Transpose, mat, 0, 0, 0));
5410   if (reuse != MAT_INPLACE_MATRIX || mat->symmetric != PETSC_BOOL3_TRUE) {
5411     PetscUseTypeMethod(mat, transpose, reuse, B);
5412     PetscCall(PetscObjectStateIncrease((PetscObject)*B));
5413   }
5414   PetscCall(PetscLogEventEnd(MAT_Transpose, mat, 0, 0, 0));
5415 
5416   if (reuse == MAT_INITIAL_MATRIX) PetscCall(MatTransposeSetPrecursor(mat, *B));
5417   if (reuse != MAT_INPLACE_MATRIX) {
5418     PetscCall(PetscObjectQuery((PetscObject)*B, "MatTransposeParent", (PetscObject *)&rB));
5419     PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5420     rb->state        = ((PetscObject)mat)->state;
5421     rb->nonzerostate = mat->nonzerostate;
5422   }
5423   PetscFunctionReturn(PETSC_SUCCESS);
5424 }
5425 
5426 /*@
5427   MatTransposeSymbolic - Computes the symbolic part of the transpose of a matrix.
5428 
5429   Collective
5430 
5431   Input Parameter:
5432 . A - the matrix to transpose
5433 
5434   Output Parameter:
5435 . 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
5436       numerical portion.
5437 
5438   Level: intermediate
5439 
5440   Note:
5441   This is not supported for many matrix types, use `MatTranspose()` in those cases
5442 
5443 .seealso: [](ch_matrices), `Mat`, `MatTransposeSetPrecursor()`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`, `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, `MAT_INPLACE_MATRIX`
5444 @*/
5445 PetscErrorCode MatTransposeSymbolic(Mat A, Mat *B)
5446 {
5447   PetscFunctionBegin;
5448   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5449   PetscValidType(A, 1);
5450   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5451   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5452   PetscCall(PetscLogEventBegin(MAT_Transpose, A, 0, 0, 0));
5453   PetscUseTypeMethod(A, transposesymbolic, B);
5454   PetscCall(PetscLogEventEnd(MAT_Transpose, A, 0, 0, 0));
5455 
5456   PetscCall(MatTransposeSetPrecursor(A, *B));
5457   PetscFunctionReturn(PETSC_SUCCESS);
5458 }
5459 
5460 PetscErrorCode MatTransposeCheckNonzeroState_Private(Mat A, Mat B)
5461 {
5462   PetscContainer  rB;
5463   MatParentState *rb;
5464 
5465   PetscFunctionBegin;
5466   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5467   PetscValidType(A, 1);
5468   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5469   PetscCheck(!A->factortype, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5470   PetscCall(PetscObjectQuery((PetscObject)B, "MatTransposeParent", (PetscObject *)&rB));
5471   PetscCheck(rB, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from call to MatTranspose()");
5472   PetscCall(PetscContainerGetPointer(rB, (void **)&rb));
5473   PetscCheck(rb->id == ((PetscObject)A)->id, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONG, "Reuse matrix used was not generated from input matrix");
5474   PetscCheck(rb->nonzerostate == A->nonzerostate, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Reuse matrix has changed nonzero structure");
5475   PetscFunctionReturn(PETSC_SUCCESS);
5476 }
5477 
5478 /*@
5479   MatIsTranspose - Test whether a matrix is another one's transpose,
5480   or its own, in which case it tests symmetry.
5481 
5482   Collective
5483 
5484   Input Parameters:
5485 + A   - the matrix to test
5486 . B   - the matrix to test against, this can equal the first parameter
5487 - tol - tolerance, differences between entries smaller than this are counted as zero
5488 
5489   Output Parameter:
5490 . flg - the result
5491 
5492   Level: intermediate
5493 
5494   Notes:
5495   The sequential algorithm has a running time of the order of the number of nonzeros; the parallel
5496   test involves parallel copies of the block off-diagonal parts of the matrix.
5497 
5498 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsSymmetric()`, `MatIsHermitian()`
5499 @*/
5500 PetscErrorCode MatIsTranspose(Mat A, Mat B, PetscReal tol, PetscBool *flg)
5501 {
5502   PetscErrorCode (*f)(Mat, Mat, PetscReal, PetscBool *), (*g)(Mat, Mat, PetscReal, PetscBool *);
5503 
5504   PetscFunctionBegin;
5505   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5506   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5507   PetscAssertPointer(flg, 4);
5508   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatIsTranspose_C", &f));
5509   PetscCall(PetscObjectQueryFunction((PetscObject)B, "MatIsTranspose_C", &g));
5510   *flg = PETSC_FALSE;
5511   if (f && g) {
5512     PetscCheck(f == g, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_NOTSAMETYPE, "Matrices do not have the same comparator for symmetry test");
5513     PetscCall((*f)(A, B, tol, flg));
5514   } else {
5515     MatType mattype;
5516 
5517     PetscCall(MatGetType(f ? B : A, &mattype));
5518     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Matrix of type %s does not support checking for transpose", mattype);
5519   }
5520   PetscFunctionReturn(PETSC_SUCCESS);
5521 }
5522 
5523 /*@
5524   MatHermitianTranspose - Computes an in-place or out-of-place Hermitian transpose of a matrix in complex conjugate.
5525 
5526   Collective
5527 
5528   Input Parameters:
5529 + mat   - the matrix to transpose and complex conjugate
5530 - reuse - either `MAT_INITIAL_MATRIX`, `MAT_REUSE_MATRIX`, or `MAT_INPLACE_MATRIX`
5531 
5532   Output Parameter:
5533 . B - the Hermitian transpose
5534 
5535   Level: intermediate
5536 
5537 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatMultTranspose()`, `MatMultTransposeAdd()`, `MatIsTranspose()`, `MatReuse`
5538 @*/
5539 PetscErrorCode MatHermitianTranspose(Mat mat, MatReuse reuse, Mat *B)
5540 {
5541   PetscFunctionBegin;
5542   PetscCall(MatTranspose(mat, reuse, B));
5543 #if defined(PETSC_USE_COMPLEX)
5544   PetscCall(MatConjugate(*B));
5545 #endif
5546   PetscFunctionReturn(PETSC_SUCCESS);
5547 }
5548 
5549 /*@
5550   MatIsHermitianTranspose - Test whether a matrix is another one's Hermitian transpose,
5551 
5552   Collective
5553 
5554   Input Parameters:
5555 + A   - the matrix to test
5556 . B   - the matrix to test against, this can equal the first parameter
5557 - tol - tolerance, differences between entries smaller than this are counted as zero
5558 
5559   Output Parameter:
5560 . flg - the result
5561 
5562   Level: intermediate
5563 
5564   Notes:
5565   Only available for `MATAIJ` matrices.
5566 
5567   The sequential algorithm
5568   has a running time of the order of the number of nonzeros; the parallel
5569   test involves parallel copies of the block off-diagonal parts of the matrix.
5570 
5571 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsTranspose()`
5572 @*/
5573 PetscErrorCode MatIsHermitianTranspose(Mat A, Mat B, PetscReal tol, PetscBool *flg)
5574 {
5575   PetscErrorCode (*f)(Mat, Mat, PetscReal, PetscBool *), (*g)(Mat, Mat, PetscReal, PetscBool *);
5576 
5577   PetscFunctionBegin;
5578   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5579   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5580   PetscAssertPointer(flg, 4);
5581   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatIsHermitianTranspose_C", &f));
5582   PetscCall(PetscObjectQueryFunction((PetscObject)B, "MatIsHermitianTranspose_C", &g));
5583   if (f && g) {
5584     PetscCheck(f != g, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_NOTSAMETYPE, "Matrices do not have the same comparator for Hermitian test");
5585     PetscCall((*f)(A, B, tol, flg));
5586   }
5587   PetscFunctionReturn(PETSC_SUCCESS);
5588 }
5589 
5590 /*@
5591   MatPermute - Creates a new matrix with rows and columns permuted from the
5592   original.
5593 
5594   Collective
5595 
5596   Input Parameters:
5597 + mat - the matrix to permute
5598 . row - row permutation, each processor supplies only the permutation for its rows
5599 - col - column permutation, each processor supplies only the permutation for its columns
5600 
5601   Output Parameter:
5602 . B - the permuted matrix
5603 
5604   Level: advanced
5605 
5606   Note:
5607   The index sets map from row/col of permuted matrix to row/col of original matrix.
5608   The index sets should be on the same communicator as mat and have the same local sizes.
5609 
5610   Developer Note:
5611   If you want to implement `MatPermute()` for a matrix type, and your approach doesn't
5612   exploit the fact that row and col are permutations, consider implementing the
5613   more general `MatCreateSubMatrix()` instead.
5614 
5615 .seealso: [](ch_matrices), `Mat`, `MatGetOrdering()`, `ISAllGather()`, `MatCreateSubMatrix()`
5616 @*/
5617 PetscErrorCode MatPermute(Mat mat, IS row, IS col, Mat *B)
5618 {
5619   PetscFunctionBegin;
5620   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5621   PetscValidType(mat, 1);
5622   PetscValidHeaderSpecific(row, IS_CLASSID, 2);
5623   PetscValidHeaderSpecific(col, IS_CLASSID, 3);
5624   PetscAssertPointer(B, 4);
5625   PetscCheckSameComm(mat, 1, row, 2);
5626   if (row != col) PetscCheckSameComm(row, 2, col, 3);
5627   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5628   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5629   PetscCheck(mat->ops->permute || mat->ops->createsubmatrix, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatPermute not available for Mat type %s", ((PetscObject)mat)->type_name);
5630   MatCheckPreallocated(mat, 1);
5631 
5632   if (mat->ops->permute) {
5633     PetscUseTypeMethod(mat, permute, row, col, B);
5634     PetscCall(PetscObjectStateIncrease((PetscObject)*B));
5635   } else {
5636     PetscCall(MatCreateSubMatrix(mat, row, col, MAT_INITIAL_MATRIX, B));
5637   }
5638   PetscFunctionReturn(PETSC_SUCCESS);
5639 }
5640 
5641 /*@
5642   MatEqual - Compares two matrices.
5643 
5644   Collective
5645 
5646   Input Parameters:
5647 + A - the first matrix
5648 - B - the second matrix
5649 
5650   Output Parameter:
5651 . flg - `PETSC_TRUE` if the matrices are equal; `PETSC_FALSE` otherwise.
5652 
5653   Level: intermediate
5654 
5655 .seealso: [](ch_matrices), `Mat`
5656 @*/
5657 PetscErrorCode MatEqual(Mat A, Mat B, PetscBool *flg)
5658 {
5659   PetscFunctionBegin;
5660   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
5661   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
5662   PetscValidType(A, 1);
5663   PetscValidType(B, 2);
5664   PetscAssertPointer(flg, 3);
5665   PetscCheckSameComm(A, 1, B, 2);
5666   MatCheckPreallocated(A, 1);
5667   MatCheckPreallocated(B, 2);
5668   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5669   PetscCheck(B->assembled, PetscObjectComm((PetscObject)B), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5670   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,
5671              B->cmap->N);
5672   if (A->ops->equal && A->ops->equal == B->ops->equal) {
5673     PetscUseTypeMethod(A, equal, B, flg);
5674   } else {
5675     PetscCall(MatMultEqual(A, B, 10, flg));
5676   }
5677   PetscFunctionReturn(PETSC_SUCCESS);
5678 }
5679 
5680 /*@
5681   MatDiagonalScale - Scales a matrix on the left and right by diagonal
5682   matrices that are stored as vectors.  Either of the two scaling
5683   matrices can be `NULL`.
5684 
5685   Collective
5686 
5687   Input Parameters:
5688 + mat - the matrix to be scaled
5689 . l   - the left scaling vector (or `NULL`)
5690 - r   - the right scaling vector (or `NULL`)
5691 
5692   Level: intermediate
5693 
5694   Note:
5695   `MatDiagonalScale()` computes $A = LAR$, where
5696   L = a diagonal matrix (stored as a vector), R = a diagonal matrix (stored as a vector)
5697   The L scales the rows of the matrix, the R scales the columns of the matrix.
5698 
5699 .seealso: [](ch_matrices), `Mat`, `MatScale()`, `MatShift()`, `MatDiagonalSet()`
5700 @*/
5701 PetscErrorCode MatDiagonalScale(Mat mat, Vec l, Vec r)
5702 {
5703   PetscFunctionBegin;
5704   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5705   PetscValidType(mat, 1);
5706   if (l) {
5707     PetscValidHeaderSpecific(l, VEC_CLASSID, 2);
5708     PetscCheckSameComm(mat, 1, l, 2);
5709   }
5710   if (r) {
5711     PetscValidHeaderSpecific(r, VEC_CLASSID, 3);
5712     PetscCheckSameComm(mat, 1, r, 3);
5713   }
5714   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5715   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5716   MatCheckPreallocated(mat, 1);
5717   if (!l && !r) PetscFunctionReturn(PETSC_SUCCESS);
5718 
5719   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
5720   PetscUseTypeMethod(mat, diagonalscale, l, r);
5721   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
5722   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5723   if (l != r) mat->symmetric = PETSC_BOOL3_FALSE;
5724   PetscFunctionReturn(PETSC_SUCCESS);
5725 }
5726 
5727 /*@
5728   MatScale - Scales all elements of a matrix by a given number.
5729 
5730   Logically Collective
5731 
5732   Input Parameters:
5733 + mat - the matrix to be scaled
5734 - a   - the scaling value
5735 
5736   Level: intermediate
5737 
5738 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
5739 @*/
5740 PetscErrorCode MatScale(Mat mat, PetscScalar a)
5741 {
5742   PetscFunctionBegin;
5743   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5744   PetscValidType(mat, 1);
5745   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5746   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5747   PetscValidLogicalCollectiveScalar(mat, a, 2);
5748   MatCheckPreallocated(mat, 1);
5749 
5750   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
5751   if (a != (PetscScalar)1.0) {
5752     PetscUseTypeMethod(mat, scale, a);
5753     PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5754   }
5755   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
5756   PetscFunctionReturn(PETSC_SUCCESS);
5757 }
5758 
5759 /*@
5760   MatNorm - Calculates various norms of a matrix.
5761 
5762   Collective
5763 
5764   Input Parameters:
5765 + mat  - the matrix
5766 - type - the type of norm, `NORM_1`, `NORM_FROBENIUS`, `NORM_INFINITY`
5767 
5768   Output Parameter:
5769 . nrm - the resulting norm
5770 
5771   Level: intermediate
5772 
5773 .seealso: [](ch_matrices), `Mat`
5774 @*/
5775 PetscErrorCode MatNorm(Mat mat, NormType type, PetscReal *nrm)
5776 {
5777   PetscFunctionBegin;
5778   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5779   PetscValidType(mat, 1);
5780   PetscAssertPointer(nrm, 3);
5781 
5782   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
5783   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
5784   MatCheckPreallocated(mat, 1);
5785 
5786   PetscUseTypeMethod(mat, norm, type, nrm);
5787   PetscFunctionReturn(PETSC_SUCCESS);
5788 }
5789 
5790 /*
5791      This variable is used to prevent counting of MatAssemblyBegin() that
5792    are called from within a MatAssemblyEnd().
5793 */
5794 static PetscInt MatAssemblyEnd_InUse = 0;
5795 /*@
5796   MatAssemblyBegin - Begins assembling the matrix.  This routine should
5797   be called after completing all calls to `MatSetValues()`.
5798 
5799   Collective
5800 
5801   Input Parameters:
5802 + mat  - the matrix
5803 - type - type of assembly, either `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY`
5804 
5805   Level: beginner
5806 
5807   Notes:
5808   `MatSetValues()` generally caches the values that belong to other MPI processes.  The matrix is ready to
5809   use only after `MatAssemblyBegin()` and `MatAssemblyEnd()` have been called.
5810 
5811   Use `MAT_FLUSH_ASSEMBLY` when switching between `ADD_VALUES` and `INSERT_VALUES`
5812   in `MatSetValues()`; use `MAT_FINAL_ASSEMBLY` for the final assembly before
5813   using the matrix.
5814 
5815   ALL processes that share a matrix MUST call `MatAssemblyBegin()` and `MatAssemblyEnd()` the SAME NUMBER of times, and each time with the
5816   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
5817   a global collective operation requiring all processes that share the matrix.
5818 
5819   Space for preallocated nonzeros that is not filled by a call to `MatSetValues()` or a related routine are compressed
5820   out by assembly. If you intend to use that extra space on a subsequent assembly, be sure to insert explicit zeros
5821   before `MAT_FINAL_ASSEMBLY` so the space is not compressed out.
5822 
5823 .seealso: [](ch_matrices), `Mat`, `MatAssemblyEnd()`, `MatSetValues()`, `MatAssembled()`
5824 @*/
5825 PetscErrorCode MatAssemblyBegin(Mat mat, MatAssemblyType type)
5826 {
5827   PetscFunctionBegin;
5828   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5829   PetscValidType(mat, 1);
5830   MatCheckPreallocated(mat, 1);
5831   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix. Did you forget to call MatSetUnfactored()?");
5832   if (mat->assembled) {
5833     mat->was_assembled = PETSC_TRUE;
5834     mat->assembled     = PETSC_FALSE;
5835   }
5836 
5837   if (!MatAssemblyEnd_InUse) {
5838     PetscCall(PetscLogEventBegin(MAT_AssemblyBegin, mat, 0, 0, 0));
5839     PetscTryTypeMethod(mat, assemblybegin, type);
5840     PetscCall(PetscLogEventEnd(MAT_AssemblyBegin, mat, 0, 0, 0));
5841   } else PetscTryTypeMethod(mat, assemblybegin, type);
5842   PetscFunctionReturn(PETSC_SUCCESS);
5843 }
5844 
5845 /*@
5846   MatAssembled - Indicates if a matrix has been assembled and is ready for
5847   use; for example, in matrix-vector product.
5848 
5849   Not Collective
5850 
5851   Input Parameter:
5852 . mat - the matrix
5853 
5854   Output Parameter:
5855 . assembled - `PETSC_TRUE` or `PETSC_FALSE`
5856 
5857   Level: advanced
5858 
5859 .seealso: [](ch_matrices), `Mat`, `MatAssemblyEnd()`, `MatSetValues()`, `MatAssemblyBegin()`
5860 @*/
5861 PetscErrorCode MatAssembled(Mat mat, PetscBool *assembled)
5862 {
5863   PetscFunctionBegin;
5864   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5865   PetscAssertPointer(assembled, 2);
5866   *assembled = mat->assembled;
5867   PetscFunctionReturn(PETSC_SUCCESS);
5868 }
5869 
5870 /*@
5871   MatAssemblyEnd - Completes assembling the matrix.  This routine should
5872   be called after `MatAssemblyBegin()`.
5873 
5874   Collective
5875 
5876   Input Parameters:
5877 + mat  - the matrix
5878 - type - type of assembly, either `MAT_FLUSH_ASSEMBLY` or `MAT_FINAL_ASSEMBLY`
5879 
5880   Options Database Keys:
5881 + -mat_view ::ascii_info             - Prints info on matrix at conclusion of `MatAssemblyEnd()`
5882 . -mat_view ::ascii_info_detail      - Prints more detailed info
5883 . -mat_view                          - Prints matrix in ASCII format
5884 . -mat_view ::ascii_matlab           - Prints matrix in MATLAB format
5885 . -mat_view draw                     - draws nonzero structure of matrix, using `MatView()` and `PetscDrawOpenX()`.
5886 . -display <name>                    - Sets display name (default is host)
5887 . -draw_pause <sec>                  - Sets number of seconds to pause after display
5888 . -mat_view socket                   - Sends matrix to socket, can be accessed from MATLAB (See [Using MATLAB with PETSc](ch_matlab))
5889 . -viewer_socket_machine <machine>   - Machine to use for socket
5890 . -viewer_socket_port <port>         - Port number to use for socket
5891 - -mat_view binary:filename[:append] - Save matrix to file in binary format
5892 
5893   Level: beginner
5894 
5895 .seealso: [](ch_matrices), `Mat`, `MatAssemblyBegin()`, `MatSetValues()`, `PetscDrawOpenX()`, `PetscDrawCreate()`, `MatView()`, `MatAssembled()`, `PetscViewerSocketOpen()`
5896 @*/
5897 PetscErrorCode MatAssemblyEnd(Mat mat, MatAssemblyType type)
5898 {
5899   static PetscInt inassm = 0;
5900   PetscBool       flg    = PETSC_FALSE;
5901 
5902   PetscFunctionBegin;
5903   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
5904   PetscValidType(mat, 1);
5905 
5906   inassm++;
5907   MatAssemblyEnd_InUse++;
5908   if (MatAssemblyEnd_InUse == 1) { /* Do the logging only the first time through */
5909     PetscCall(PetscLogEventBegin(MAT_AssemblyEnd, mat, 0, 0, 0));
5910     PetscTryTypeMethod(mat, assemblyend, type);
5911     PetscCall(PetscLogEventEnd(MAT_AssemblyEnd, mat, 0, 0, 0));
5912   } else PetscTryTypeMethod(mat, assemblyend, type);
5913 
5914   /* Flush assembly is not a true assembly */
5915   if (type != MAT_FLUSH_ASSEMBLY) {
5916     if (mat->num_ass) {
5917       if (!mat->symmetry_eternal) {
5918         mat->symmetric = PETSC_BOOL3_UNKNOWN;
5919         mat->hermitian = PETSC_BOOL3_UNKNOWN;
5920       }
5921       if (!mat->structural_symmetry_eternal && mat->ass_nonzerostate != mat->nonzerostate) mat->structurally_symmetric = PETSC_BOOL3_UNKNOWN;
5922       if (!mat->spd_eternal) mat->spd = PETSC_BOOL3_UNKNOWN;
5923     }
5924     mat->num_ass++;
5925     mat->assembled        = PETSC_TRUE;
5926     mat->ass_nonzerostate = mat->nonzerostate;
5927   }
5928 
5929   mat->insertmode = NOT_SET_VALUES;
5930   MatAssemblyEnd_InUse--;
5931   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
5932   if (inassm == 1 && type != MAT_FLUSH_ASSEMBLY) {
5933     PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
5934 
5935     if (mat->checksymmetryonassembly) {
5936       PetscCall(MatIsSymmetric(mat, mat->checksymmetrytol, &flg));
5937       if (flg) {
5938         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "Matrix is symmetric (tolerance %g)\n", (double)mat->checksymmetrytol));
5939       } else {
5940         PetscCall(PetscPrintf(PetscObjectComm((PetscObject)mat), "Matrix is not symmetric (tolerance %g)\n", (double)mat->checksymmetrytol));
5941       }
5942     }
5943     if (mat->nullsp && mat->checknullspaceonassembly) PetscCall(MatNullSpaceTest(mat->nullsp, mat, NULL));
5944   }
5945   inassm--;
5946   PetscFunctionReturn(PETSC_SUCCESS);
5947 }
5948 
5949 // PetscClangLinter pragma disable: -fdoc-section-header-unknown
5950 /*@
5951   MatSetOption - Sets a parameter option for a matrix. Some options
5952   may be specific to certain storage formats.  Some options
5953   determine how values will be inserted (or added). Sorted,
5954   row-oriented input will generally assemble the fastest. The default
5955   is row-oriented.
5956 
5957   Logically Collective for certain operations, such as `MAT_SPD`, not collective for `MAT_ROW_ORIENTED`, see `MatOption`
5958 
5959   Input Parameters:
5960 + mat - the matrix
5961 . op  - the option, one of those listed below (and possibly others),
5962 - flg - turn the option on (`PETSC_TRUE`) or off (`PETSC_FALSE`)
5963 
5964   Options Describing Matrix Structure:
5965 + `MAT_SPD`                         - symmetric positive definite
5966 . `MAT_SYMMETRIC`                   - symmetric in terms of both structure and value
5967 . `MAT_HERMITIAN`                   - transpose is the complex conjugation
5968 . `MAT_STRUCTURALLY_SYMMETRIC`      - symmetric nonzero structure
5969 . `MAT_SYMMETRY_ETERNAL`            - indicates the symmetry (or Hermitian structure) or its absence will persist through any changes to the matrix
5970 . `MAT_STRUCTURAL_SYMMETRY_ETERNAL` - indicates the structural symmetry or its absence will persist through any changes to the matrix
5971 . `MAT_SPD_ETERNAL`                 - indicates the value of `MAT_SPD` (true or false) will persist through any changes to the matrix
5972 
5973    These are not really options of the matrix, they are knowledge about the structure of the matrix that users may provide so that they
5974    do not need to be computed (usually at a high cost)
5975 
5976    Options For Use with `MatSetValues()`:
5977    Insert a logically dense subblock, which can be
5978 . `MAT_ROW_ORIENTED`                - row-oriented (default)
5979 
5980    These options reflect the data you pass in with `MatSetValues()`; it has
5981    nothing to do with how the data is stored internally in the matrix
5982    data structure.
5983 
5984    When (re)assembling a matrix, we can restrict the input for
5985    efficiency/debugging purposes.  These options include
5986 . `MAT_NEW_NONZERO_LOCATIONS`       - additional insertions will be allowed if they generate a new nonzero (slow)
5987 . `MAT_FORCE_DIAGONAL_ENTRIES`      - forces diagonal entries to be allocated
5988 . `MAT_IGNORE_OFF_PROC_ENTRIES`     - drops off-processor entries
5989 . `MAT_NEW_NONZERO_LOCATION_ERR`    - generates an error for new matrix entry
5990 . `MAT_USE_HASH_TABLE`              - uses a hash table to speed up matrix assembly
5991 . `MAT_NO_OFF_PROC_ENTRIES`         - you know each process will only set values for its own rows, will generate an error if
5992         any process sets values for another process. This avoids all reductions in the MatAssembly routines and thus improves
5993         performance for very large process counts.
5994 - `MAT_SUBSET_OFF_PROC_ENTRIES`     - you know that the first assembly after setting this flag will set a superset
5995         of the off-process entries required for all subsequent assemblies. This avoids a rendezvous step in the MatAssembly
5996         functions, instead sending only neighbor messages.
5997 
5998   Level: intermediate
5999 
6000   Notes:
6001   Except for `MAT_UNUSED_NONZERO_LOCATION_ERR` and  `MAT_ROW_ORIENTED` all processes that share the matrix must pass the same value in flg!
6002 
6003   Some options are relevant only for particular matrix types and
6004   are thus ignored by others.  Other options are not supported by
6005   certain matrix types and will generate an error message if set.
6006 
6007   If using Fortran to compute a matrix, one may need to
6008   use the column-oriented option (or convert to the row-oriented
6009   format).
6010 
6011   `MAT_NEW_NONZERO_LOCATIONS` set to `PETSC_FALSE` indicates that any add or insertion
6012   that would generate a new entry in the nonzero structure is instead
6013   ignored.  Thus, if memory has not already been allocated for this particular
6014   data, then the insertion is ignored. For dense matrices, in which
6015   the entire array is allocated, no entries are ever ignored.
6016   Set after the first `MatAssemblyEnd()`. If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
6017 
6018   `MAT_NEW_NONZERO_LOCATION_ERR` set to PETSC_TRUE indicates that any add or insertion
6019   that would generate a new entry in the nonzero structure instead produces
6020   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
6021 
6022   `MAT_NEW_NONZERO_ALLOCATION_ERR` set to `PETSC_TRUE` indicates that any add or insertion
6023   that would generate a new entry that has not been preallocated will
6024   instead produce an error. (Currently supported for `MATAIJ` and `MATBAIJ` formats
6025   only.) This is a useful flag when debugging matrix memory preallocation.
6026   If this option is set, then the `MatAssemblyBegin()`/`MatAssemblyEnd()` processes has one less global reduction
6027 
6028   `MAT_IGNORE_OFF_PROC_ENTRIES` set to `PETSC_TRUE` indicates entries destined for
6029   other processors should be dropped, rather than stashed.
6030   This is useful if you know that the "owning" processor is also
6031   always generating the correct matrix entries, so that PETSc need
6032   not transfer duplicate entries generated on another processor.
6033 
6034   `MAT_USE_HASH_TABLE` indicates that a hash table be used to improve the
6035   searches during matrix assembly. When this flag is set, the hash table
6036   is created during the first matrix assembly. This hash table is
6037   used the next time through, during `MatSetValues()`/`MatSetValuesBlocked()`
6038   to improve the searching of indices. `MAT_NEW_NONZERO_LOCATIONS` flag
6039   should be used with `MAT_USE_HASH_TABLE` flag. This option is currently
6040   supported by `MATMPIBAIJ` format only.
6041 
6042   `MAT_KEEP_NONZERO_PATTERN` indicates when `MatZeroRows()` is called the zeroed entries
6043   are kept in the nonzero structure. This flag is not used for `MatZeroRowsColumns()`
6044 
6045   `MAT_IGNORE_ZERO_ENTRIES` - for `MATAIJ` and `MATIS` matrices this will stop zero values from creating
6046   a zero location in the matrix
6047 
6048   `MAT_USE_INODES` - indicates using inode version of the code - works with `MATAIJ` matrix types
6049 
6050   `MAT_NO_OFF_PROC_ZERO_ROWS` - you know each process will only zero its own rows. This avoids all reductions in the
6051   zero row routines and thus improves performance for very large process counts.
6052 
6053   `MAT_IGNORE_LOWER_TRIANGULAR` - For `MATSBAIJ` matrices will ignore any insertions you make in the lower triangular
6054   part of the matrix (since they should match the upper triangular part).
6055 
6056   `MAT_SORTED_FULL` - each process provides exactly its local rows; all column indices for a given row are passed in a
6057   single call to `MatSetValues()`, preallocation is perfect, row-oriented, `INSERT_VALUES` is used. Common
6058   with finite difference schemes with non-periodic boundary conditions.
6059 
6060   Developer Note:
6061   `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, and `MAT_SPD_ETERNAL` are used by `MatAssemblyEnd()` and in other
6062   places where otherwise the value of `MAT_SYMMETRIC`, `MAT_STRUCTURALLY_SYMMETRIC` or `MAT_SPD` would need to be changed back
6063   to `PETSC_BOOL3_UNKNOWN` because the matrix values had changed so the code cannot be certain that the related property had
6064   not changed.
6065 
6066 .seealso: [](ch_matrices), `MatOption`, `Mat`, `MatGetOption()`
6067 @*/
6068 PetscErrorCode MatSetOption(Mat mat, MatOption op, PetscBool flg)
6069 {
6070   PetscFunctionBegin;
6071   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6072   if (op > 0) {
6073     PetscValidLogicalCollectiveEnum(mat, op, 2);
6074     PetscValidLogicalCollectiveBool(mat, flg, 3);
6075   }
6076 
6077   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);
6078 
6079   switch (op) {
6080   case MAT_FORCE_DIAGONAL_ENTRIES:
6081     mat->force_diagonals = flg;
6082     PetscFunctionReturn(PETSC_SUCCESS);
6083   case MAT_NO_OFF_PROC_ENTRIES:
6084     mat->nooffprocentries = flg;
6085     PetscFunctionReturn(PETSC_SUCCESS);
6086   case MAT_SUBSET_OFF_PROC_ENTRIES:
6087     mat->assembly_subset = flg;
6088     if (!mat->assembly_subset) { /* See the same logic in VecAssembly wrt VEC_SUBSET_OFF_PROC_ENTRIES */
6089 #if !defined(PETSC_HAVE_MPIUNI)
6090       PetscCall(MatStashScatterDestroy_BTS(&mat->stash));
6091 #endif
6092       mat->stash.first_assembly_done = PETSC_FALSE;
6093     }
6094     PetscFunctionReturn(PETSC_SUCCESS);
6095   case MAT_NO_OFF_PROC_ZERO_ROWS:
6096     mat->nooffproczerorows = flg;
6097     PetscFunctionReturn(PETSC_SUCCESS);
6098   case MAT_SPD:
6099     if (flg) {
6100       mat->spd                    = PETSC_BOOL3_TRUE;
6101       mat->symmetric              = PETSC_BOOL3_TRUE;
6102       mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6103     } else {
6104       mat->spd = PETSC_BOOL3_FALSE;
6105     }
6106     break;
6107   case MAT_SYMMETRIC:
6108     mat->symmetric = flg ? PETSC_BOOL3_TRUE : PETSC_BOOL3_FALSE;
6109     if (flg) mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6110 #if !defined(PETSC_USE_COMPLEX)
6111     mat->hermitian = flg ? PETSC_BOOL3_TRUE : PETSC_BOOL3_FALSE;
6112 #endif
6113     break;
6114   case MAT_HERMITIAN:
6115     mat->hermitian = flg ? PETSC_BOOL3_TRUE : PETSC_BOOL3_FALSE;
6116     if (flg) mat->structurally_symmetric = PETSC_BOOL3_TRUE;
6117 #if !defined(PETSC_USE_COMPLEX)
6118     mat->symmetric = flg ? PETSC_BOOL3_TRUE : PETSC_BOOL3_FALSE;
6119 #endif
6120     break;
6121   case MAT_STRUCTURALLY_SYMMETRIC:
6122     mat->structurally_symmetric = flg ? PETSC_BOOL3_TRUE : PETSC_BOOL3_FALSE;
6123     break;
6124   case MAT_SYMMETRY_ETERNAL:
6125     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");
6126     mat->symmetry_eternal = flg;
6127     if (flg) mat->structural_symmetry_eternal = PETSC_TRUE;
6128     break;
6129   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
6130     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");
6131     mat->structural_symmetry_eternal = flg;
6132     break;
6133   case MAT_SPD_ETERNAL:
6134     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");
6135     mat->spd_eternal = flg;
6136     if (flg) {
6137       mat->structural_symmetry_eternal = PETSC_TRUE;
6138       mat->symmetry_eternal            = PETSC_TRUE;
6139     }
6140     break;
6141   case MAT_STRUCTURE_ONLY:
6142     mat->structure_only = flg;
6143     break;
6144   case MAT_SORTED_FULL:
6145     mat->sortedfull = flg;
6146     break;
6147   default:
6148     break;
6149   }
6150   PetscTryTypeMethod(mat, setoption, op, flg);
6151   PetscFunctionReturn(PETSC_SUCCESS);
6152 }
6153 
6154 /*@
6155   MatGetOption - Gets a parameter option that has been set for a matrix.
6156 
6157   Logically Collective
6158 
6159   Input Parameters:
6160 + mat - the matrix
6161 - op  - the option, this only responds to certain options, check the code for which ones
6162 
6163   Output Parameter:
6164 . flg - turn the option on (`PETSC_TRUE`) or off (`PETSC_FALSE`)
6165 
6166   Level: intermediate
6167 
6168   Notes:
6169   Can only be called after `MatSetSizes()` and `MatSetType()` have been set.
6170 
6171   Certain option values may be unknown, for those use the routines `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, or
6172   `MatIsSymmetricKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
6173 
6174 .seealso: [](ch_matrices), `Mat`, `MatOption`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`,
6175     `MatIsSymmetricKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
6176 @*/
6177 PetscErrorCode MatGetOption(Mat mat, MatOption op, PetscBool *flg)
6178 {
6179   PetscFunctionBegin;
6180   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6181   PetscValidType(mat, 1);
6182 
6183   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);
6184   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()");
6185 
6186   switch (op) {
6187   case MAT_NO_OFF_PROC_ENTRIES:
6188     *flg = mat->nooffprocentries;
6189     break;
6190   case MAT_NO_OFF_PROC_ZERO_ROWS:
6191     *flg = mat->nooffproczerorows;
6192     break;
6193   case MAT_SYMMETRIC:
6194     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsSymmetric() or MatIsSymmetricKnown()");
6195     break;
6196   case MAT_HERMITIAN:
6197     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsHermitian() or MatIsHermitianKnown()");
6198     break;
6199   case MAT_STRUCTURALLY_SYMMETRIC:
6200     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsStructurallySymmetric() or MatIsStructurallySymmetricKnown()");
6201     break;
6202   case MAT_SPD:
6203     SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Use MatIsSPDKnown()");
6204     break;
6205   case MAT_SYMMETRY_ETERNAL:
6206     *flg = mat->symmetry_eternal;
6207     break;
6208   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
6209     *flg = mat->symmetry_eternal;
6210     break;
6211   default:
6212     break;
6213   }
6214   PetscFunctionReturn(PETSC_SUCCESS);
6215 }
6216 
6217 /*@
6218   MatZeroEntries - Zeros all entries of a matrix.  For sparse matrices
6219   this routine retains the old nonzero structure.
6220 
6221   Logically Collective
6222 
6223   Input Parameter:
6224 . mat - the matrix
6225 
6226   Level: intermediate
6227 
6228   Note:
6229   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.
6230   See the Performance chapter of the users manual for information on preallocating matrices.
6231 
6232 .seealso: [](ch_matrices), `Mat`, `MatZeroRows()`, `MatZeroRowsColumns()`
6233 @*/
6234 PetscErrorCode MatZeroEntries(Mat mat)
6235 {
6236   PetscFunctionBegin;
6237   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6238   PetscValidType(mat, 1);
6239   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6240   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");
6241   MatCheckPreallocated(mat, 1);
6242 
6243   PetscCall(PetscLogEventBegin(MAT_ZeroEntries, mat, 0, 0, 0));
6244   PetscUseTypeMethod(mat, zeroentries);
6245   PetscCall(PetscLogEventEnd(MAT_ZeroEntries, mat, 0, 0, 0));
6246   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6247   PetscFunctionReturn(PETSC_SUCCESS);
6248 }
6249 
6250 /*@
6251   MatZeroRowsColumns - Zeros all entries (except possibly the main diagonal)
6252   of a set of rows and columns of a matrix.
6253 
6254   Collective
6255 
6256   Input Parameters:
6257 + mat     - the matrix
6258 . numRows - the number of rows/columns to zero
6259 . rows    - the global row indices
6260 . diag    - value put in the diagonal of the eliminated rows
6261 . x       - optional vector of the solution for zeroed rows (other entries in vector are not used), these must be set before this call
6262 - b       - optional vector of the right-hand side, that will be adjusted by provided solution entries
6263 
6264   Level: intermediate
6265 
6266   Notes:
6267   This routine, along with `MatZeroRows()`, is typically used to eliminate known Dirichlet boundary conditions from a linear system.
6268 
6269   For each zeroed row, the value of the corresponding `b` is set to diag times the value of the corresponding `x`.
6270   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
6271 
6272   If the resulting linear system is to be solved with `KSP` then one can (but does not have to) call `KSPSetInitialGuessNonzero()` to allow the
6273   Krylov method to take advantage of the known solution on the zeroed rows.
6274 
6275   For the parallel case, all processes that share the matrix (i.e.,
6276   those in the communicator used for matrix creation) MUST call this
6277   routine, regardless of whether any rows being zeroed are owned by
6278   them.
6279 
6280   Unlike `MatZeroRows()`, this ignores the `MAT_KEEP_NONZERO_PATTERN` option value set with `MatSetOption()`, it merely zeros those entries in the matrix, but never
6281   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
6282   missing.
6283 
6284   Each processor can indicate any rows in the entire matrix to be zeroed (i.e. each process does NOT have to
6285   list only rows local to itself).
6286 
6287   The option `MAT_NO_OFF_PROC_ZERO_ROWS` does not apply to this routine.
6288 
6289 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRows()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6290           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6291 @*/
6292 PetscErrorCode MatZeroRowsColumns(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6293 {
6294   PetscFunctionBegin;
6295   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6296   PetscValidType(mat, 1);
6297   if (numRows) PetscAssertPointer(rows, 3);
6298   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6299   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6300   MatCheckPreallocated(mat, 1);
6301 
6302   PetscUseTypeMethod(mat, zerorowscolumns, numRows, rows, diag, x, b);
6303   PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
6304   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6305   PetscFunctionReturn(PETSC_SUCCESS);
6306 }
6307 
6308 /*@
6309   MatZeroRowsColumnsIS - Zeros all entries (except possibly the main diagonal)
6310   of a set of rows and columns of a matrix.
6311 
6312   Collective
6313 
6314   Input Parameters:
6315 + mat  - the matrix
6316 . is   - the rows to zero
6317 . diag - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6318 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6319 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6320 
6321   Level: intermediate
6322 
6323   Note:
6324   See `MatZeroRowsColumns()` for details on how this routine operates.
6325 
6326 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6327           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRows()`, `MatZeroRowsColumnsStencil()`
6328 @*/
6329 PetscErrorCode MatZeroRowsColumnsIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6330 {
6331   PetscInt        numRows;
6332   const PetscInt *rows;
6333 
6334   PetscFunctionBegin;
6335   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6336   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6337   PetscValidType(mat, 1);
6338   PetscValidType(is, 2);
6339   PetscCall(ISGetLocalSize(is, &numRows));
6340   PetscCall(ISGetIndices(is, &rows));
6341   PetscCall(MatZeroRowsColumns(mat, numRows, rows, diag, x, b));
6342   PetscCall(ISRestoreIndices(is, &rows));
6343   PetscFunctionReturn(PETSC_SUCCESS);
6344 }
6345 
6346 /*@
6347   MatZeroRows - Zeros all entries (except possibly the main diagonal)
6348   of a set of rows of a matrix.
6349 
6350   Collective
6351 
6352   Input Parameters:
6353 + mat     - the matrix
6354 . numRows - the number of rows to zero
6355 . rows    - the global row indices
6356 . diag    - value put in the diagonal of the zeroed rows
6357 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used), these must be set before this call
6358 - b       - optional vector of right-hand side, that will be adjusted by provided solution entries
6359 
6360   Level: intermediate
6361 
6362   Notes:
6363   This routine, along with `MatZeroRowsColumns()`, is typically used to eliminate known Dirichlet boundary conditions from a linear system.
6364 
6365   For each zeroed row, the value of the corresponding `b` is set to `diag` times the value of the corresponding `x`.
6366 
6367   If the resulting linear system is to be solved with `KSP` then one can (but does not have to) call `KSPSetInitialGuessNonzero()` to allow the
6368   Krylov method to take advantage of the known solution on the zeroed rows.
6369 
6370   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)
6371   from the matrix.
6372 
6373   Unlike `MatZeroRowsColumns()` for the `MATAIJ` and `MATBAIJ` matrix formats this removes the old nonzero structure, from the eliminated rows of the matrix
6374   but does not release memory.  Because of this removal matrix-vector products with the adjusted matrix will be a bit faster. For the dense and block diagonal
6375   formats this does not alter the nonzero structure.
6376 
6377   If the option `MatSetOption`(mat,`MAT_KEEP_NONZERO_PATTERN`,`PETSC_TRUE`) the nonzero structure
6378   of the matrix is not changed the values are
6379   merely zeroed.
6380 
6381   The user can set a value in the diagonal entry (or for the `MATAIJ` format
6382   formats can optionally remove the main diagonal entry from the
6383   nonzero structure as well, by passing 0.0 as the final argument).
6384 
6385   For the parallel case, all processes that share the matrix (i.e.,
6386   those in the communicator used for matrix creation) MUST call this
6387   routine, regardless of whether any rows being zeroed are owned by
6388   them.
6389 
6390   Each processor can indicate any rows in the entire matrix to be zeroed (i.e. each process does NOT have to
6391   list only rows local to itself).
6392 
6393   You can call `MatSetOption`(mat,`MAT_NO_OFF_PROC_ZERO_ROWS`,`PETSC_TRUE`) if each process indicates only rows it
6394   owns that are to be zeroed. This saves a global synchronization in the implementation.
6395 
6396 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6397           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`, `PCREDISTRIBUTE`, `MAT_KEEP_NONZERO_PATTERN`
6398 @*/
6399 PetscErrorCode MatZeroRows(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6400 {
6401   PetscFunctionBegin;
6402   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6403   PetscValidType(mat, 1);
6404   if (numRows) PetscAssertPointer(rows, 3);
6405   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6406   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6407   MatCheckPreallocated(mat, 1);
6408 
6409   PetscUseTypeMethod(mat, zerorows, numRows, rows, diag, x, b);
6410   PetscCall(MatViewFromOptions(mat, NULL, "-mat_view"));
6411   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6412   PetscFunctionReturn(PETSC_SUCCESS);
6413 }
6414 
6415 /*@
6416   MatZeroRowsIS - Zeros all entries (except possibly the main diagonal)
6417   of a set of rows of a matrix.
6418 
6419   Collective
6420 
6421   Input Parameters:
6422 + mat  - the matrix
6423 . is   - index set of rows to remove (if `NULL` then no row is removed)
6424 . diag - value put in all diagonals of eliminated rows
6425 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6426 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6427 
6428   Level: intermediate
6429 
6430   Note:
6431   See `MatZeroRows()` for details on how this routine operates.
6432 
6433 .seealso: [](ch_matrices), `Mat`, `MatZeroRows()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6434           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6435 @*/
6436 PetscErrorCode MatZeroRowsIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6437 {
6438   PetscInt        numRows = 0;
6439   const PetscInt *rows    = NULL;
6440 
6441   PetscFunctionBegin;
6442   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6443   PetscValidType(mat, 1);
6444   if (is) {
6445     PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6446     PetscCall(ISGetLocalSize(is, &numRows));
6447     PetscCall(ISGetIndices(is, &rows));
6448   }
6449   PetscCall(MatZeroRows(mat, numRows, rows, diag, x, b));
6450   if (is) PetscCall(ISRestoreIndices(is, &rows));
6451   PetscFunctionReturn(PETSC_SUCCESS);
6452 }
6453 
6454 /*@
6455   MatZeroRowsStencil - Zeros all entries (except possibly the main diagonal)
6456   of a set of rows of a matrix. These rows must be local to the process.
6457 
6458   Collective
6459 
6460   Input Parameters:
6461 + mat     - the matrix
6462 . numRows - the number of rows to remove
6463 . rows    - the grid coordinates (and component number when dof > 1) for matrix rows
6464 . diag    - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6465 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6466 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6467 
6468   Level: intermediate
6469 
6470   Notes:
6471   See `MatZeroRows()` for details on how this routine operates.
6472 
6473   The grid coordinates are across the entire grid, not just the local portion
6474 
6475   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
6476   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
6477   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
6478   `DM_BOUNDARY_PERIODIC` boundary type.
6479 
6480   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
6481   a single value per point) you can skip filling those indices.
6482 
6483   Fortran Note:
6484   `idxm` and `idxn` should be declared as
6485 $     MatStencil idxm(4, m)
6486   and the values inserted using
6487 .vb
6488     idxm(MatStencil_i, 1) = i
6489     idxm(MatStencil_j, 1) = j
6490     idxm(MatStencil_k, 1) = k
6491     idxm(MatStencil_c, 1) = c
6492    etc
6493 .ve
6494 
6495 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRows()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6496           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6497 @*/
6498 PetscErrorCode MatZeroRowsStencil(Mat mat, PetscInt numRows, const MatStencil rows[], PetscScalar diag, Vec x, Vec b)
6499 {
6500   PetscInt  dim    = mat->stencil.dim;
6501   PetscInt  sdim   = dim - (1 - (PetscInt)mat->stencil.noc);
6502   PetscInt *dims   = mat->stencil.dims + 1;
6503   PetscInt *starts = mat->stencil.starts;
6504   PetscInt *dxm    = (PetscInt *)rows;
6505   PetscInt *jdxm, i, j, tmp, numNewRows = 0;
6506 
6507   PetscFunctionBegin;
6508   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6509   PetscValidType(mat, 1);
6510   if (numRows) PetscAssertPointer(rows, 3);
6511 
6512   PetscCall(PetscMalloc1(numRows, &jdxm));
6513   for (i = 0; i < numRows; ++i) {
6514     /* Skip unused dimensions (they are ordered k, j, i, c) */
6515     for (j = 0; j < 3 - sdim; ++j) dxm++;
6516     /* Local index in X dir */
6517     tmp = *dxm++ - starts[0];
6518     /* Loop over remaining dimensions */
6519     for (j = 0; j < dim - 1; ++j) {
6520       /* If nonlocal, set index to be negative */
6521       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = PETSC_INT_MIN;
6522       /* Update local index */
6523       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
6524     }
6525     /* Skip component slot if necessary */
6526     if (mat->stencil.noc) dxm++;
6527     /* Local row number */
6528     if (tmp >= 0) jdxm[numNewRows++] = tmp;
6529   }
6530   PetscCall(MatZeroRowsLocal(mat, numNewRows, jdxm, diag, x, b));
6531   PetscCall(PetscFree(jdxm));
6532   PetscFunctionReturn(PETSC_SUCCESS);
6533 }
6534 
6535 /*@
6536   MatZeroRowsColumnsStencil - Zeros all row and column entries (except possibly the main diagonal)
6537   of a set of rows and columns of a matrix.
6538 
6539   Collective
6540 
6541   Input Parameters:
6542 + mat     - the matrix
6543 . numRows - the number of rows/columns to remove
6544 . rows    - the grid coordinates (and component number when dof > 1) for matrix rows
6545 . diag    - value put in all diagonals of eliminated rows (0.0 will even eliminate diagonal entry)
6546 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6547 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6548 
6549   Level: intermediate
6550 
6551   Notes:
6552   See `MatZeroRowsColumns()` for details on how this routine operates.
6553 
6554   The grid coordinates are across the entire grid, not just the local portion
6555 
6556   For periodic boundary conditions use negative indices for values to the left (below 0; that are to be
6557   obtained by wrapping values from right edge). For values to the right of the last entry using that index plus one
6558   etc to obtain values that obtained by wrapping the values from the left edge. This does not work for anything but the
6559   `DM_BOUNDARY_PERIODIC` boundary type.
6560 
6561   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
6562   a single value per point) you can skip filling those indices.
6563 
6564   Fortran Note:
6565   `idxm` and `idxn` should be declared as
6566 $     MatStencil idxm(4, m)
6567   and the values inserted using
6568 .vb
6569     idxm(MatStencil_i, 1) = i
6570     idxm(MatStencil_j, 1) = j
6571     idxm(MatStencil_k, 1) = k
6572     idxm(MatStencil_c, 1) = c
6573     etc
6574 .ve
6575 
6576 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6577           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRows()`
6578 @*/
6579 PetscErrorCode MatZeroRowsColumnsStencil(Mat mat, PetscInt numRows, const MatStencil rows[], PetscScalar diag, Vec x, Vec b)
6580 {
6581   PetscInt  dim    = mat->stencil.dim;
6582   PetscInt  sdim   = dim - (1 - (PetscInt)mat->stencil.noc);
6583   PetscInt *dims   = mat->stencil.dims + 1;
6584   PetscInt *starts = mat->stencil.starts;
6585   PetscInt *dxm    = (PetscInt *)rows;
6586   PetscInt *jdxm, i, j, tmp, numNewRows = 0;
6587 
6588   PetscFunctionBegin;
6589   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6590   PetscValidType(mat, 1);
6591   if (numRows) PetscAssertPointer(rows, 3);
6592 
6593   PetscCall(PetscMalloc1(numRows, &jdxm));
6594   for (i = 0; i < numRows; ++i) {
6595     /* Skip unused dimensions (they are ordered k, j, i, c) */
6596     for (j = 0; j < 3 - sdim; ++j) dxm++;
6597     /* Local index in X dir */
6598     tmp = *dxm++ - starts[0];
6599     /* Loop over remaining dimensions */
6600     for (j = 0; j < dim - 1; ++j) {
6601       /* If nonlocal, set index to be negative */
6602       if ((*dxm++ - starts[j + 1]) < 0 || tmp < 0) tmp = PETSC_INT_MIN;
6603       /* Update local index */
6604       else tmp = tmp * dims[j] + *(dxm - 1) - starts[j + 1];
6605     }
6606     /* Skip component slot if necessary */
6607     if (mat->stencil.noc) dxm++;
6608     /* Local row number */
6609     if (tmp >= 0) jdxm[numNewRows++] = tmp;
6610   }
6611   PetscCall(MatZeroRowsColumnsLocal(mat, numNewRows, jdxm, diag, x, b));
6612   PetscCall(PetscFree(jdxm));
6613   PetscFunctionReturn(PETSC_SUCCESS);
6614 }
6615 
6616 /*@
6617   MatZeroRowsLocal - Zeros all entries (except possibly the main diagonal)
6618   of a set of rows of a matrix; using local numbering of rows.
6619 
6620   Collective
6621 
6622   Input Parameters:
6623 + mat     - the matrix
6624 . numRows - the number of rows to remove
6625 . rows    - the local row indices
6626 . diag    - value put in all diagonals of eliminated rows
6627 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6628 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6629 
6630   Level: intermediate
6631 
6632   Notes:
6633   Before calling `MatZeroRowsLocal()`, the user must first set the
6634   local-to-global mapping by calling MatSetLocalToGlobalMapping(), this is often already set for matrices obtained with `DMCreateMatrix()`.
6635 
6636   See `MatZeroRows()` for details on how this routine operates.
6637 
6638 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRows()`, `MatSetOption()`,
6639           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6640 @*/
6641 PetscErrorCode MatZeroRowsLocal(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6642 {
6643   PetscFunctionBegin;
6644   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6645   PetscValidType(mat, 1);
6646   if (numRows) PetscAssertPointer(rows, 3);
6647   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6648   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6649   MatCheckPreallocated(mat, 1);
6650 
6651   if (mat->ops->zerorowslocal) {
6652     PetscUseTypeMethod(mat, zerorowslocal, numRows, rows, diag, x, b);
6653   } else {
6654     IS              is, newis;
6655     const PetscInt *newRows;
6656 
6657     PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Need to provide local to global mapping to matrix first");
6658     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numRows, rows, PETSC_COPY_VALUES, &is));
6659     PetscCall(ISLocalToGlobalMappingApplyIS(mat->rmap->mapping, is, &newis));
6660     PetscCall(ISGetIndices(newis, &newRows));
6661     PetscUseTypeMethod(mat, zerorows, numRows, newRows, diag, x, b);
6662     PetscCall(ISRestoreIndices(newis, &newRows));
6663     PetscCall(ISDestroy(&newis));
6664     PetscCall(ISDestroy(&is));
6665   }
6666   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6667   PetscFunctionReturn(PETSC_SUCCESS);
6668 }
6669 
6670 /*@
6671   MatZeroRowsLocalIS - Zeros all entries (except possibly the main diagonal)
6672   of a set of rows of a matrix; using local numbering of rows.
6673 
6674   Collective
6675 
6676   Input Parameters:
6677 + mat  - the matrix
6678 . is   - index set of rows to remove
6679 . diag - value put in all diagonals of eliminated rows
6680 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6681 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6682 
6683   Level: intermediate
6684 
6685   Notes:
6686   Before calling `MatZeroRowsLocalIS()`, the user must first set the
6687   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6688 
6689   See `MatZeroRows()` for details on how this routine operates.
6690 
6691 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRows()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6692           `MatZeroRowsColumnsLocal()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6693 @*/
6694 PetscErrorCode MatZeroRowsLocalIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6695 {
6696   PetscInt        numRows;
6697   const PetscInt *rows;
6698 
6699   PetscFunctionBegin;
6700   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6701   PetscValidType(mat, 1);
6702   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6703   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6704   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6705   MatCheckPreallocated(mat, 1);
6706 
6707   PetscCall(ISGetLocalSize(is, &numRows));
6708   PetscCall(ISGetIndices(is, &rows));
6709   PetscCall(MatZeroRowsLocal(mat, numRows, rows, diag, x, b));
6710   PetscCall(ISRestoreIndices(is, &rows));
6711   PetscFunctionReturn(PETSC_SUCCESS);
6712 }
6713 
6714 /*@
6715   MatZeroRowsColumnsLocal - Zeros all entries (except possibly the main diagonal)
6716   of a set of rows and columns of a matrix; using local numbering of rows.
6717 
6718   Collective
6719 
6720   Input Parameters:
6721 + mat     - the matrix
6722 . numRows - the number of rows to remove
6723 . rows    - the global row indices
6724 . diag    - value put in all diagonals of eliminated rows
6725 . x       - optional vector of solutions for zeroed rows (other entries in vector are not used)
6726 - b       - optional vector of right-hand side, that will be adjusted by provided solution
6727 
6728   Level: intermediate
6729 
6730   Notes:
6731   Before calling `MatZeroRowsColumnsLocal()`, the user must first set the
6732   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6733 
6734   See `MatZeroRowsColumns()` for details on how this routine operates.
6735 
6736 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6737           `MatZeroRows()`, `MatZeroRowsColumnsLocalIS()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6738 @*/
6739 PetscErrorCode MatZeroRowsColumnsLocal(Mat mat, PetscInt numRows, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
6740 {
6741   IS              is, newis;
6742   const PetscInt *newRows;
6743 
6744   PetscFunctionBegin;
6745   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6746   PetscValidType(mat, 1);
6747   if (numRows) PetscAssertPointer(rows, 3);
6748   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6749   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6750   MatCheckPreallocated(mat, 1);
6751 
6752   PetscCheck(mat->cmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Need to provide local to global mapping to matrix first");
6753   PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numRows, rows, PETSC_COPY_VALUES, &is));
6754   PetscCall(ISLocalToGlobalMappingApplyIS(mat->cmap->mapping, is, &newis));
6755   PetscCall(ISGetIndices(newis, &newRows));
6756   PetscUseTypeMethod(mat, zerorowscolumns, numRows, newRows, diag, x, b);
6757   PetscCall(ISRestoreIndices(newis, &newRows));
6758   PetscCall(ISDestroy(&newis));
6759   PetscCall(ISDestroy(&is));
6760   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
6761   PetscFunctionReturn(PETSC_SUCCESS);
6762 }
6763 
6764 /*@
6765   MatZeroRowsColumnsLocalIS - Zeros all entries (except possibly the main diagonal)
6766   of a set of rows and columns of a matrix; using local numbering of rows.
6767 
6768   Collective
6769 
6770   Input Parameters:
6771 + mat  - the matrix
6772 . is   - index set of rows to remove
6773 . diag - value put in all diagonals of eliminated rows
6774 . x    - optional vector of solutions for zeroed rows (other entries in vector are not used)
6775 - b    - optional vector of right-hand side, that will be adjusted by provided solution
6776 
6777   Level: intermediate
6778 
6779   Notes:
6780   Before calling `MatZeroRowsColumnsLocalIS()`, the user must first set the
6781   local-to-global mapping by calling `MatSetLocalToGlobalMapping()`, this is often already set for matrices obtained with `DMCreateMatrix()`.
6782 
6783   See `MatZeroRowsColumns()` for details on how this routine operates.
6784 
6785 .seealso: [](ch_matrices), `Mat`, `MatZeroRowsIS()`, `MatZeroRowsColumns()`, `MatZeroRowsLocalIS()`, `MatZeroRowsStencil()`, `MatZeroEntries()`, `MatZeroRowsLocal()`, `MatSetOption()`,
6786           `MatZeroRowsColumnsLocal()`, `MatZeroRows()`, `MatZeroRowsColumnsIS()`, `MatZeroRowsColumnsStencil()`
6787 @*/
6788 PetscErrorCode MatZeroRowsColumnsLocalIS(Mat mat, IS is, PetscScalar diag, Vec x, Vec b)
6789 {
6790   PetscInt        numRows;
6791   const PetscInt *rows;
6792 
6793   PetscFunctionBegin;
6794   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6795   PetscValidType(mat, 1);
6796   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
6797   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
6798   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
6799   MatCheckPreallocated(mat, 1);
6800 
6801   PetscCall(ISGetLocalSize(is, &numRows));
6802   PetscCall(ISGetIndices(is, &rows));
6803   PetscCall(MatZeroRowsColumnsLocal(mat, numRows, rows, diag, x, b));
6804   PetscCall(ISRestoreIndices(is, &rows));
6805   PetscFunctionReturn(PETSC_SUCCESS);
6806 }
6807 
6808 /*@
6809   MatGetSize - Returns the numbers of rows and columns in a matrix.
6810 
6811   Not Collective
6812 
6813   Input Parameter:
6814 . mat - the matrix
6815 
6816   Output Parameters:
6817 + m - the number of global rows
6818 - n - the number of global columns
6819 
6820   Level: beginner
6821 
6822   Note:
6823   Both output parameters can be `NULL` on input.
6824 
6825 .seealso: [](ch_matrices), `Mat`, `MatSetSizes()`, `MatGetLocalSize()`
6826 @*/
6827 PetscErrorCode MatGetSize(Mat mat, PetscInt *m, PetscInt *n)
6828 {
6829   PetscFunctionBegin;
6830   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6831   if (m) *m = mat->rmap->N;
6832   if (n) *n = mat->cmap->N;
6833   PetscFunctionReturn(PETSC_SUCCESS);
6834 }
6835 
6836 /*@
6837   MatGetLocalSize - For most matrix formats, excluding `MATELEMENTAL` and `MATSCALAPACK`, Returns the number of local rows and local columns
6838   of a matrix. For all matrices this is the local size of the left and right vectors as returned by `MatCreateVecs()`.
6839 
6840   Not Collective
6841 
6842   Input Parameter:
6843 . mat - the matrix
6844 
6845   Output Parameters:
6846 + m - the number of local rows, use `NULL` to not obtain this value
6847 - n - the number of local columns, use `NULL` to not obtain this value
6848 
6849   Level: beginner
6850 
6851 .seealso: [](ch_matrices), `Mat`, `MatSetSizes()`, `MatGetSize()`
6852 @*/
6853 PetscErrorCode MatGetLocalSize(Mat mat, PetscInt *m, PetscInt *n)
6854 {
6855   PetscFunctionBegin;
6856   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6857   if (m) PetscAssertPointer(m, 2);
6858   if (n) PetscAssertPointer(n, 3);
6859   if (m) *m = mat->rmap->n;
6860   if (n) *n = mat->cmap->n;
6861   PetscFunctionReturn(PETSC_SUCCESS);
6862 }
6863 
6864 /*@
6865   MatGetOwnershipRangeColumn - Returns the range of matrix columns associated with rows of a
6866   vector one multiplies this matrix by that are owned by this processor.
6867 
6868   Not Collective, unless matrix has not been allocated, then collective
6869 
6870   Input Parameter:
6871 . mat - the matrix
6872 
6873   Output Parameters:
6874 + m - the global index of the first local column, use `NULL` to not obtain this value
6875 - n - one more than the global index of the last local column, use `NULL` to not obtain this value
6876 
6877   Level: developer
6878 
6879   Notes:
6880   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6881 
6882   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6883   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6884 
6885   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6886   the local values in the matrix.
6887 
6888   Returns the columns of the "diagonal block" for most sparse matrix formats. See [Matrix
6889   Layouts](sec_matlayout) for details on matrix layouts.
6890 
6891 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`,
6892           `MatSetSizes()`, `MatCreateAIJ()`, `DMDAGetGhostCorners()`, `DM`
6893 @*/
6894 PetscErrorCode MatGetOwnershipRangeColumn(Mat mat, PetscInt *m, PetscInt *n)
6895 {
6896   PetscFunctionBegin;
6897   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6898   PetscValidType(mat, 1);
6899   if (m) PetscAssertPointer(m, 2);
6900   if (n) PetscAssertPointer(n, 3);
6901   MatCheckPreallocated(mat, 1);
6902   if (m) *m = mat->cmap->rstart;
6903   if (n) *n = mat->cmap->rend;
6904   PetscFunctionReturn(PETSC_SUCCESS);
6905 }
6906 
6907 /*@
6908   MatGetOwnershipRange - For matrices that own values by row, excludes `MATELEMENTAL` and `MATSCALAPACK`, returns the range of matrix rows owned by
6909   this MPI process.
6910 
6911   Not Collective
6912 
6913   Input Parameter:
6914 . mat - the matrix
6915 
6916   Output Parameters:
6917 + m - the global index of the first local row, use `NULL` to not obtain this value
6918 - n - one more than the global index of the last local row, use `NULL` to not obtain this value
6919 
6920   Level: beginner
6921 
6922   Notes:
6923   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6924 
6925   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6926   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6927 
6928   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6929   the local values in the matrix.
6930 
6931   The high argument is one more than the last element stored locally.
6932 
6933   For all matrices  it returns the range of matrix rows associated with rows of a vector that
6934   would contain the result of a matrix vector product with this matrix. See [Matrix
6935   Layouts](sec_matlayout) for details on matrix layouts.
6936 
6937 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscSplitOwnership()`,
6938           `PetscSplitOwnershipBlock()`, `PetscLayout`, `MatSetSizes()`, `MatCreateAIJ()`, `DMDAGetGhostCorners()`, `DM`
6939 @*/
6940 PetscErrorCode MatGetOwnershipRange(Mat mat, PetscInt *m, PetscInt *n)
6941 {
6942   PetscFunctionBegin;
6943   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6944   PetscValidType(mat, 1);
6945   if (m) PetscAssertPointer(m, 2);
6946   if (n) PetscAssertPointer(n, 3);
6947   MatCheckPreallocated(mat, 1);
6948   if (m) *m = mat->rmap->rstart;
6949   if (n) *n = mat->rmap->rend;
6950   PetscFunctionReturn(PETSC_SUCCESS);
6951 }
6952 
6953 /*@C
6954   MatGetOwnershipRanges - For matrices that own values by row, excludes `MATELEMENTAL` and
6955   `MATSCALAPACK`, returns the range of matrix rows owned by each process.
6956 
6957   Not Collective, unless matrix has not been allocated
6958 
6959   Input Parameter:
6960 . mat - the matrix
6961 
6962   Output Parameter:
6963 . ranges - start of each processors portion plus one more than the total length at the end, of length `size` + 1
6964            where `size` is the number of MPI processes used by `mat`
6965 
6966   Level: beginner
6967 
6968   Notes:
6969   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
6970 
6971   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
6972   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
6973 
6974   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
6975   the local values in the matrix.
6976 
6977   For all matrices  it returns the ranges of matrix rows associated with rows of a vector that
6978   would contain the result of a matrix vector product with this matrix. See [Matrix
6979   Layouts](sec_matlayout) for details on matrix layouts.
6980 
6981 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`,
6982           `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`, `MatSetSizes()`, `MatCreateAIJ()`,
6983           `DMDAGetGhostCorners()`, `DM`
6984 @*/
6985 PetscErrorCode MatGetOwnershipRanges(Mat mat, const PetscInt *ranges[])
6986 {
6987   PetscFunctionBegin;
6988   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
6989   PetscValidType(mat, 1);
6990   MatCheckPreallocated(mat, 1);
6991   PetscCall(PetscLayoutGetRanges(mat->rmap, ranges));
6992   PetscFunctionReturn(PETSC_SUCCESS);
6993 }
6994 
6995 /*@C
6996   MatGetOwnershipRangesColumn - Returns the ranges of matrix columns associated with rows of a
6997   vector one multiplies this vector by that are owned by each processor.
6998 
6999   Not Collective, unless matrix has not been allocated
7000 
7001   Input Parameter:
7002 . mat - the matrix
7003 
7004   Output Parameter:
7005 . ranges - start of each processors portion plus one more than the total length at the end
7006 
7007   Level: beginner
7008 
7009   Notes:
7010   If the `Mat` was obtained from a `DM` with `DMCreateMatrix()`, then the range values are determined by the specific `DM`.
7011 
7012   If the `Mat` was created directly the range values are determined by the local size passed to `MatSetSizes()` or `MatCreateAIJ()`.
7013   If `PETSC_DECIDE` was passed as the local size, then the vector uses default values for the range using `PetscSplitOwnership()`.
7014 
7015   For certain `DM`, such as `DMDA`, it is better to use `DM` specific routines, such as `DMDAGetGhostCorners()`, to determine
7016   the local values in the matrix.
7017 
7018   Returns the columns of the "diagonal blocks", for most sparse matrix formats. See [Matrix
7019   Layouts](sec_matlayout) for details on matrix layouts.
7020 
7021 .seealso: [](ch_matrices), `Mat`, `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRanges()`,
7022           `PetscSplitOwnership()`, `PetscSplitOwnershipBlock()`, `PetscLayout`, `MatSetSizes()`, `MatCreateAIJ()`,
7023           `DMDAGetGhostCorners()`, `DM`
7024 @*/
7025 PetscErrorCode MatGetOwnershipRangesColumn(Mat mat, const PetscInt *ranges[])
7026 {
7027   PetscFunctionBegin;
7028   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7029   PetscValidType(mat, 1);
7030   MatCheckPreallocated(mat, 1);
7031   PetscCall(PetscLayoutGetRanges(mat->cmap, ranges));
7032   PetscFunctionReturn(PETSC_SUCCESS);
7033 }
7034 
7035 /*@
7036   MatGetOwnershipIS - Get row and column ownership of a matrices' values as index sets.
7037 
7038   Not Collective
7039 
7040   Input Parameter:
7041 . A - matrix
7042 
7043   Output Parameters:
7044 + rows - rows in which this process owns elements, , use `NULL` to not obtain this value
7045 - cols - columns in which this process owns elements, use `NULL` to not obtain this value
7046 
7047   Level: intermediate
7048 
7049   Note:
7050   You should call `ISDestroy()` on the returned `IS`
7051 
7052   For most matrices, excluding `MATELEMENTAL` and `MATSCALAPACK`, this corresponds to values
7053   returned by `MatGetOwnershipRange()`, `MatGetOwnershipRangeColumn()`. For `MATELEMENTAL` and
7054   `MATSCALAPACK` the ownership is more complicated. See [Matrix Layouts](sec_matlayout) for
7055   details on matrix layouts.
7056 
7057 .seealso: [](ch_matrices), `IS`, `Mat`, `MatGetOwnershipRanges()`, `MatSetValues()`, `MATELEMENTAL`, `MATSCALAPACK`
7058 @*/
7059 PetscErrorCode MatGetOwnershipIS(Mat A, IS *rows, IS *cols)
7060 {
7061   PetscErrorCode (*f)(Mat, IS *, IS *);
7062 
7063   PetscFunctionBegin;
7064   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
7065   PetscValidType(A, 1);
7066   MatCheckPreallocated(A, 1);
7067   PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatGetOwnershipIS_C", &f));
7068   if (f) {
7069     PetscCall((*f)(A, rows, cols));
7070   } else { /* Create a standard row-based partition, each process is responsible for ALL columns in their row block */
7071     if (rows) PetscCall(ISCreateStride(PETSC_COMM_SELF, A->rmap->n, A->rmap->rstart, 1, rows));
7072     if (cols) PetscCall(ISCreateStride(PETSC_COMM_SELF, A->cmap->N, 0, 1, cols));
7073   }
7074   PetscFunctionReturn(PETSC_SUCCESS);
7075 }
7076 
7077 /*@
7078   MatILUFactorSymbolic - Performs symbolic ILU factorization of a matrix obtained with `MatGetFactor()`
7079   Uses levels of fill only, not drop tolerance. Use `MatLUFactorNumeric()`
7080   to complete the factorization.
7081 
7082   Collective
7083 
7084   Input Parameters:
7085 + fact - the factorized matrix obtained with `MatGetFactor()`
7086 . mat  - the matrix
7087 . row  - row permutation
7088 . col  - column permutation
7089 - info - structure containing
7090 .vb
7091       levels - number of levels of fill.
7092       expected fill - as ratio of original fill.
7093       1 or 0 - indicating force fill on diagonal (improves robustness for matrices
7094                 missing diagonal entries)
7095 .ve
7096 
7097   Level: developer
7098 
7099   Notes:
7100   See [Matrix Factorization](sec_matfactor) for additional information.
7101 
7102   Most users should employ the `KSP` interface for linear solvers
7103   instead of working directly with matrix algebra routines such as this.
7104   See, e.g., `KSPCreate()`.
7105 
7106   Uses the definition of level of fill as in Y. Saad, {cite}`saad2003`
7107 
7108   Developer Note:
7109   The Fortran interface is not autogenerated as the
7110   interface definition cannot be generated correctly [due to `MatFactorInfo`]
7111 
7112 .seealso: [](ch_matrices), `Mat`, [Matrix Factorization](sec_matfactor), `MatGetFactor()`, `MatLUFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
7113           `MatGetOrdering()`, `MatFactorInfo`
7114 @*/
7115 PetscErrorCode MatILUFactorSymbolic(Mat fact, Mat mat, IS row, IS col, const MatFactorInfo *info)
7116 {
7117   PetscFunctionBegin;
7118   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
7119   PetscValidType(mat, 2);
7120   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 3);
7121   if (col) PetscValidHeaderSpecific(col, IS_CLASSID, 4);
7122   PetscAssertPointer(info, 5);
7123   PetscAssertPointer(fact, 1);
7124   PetscCheck(info->levels >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Levels of fill negative %" PetscInt_FMT, (PetscInt)info->levels);
7125   PetscCheck(info->fill >= 1.0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Expected fill less than 1.0 %g", (double)info->fill);
7126   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7127   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7128   MatCheckPreallocated(mat, 2);
7129 
7130   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_ILUFactorSymbolic, mat, row, col, 0));
7131   PetscUseTypeMethod(fact, ilufactorsymbolic, mat, row, col, info);
7132   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_ILUFactorSymbolic, mat, row, col, 0));
7133   PetscFunctionReturn(PETSC_SUCCESS);
7134 }
7135 
7136 /*@
7137   MatICCFactorSymbolic - Performs symbolic incomplete
7138   Cholesky factorization for a symmetric matrix.  Use
7139   `MatCholeskyFactorNumeric()` to complete the factorization.
7140 
7141   Collective
7142 
7143   Input Parameters:
7144 + fact - the factorized matrix obtained with `MatGetFactor()`
7145 . mat  - the matrix to be factored
7146 . perm - row and column permutation
7147 - info - structure containing
7148 .vb
7149       levels - number of levels of fill.
7150       expected fill - as ratio of original fill.
7151 .ve
7152 
7153   Level: developer
7154 
7155   Notes:
7156   Most users should employ the `KSP` interface for linear solvers
7157   instead of working directly with matrix algebra routines such as this.
7158   See, e.g., `KSPCreate()`.
7159 
7160   This uses the definition of level of fill as in Y. Saad {cite}`saad2003`
7161 
7162   Developer Note:
7163   The Fortran interface is not autogenerated as the
7164   interface definition cannot be generated correctly [due to `MatFactorInfo`]
7165 
7166 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactorNumeric()`, `MatCholeskyFactor()`, `MatFactorInfo`
7167 @*/
7168 PetscErrorCode MatICCFactorSymbolic(Mat fact, Mat mat, IS perm, const MatFactorInfo *info)
7169 {
7170   PetscFunctionBegin;
7171   PetscValidHeaderSpecific(mat, MAT_CLASSID, 2);
7172   PetscValidType(mat, 2);
7173   if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 3);
7174   PetscAssertPointer(info, 4);
7175   PetscAssertPointer(fact, 1);
7176   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7177   PetscCheck(info->levels >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Levels negative %" PetscInt_FMT, (PetscInt)info->levels);
7178   PetscCheck(info->fill >= 1.0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Expected fill less than 1.0 %g", (double)info->fill);
7179   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7180   MatCheckPreallocated(mat, 2);
7181 
7182   if (!fact->trivialsymbolic) PetscCall(PetscLogEventBegin(MAT_ICCFactorSymbolic, mat, perm, 0, 0));
7183   PetscUseTypeMethod(fact, iccfactorsymbolic, mat, perm, info);
7184   if (!fact->trivialsymbolic) PetscCall(PetscLogEventEnd(MAT_ICCFactorSymbolic, mat, perm, 0, 0));
7185   PetscFunctionReturn(PETSC_SUCCESS);
7186 }
7187 
7188 /*@C
7189   MatCreateSubMatrices - Extracts several submatrices from a matrix. If submat
7190   points to an array of valid matrices, they may be reused to store the new
7191   submatrices.
7192 
7193   Collective
7194 
7195   Input Parameters:
7196 + mat   - the matrix
7197 . n     - the number of submatrixes to be extracted (on this processor, may be zero)
7198 . irow  - index set of rows to extract
7199 . icol  - index set of columns to extract
7200 - scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
7201 
7202   Output Parameter:
7203 . submat - the array of submatrices
7204 
7205   Level: advanced
7206 
7207   Notes:
7208   `MatCreateSubMatrices()` can extract ONLY sequential submatrices
7209   (from both sequential and parallel matrices). Use `MatCreateSubMatrix()`
7210   to extract a parallel submatrix.
7211 
7212   Some matrix types place restrictions on the row and column
7213   indices, such as that they be sorted or that they be equal to each other.
7214 
7215   The index sets may not have duplicate entries.
7216 
7217   When extracting submatrices from a parallel matrix, each processor can
7218   form a different submatrix by setting the rows and columns of its
7219   individual index sets according to the local submatrix desired.
7220 
7221   When finished using the submatrices, the user should destroy
7222   them with `MatDestroySubMatrices()`.
7223 
7224   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
7225   original matrix has not changed from that last call to `MatCreateSubMatrices()`.
7226 
7227   This routine creates the matrices in submat; you should NOT create them before
7228   calling it. It also allocates the array of matrix pointers submat.
7229 
7230   For `MATBAIJ` matrices the index sets must respect the block structure, that is if they
7231   request one row/column in a block, they must request all rows/columns that are in
7232   that block. For example, if the block size is 2 you cannot request just row 0 and
7233   column 0.
7234 
7235   Fortran Note:
7236   One must pass in as `submat` a `Mat` array of size at least `n`+1.
7237 
7238 .seealso: [](ch_matrices), `Mat`, `MatDestroySubMatrices()`, `MatCreateSubMatrix()`, `MatGetRow()`, `MatGetDiagonal()`, `MatReuse`
7239 @*/
7240 PetscErrorCode MatCreateSubMatrices(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
7241 {
7242   PetscInt  i;
7243   PetscBool eq;
7244 
7245   PetscFunctionBegin;
7246   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7247   PetscValidType(mat, 1);
7248   if (n) {
7249     PetscAssertPointer(irow, 3);
7250     for (i = 0; i < n; i++) PetscValidHeaderSpecific(irow[i], IS_CLASSID, 3);
7251     PetscAssertPointer(icol, 4);
7252     for (i = 0; i < n; i++) PetscValidHeaderSpecific(icol[i], IS_CLASSID, 4);
7253   }
7254   PetscAssertPointer(submat, 6);
7255   if (n && scall == MAT_REUSE_MATRIX) {
7256     PetscAssertPointer(*submat, 6);
7257     for (i = 0; i < n; i++) PetscValidHeaderSpecific((*submat)[i], MAT_CLASSID, 6);
7258   }
7259   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7260   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7261   MatCheckPreallocated(mat, 1);
7262   PetscCall(PetscLogEventBegin(MAT_CreateSubMats, mat, 0, 0, 0));
7263   PetscUseTypeMethod(mat, createsubmatrices, n, irow, icol, scall, submat);
7264   PetscCall(PetscLogEventEnd(MAT_CreateSubMats, mat, 0, 0, 0));
7265   for (i = 0; i < n; i++) {
7266     (*submat)[i]->factortype = MAT_FACTOR_NONE; /* in case in place factorization was previously done on submatrix */
7267     PetscCall(ISEqualUnsorted(irow[i], icol[i], &eq));
7268     if (eq) PetscCall(MatPropagateSymmetryOptions(mat, (*submat)[i]));
7269 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
7270     if (mat->boundtocpu && mat->bindingpropagates) {
7271       PetscCall(MatBindToCPU((*submat)[i], PETSC_TRUE));
7272       PetscCall(MatSetBindingPropagates((*submat)[i], PETSC_TRUE));
7273     }
7274 #endif
7275   }
7276   PetscFunctionReturn(PETSC_SUCCESS);
7277 }
7278 
7279 /*@C
7280   MatCreateSubMatricesMPI - Extracts MPI submatrices across a sub communicator of mat (by pairs of `IS` that may live on subcomms).
7281 
7282   Collective
7283 
7284   Input Parameters:
7285 + mat   - the matrix
7286 . n     - the number of submatrixes to be extracted
7287 . irow  - index set of rows to extract
7288 . icol  - index set of columns to extract
7289 - scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
7290 
7291   Output Parameter:
7292 . submat - the array of submatrices
7293 
7294   Level: advanced
7295 
7296   Note:
7297   This is used by `PCGASM`
7298 
7299 .seealso: [](ch_matrices), `Mat`, `PCGASM`, `MatCreateSubMatrices()`, `MatCreateSubMatrix()`, `MatGetRow()`, `MatGetDiagonal()`, `MatReuse`
7300 @*/
7301 PetscErrorCode MatCreateSubMatricesMPI(Mat mat, PetscInt n, const IS irow[], const IS icol[], MatReuse scall, Mat *submat[])
7302 {
7303   PetscInt  i;
7304   PetscBool eq;
7305 
7306   PetscFunctionBegin;
7307   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7308   PetscValidType(mat, 1);
7309   if (n) {
7310     PetscAssertPointer(irow, 3);
7311     PetscValidHeaderSpecific(*irow, IS_CLASSID, 3);
7312     PetscAssertPointer(icol, 4);
7313     PetscValidHeaderSpecific(*icol, IS_CLASSID, 4);
7314   }
7315   PetscAssertPointer(submat, 6);
7316   if (n && scall == MAT_REUSE_MATRIX) {
7317     PetscAssertPointer(*submat, 6);
7318     PetscValidHeaderSpecific(**submat, MAT_CLASSID, 6);
7319   }
7320   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7321   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7322   MatCheckPreallocated(mat, 1);
7323 
7324   PetscCall(PetscLogEventBegin(MAT_CreateSubMats, mat, 0, 0, 0));
7325   PetscUseTypeMethod(mat, createsubmatricesmpi, n, irow, icol, scall, submat);
7326   PetscCall(PetscLogEventEnd(MAT_CreateSubMats, mat, 0, 0, 0));
7327   for (i = 0; i < n; i++) {
7328     PetscCall(ISEqualUnsorted(irow[i], icol[i], &eq));
7329     if (eq) PetscCall(MatPropagateSymmetryOptions(mat, (*submat)[i]));
7330   }
7331   PetscFunctionReturn(PETSC_SUCCESS);
7332 }
7333 
7334 /*@C
7335   MatDestroyMatrices - Destroys an array of matrices.
7336 
7337   Collective
7338 
7339   Input Parameters:
7340 + n   - the number of local matrices
7341 - mat - the matrices (this is a pointer to the array of matrices)
7342 
7343   Level: advanced
7344 
7345   Notes:
7346   Frees not only the matrices, but also the array that contains the matrices
7347 
7348   For matrices obtained with  `MatCreateSubMatrices()` use `MatDestroySubMatrices()`
7349 
7350   Fortran Note:
7351   Does not free the `mat` array.
7352 
7353 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatDestroySubMatrices()`
7354 @*/
7355 PetscErrorCode MatDestroyMatrices(PetscInt n, Mat *mat[])
7356 {
7357   PetscInt i;
7358 
7359   PetscFunctionBegin;
7360   if (!*mat) PetscFunctionReturn(PETSC_SUCCESS);
7361   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy negative number of matrices %" PetscInt_FMT, n);
7362   PetscAssertPointer(mat, 2);
7363 
7364   for (i = 0; i < n; i++) PetscCall(MatDestroy(&(*mat)[i]));
7365 
7366   /* memory is allocated even if n = 0 */
7367   PetscCall(PetscFree(*mat));
7368   PetscFunctionReturn(PETSC_SUCCESS);
7369 }
7370 
7371 /*@C
7372   MatDestroySubMatrices - Destroys a set of matrices obtained with `MatCreateSubMatrices()`.
7373 
7374   Collective
7375 
7376   Input Parameters:
7377 + n   - the number of local matrices
7378 - mat - the matrices (this is a pointer to the array of matrices, just to match the calling
7379                        sequence of `MatCreateSubMatrices()`)
7380 
7381   Level: advanced
7382 
7383   Note:
7384   Frees not only the matrices, but also the array that contains the matrices
7385 
7386   Fortran Note:
7387   Does not free the `mat` array.
7388 
7389 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatDestroyMatrices()`
7390 @*/
7391 PetscErrorCode MatDestroySubMatrices(PetscInt n, Mat *mat[])
7392 {
7393   Mat mat0;
7394 
7395   PetscFunctionBegin;
7396   if (!*mat) PetscFunctionReturn(PETSC_SUCCESS);
7397   /* mat[] is an array of length n+1, see MatCreateSubMatrices_xxx() */
7398   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Trying to destroy negative number of matrices %" PetscInt_FMT, n);
7399   PetscAssertPointer(mat, 2);
7400 
7401   mat0 = (*mat)[0];
7402   if (mat0 && mat0->ops->destroysubmatrices) {
7403     PetscCall((*mat0->ops->destroysubmatrices)(n, mat));
7404   } else {
7405     PetscCall(MatDestroyMatrices(n, mat));
7406   }
7407   PetscFunctionReturn(PETSC_SUCCESS);
7408 }
7409 
7410 /*@
7411   MatGetSeqNonzeroStructure - Extracts the nonzero structure from a matrix and stores it, in its entirety, on each process
7412 
7413   Collective
7414 
7415   Input Parameter:
7416 . mat - the matrix
7417 
7418   Output Parameter:
7419 . matstruct - the sequential matrix with the nonzero structure of `mat`
7420 
7421   Level: developer
7422 
7423 .seealso: [](ch_matrices), `Mat`, `MatDestroySeqNonzeroStructure()`, `MatCreateSubMatrices()`, `MatDestroyMatrices()`
7424 @*/
7425 PetscErrorCode MatGetSeqNonzeroStructure(Mat mat, Mat *matstruct)
7426 {
7427   PetscFunctionBegin;
7428   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7429   PetscAssertPointer(matstruct, 2);
7430 
7431   PetscValidType(mat, 1);
7432   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7433   MatCheckPreallocated(mat, 1);
7434 
7435   PetscCall(PetscLogEventBegin(MAT_GetSeqNonzeroStructure, mat, 0, 0, 0));
7436   PetscUseTypeMethod(mat, getseqnonzerostructure, matstruct);
7437   PetscCall(PetscLogEventEnd(MAT_GetSeqNonzeroStructure, mat, 0, 0, 0));
7438   PetscFunctionReturn(PETSC_SUCCESS);
7439 }
7440 
7441 /*@C
7442   MatDestroySeqNonzeroStructure - Destroys matrix obtained with `MatGetSeqNonzeroStructure()`.
7443 
7444   Collective
7445 
7446   Input Parameter:
7447 . mat - the matrix
7448 
7449   Level: advanced
7450 
7451   Note:
7452   This is not needed, one can just call `MatDestroy()`
7453 
7454 .seealso: [](ch_matrices), `Mat`, `MatGetSeqNonzeroStructure()`
7455 @*/
7456 PetscErrorCode MatDestroySeqNonzeroStructure(Mat *mat)
7457 {
7458   PetscFunctionBegin;
7459   PetscAssertPointer(mat, 1);
7460   PetscCall(MatDestroy(mat));
7461   PetscFunctionReturn(PETSC_SUCCESS);
7462 }
7463 
7464 /*@
7465   MatIncreaseOverlap - Given a set of submatrices indicated by index sets,
7466   replaces the index sets by larger ones that represent submatrices with
7467   additional overlap.
7468 
7469   Collective
7470 
7471   Input Parameters:
7472 + mat - the matrix
7473 . n   - the number of index sets
7474 . is  - the array of index sets (these index sets will changed during the call)
7475 - ov  - the additional overlap requested
7476 
7477   Options Database Key:
7478 . -mat_increase_overlap_scalable - use a scalable algorithm to compute the overlap (supported by MPIAIJ matrix)
7479 
7480   Level: developer
7481 
7482   Note:
7483   The computed overlap preserves the matrix block sizes when the blocks are square.
7484   That is: if a matrix nonzero for a given block would increase the overlap all columns associated with
7485   that block are included in the overlap regardless of whether each specific column would increase the overlap.
7486 
7487 .seealso: [](ch_matrices), `Mat`, `PCASM`, `MatSetBlockSize()`, `MatIncreaseOverlapSplit()`, `MatCreateSubMatrices()`
7488 @*/
7489 PetscErrorCode MatIncreaseOverlap(Mat mat, PetscInt n, IS is[], PetscInt ov)
7490 {
7491   PetscInt i, bs, cbs;
7492 
7493   PetscFunctionBegin;
7494   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7495   PetscValidType(mat, 1);
7496   PetscValidLogicalCollectiveInt(mat, n, 2);
7497   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have one or more domains, you have %" PetscInt_FMT, n);
7498   if (n) {
7499     PetscAssertPointer(is, 3);
7500     for (i = 0; i < n; i++) PetscValidHeaderSpecific(is[i], IS_CLASSID, 3);
7501   }
7502   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7503   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7504   MatCheckPreallocated(mat, 1);
7505 
7506   if (!ov || !n) PetscFunctionReturn(PETSC_SUCCESS);
7507   PetscCall(PetscLogEventBegin(MAT_IncreaseOverlap, mat, 0, 0, 0));
7508   PetscUseTypeMethod(mat, increaseoverlap, n, is, ov);
7509   PetscCall(PetscLogEventEnd(MAT_IncreaseOverlap, mat, 0, 0, 0));
7510   PetscCall(MatGetBlockSizes(mat, &bs, &cbs));
7511   if (bs == cbs) {
7512     for (i = 0; i < n; i++) PetscCall(ISSetBlockSize(is[i], bs));
7513   }
7514   PetscFunctionReturn(PETSC_SUCCESS);
7515 }
7516 
7517 PetscErrorCode MatIncreaseOverlapSplit_Single(Mat, IS *, PetscInt);
7518 
7519 /*@
7520   MatIncreaseOverlapSplit - Given a set of submatrices indicated by index sets across
7521   a sub communicator, replaces the index sets by larger ones that represent submatrices with
7522   additional overlap.
7523 
7524   Collective
7525 
7526   Input Parameters:
7527 + mat - the matrix
7528 . n   - the number of index sets
7529 . is  - the array of index sets (these index sets will changed during the call)
7530 - ov  - the additional overlap requested
7531 
7532   `   Options Database Key:
7533 . -mat_increase_overlap_scalable - use a scalable algorithm to compute the overlap (supported by MPIAIJ matrix)
7534 
7535   Level: developer
7536 
7537 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatIncreaseOverlap()`
7538 @*/
7539 PetscErrorCode MatIncreaseOverlapSplit(Mat mat, PetscInt n, IS is[], PetscInt ov)
7540 {
7541   PetscInt i;
7542 
7543   PetscFunctionBegin;
7544   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7545   PetscValidType(mat, 1);
7546   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must have one or more domains, you have %" PetscInt_FMT, n);
7547   if (n) {
7548     PetscAssertPointer(is, 3);
7549     PetscValidHeaderSpecific(*is, IS_CLASSID, 3);
7550   }
7551   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
7552   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
7553   MatCheckPreallocated(mat, 1);
7554   if (!ov) PetscFunctionReturn(PETSC_SUCCESS);
7555   PetscCall(PetscLogEventBegin(MAT_IncreaseOverlap, mat, 0, 0, 0));
7556   for (i = 0; i < n; i++) PetscCall(MatIncreaseOverlapSplit_Single(mat, &is[i], ov));
7557   PetscCall(PetscLogEventEnd(MAT_IncreaseOverlap, mat, 0, 0, 0));
7558   PetscFunctionReturn(PETSC_SUCCESS);
7559 }
7560 
7561 /*@
7562   MatGetBlockSize - Returns the matrix block size.
7563 
7564   Not Collective
7565 
7566   Input Parameter:
7567 . mat - the matrix
7568 
7569   Output Parameter:
7570 . bs - block size
7571 
7572   Level: intermediate
7573 
7574   Notes:
7575   Block row formats are `MATBAIJ` and `MATSBAIJ` ALWAYS have square block storage in the matrix.
7576 
7577   If the block size has not been set yet this routine returns 1.
7578 
7579 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSizes()`
7580 @*/
7581 PetscErrorCode MatGetBlockSize(Mat mat, PetscInt *bs)
7582 {
7583   PetscFunctionBegin;
7584   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7585   PetscAssertPointer(bs, 2);
7586   *bs = PetscAbs(mat->rmap->bs);
7587   PetscFunctionReturn(PETSC_SUCCESS);
7588 }
7589 
7590 /*@
7591   MatGetBlockSizes - Returns the matrix block row and column sizes.
7592 
7593   Not Collective
7594 
7595   Input Parameter:
7596 . mat - the matrix
7597 
7598   Output Parameters:
7599 + rbs - row block size
7600 - cbs - column block size
7601 
7602   Level: intermediate
7603 
7604   Notes:
7605   Block row formats are `MATBAIJ` and `MATSBAIJ` ALWAYS have square block storage in the matrix.
7606   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
7607 
7608   If a block size has not been set yet this routine returns 1.
7609 
7610 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatSetBlockSizes()`
7611 @*/
7612 PetscErrorCode MatGetBlockSizes(Mat mat, PetscInt *rbs, PetscInt *cbs)
7613 {
7614   PetscFunctionBegin;
7615   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7616   if (rbs) PetscAssertPointer(rbs, 2);
7617   if (cbs) PetscAssertPointer(cbs, 3);
7618   if (rbs) *rbs = PetscAbs(mat->rmap->bs);
7619   if (cbs) *cbs = PetscAbs(mat->cmap->bs);
7620   PetscFunctionReturn(PETSC_SUCCESS);
7621 }
7622 
7623 /*@
7624   MatSetBlockSize - Sets the matrix block size.
7625 
7626   Logically Collective
7627 
7628   Input Parameters:
7629 + mat - the matrix
7630 - bs  - block size
7631 
7632   Level: intermediate
7633 
7634   Notes:
7635   Block row formats are `MATBAIJ` and `MATSBAIJ` formats ALWAYS have square block storage in the matrix.
7636   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
7637 
7638   For `MATAIJ` matrix format, this function can be called at a later stage, provided that the specified block size
7639   is compatible with the matrix local sizes.
7640 
7641 .seealso: [](ch_matrices), `Mat`, `MATBAIJ`, `MATSBAIJ`, `MATAIJ`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`
7642 @*/
7643 PetscErrorCode MatSetBlockSize(Mat mat, PetscInt bs)
7644 {
7645   PetscFunctionBegin;
7646   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7647   PetscValidLogicalCollectiveInt(mat, bs, 2);
7648   PetscCall(MatSetBlockSizes(mat, bs, bs));
7649   PetscFunctionReturn(PETSC_SUCCESS);
7650 }
7651 
7652 typedef struct {
7653   PetscInt         n;
7654   IS              *is;
7655   Mat             *mat;
7656   PetscObjectState nonzerostate;
7657   Mat              C;
7658 } EnvelopeData;
7659 
7660 static PetscErrorCode EnvelopeDataDestroy(void **ptr)
7661 {
7662   EnvelopeData *edata = (EnvelopeData *)*ptr;
7663 
7664   PetscFunctionBegin;
7665   for (PetscInt i = 0; i < edata->n; i++) PetscCall(ISDestroy(&edata->is[i]));
7666   PetscCall(PetscFree(edata->is));
7667   PetscCall(PetscFree(edata));
7668   PetscFunctionReturn(PETSC_SUCCESS);
7669 }
7670 
7671 /*@
7672   MatComputeVariableBlockEnvelope - Given a matrix whose nonzeros are in blocks along the diagonal this computes and stores
7673   the sizes of these blocks in the matrix. An individual block may lie over several processes.
7674 
7675   Collective
7676 
7677   Input Parameter:
7678 . mat - the matrix
7679 
7680   Level: intermediate
7681 
7682   Notes:
7683   There can be zeros within the blocks
7684 
7685   The blocks can overlap between processes, including laying on more than two processes
7686 
7687 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatSetVariableBlockSizes()`
7688 @*/
7689 PetscErrorCode MatComputeVariableBlockEnvelope(Mat mat)
7690 {
7691   PetscInt           n, *sizes, *starts, i = 0, env = 0, tbs = 0, lblocks = 0, rstart, II, ln = 0, cnt = 0, cstart, cend;
7692   PetscInt          *diag, *odiag, sc;
7693   VecScatter         scatter;
7694   PetscScalar       *seqv;
7695   const PetscScalar *parv;
7696   const PetscInt    *ia, *ja;
7697   PetscBool          set, flag, done;
7698   Mat                AA = mat, A;
7699   MPI_Comm           comm;
7700   PetscMPIInt        rank, size, tag;
7701   MPI_Status         status;
7702   PetscContainer     container;
7703   EnvelopeData      *edata;
7704   Vec                seq, par;
7705   IS                 isglobal;
7706 
7707   PetscFunctionBegin;
7708   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7709   PetscCall(MatIsSymmetricKnown(mat, &set, &flag));
7710   if (!set || !flag) {
7711     /* TODO: only needs nonzero structure of transpose */
7712     PetscCall(MatTranspose(mat, MAT_INITIAL_MATRIX, &AA));
7713     PetscCall(MatAXPY(AA, 1.0, mat, DIFFERENT_NONZERO_PATTERN));
7714   }
7715   PetscCall(MatAIJGetLocalMat(AA, &A));
7716   PetscCall(MatGetRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ia, &ja, &done));
7717   PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Unable to get IJ structure from matrix");
7718 
7719   PetscCall(MatGetLocalSize(mat, &n, NULL));
7720   PetscCall(PetscObjectGetNewTag((PetscObject)mat, &tag));
7721   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
7722   PetscCallMPI(MPI_Comm_size(comm, &size));
7723   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7724 
7725   PetscCall(PetscMalloc2(n, &sizes, n, &starts));
7726 
7727   if (rank > 0) {
7728     PetscCallMPI(MPI_Recv(&env, 1, MPIU_INT, rank - 1, tag, comm, &status));
7729     PetscCallMPI(MPI_Recv(&tbs, 1, MPIU_INT, rank - 1, tag, comm, &status));
7730   }
7731   PetscCall(MatGetOwnershipRange(mat, &rstart, NULL));
7732   for (i = 0; i < n; i++) {
7733     env = PetscMax(env, ja[ia[i + 1] - 1]);
7734     II  = rstart + i;
7735     if (env == II) {
7736       starts[lblocks]  = tbs;
7737       sizes[lblocks++] = 1 + II - tbs;
7738       tbs              = 1 + II;
7739     }
7740   }
7741   if (rank < size - 1) {
7742     PetscCallMPI(MPI_Send(&env, 1, MPIU_INT, rank + 1, tag, comm));
7743     PetscCallMPI(MPI_Send(&tbs, 1, MPIU_INT, rank + 1, tag, comm));
7744   }
7745 
7746   PetscCall(MatRestoreRowIJ(A, 0, PETSC_FALSE, PETSC_FALSE, &n, &ia, &ja, &done));
7747   if (!set || !flag) PetscCall(MatDestroy(&AA));
7748   PetscCall(MatDestroy(&A));
7749 
7750   PetscCall(PetscNew(&edata));
7751   PetscCall(MatGetNonzeroState(mat, &edata->nonzerostate));
7752   edata->n = lblocks;
7753   /* create IS needed for extracting blocks from the original matrix */
7754   PetscCall(PetscMalloc1(lblocks, &edata->is));
7755   for (PetscInt i = 0; i < lblocks; i++) PetscCall(ISCreateStride(PETSC_COMM_SELF, sizes[i], starts[i], 1, &edata->is[i]));
7756 
7757   /* Create the resulting inverse matrix structure with preallocation information */
7758   PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &edata->C));
7759   PetscCall(MatSetSizes(edata->C, mat->rmap->n, mat->cmap->n, mat->rmap->N, mat->cmap->N));
7760   PetscCall(MatSetBlockSizesFromMats(edata->C, mat, mat));
7761   PetscCall(MatSetType(edata->C, MATAIJ));
7762 
7763   /* Communicate the start and end of each row, from each block to the correct rank */
7764   /* TODO: Use PetscSF instead of VecScatter */
7765   for (PetscInt i = 0; i < lblocks; i++) ln += sizes[i];
7766   PetscCall(VecCreateSeq(PETSC_COMM_SELF, 2 * ln, &seq));
7767   PetscCall(VecGetArrayWrite(seq, &seqv));
7768   for (PetscInt i = 0; i < lblocks; i++) {
7769     for (PetscInt j = 0; j < sizes[i]; j++) {
7770       seqv[cnt]     = starts[i];
7771       seqv[cnt + 1] = starts[i] + sizes[i];
7772       cnt += 2;
7773     }
7774   }
7775   PetscCall(VecRestoreArrayWrite(seq, &seqv));
7776   PetscCallMPI(MPI_Scan(&cnt, &sc, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)mat)));
7777   sc -= cnt;
7778   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)mat), 2 * mat->rmap->n, 2 * mat->rmap->N, &par));
7779   PetscCall(ISCreateStride(PETSC_COMM_SELF, cnt, sc, 1, &isglobal));
7780   PetscCall(VecScatterCreate(seq, NULL, par, isglobal, &scatter));
7781   PetscCall(ISDestroy(&isglobal));
7782   PetscCall(VecScatterBegin(scatter, seq, par, INSERT_VALUES, SCATTER_FORWARD));
7783   PetscCall(VecScatterEnd(scatter, seq, par, INSERT_VALUES, SCATTER_FORWARD));
7784   PetscCall(VecScatterDestroy(&scatter));
7785   PetscCall(VecDestroy(&seq));
7786   PetscCall(MatGetOwnershipRangeColumn(mat, &cstart, &cend));
7787   PetscCall(PetscMalloc2(mat->rmap->n, &diag, mat->rmap->n, &odiag));
7788   PetscCall(VecGetArrayRead(par, &parv));
7789   cnt = 0;
7790   PetscCall(MatGetSize(mat, NULL, &n));
7791   for (PetscInt i = 0; i < mat->rmap->n; i++) {
7792     PetscInt start, end, d = 0, od = 0;
7793 
7794     start = (PetscInt)PetscRealPart(parv[cnt]);
7795     end   = (PetscInt)PetscRealPart(parv[cnt + 1]);
7796     cnt += 2;
7797 
7798     if (start < cstart) {
7799       od += cstart - start + n - cend;
7800       d += cend - cstart;
7801     } else if (start < cend) {
7802       od += n - cend;
7803       d += cend - start;
7804     } else od += n - start;
7805     if (end <= cstart) {
7806       od -= cstart - end + n - cend;
7807       d -= cend - cstart;
7808     } else if (end < cend) {
7809       od -= n - cend;
7810       d -= cend - end;
7811     } else od -= n - end;
7812 
7813     odiag[i] = od;
7814     diag[i]  = d;
7815   }
7816   PetscCall(VecRestoreArrayRead(par, &parv));
7817   PetscCall(VecDestroy(&par));
7818   PetscCall(MatXAIJSetPreallocation(edata->C, mat->rmap->bs, diag, odiag, NULL, NULL));
7819   PetscCall(PetscFree2(diag, odiag));
7820   PetscCall(PetscFree2(sizes, starts));
7821 
7822   PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container));
7823   PetscCall(PetscContainerSetPointer(container, edata));
7824   PetscCall(PetscContainerSetCtxDestroy(container, EnvelopeDataDestroy));
7825   PetscCall(PetscObjectCompose((PetscObject)mat, "EnvelopeData", (PetscObject)container));
7826   PetscCall(PetscObjectDereference((PetscObject)container));
7827   PetscFunctionReturn(PETSC_SUCCESS);
7828 }
7829 
7830 /*@
7831   MatInvertVariableBlockEnvelope - set matrix C to be the inverted block diagonal of matrix A
7832 
7833   Collective
7834 
7835   Input Parameters:
7836 + A     - the matrix
7837 - reuse - indicates if the `C` matrix was obtained from a previous call to this routine
7838 
7839   Output Parameter:
7840 . C - matrix with inverted block diagonal of `A`
7841 
7842   Level: advanced
7843 
7844   Note:
7845   For efficiency the matrix `A` should have all the nonzero entries clustered in smallish blocks along the diagonal.
7846 
7847 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatComputeBlockDiagonal()`
7848 @*/
7849 PetscErrorCode MatInvertVariableBlockEnvelope(Mat A, MatReuse reuse, Mat *C)
7850 {
7851   PetscContainer   container;
7852   EnvelopeData    *edata;
7853   PetscObjectState nonzerostate;
7854 
7855   PetscFunctionBegin;
7856   PetscCall(PetscObjectQuery((PetscObject)A, "EnvelopeData", (PetscObject *)&container));
7857   if (!container) {
7858     PetscCall(MatComputeVariableBlockEnvelope(A));
7859     PetscCall(PetscObjectQuery((PetscObject)A, "EnvelopeData", (PetscObject *)&container));
7860   }
7861   PetscCall(PetscContainerGetPointer(container, (void **)&edata));
7862   PetscCall(MatGetNonzeroState(A, &nonzerostate));
7863   PetscCheck(nonzerostate <= edata->nonzerostate, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Cannot handle changes to matrix nonzero structure");
7864   PetscCheck(reuse != MAT_REUSE_MATRIX || *C == edata->C, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "C matrix must be the same as previously output");
7865 
7866   PetscCall(MatCreateSubMatrices(A, edata->n, edata->is, edata->is, MAT_INITIAL_MATRIX, &edata->mat));
7867   *C = edata->C;
7868 
7869   for (PetscInt i = 0; i < edata->n; i++) {
7870     Mat          D;
7871     PetscScalar *dvalues;
7872 
7873     PetscCall(MatConvert(edata->mat[i], MATSEQDENSE, MAT_INITIAL_MATRIX, &D));
7874     PetscCall(MatSetOption(*C, MAT_ROW_ORIENTED, PETSC_FALSE));
7875     PetscCall(MatSeqDenseInvert(D));
7876     PetscCall(MatDenseGetArray(D, &dvalues));
7877     PetscCall(MatSetValuesIS(*C, edata->is[i], edata->is[i], dvalues, INSERT_VALUES));
7878     PetscCall(MatDestroy(&D));
7879   }
7880   PetscCall(MatDestroySubMatrices(edata->n, &edata->mat));
7881   PetscCall(MatAssemblyBegin(*C, MAT_FINAL_ASSEMBLY));
7882   PetscCall(MatAssemblyEnd(*C, MAT_FINAL_ASSEMBLY));
7883   PetscFunctionReturn(PETSC_SUCCESS);
7884 }
7885 
7886 /*@
7887   MatSetVariableBlockSizes - Sets diagonal point-blocks of the matrix that need not be of the same size
7888 
7889   Not Collective
7890 
7891   Input Parameters:
7892 + mat     - the matrix
7893 . nblocks - the number of blocks on this process, each block can only exist on a single process
7894 - bsizes  - the block sizes
7895 
7896   Level: intermediate
7897 
7898   Notes:
7899   Currently used by `PCVPBJACOBI` for `MATAIJ` matrices
7900 
7901   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.
7902 
7903 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`, `MatGetVariableBlockSizes()`,
7904           `MatComputeVariableBlockEnvelope()`, `PCVPBJACOBI`
7905 @*/
7906 PetscErrorCode MatSetVariableBlockSizes(Mat mat, PetscInt nblocks, const PetscInt bsizes[])
7907 {
7908   PetscInt ncnt = 0, nlocal;
7909 
7910   PetscFunctionBegin;
7911   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7912   PetscCall(MatGetLocalSize(mat, &nlocal, NULL));
7913   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);
7914   for (PetscInt i = 0; i < nblocks; i++) ncnt += bsizes[i];
7915   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);
7916   PetscCall(PetscFree(mat->bsizes));
7917   mat->nblocks = nblocks;
7918   PetscCall(PetscMalloc1(nblocks, &mat->bsizes));
7919   PetscCall(PetscArraycpy(mat->bsizes, bsizes, nblocks));
7920   PetscFunctionReturn(PETSC_SUCCESS);
7921 }
7922 
7923 /*@C
7924   MatGetVariableBlockSizes - Gets a diagonal blocks of the matrix that need not be of the same size
7925 
7926   Not Collective; No Fortran Support
7927 
7928   Input Parameter:
7929 . mat - the matrix
7930 
7931   Output Parameters:
7932 + nblocks - the number of blocks on this process
7933 - bsizes  - the block sizes
7934 
7935   Level: intermediate
7936 
7937 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`, `MatGetBlockSizes()`, `MatSetVariableBlockSizes()`, `MatComputeVariableBlockEnvelope()`
7938 @*/
7939 PetscErrorCode MatGetVariableBlockSizes(Mat mat, PetscInt *nblocks, const PetscInt *bsizes[])
7940 {
7941   PetscFunctionBegin;
7942   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7943   if (nblocks) *nblocks = mat->nblocks;
7944   if (bsizes) *bsizes = mat->bsizes;
7945   PetscFunctionReturn(PETSC_SUCCESS);
7946 }
7947 
7948 /*@
7949   MatSetBlockSizes - Sets the matrix block row and column sizes.
7950 
7951   Logically Collective
7952 
7953   Input Parameters:
7954 + mat - the matrix
7955 . rbs - row block size
7956 - cbs - column block size
7957 
7958   Level: intermediate
7959 
7960   Notes:
7961   Block row formats are `MATBAIJ` and  `MATSBAIJ`. These formats ALWAYS have square block storage in the matrix.
7962   If you pass a different block size for the columns than the rows, the row block size determines the square block storage.
7963   This must be called before `MatSetUp()` or MatXXXSetPreallocation() (or will default to 1) and the block size cannot be changed later.
7964 
7965   For `MATAIJ` matrix this function can be called at a later stage, provided that the specified block sizes
7966   are compatible with the matrix local sizes.
7967 
7968   The row and column block size determine the blocksize of the "row" and "column" vectors returned by `MatCreateVecs()`.
7969 
7970 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSize()`, `MatGetBlockSizes()`
7971 @*/
7972 PetscErrorCode MatSetBlockSizes(Mat mat, PetscInt rbs, PetscInt cbs)
7973 {
7974   PetscFunctionBegin;
7975   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
7976   PetscValidLogicalCollectiveInt(mat, rbs, 2);
7977   PetscValidLogicalCollectiveInt(mat, cbs, 3);
7978   PetscTryTypeMethod(mat, setblocksizes, rbs, cbs);
7979   if (mat->rmap->refcnt) {
7980     ISLocalToGlobalMapping l2g  = NULL;
7981     PetscLayout            nmap = NULL;
7982 
7983     PetscCall(PetscLayoutDuplicate(mat->rmap, &nmap));
7984     if (mat->rmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->rmap->mapping, &l2g));
7985     PetscCall(PetscLayoutDestroy(&mat->rmap));
7986     mat->rmap          = nmap;
7987     mat->rmap->mapping = l2g;
7988   }
7989   if (mat->cmap->refcnt) {
7990     ISLocalToGlobalMapping l2g  = NULL;
7991     PetscLayout            nmap = NULL;
7992 
7993     PetscCall(PetscLayoutDuplicate(mat->cmap, &nmap));
7994     if (mat->cmap->mapping) PetscCall(ISLocalToGlobalMappingDuplicate(mat->cmap->mapping, &l2g));
7995     PetscCall(PetscLayoutDestroy(&mat->cmap));
7996     mat->cmap          = nmap;
7997     mat->cmap->mapping = l2g;
7998   }
7999   PetscCall(PetscLayoutSetBlockSize(mat->rmap, rbs));
8000   PetscCall(PetscLayoutSetBlockSize(mat->cmap, cbs));
8001   PetscFunctionReturn(PETSC_SUCCESS);
8002 }
8003 
8004 /*@
8005   MatSetBlockSizesFromMats - Sets the matrix block row and column sizes to match a pair of matrices
8006 
8007   Logically Collective
8008 
8009   Input Parameters:
8010 + mat     - the matrix
8011 . fromRow - matrix from which to copy row block size
8012 - fromCol - matrix from which to copy column block size (can be same as fromRow)
8013 
8014   Level: developer
8015 
8016 .seealso: [](ch_matrices), `Mat`, `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`, `MatGetBlockSize()`, `MatSetBlockSizes()`
8017 @*/
8018 PetscErrorCode MatSetBlockSizesFromMats(Mat mat, Mat fromRow, Mat fromCol)
8019 {
8020   PetscFunctionBegin;
8021   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8022   PetscValidHeaderSpecific(fromRow, MAT_CLASSID, 2);
8023   PetscValidHeaderSpecific(fromCol, MAT_CLASSID, 3);
8024   if (fromRow->rmap->bs > 0) PetscCall(PetscLayoutSetBlockSize(mat->rmap, fromRow->rmap->bs));
8025   if (fromCol->cmap->bs > 0) PetscCall(PetscLayoutSetBlockSize(mat->cmap, fromCol->cmap->bs));
8026   PetscFunctionReturn(PETSC_SUCCESS);
8027 }
8028 
8029 /*@
8030   MatResidual - Default routine to calculate the residual r = b - Ax
8031 
8032   Collective
8033 
8034   Input Parameters:
8035 + mat - the matrix
8036 . b   - the right-hand-side
8037 - x   - the approximate solution
8038 
8039   Output Parameter:
8040 . r - location to store the residual
8041 
8042   Level: developer
8043 
8044 .seealso: [](ch_matrices), `Mat`, `MatMult()`, `MatMultAdd()`, `PCMGSetResidual()`
8045 @*/
8046 PetscErrorCode MatResidual(Mat mat, Vec b, Vec x, Vec r)
8047 {
8048   PetscFunctionBegin;
8049   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8050   PetscValidHeaderSpecific(b, VEC_CLASSID, 2);
8051   PetscValidHeaderSpecific(x, VEC_CLASSID, 3);
8052   PetscValidHeaderSpecific(r, VEC_CLASSID, 4);
8053   PetscValidType(mat, 1);
8054   MatCheckPreallocated(mat, 1);
8055   PetscCall(PetscLogEventBegin(MAT_Residual, mat, 0, 0, 0));
8056   if (!mat->ops->residual) {
8057     PetscCall(MatMult(mat, x, r));
8058     PetscCall(VecAYPX(r, -1.0, b));
8059   } else {
8060     PetscUseTypeMethod(mat, residual, b, x, r);
8061   }
8062   PetscCall(PetscLogEventEnd(MAT_Residual, mat, 0, 0, 0));
8063   PetscFunctionReturn(PETSC_SUCCESS);
8064 }
8065 
8066 /*MC
8067     MatGetRowIJF90 - Obtains the compressed row storage i and j indices for the local rows of a sparse matrix
8068 
8069     Synopsis:
8070     MatGetRowIJF90(Mat A, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt n, {PetscInt, pointer :: ia(:)}, {PetscInt, pointer :: ja(:)}, PetscBool done,integer ierr)
8071 
8072     Not Collective
8073 
8074     Input Parameters:
8075 +   A - the matrix
8076 .   shift -  0 or 1 indicating we want the indices starting at 0 or 1
8077 .   symmetric - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8078 -   inodecompressed - `PETSC_TRUE` or `PETSC_FALSE`  indicating if the nonzero structure of the
8079                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8080                  always used.
8081 
8082     Output Parameters:
8083 +   n - number of local rows in the (possibly compressed) matrix
8084 .   ia - the row pointers; that is ia[0] = 0, ia[row] = ia[row-1] + number of elements in that row of the matrix
8085 .   ja - the column indices
8086 -   done - indicates if the routine actually worked and returned appropriate ia[] and ja[] arrays; callers
8087            are responsible for handling the case when done == `PETSC_FALSE` and ia and ja are not set
8088 
8089     Level: developer
8090 
8091     Note:
8092     Use  `MatRestoreRowIJF90()` when you no longer need access to the data
8093 
8094 .seealso: [](ch_matrices), [](sec_fortranarrays), `Mat`, `MATMPIAIJ`, `MatGetRowIJ()`, `MatRestoreRowIJ()`, `MatRestoreRowIJF90()`
8095 M*/
8096 
8097 /*MC
8098     MatRestoreRowIJF90 - restores the compressed row storage i and j indices for the local rows of a sparse matrix obtained with `MatGetRowIJF90()`
8099 
8100     Synopsis:
8101     MatRestoreRowIJF90(Mat A, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt n, {PetscInt, pointer :: ia(:)}, {PetscInt, pointer :: ja(:)}, PetscBool done,integer ierr)
8102 
8103     Not Collective
8104 
8105     Input Parameters:
8106 +   A - the  matrix
8107 .   shift -  0 or 1 indicating we want the indices starting at 0 or 1
8108 .   symmetric - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8109     inodecompressed - `PETSC_TRUE` or `PETSC_FALSE`  indicating if the nonzero structure of the
8110                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8111                  always used.
8112 .   n - number of local rows in the (possibly compressed) matrix
8113 .   ia - the row pointers; that is ia[0] = 0, ia[row] = ia[row-1] + number of elements in that row of the matrix
8114 .   ja - the column indices
8115 -   done - indicates if the routine actually worked and returned appropriate ia[] and ja[] arrays; callers
8116            are responsible for handling the case when done == `PETSC_FALSE` and ia and ja are not set
8117 
8118     Level: developer
8119 
8120 .seealso: [](ch_matrices), [](sec_fortranarrays), `Mat`, `MATMPIAIJ`, `MatGetRowIJ()`, `MatRestoreRowIJ()`, `MatGetRowIJF90()`
8121 M*/
8122 
8123 /*@C
8124   MatGetRowIJ - Returns the compressed row storage i and j indices for the local rows of a sparse matrix
8125 
8126   Collective
8127 
8128   Input Parameters:
8129 + mat             - the matrix
8130 . shift           - 0 or 1 indicating we want the indices starting at 0 or 1
8131 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8132 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE`  indicating if the nonzero structure of the
8133                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8134                  always used.
8135 
8136   Output Parameters:
8137 + n    - number of local rows in the (possibly compressed) matrix, use `NULL` if not needed
8138 . 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
8139 . ja   - the column indices, use `NULL` if not needed
8140 - done - indicates if the routine actually worked and returned appropriate ia[] and ja[] arrays; callers
8141            are responsible for handling the case when done == `PETSC_FALSE` and ia and ja are not set
8142 
8143   Level: developer
8144 
8145   Notes:
8146   You CANNOT change any of the ia[] or ja[] values.
8147 
8148   Use `MatRestoreRowIJ()` when you are finished accessing the ia[] and ja[] values.
8149 
8150   Fortran Notes:
8151   Use
8152 .vb
8153     PetscInt, pointer :: ia(:),ja(:)
8154     call MatGetRowIJF90(mat,shift,symmetric,inodecompressed,n,ia,ja,done,ierr)
8155     ! Access the ith and jth entries via ia(i) and ja(j)
8156 .ve
8157 
8158   `MatGetRowIJ()` Fortran binding is deprecated (since PETSc 3.19), use `MatGetRowIJF90()`
8159 
8160 .seealso: [](ch_matrices), `Mat`, `MATAIJ`, `MatGetRowIJF90()`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`, `MatSeqAIJGetArray()`
8161 @*/
8162 PetscErrorCode MatGetRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8163 {
8164   PetscFunctionBegin;
8165   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8166   PetscValidType(mat, 1);
8167   if (n) PetscAssertPointer(n, 5);
8168   if (ia) PetscAssertPointer(ia, 6);
8169   if (ja) PetscAssertPointer(ja, 7);
8170   if (done) PetscAssertPointer(done, 8);
8171   MatCheckPreallocated(mat, 1);
8172   if (!mat->ops->getrowij && done) *done = PETSC_FALSE;
8173   else {
8174     if (done) *done = PETSC_TRUE;
8175     PetscCall(PetscLogEventBegin(MAT_GetRowIJ, mat, 0, 0, 0));
8176     PetscUseTypeMethod(mat, getrowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8177     PetscCall(PetscLogEventEnd(MAT_GetRowIJ, mat, 0, 0, 0));
8178   }
8179   PetscFunctionReturn(PETSC_SUCCESS);
8180 }
8181 
8182 /*@C
8183   MatGetColumnIJ - Returns the compressed column storage i and j indices for sequential matrices.
8184 
8185   Collective
8186 
8187   Input Parameters:
8188 + mat             - the matrix
8189 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8190 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be
8191                 symmetrized
8192 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8193                  inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8194                  always used.
8195 . n               - number of columns in the (possibly compressed) matrix
8196 . ia              - the column pointers; that is ia[0] = 0, ia[col] = i[col-1] + number of elements in that col of the matrix
8197 - ja              - the row indices
8198 
8199   Output Parameter:
8200 . done - `PETSC_TRUE` or `PETSC_FALSE`, indicating whether the values have been returned
8201 
8202   Level: developer
8203 
8204 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreColumnIJ()`
8205 @*/
8206 PetscErrorCode MatGetColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8207 {
8208   PetscFunctionBegin;
8209   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8210   PetscValidType(mat, 1);
8211   PetscAssertPointer(n, 5);
8212   if (ia) PetscAssertPointer(ia, 6);
8213   if (ja) PetscAssertPointer(ja, 7);
8214   PetscAssertPointer(done, 8);
8215   MatCheckPreallocated(mat, 1);
8216   if (!mat->ops->getcolumnij) *done = PETSC_FALSE;
8217   else {
8218     *done = PETSC_TRUE;
8219     PetscUseTypeMethod(mat, getcolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8220   }
8221   PetscFunctionReturn(PETSC_SUCCESS);
8222 }
8223 
8224 /*@C
8225   MatRestoreRowIJ - Call after you are completed with the ia,ja indices obtained with `MatGetRowIJ()`.
8226 
8227   Collective
8228 
8229   Input Parameters:
8230 + mat             - the matrix
8231 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8232 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8233 . inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8234                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8235                     always used.
8236 . n               - size of (possibly compressed) matrix
8237 . ia              - the row pointers
8238 - ja              - the column indices
8239 
8240   Output Parameter:
8241 . done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8242 
8243   Level: developer
8244 
8245   Note:
8246   This routine zeros out `n`, `ia`, and `ja`. This is to prevent accidental
8247   us of the array after it has been restored. If you pass `NULL`, it will
8248   not zero the pointers.  Use of ia or ja after `MatRestoreRowIJ()` is invalid.
8249 
8250   Fortran Note:
8251   `MatRestoreRowIJ()` Fortran binding is deprecated (since PETSc 3.19), use `MatRestoreRowIJF90()`
8252 
8253 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatRestoreRowIJF90()`, `MatRestoreColumnIJ()`
8254 @*/
8255 PetscErrorCode MatRestoreRowIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8256 {
8257   PetscFunctionBegin;
8258   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8259   PetscValidType(mat, 1);
8260   if (ia) PetscAssertPointer(ia, 6);
8261   if (ja) PetscAssertPointer(ja, 7);
8262   if (done) PetscAssertPointer(done, 8);
8263   MatCheckPreallocated(mat, 1);
8264 
8265   if (!mat->ops->restorerowij && done) *done = PETSC_FALSE;
8266   else {
8267     if (done) *done = PETSC_TRUE;
8268     PetscUseTypeMethod(mat, restorerowij, shift, symmetric, inodecompressed, n, ia, ja, done);
8269     if (n) *n = 0;
8270     if (ia) *ia = NULL;
8271     if (ja) *ja = NULL;
8272   }
8273   PetscFunctionReturn(PETSC_SUCCESS);
8274 }
8275 
8276 /*@C
8277   MatRestoreColumnIJ - Call after you are completed with the ia,ja indices obtained with `MatGetColumnIJ()`.
8278 
8279   Collective
8280 
8281   Input Parameters:
8282 + mat             - the matrix
8283 . shift           - 1 or zero indicating we want the indices starting at 0 or 1
8284 . symmetric       - `PETSC_TRUE` or `PETSC_FALSE` indicating the matrix data structure should be symmetrized
8285 - inodecompressed - `PETSC_TRUE` or `PETSC_FALSE` indicating if the nonzero structure of the
8286                     inodes or the nonzero elements is wanted. For `MATBAIJ` matrices the compressed version is
8287                     always used.
8288 
8289   Output Parameters:
8290 + n    - size of (possibly compressed) matrix
8291 . ia   - the column pointers
8292 . ja   - the row indices
8293 - done - `PETSC_TRUE` or `PETSC_FALSE` indicated that the values have been returned
8294 
8295   Level: developer
8296 
8297 .seealso: [](ch_matrices), `Mat`, `MatGetColumnIJ()`, `MatRestoreRowIJ()`
8298 @*/
8299 PetscErrorCode MatRestoreColumnIJ(Mat mat, PetscInt shift, PetscBool symmetric, PetscBool inodecompressed, PetscInt *n, const PetscInt *ia[], const PetscInt *ja[], PetscBool *done)
8300 {
8301   PetscFunctionBegin;
8302   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8303   PetscValidType(mat, 1);
8304   if (ia) PetscAssertPointer(ia, 6);
8305   if (ja) PetscAssertPointer(ja, 7);
8306   PetscAssertPointer(done, 8);
8307   MatCheckPreallocated(mat, 1);
8308 
8309   if (!mat->ops->restorecolumnij) *done = PETSC_FALSE;
8310   else {
8311     *done = PETSC_TRUE;
8312     PetscUseTypeMethod(mat, restorecolumnij, shift, symmetric, inodecompressed, n, ia, ja, done);
8313     if (n) *n = 0;
8314     if (ia) *ia = NULL;
8315     if (ja) *ja = NULL;
8316   }
8317   PetscFunctionReturn(PETSC_SUCCESS);
8318 }
8319 
8320 /*@
8321   MatColoringPatch - Used inside matrix coloring routines that use `MatGetRowIJ()` and/or
8322   `MatGetColumnIJ()`.
8323 
8324   Collective
8325 
8326   Input Parameters:
8327 + mat        - the matrix
8328 . ncolors    - maximum color value
8329 . n          - number of entries in colorarray
8330 - colorarray - array indicating color for each column
8331 
8332   Output Parameter:
8333 . iscoloring - coloring generated using colorarray information
8334 
8335   Level: developer
8336 
8337 .seealso: [](ch_matrices), `Mat`, `MatGetRowIJ()`, `MatGetColumnIJ()`
8338 @*/
8339 PetscErrorCode MatColoringPatch(Mat mat, PetscInt ncolors, PetscInt n, ISColoringValue colorarray[], ISColoring *iscoloring)
8340 {
8341   PetscFunctionBegin;
8342   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8343   PetscValidType(mat, 1);
8344   PetscAssertPointer(colorarray, 4);
8345   PetscAssertPointer(iscoloring, 5);
8346   MatCheckPreallocated(mat, 1);
8347 
8348   if (!mat->ops->coloringpatch) {
8349     PetscCall(ISColoringCreate(PetscObjectComm((PetscObject)mat), ncolors, n, colorarray, PETSC_OWN_POINTER, iscoloring));
8350   } else {
8351     PetscUseTypeMethod(mat, coloringpatch, ncolors, n, colorarray, iscoloring);
8352   }
8353   PetscFunctionReturn(PETSC_SUCCESS);
8354 }
8355 
8356 /*@
8357   MatSetUnfactored - Resets a factored matrix to be treated as unfactored.
8358 
8359   Logically Collective
8360 
8361   Input Parameter:
8362 . mat - the factored matrix to be reset
8363 
8364   Level: developer
8365 
8366   Notes:
8367   This routine should be used only with factored matrices formed by in-place
8368   factorization via ILU(0) (or by in-place LU factorization for the `MATSEQDENSE`
8369   format).  This option can save memory, for example, when solving nonlinear
8370   systems with a matrix-free Newton-Krylov method and a matrix-based, in-place
8371   ILU(0) preconditioner.
8372 
8373   One can specify in-place ILU(0) factorization by calling
8374 .vb
8375      PCType(pc,PCILU);
8376      PCFactorSeUseInPlace(pc);
8377 .ve
8378   or by using the options -pc_type ilu -pc_factor_in_place
8379 
8380   In-place factorization ILU(0) can also be used as a local
8381   solver for the blocks within the block Jacobi or additive Schwarz
8382   methods (runtime option: -sub_pc_factor_in_place).  See Users-Manual: ch_pc
8383   for details on setting local solver options.
8384 
8385   Most users should employ the `KSP` interface for linear solvers
8386   instead of working directly with matrix algebra routines such as this.
8387   See, e.g., `KSPCreate()`.
8388 
8389 .seealso: [](ch_matrices), `Mat`, `PCFactorSetUseInPlace()`, `PCFactorGetUseInPlace()`
8390 @*/
8391 PetscErrorCode MatSetUnfactored(Mat mat)
8392 {
8393   PetscFunctionBegin;
8394   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8395   PetscValidType(mat, 1);
8396   MatCheckPreallocated(mat, 1);
8397   mat->factortype = MAT_FACTOR_NONE;
8398   if (!mat->ops->setunfactored) PetscFunctionReturn(PETSC_SUCCESS);
8399   PetscUseTypeMethod(mat, setunfactored);
8400   PetscFunctionReturn(PETSC_SUCCESS);
8401 }
8402 
8403 /*MC
8404     MatDenseGetArrayF90 - Accesses a matrix array from Fortran
8405 
8406     Synopsis:
8407     MatDenseGetArrayF90(Mat x,{Scalar, pointer :: xx_v(:,:)},integer ierr)
8408 
8409     Not Collective
8410 
8411     Input Parameter:
8412 .   x - matrix
8413 
8414     Output Parameters:
8415 +   xx_v - the Fortran pointer to the array
8416 -   ierr - error code
8417 
8418     Example of Usage:
8419 .vb
8420       PetscScalar, pointer xx_v(:,:)
8421       ....
8422       call MatDenseGetArrayF90(x,xx_v,ierr)
8423       a = xx_v(3)
8424       call MatDenseRestoreArrayF90(x,xx_v,ierr)
8425 .ve
8426 
8427     Level: advanced
8428 
8429 .seealso: [](ch_matrices), `Mat`, `MatDenseRestoreArrayF90()`, `MatDenseGetArray()`, `MatDenseRestoreArray()`, `MatSeqAIJGetArrayF90()`
8430 M*/
8431 
8432 /*MC
8433     MatDenseRestoreArrayF90 - Restores a matrix array that has been
8434     accessed with `MatDenseGetArrayF90()`.
8435 
8436     Synopsis:
8437     MatDenseRestoreArrayF90(Mat x,{Scalar, pointer :: xx_v(:,:)},integer ierr)
8438 
8439     Not Collective
8440 
8441     Input Parameters:
8442 +   x - matrix
8443 -   xx_v - the Fortran90 pointer to the array
8444 
8445     Output Parameter:
8446 .   ierr - error code
8447 
8448     Example of Usage:
8449 .vb
8450        PetscScalar, pointer xx_v(:,:)
8451        ....
8452        call MatDenseGetArrayF90(x,xx_v,ierr)
8453        a = xx_v(3)
8454        call MatDenseRestoreArrayF90(x,xx_v,ierr)
8455 .ve
8456 
8457     Level: advanced
8458 
8459 .seealso: [](ch_matrices), `Mat`, `MatDenseGetArrayF90()`, `MatDenseGetArray()`, `MatDenseRestoreArray()`, `MatSeqAIJRestoreArrayF90()`
8460 M*/
8461 
8462 /*MC
8463     MatSeqAIJGetArrayF90 - Accesses a matrix array from Fortran.
8464 
8465     Synopsis:
8466     MatSeqAIJGetArrayF90(Mat x,{Scalar, pointer :: xx_v(:)},integer ierr)
8467 
8468     Not Collective
8469 
8470     Input Parameter:
8471 .   x - matrix
8472 
8473     Output Parameters:
8474 +   xx_v - the Fortran pointer to the array
8475 -   ierr - error code
8476 
8477     Example of Usage:
8478 .vb
8479       PetscScalar, pointer xx_v(:)
8480       ....
8481       call MatSeqAIJGetArrayF90(x,xx_v,ierr)
8482       a = xx_v(3)
8483       call MatSeqAIJRestoreArrayF90(x,xx_v,ierr)
8484 .ve
8485 
8486     Level: advanced
8487 
8488 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJRestoreArrayF90()`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArray()`, `MatDenseGetArrayF90()`
8489 M*/
8490 
8491 /*MC
8492     MatSeqAIJRestoreArrayF90 - Restores a matrix array that has been
8493     accessed with `MatSeqAIJGetArrayF90()`.
8494 
8495     Synopsis:
8496     MatSeqAIJRestoreArrayF90(Mat x,{Scalar, pointer :: xx_v(:)},integer ierr)
8497 
8498     Not Collective
8499 
8500     Input Parameters:
8501 +   x - matrix
8502 -   xx_v - the Fortran90 pointer to the array
8503 
8504     Output Parameter:
8505 .   ierr - error code
8506 
8507     Example of Usage:
8508 .vb
8509        PetscScalar, pointer xx_v(:)
8510        ....
8511        call MatSeqAIJGetArrayF90(x,xx_v,ierr)
8512        a = xx_v(3)
8513        call MatSeqAIJRestoreArrayF90(x,xx_v,ierr)
8514 .ve
8515 
8516     Level: advanced
8517 
8518 .seealso: [](ch_matrices), `Mat`, `MatSeqAIJGetArrayF90()`, `MatSeqAIJGetArray()`, `MatSeqAIJRestoreArray()`, `MatDenseRestoreArrayF90()`
8519 M*/
8520 
8521 /*@
8522   MatCreateSubMatrix - Gets a single submatrix on the same number of processors
8523   as the original matrix.
8524 
8525   Collective
8526 
8527   Input Parameters:
8528 + mat   - the original matrix
8529 . isrow - parallel `IS` containing the rows this processor should obtain
8530 . 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.
8531 - cll   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
8532 
8533   Output Parameter:
8534 . newmat - the new submatrix, of the same type as the original matrix
8535 
8536   Level: advanced
8537 
8538   Notes:
8539   The submatrix will be able to be multiplied with vectors using the same layout as `iscol`.
8540 
8541   Some matrix types place restrictions on the row and column indices, such
8542   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;
8543   for example, if the block size is 3 one cannot select the 0 and 2 rows without selecting the 1 row.
8544 
8545   The index sets may not have duplicate entries.
8546 
8547   The first time this is called you should use a cll of `MAT_INITIAL_MATRIX`,
8548   the `MatCreateSubMatrix()` routine will create the newmat for you. Any additional calls
8549   to this routine with a mat of the same nonzero structure and with a call of `MAT_REUSE_MATRIX`
8550   will reuse the matrix generated the first time.  You should call `MatDestroy()` on `newmat` when
8551   you are finished using it.
8552 
8553   The communicator of the newly obtained matrix is ALWAYS the same as the communicator of
8554   the input matrix.
8555 
8556   If `iscol` is `NULL` then all columns are obtained (not supported in Fortran).
8557 
8558   If `isrow` and `iscol` have a nontrivial block-size, then the resulting matrix has this block-size as well. This feature
8559   is used by `PCFIELDSPLIT` to allow easy nesting of its use.
8560 
8561   Example usage:
8562   Consider the following 8x8 matrix with 34 non-zero values, that is
8563   assembled across 3 processors. Let's assume that proc0 owns 3 rows,
8564   proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
8565   as follows
8566 .vb
8567             1  2  0  |  0  3  0  |  0  4
8568     Proc0   0  5  6  |  7  0  0  |  8  0
8569             9  0 10  | 11  0  0  | 12  0
8570     -------------------------------------
8571            13  0 14  | 15 16 17  |  0  0
8572     Proc1   0 18  0  | 19 20 21  |  0  0
8573             0  0  0  | 22 23  0  | 24  0
8574     -------------------------------------
8575     Proc2  25 26 27  |  0  0 28  | 29  0
8576            30  0  0  | 31 32 33  |  0 34
8577 .ve
8578 
8579   Suppose `isrow` = [0 1 | 4 | 6 7] and `iscol` = [1 2 | 3 4 5 | 6].  The resulting submatrix is
8580 
8581 .vb
8582             2  0  |  0  3  0  |  0
8583     Proc0   5  6  |  7  0  0  |  8
8584     -------------------------------
8585     Proc1  18  0  | 19 20 21  |  0
8586     -------------------------------
8587     Proc2  26 27  |  0  0 28  | 29
8588             0  0  | 31 32 33  |  0
8589 .ve
8590 
8591 .seealso: [](ch_matrices), `Mat`, `MatCreateSubMatrices()`, `MatCreateSubMatricesMPI()`, `MatCreateSubMatrixVirtual()`, `MatSubMatrixVirtualUpdate()`
8592 @*/
8593 PetscErrorCode MatCreateSubMatrix(Mat mat, IS isrow, IS iscol, MatReuse cll, Mat *newmat)
8594 {
8595   PetscMPIInt size;
8596   Mat        *local;
8597   IS          iscoltmp;
8598   PetscBool   flg;
8599 
8600   PetscFunctionBegin;
8601   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8602   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
8603   if (iscol) PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
8604   PetscAssertPointer(newmat, 5);
8605   if (cll == MAT_REUSE_MATRIX) PetscValidHeaderSpecific(*newmat, MAT_CLASSID, 5);
8606   PetscValidType(mat, 1);
8607   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
8608   PetscCheck(cll != MAT_IGNORE_MATRIX, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Cannot use MAT_IGNORE_MATRIX");
8609 
8610   MatCheckPreallocated(mat, 1);
8611   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
8612 
8613   if (!iscol || isrow == iscol) {
8614     PetscBool   stride;
8615     PetscMPIInt grabentirematrix = 0, grab;
8616     PetscCall(PetscObjectTypeCompare((PetscObject)isrow, ISSTRIDE, &stride));
8617     if (stride) {
8618       PetscInt first, step, n, rstart, rend;
8619       PetscCall(ISStrideGetInfo(isrow, &first, &step));
8620       if (step == 1) {
8621         PetscCall(MatGetOwnershipRange(mat, &rstart, &rend));
8622         if (rstart == first) {
8623           PetscCall(ISGetLocalSize(isrow, &n));
8624           if (n == rend - rstart) grabentirematrix = 1;
8625         }
8626       }
8627     }
8628     PetscCallMPI(MPIU_Allreduce(&grabentirematrix, &grab, 1, MPI_INT, MPI_MIN, PetscObjectComm((PetscObject)mat)));
8629     if (grab) {
8630       PetscCall(PetscInfo(mat, "Getting entire matrix as submatrix\n"));
8631       if (cll == MAT_INITIAL_MATRIX) {
8632         *newmat = mat;
8633         PetscCall(PetscObjectReference((PetscObject)mat));
8634       }
8635       PetscFunctionReturn(PETSC_SUCCESS);
8636     }
8637   }
8638 
8639   if (!iscol) {
8640     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)mat), mat->cmap->n, mat->cmap->rstart, 1, &iscoltmp));
8641   } else {
8642     iscoltmp = iscol;
8643   }
8644 
8645   /* if original matrix is on just one processor then use submatrix generated */
8646   if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1 && cll == MAT_REUSE_MATRIX) {
8647     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_REUSE_MATRIX, &newmat));
8648     goto setproperties;
8649   } else if (mat->ops->createsubmatrices && !mat->ops->createsubmatrix && size == 1) {
8650     PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscoltmp, MAT_INITIAL_MATRIX, &local));
8651     *newmat = *local;
8652     PetscCall(PetscFree(local));
8653     goto setproperties;
8654   } else if (!mat->ops->createsubmatrix) {
8655     /* Create a new matrix type that implements the operation using the full matrix */
8656     PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8657     switch (cll) {
8658     case MAT_INITIAL_MATRIX:
8659       PetscCall(MatCreateSubMatrixVirtual(mat, isrow, iscoltmp, newmat));
8660       break;
8661     case MAT_REUSE_MATRIX:
8662       PetscCall(MatSubMatrixVirtualUpdate(*newmat, mat, isrow, iscoltmp));
8663       break;
8664     default:
8665       SETERRQ(PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "Invalid MatReuse, must be either MAT_INITIAL_MATRIX or MAT_REUSE_MATRIX");
8666     }
8667     PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8668     goto setproperties;
8669   }
8670 
8671   PetscCall(PetscLogEventBegin(MAT_CreateSubMat, mat, 0, 0, 0));
8672   PetscUseTypeMethod(mat, createsubmatrix, isrow, iscoltmp, cll, newmat);
8673   PetscCall(PetscLogEventEnd(MAT_CreateSubMat, mat, 0, 0, 0));
8674 
8675 setproperties:
8676   if ((*newmat)->symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->structurally_symmetric == PETSC_BOOL3_UNKNOWN && (*newmat)->spd == PETSC_BOOL3_UNKNOWN && (*newmat)->hermitian == PETSC_BOOL3_UNKNOWN) {
8677     PetscCall(ISEqualUnsorted(isrow, iscoltmp, &flg));
8678     if (flg) PetscCall(MatPropagateSymmetryOptions(mat, *newmat));
8679   }
8680   if (!iscol) PetscCall(ISDestroy(&iscoltmp));
8681   if (*newmat && cll == MAT_INITIAL_MATRIX) PetscCall(PetscObjectStateIncrease((PetscObject)*newmat));
8682   PetscFunctionReturn(PETSC_SUCCESS);
8683 }
8684 
8685 /*@
8686   MatPropagateSymmetryOptions - Propagates symmetry options set on a matrix to another matrix
8687 
8688   Not Collective
8689 
8690   Input Parameters:
8691 + A - the matrix we wish to propagate options from
8692 - B - the matrix we wish to propagate options to
8693 
8694   Level: beginner
8695 
8696   Note:
8697   Propagates the options associated to `MAT_SYMMETRY_ETERNAL`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_HERMITIAN`, `MAT_SPD`, `MAT_SYMMETRIC`, and `MAT_STRUCTURAL_SYMMETRY_ETERNAL`
8698 
8699 .seealso: [](ch_matrices), `Mat`, `MatSetOption()`, `MatIsSymmetricKnown()`, `MatIsSPDKnown()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetricKnown()`
8700 @*/
8701 PetscErrorCode MatPropagateSymmetryOptions(Mat A, Mat B)
8702 {
8703   PetscFunctionBegin;
8704   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8705   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
8706   B->symmetry_eternal            = A->symmetry_eternal;
8707   B->structural_symmetry_eternal = A->structural_symmetry_eternal;
8708   B->symmetric                   = A->symmetric;
8709   B->structurally_symmetric      = A->structurally_symmetric;
8710   B->spd                         = A->spd;
8711   B->hermitian                   = A->hermitian;
8712   PetscFunctionReturn(PETSC_SUCCESS);
8713 }
8714 
8715 /*@
8716   MatStashSetInitialSize - sets the sizes of the matrix stash, that is
8717   used during the assembly process to store values that belong to
8718   other processors.
8719 
8720   Not Collective
8721 
8722   Input Parameters:
8723 + mat   - the matrix
8724 . size  - the initial size of the stash.
8725 - bsize - the initial size of the block-stash(if used).
8726 
8727   Options Database Keys:
8728 + -matstash_initial_size <size> or <size0,size1,...sizep-1>            - set initial size
8729 - -matstash_block_initial_size <bsize>  or <bsize0,bsize1,...bsizep-1> - set initial block size
8730 
8731   Level: intermediate
8732 
8733   Notes:
8734   The block-stash is used for values set with `MatSetValuesBlocked()` while
8735   the stash is used for values set with `MatSetValues()`
8736 
8737   Run with the option -info and look for output of the form
8738   MatAssemblyBegin_MPIXXX:Stash has MM entries, uses nn mallocs.
8739   to determine the appropriate value, MM, to use for size and
8740   MatAssemblyBegin_MPIXXX:Block-Stash has BMM entries, uses nn mallocs.
8741   to determine the value, BMM to use for bsize
8742 
8743 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashGetInfo()`
8744 @*/
8745 PetscErrorCode MatStashSetInitialSize(Mat mat, PetscInt size, PetscInt bsize)
8746 {
8747   PetscFunctionBegin;
8748   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
8749   PetscValidType(mat, 1);
8750   PetscCall(MatStashSetInitialSize_Private(&mat->stash, size));
8751   PetscCall(MatStashSetInitialSize_Private(&mat->bstash, bsize));
8752   PetscFunctionReturn(PETSC_SUCCESS);
8753 }
8754 
8755 /*@
8756   MatInterpolateAdd - $w = y + A*x$ or $A^T*x$ depending on the shape of
8757   the matrix
8758 
8759   Neighbor-wise Collective
8760 
8761   Input Parameters:
8762 + A - the matrix
8763 . x - the vector to be multiplied by the interpolation operator
8764 - y - the vector to be added to the result
8765 
8766   Output Parameter:
8767 . w - the resulting vector
8768 
8769   Level: intermediate
8770 
8771   Notes:
8772   `w` may be the same vector as `y`.
8773 
8774   This allows one to use either the restriction or interpolation (its transpose)
8775   matrix to do the interpolation
8776 
8777 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8778 @*/
8779 PetscErrorCode MatInterpolateAdd(Mat A, Vec x, Vec y, Vec w)
8780 {
8781   PetscInt M, N, Ny;
8782 
8783   PetscFunctionBegin;
8784   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8785   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8786   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8787   PetscValidHeaderSpecific(w, VEC_CLASSID, 4);
8788   PetscCall(MatGetSize(A, &M, &N));
8789   PetscCall(VecGetSize(y, &Ny));
8790   if (M == Ny) {
8791     PetscCall(MatMultAdd(A, x, y, w));
8792   } else {
8793     PetscCall(MatMultTransposeAdd(A, x, y, w));
8794   }
8795   PetscFunctionReturn(PETSC_SUCCESS);
8796 }
8797 
8798 /*@
8799   MatInterpolate - $y = A*x$ or $A^T*x$ depending on the shape of
8800   the matrix
8801 
8802   Neighbor-wise Collective
8803 
8804   Input Parameters:
8805 + A - the matrix
8806 - x - the vector to be interpolated
8807 
8808   Output Parameter:
8809 . y - the resulting vector
8810 
8811   Level: intermediate
8812 
8813   Note:
8814   This allows one to use either the restriction or interpolation (its transpose)
8815   matrix to do the interpolation
8816 
8817 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatRestrict()`, `PCMG`
8818 @*/
8819 PetscErrorCode MatInterpolate(Mat A, Vec x, Vec y)
8820 {
8821   PetscInt M, N, Ny;
8822 
8823   PetscFunctionBegin;
8824   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8825   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8826   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8827   PetscCall(MatGetSize(A, &M, &N));
8828   PetscCall(VecGetSize(y, &Ny));
8829   if (M == Ny) {
8830     PetscCall(MatMult(A, x, y));
8831   } else {
8832     PetscCall(MatMultTranspose(A, x, y));
8833   }
8834   PetscFunctionReturn(PETSC_SUCCESS);
8835 }
8836 
8837 /*@
8838   MatRestrict - $y = A*x$ or $A^T*x$
8839 
8840   Neighbor-wise Collective
8841 
8842   Input Parameters:
8843 + A - the matrix
8844 - x - the vector to be restricted
8845 
8846   Output Parameter:
8847 . y - the resulting vector
8848 
8849   Level: intermediate
8850 
8851   Note:
8852   This allows one to use either the restriction or interpolation (its transpose)
8853   matrix to do the restriction
8854 
8855 .seealso: [](ch_matrices), `Mat`, `MatMultAdd()`, `MatMultTransposeAdd()`, `MatInterpolate()`, `PCMG`
8856 @*/
8857 PetscErrorCode MatRestrict(Mat A, Vec x, Vec y)
8858 {
8859   PetscInt M, N, Nx;
8860 
8861   PetscFunctionBegin;
8862   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8863   PetscValidHeaderSpecific(x, VEC_CLASSID, 2);
8864   PetscValidHeaderSpecific(y, VEC_CLASSID, 3);
8865   PetscCall(MatGetSize(A, &M, &N));
8866   PetscCall(VecGetSize(x, &Nx));
8867   if (M == Nx) {
8868     PetscCall(MatMultTranspose(A, x, y));
8869   } else {
8870     PetscCall(MatMult(A, x, y));
8871   }
8872   PetscFunctionReturn(PETSC_SUCCESS);
8873 }
8874 
8875 /*@
8876   MatMatInterpolateAdd - $Y = W + A*X$ or $W + A^T*X$ depending on the shape of `A`
8877 
8878   Neighbor-wise Collective
8879 
8880   Input Parameters:
8881 + A - the matrix
8882 . x - the input dense matrix to be multiplied
8883 - w - the input dense matrix to be added to the result
8884 
8885   Output Parameter:
8886 . y - the output dense matrix
8887 
8888   Level: intermediate
8889 
8890   Note:
8891   This allows one to use either the restriction or interpolation (its transpose)
8892   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8893   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8894 
8895 .seealso: [](ch_matrices), `Mat`, `MatInterpolateAdd()`, `MatMatInterpolate()`, `MatMatRestrict()`, `PCMG`
8896 @*/
8897 PetscErrorCode MatMatInterpolateAdd(Mat A, Mat x, Mat w, Mat *y)
8898 {
8899   PetscInt  M, N, Mx, Nx, Mo, My = 0, Ny = 0;
8900   PetscBool trans = PETSC_TRUE;
8901   MatReuse  reuse = MAT_INITIAL_MATRIX;
8902 
8903   PetscFunctionBegin;
8904   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
8905   PetscValidHeaderSpecific(x, MAT_CLASSID, 2);
8906   PetscValidType(x, 2);
8907   if (w) PetscValidHeaderSpecific(w, MAT_CLASSID, 3);
8908   if (*y) PetscValidHeaderSpecific(*y, MAT_CLASSID, 4);
8909   PetscCall(MatGetSize(A, &M, &N));
8910   PetscCall(MatGetSize(x, &Mx, &Nx));
8911   if (N == Mx) trans = PETSC_FALSE;
8912   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);
8913   Mo = trans ? N : M;
8914   if (*y) {
8915     PetscCall(MatGetSize(*y, &My, &Ny));
8916     if (Mo == My && Nx == Ny) {
8917       reuse = MAT_REUSE_MATRIX;
8918     } else {
8919       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);
8920       PetscCall(MatDestroy(y));
8921     }
8922   }
8923 
8924   if (w && *y == w) { /* this is to minimize changes in PCMG */
8925     PetscBool flg;
8926 
8927     PetscCall(PetscObjectQuery((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject *)&w));
8928     if (w) {
8929       PetscInt My, Ny, Mw, Nw;
8930 
8931       PetscCall(PetscObjectTypeCompare((PetscObject)*y, ((PetscObject)w)->type_name, &flg));
8932       PetscCall(MatGetSize(*y, &My, &Ny));
8933       PetscCall(MatGetSize(w, &Mw, &Nw));
8934       if (!flg || My != Mw || Ny != Nw) w = NULL;
8935     }
8936     if (!w) {
8937       PetscCall(MatDuplicate(*y, MAT_COPY_VALUES, &w));
8938       PetscCall(PetscObjectCompose((PetscObject)*y, "__MatMatIntAdd_w", (PetscObject)w));
8939       PetscCall(PetscObjectDereference((PetscObject)w));
8940     } else {
8941       PetscCall(MatCopy(*y, w, UNKNOWN_NONZERO_PATTERN));
8942     }
8943   }
8944   if (!trans) {
8945     PetscCall(MatMatMult(A, x, reuse, PETSC_DETERMINE, y));
8946   } else {
8947     PetscCall(MatTransposeMatMult(A, x, reuse, PETSC_DETERMINE, y));
8948   }
8949   if (w) PetscCall(MatAXPY(*y, 1.0, w, UNKNOWN_NONZERO_PATTERN));
8950   PetscFunctionReturn(PETSC_SUCCESS);
8951 }
8952 
8953 /*@
8954   MatMatInterpolate - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8955 
8956   Neighbor-wise Collective
8957 
8958   Input Parameters:
8959 + A - the matrix
8960 - x - the input dense matrix
8961 
8962   Output Parameter:
8963 . y - the output dense matrix
8964 
8965   Level: intermediate
8966 
8967   Note:
8968   This allows one to use either the restriction or interpolation (its transpose)
8969   matrix to do the interpolation. `y` matrix can be reused if already created with the proper sizes,
8970   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8971 
8972 .seealso: [](ch_matrices), `Mat`, `MatInterpolate()`, `MatRestrict()`, `MatMatRestrict()`, `PCMG`
8973 @*/
8974 PetscErrorCode MatMatInterpolate(Mat A, Mat x, Mat *y)
8975 {
8976   PetscFunctionBegin;
8977   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
8978   PetscFunctionReturn(PETSC_SUCCESS);
8979 }
8980 
8981 /*@
8982   MatMatRestrict - $Y = A*X$ or $A^T*X$ depending on the shape of `A`
8983 
8984   Neighbor-wise Collective
8985 
8986   Input Parameters:
8987 + A - the matrix
8988 - x - the input dense matrix
8989 
8990   Output Parameter:
8991 . y - the output dense matrix
8992 
8993   Level: intermediate
8994 
8995   Note:
8996   This allows one to use either the restriction or interpolation (its transpose)
8997   matrix to do the restriction. `y` matrix can be reused if already created with the proper sizes,
8998   otherwise it will be recreated. `y` must be initialized to `NULL` if not supplied.
8999 
9000 .seealso: [](ch_matrices), `Mat`, `MatRestrict()`, `MatInterpolate()`, `MatMatInterpolate()`, `PCMG`
9001 @*/
9002 PetscErrorCode MatMatRestrict(Mat A, Mat x, Mat *y)
9003 {
9004   PetscFunctionBegin;
9005   PetscCall(MatMatInterpolateAdd(A, x, NULL, y));
9006   PetscFunctionReturn(PETSC_SUCCESS);
9007 }
9008 
9009 /*@
9010   MatGetNullSpace - retrieves the null space of a matrix.
9011 
9012   Logically Collective
9013 
9014   Input Parameters:
9015 + mat    - the matrix
9016 - nullsp - the null space object
9017 
9018   Level: developer
9019 
9020 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetNullSpace()`, `MatNullSpace`
9021 @*/
9022 PetscErrorCode MatGetNullSpace(Mat mat, MatNullSpace *nullsp)
9023 {
9024   PetscFunctionBegin;
9025   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9026   PetscAssertPointer(nullsp, 2);
9027   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->nullsp) ? mat->transnullsp : mat->nullsp;
9028   PetscFunctionReturn(PETSC_SUCCESS);
9029 }
9030 
9031 /*@C
9032   MatGetNullSpaces - gets the null spaces, transpose null spaces, and near null spaces from an array of matrices
9033 
9034   Logically Collective
9035 
9036   Input Parameters:
9037 + n   - the number of matrices
9038 - mat - the array of matrices
9039 
9040   Output Parameters:
9041 . nullsp - an array of null spaces, `NULL` for each matrix that does not have a null space, length 3 * `n`
9042 
9043   Level: developer
9044 
9045   Note:
9046   Call `MatRestoreNullspaces()` to provide these to another array of matrices
9047 
9048 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
9049           `MatNullSpaceRemove()`, `MatRestoreNullSpaces()`
9050 @*/
9051 PetscErrorCode MatGetNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
9052 {
9053   PetscFunctionBegin;
9054   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
9055   PetscAssertPointer(mat, 2);
9056   PetscAssertPointer(nullsp, 3);
9057 
9058   PetscCall(PetscCalloc1(3 * n, nullsp));
9059   for (PetscInt i = 0; i < n; i++) {
9060     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
9061     (*nullsp)[i] = mat[i]->nullsp;
9062     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[i]));
9063     (*nullsp)[n + i] = mat[i]->nearnullsp;
9064     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[n + i]));
9065     (*nullsp)[2 * n + i] = mat[i]->transnullsp;
9066     PetscCall(PetscObjectReference((PetscObject)(*nullsp)[2 * n + i]));
9067   }
9068   PetscFunctionReturn(PETSC_SUCCESS);
9069 }
9070 
9071 /*@C
9072   MatRestoreNullSpaces - sets the null spaces, transpose null spaces, and near null spaces obtained with `MatGetNullSpaces()` for an array of matrices
9073 
9074   Logically Collective
9075 
9076   Input Parameters:
9077 + n      - the number of matrices
9078 . mat    - the array of matrices
9079 - nullsp - an array of null spaces
9080 
9081   Level: developer
9082 
9083   Note:
9084   Call `MatGetNullSpaces()` to create `nullsp`
9085 
9086 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`,
9087           `MatNullSpaceRemove()`, `MatGetNullSpaces()`
9088 @*/
9089 PetscErrorCode MatRestoreNullSpaces(PetscInt n, Mat mat[], MatNullSpace *nullsp[])
9090 {
9091   PetscFunctionBegin;
9092   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of matrices %" PetscInt_FMT " must be non-negative", n);
9093   PetscAssertPointer(mat, 2);
9094   PetscAssertPointer(nullsp, 3);
9095   PetscAssertPointer(*nullsp, 3);
9096 
9097   for (PetscInt i = 0; i < n; i++) {
9098     PetscValidHeaderSpecific(mat[i], MAT_CLASSID, 2);
9099     PetscCall(MatSetNullSpace(mat[i], (*nullsp)[i]));
9100     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[i]));
9101     PetscCall(MatSetNearNullSpace(mat[i], (*nullsp)[n + i]));
9102     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[n + i]));
9103     PetscCall(MatSetTransposeNullSpace(mat[i], (*nullsp)[2 * n + i]));
9104     PetscCall(PetscObjectDereference((PetscObject)(*nullsp)[2 * n + i]));
9105   }
9106   PetscCall(PetscFree(*nullsp));
9107   PetscFunctionReturn(PETSC_SUCCESS);
9108 }
9109 
9110 /*@
9111   MatSetNullSpace - attaches a null space to a matrix.
9112 
9113   Logically Collective
9114 
9115   Input Parameters:
9116 + mat    - the matrix
9117 - nullsp - the null space object
9118 
9119   Level: advanced
9120 
9121   Notes:
9122   This null space is used by the `KSP` linear solvers to solve singular systems.
9123 
9124   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`
9125 
9126   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 to
9127   to zero but the linear system will still be solved in a least squares sense.
9128 
9129   The fundamental theorem of linear algebra (Gilbert Strang, Introduction to Applied Mathematics, page 72) states that
9130   the domain of a matrix A (from $R^n$ to $R^m$ (m rows, n columns) $R^n$ = the direct sum of the null space of A, n(A), + the range of $A^T$, $R(A^T)$.
9131   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
9132   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
9133   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$).
9134   This  \hat{b} can be obtained by calling `MatNullSpaceRemove()` with the null space of the transpose of the matrix.
9135 
9136   If the matrix is known to be symmetric because it is an `MATSBAIJ` matrix or one as called
9137   `MatSetOption`(mat,`MAT_SYMMETRIC` or possibly `MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`); this
9138   routine also automatically calls `MatSetTransposeNullSpace()`.
9139 
9140   The user should call `MatNullSpaceDestroy()`.
9141 
9142 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetTransposeNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`,
9143           `KSPSetPCSide()`
9144 @*/
9145 PetscErrorCode MatSetNullSpace(Mat mat, MatNullSpace nullsp)
9146 {
9147   PetscFunctionBegin;
9148   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9149   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9150   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9151   PetscCall(MatNullSpaceDestroy(&mat->nullsp));
9152   mat->nullsp = nullsp;
9153   if (mat->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetTransposeNullSpace(mat, nullsp));
9154   PetscFunctionReturn(PETSC_SUCCESS);
9155 }
9156 
9157 /*@
9158   MatGetTransposeNullSpace - retrieves the null space of the transpose of a matrix.
9159 
9160   Logically Collective
9161 
9162   Input Parameters:
9163 + mat    - the matrix
9164 - nullsp - the null space object
9165 
9166   Level: developer
9167 
9168 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatSetTransposeNullSpace()`, `MatSetNullSpace()`, `MatGetNullSpace()`
9169 @*/
9170 PetscErrorCode MatGetTransposeNullSpace(Mat mat, MatNullSpace *nullsp)
9171 {
9172   PetscFunctionBegin;
9173   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9174   PetscValidType(mat, 1);
9175   PetscAssertPointer(nullsp, 2);
9176   *nullsp = (mat->symmetric == PETSC_BOOL3_TRUE && !mat->transnullsp) ? mat->nullsp : mat->transnullsp;
9177   PetscFunctionReturn(PETSC_SUCCESS);
9178 }
9179 
9180 /*@
9181   MatSetTransposeNullSpace - attaches the null space of a transpose of a matrix to the matrix
9182 
9183   Logically Collective
9184 
9185   Input Parameters:
9186 + mat    - the matrix
9187 - nullsp - the null space object
9188 
9189   Level: advanced
9190 
9191   Notes:
9192   This allows solving singular linear systems defined by the transpose of the matrix using `KSP` solvers with left preconditioning.
9193 
9194   See `MatSetNullSpace()`
9195 
9196 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatSetNullSpace()`, `MatGetTransposeNullSpace()`, `MatNullSpaceRemove()`, `KSPSetPCSide()`
9197 @*/
9198 PetscErrorCode MatSetTransposeNullSpace(Mat mat, MatNullSpace nullsp)
9199 {
9200   PetscFunctionBegin;
9201   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9202   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9203   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9204   PetscCall(MatNullSpaceDestroy(&mat->transnullsp));
9205   mat->transnullsp = nullsp;
9206   PetscFunctionReturn(PETSC_SUCCESS);
9207 }
9208 
9209 /*@
9210   MatSetNearNullSpace - attaches a null space to a matrix, which is often the null space (rigid body modes) of the operator without boundary conditions
9211   This null space will be used to provide near null space vectors to a multigrid preconditioner built from this matrix.
9212 
9213   Logically Collective
9214 
9215   Input Parameters:
9216 + mat    - the matrix
9217 - nullsp - the null space object
9218 
9219   Level: advanced
9220 
9221   Notes:
9222   Overwrites any previous near null space that may have been attached
9223 
9224   You can remove the null space by calling this routine with an `nullsp` of `NULL`
9225 
9226 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatCreate()`, `MatNullSpaceCreate()`, `MatSetNullSpace()`, `MatNullSpaceCreateRigidBody()`, `MatGetNearNullSpace()`
9227 @*/
9228 PetscErrorCode MatSetNearNullSpace(Mat mat, MatNullSpace nullsp)
9229 {
9230   PetscFunctionBegin;
9231   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9232   PetscValidType(mat, 1);
9233   if (nullsp) PetscValidHeaderSpecific(nullsp, MAT_NULLSPACE_CLASSID, 2);
9234   MatCheckPreallocated(mat, 1);
9235   if (nullsp) PetscCall(PetscObjectReference((PetscObject)nullsp));
9236   PetscCall(MatNullSpaceDestroy(&mat->nearnullsp));
9237   mat->nearnullsp = nullsp;
9238   PetscFunctionReturn(PETSC_SUCCESS);
9239 }
9240 
9241 /*@
9242   MatGetNearNullSpace - Get null space attached with `MatSetNearNullSpace()`
9243 
9244   Not Collective
9245 
9246   Input Parameter:
9247 . mat - the matrix
9248 
9249   Output Parameter:
9250 . nullsp - the null space object, `NULL` if not set
9251 
9252   Level: advanced
9253 
9254 .seealso: [](ch_matrices), `Mat`, `MatNullSpace`, `MatSetNearNullSpace()`, `MatGetNullSpace()`, `MatNullSpaceCreate()`
9255 @*/
9256 PetscErrorCode MatGetNearNullSpace(Mat mat, MatNullSpace *nullsp)
9257 {
9258   PetscFunctionBegin;
9259   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9260   PetscValidType(mat, 1);
9261   PetscAssertPointer(nullsp, 2);
9262   MatCheckPreallocated(mat, 1);
9263   *nullsp = mat->nearnullsp;
9264   PetscFunctionReturn(PETSC_SUCCESS);
9265 }
9266 
9267 /*@
9268   MatICCFactor - Performs in-place incomplete Cholesky factorization of matrix.
9269 
9270   Collective
9271 
9272   Input Parameters:
9273 + mat  - the matrix
9274 . row  - row/column permutation
9275 - info - information on desired factorization process
9276 
9277   Level: developer
9278 
9279   Notes:
9280   Probably really in-place only when level of fill is zero, otherwise allocates
9281   new space to store factored matrix and deletes previous memory.
9282 
9283   Most users should employ the `KSP` interface for linear solvers
9284   instead of working directly with matrix algebra routines such as this.
9285   See, e.g., `KSPCreate()`.
9286 
9287   Developer Note:
9288   The Fortran interface is not autogenerated as the
9289   interface definition cannot be generated correctly [due to `MatFactorInfo`]
9290 
9291 .seealso: [](ch_matrices), `Mat`, `MatFactorInfo`, `MatGetFactor()`, `MatICCFactorSymbolic()`, `MatLUFactorNumeric()`, `MatCholeskyFactor()`
9292 @*/
9293 PetscErrorCode MatICCFactor(Mat mat, IS row, const MatFactorInfo *info)
9294 {
9295   PetscFunctionBegin;
9296   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9297   PetscValidType(mat, 1);
9298   if (row) PetscValidHeaderSpecific(row, IS_CLASSID, 2);
9299   PetscAssertPointer(info, 3);
9300   PetscCheck(mat->rmap->N == mat->cmap->N, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "matrix must be square");
9301   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
9302   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
9303   MatCheckPreallocated(mat, 1);
9304   PetscUseTypeMethod(mat, iccfactor, row, info);
9305   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9306   PetscFunctionReturn(PETSC_SUCCESS);
9307 }
9308 
9309 /*@
9310   MatDiagonalScaleLocal - Scales columns of a matrix given the scaling values including the
9311   ghosted ones.
9312 
9313   Not Collective
9314 
9315   Input Parameters:
9316 + mat  - the matrix
9317 - diag - the diagonal values, including ghost ones
9318 
9319   Level: developer
9320 
9321   Notes:
9322   Works only for `MATMPIAIJ` and `MATMPIBAIJ` matrices
9323 
9324   This allows one to avoid during communication to perform the scaling that must be done with `MatDiagonalScale()`
9325 
9326 .seealso: [](ch_matrices), `Mat`, `MatDiagonalScale()`
9327 @*/
9328 PetscErrorCode MatDiagonalScaleLocal(Mat mat, Vec diag)
9329 {
9330   PetscMPIInt size;
9331 
9332   PetscFunctionBegin;
9333   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9334   PetscValidHeaderSpecific(diag, VEC_CLASSID, 2);
9335   PetscValidType(mat, 1);
9336 
9337   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must be already assembled");
9338   PetscCall(PetscLogEventBegin(MAT_Scale, mat, 0, 0, 0));
9339   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
9340   if (size == 1) {
9341     PetscInt n, m;
9342     PetscCall(VecGetSize(diag, &n));
9343     PetscCall(MatGetSize(mat, NULL, &m));
9344     PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supported for sequential matrices when no ghost points/periodic conditions");
9345     PetscCall(MatDiagonalScale(mat, NULL, diag));
9346   } else {
9347     PetscUseMethod(mat, "MatDiagonalScaleLocal_C", (Mat, Vec), (mat, diag));
9348   }
9349   PetscCall(PetscLogEventEnd(MAT_Scale, mat, 0, 0, 0));
9350   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
9351   PetscFunctionReturn(PETSC_SUCCESS);
9352 }
9353 
9354 /*@
9355   MatGetInertia - Gets the inertia from a factored matrix
9356 
9357   Collective
9358 
9359   Input Parameter:
9360 . mat - the matrix
9361 
9362   Output Parameters:
9363 + nneg  - number of negative eigenvalues
9364 . nzero - number of zero eigenvalues
9365 - npos  - number of positive eigenvalues
9366 
9367   Level: advanced
9368 
9369   Note:
9370   Matrix must have been factored by `MatCholeskyFactor()`
9371 
9372 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatCholeskyFactor()`
9373 @*/
9374 PetscErrorCode MatGetInertia(Mat mat, PetscInt *nneg, PetscInt *nzero, PetscInt *npos)
9375 {
9376   PetscFunctionBegin;
9377   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9378   PetscValidType(mat, 1);
9379   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9380   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Numeric factor mat is not assembled");
9381   PetscUseTypeMethod(mat, getinertia, nneg, nzero, npos);
9382   PetscFunctionReturn(PETSC_SUCCESS);
9383 }
9384 
9385 /*@C
9386   MatSolves - Solves $A x = b$, given a factored matrix, for a collection of vectors
9387 
9388   Neighbor-wise Collective
9389 
9390   Input Parameters:
9391 + mat - the factored matrix obtained with `MatGetFactor()`
9392 - b   - the right-hand-side vectors
9393 
9394   Output Parameter:
9395 . x - the result vectors
9396 
9397   Level: developer
9398 
9399   Note:
9400   The vectors `b` and `x` cannot be the same.  I.e., one cannot
9401   call `MatSolves`(A,x,x).
9402 
9403 .seealso: [](ch_matrices), `Mat`, `Vecs`, `MatSolveAdd()`, `MatSolveTranspose()`, `MatSolveTransposeAdd()`, `MatSolve()`
9404 @*/
9405 PetscErrorCode MatSolves(Mat mat, Vecs b, Vecs x)
9406 {
9407   PetscFunctionBegin;
9408   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9409   PetscValidType(mat, 1);
9410   PetscCheck(x != b, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_IDN, "x and b must be different vectors");
9411   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Unfactored matrix");
9412   if (!mat->rmap->N && !mat->cmap->N) PetscFunctionReturn(PETSC_SUCCESS);
9413 
9414   MatCheckPreallocated(mat, 1);
9415   PetscCall(PetscLogEventBegin(MAT_Solves, mat, 0, 0, 0));
9416   PetscUseTypeMethod(mat, solves, b, x);
9417   PetscCall(PetscLogEventEnd(MAT_Solves, mat, 0, 0, 0));
9418   PetscFunctionReturn(PETSC_SUCCESS);
9419 }
9420 
9421 /*@
9422   MatIsSymmetric - Test whether a matrix is symmetric
9423 
9424   Collective
9425 
9426   Input Parameters:
9427 + A   - the matrix to test
9428 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact transpose)
9429 
9430   Output Parameter:
9431 . flg - the result
9432 
9433   Level: intermediate
9434 
9435   Notes:
9436   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9437 
9438   If the matrix does not yet know if it is symmetric or not this can be an expensive operation, also available `MatIsSymmetricKnown()`
9439 
9440   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9441   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9442 
9443 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetricKnown()`,
9444           `MAT_SYMMETRIC`, `MAT_SYMMETRY_ETERNAL`
9445 @*/
9446 PetscErrorCode MatIsSymmetric(Mat A, PetscReal tol, PetscBool *flg)
9447 {
9448   PetscFunctionBegin;
9449   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9450   PetscAssertPointer(flg, 3);
9451   if (A->symmetric != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->symmetric);
9452   else {
9453     if (A->ops->issymmetric) PetscUseTypeMethod(A, issymmetric, tol, flg);
9454     else PetscCall(MatIsTranspose(A, A, tol, flg));
9455     if (!tol) PetscCall(MatSetOption(A, MAT_SYMMETRIC, *flg));
9456   }
9457   PetscFunctionReturn(PETSC_SUCCESS);
9458 }
9459 
9460 /*@
9461   MatIsHermitian - Test whether a matrix is Hermitian
9462 
9463   Collective
9464 
9465   Input Parameters:
9466 + A   - the matrix to test
9467 - tol - difference between value and its transpose less than this amount counts as equal (use 0.0 for exact Hermitian)
9468 
9469   Output Parameter:
9470 . flg - the result
9471 
9472   Level: intermediate
9473 
9474   Notes:
9475   For real numbers `MatIsSymmetric()` and `MatIsHermitian()` return identical results
9476 
9477   If the matrix does not yet know if it is Hermitian or not this can be an expensive operation, also available `MatIsHermitianKnown()`
9478 
9479   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9480   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMEMTRY_ETERNAL`,`PETSC_TRUE`)
9481 
9482 .seealso: [](ch_matrices), `Mat`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitianKnown()`, `MatIsStructurallySymmetric()`, `MatSetOption()`,
9483           `MatIsSymmetricKnown()`, `MatIsSymmetric()`, `MAT_HERMITIAN`, `MAT_SYMMETRY_ETERNAL`
9484 @*/
9485 PetscErrorCode MatIsHermitian(Mat A, PetscReal tol, PetscBool *flg)
9486 {
9487   PetscFunctionBegin;
9488   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9489   PetscAssertPointer(flg, 3);
9490   if (A->hermitian != PETSC_BOOL3_UNKNOWN && !tol) *flg = PetscBool3ToBool(A->hermitian);
9491   else {
9492     if (A->ops->ishermitian) PetscUseTypeMethod(A, ishermitian, tol, flg);
9493     else PetscCall(MatIsHermitianTranspose(A, A, tol, flg));
9494     if (!tol) PetscCall(MatSetOption(A, MAT_HERMITIAN, *flg));
9495   }
9496   PetscFunctionReturn(PETSC_SUCCESS);
9497 }
9498 
9499 /*@
9500   MatIsSymmetricKnown - Checks if a matrix knows if it is symmetric or not and its symmetric state
9501 
9502   Not Collective
9503 
9504   Input Parameter:
9505 . A - the matrix to check
9506 
9507   Output Parameters:
9508 + set - `PETSC_TRUE` if the matrix knows its symmetry state (this tells you if the next flag is valid)
9509 - flg - the result (only valid if set is `PETSC_TRUE`)
9510 
9511   Level: advanced
9512 
9513   Notes:
9514   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsSymmetric()`
9515   if you want it explicitly checked
9516 
9517   One can declare that a matrix is symmetric with `MatSetOption`(mat,`MAT_SYMMETRIC`,`PETSC_TRUE`) and if it is known to remain symmetric
9518   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9519 
9520 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9521 @*/
9522 PetscErrorCode MatIsSymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9523 {
9524   PetscFunctionBegin;
9525   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9526   PetscAssertPointer(set, 2);
9527   PetscAssertPointer(flg, 3);
9528   if (A->symmetric != PETSC_BOOL3_UNKNOWN) {
9529     *set = PETSC_TRUE;
9530     *flg = PetscBool3ToBool(A->symmetric);
9531   } else {
9532     *set = PETSC_FALSE;
9533   }
9534   PetscFunctionReturn(PETSC_SUCCESS);
9535 }
9536 
9537 /*@
9538   MatIsSPDKnown - Checks if a matrix knows if it is symmetric positive definite or not and its symmetric positive definite state
9539 
9540   Not Collective
9541 
9542   Input Parameter:
9543 . A - the matrix to check
9544 
9545   Output Parameters:
9546 + set - `PETSC_TRUE` if the matrix knows its symmetric positive definite state (this tells you if the next flag is valid)
9547 - flg - the result (only valid if set is `PETSC_TRUE`)
9548 
9549   Level: advanced
9550 
9551   Notes:
9552   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`).
9553 
9554   One can declare that a matrix is SPD with `MatSetOption`(mat,`MAT_SPD`,`PETSC_TRUE`) and if it is known to remain SPD
9555   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SPD_ETERNAL`,`PETSC_TRUE`)
9556 
9557 .seealso: [](ch_matrices), `Mat`, `MAT_SPD_ETERNAL`, `MAT_SPD`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9558 @*/
9559 PetscErrorCode MatIsSPDKnown(Mat A, PetscBool *set, PetscBool *flg)
9560 {
9561   PetscFunctionBegin;
9562   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9563   PetscAssertPointer(set, 2);
9564   PetscAssertPointer(flg, 3);
9565   if (A->spd != PETSC_BOOL3_UNKNOWN) {
9566     *set = PETSC_TRUE;
9567     *flg = PetscBool3ToBool(A->spd);
9568   } else {
9569     *set = PETSC_FALSE;
9570   }
9571   PetscFunctionReturn(PETSC_SUCCESS);
9572 }
9573 
9574 /*@
9575   MatIsHermitianKnown - Checks if a matrix knows if it is Hermitian or not and its Hermitian state
9576 
9577   Not Collective
9578 
9579   Input Parameter:
9580 . A - the matrix to check
9581 
9582   Output Parameters:
9583 + set - `PETSC_TRUE` if the matrix knows its Hermitian state (this tells you if the next flag is valid)
9584 - flg - the result (only valid if set is `PETSC_TRUE`)
9585 
9586   Level: advanced
9587 
9588   Notes:
9589   Does not check the matrix values directly, so this may return unknown (set = `PETSC_FALSE`). Use `MatIsHermitian()`
9590   if you want it explicitly checked
9591 
9592   One can declare that a matrix is Hermitian with `MatSetOption`(mat,`MAT_HERMITIAN`,`PETSC_TRUE`) and if it is known to remain Hermitian
9593   after changes to the matrices values one can call `MatSetOption`(mat,`MAT_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9594 
9595 .seealso: [](ch_matrices), `Mat`, `MAT_SYMMETRY_ETERNAL`, `MAT_HERMITIAN`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`
9596 @*/
9597 PetscErrorCode MatIsHermitianKnown(Mat A, PetscBool *set, PetscBool *flg)
9598 {
9599   PetscFunctionBegin;
9600   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9601   PetscAssertPointer(set, 2);
9602   PetscAssertPointer(flg, 3);
9603   if (A->hermitian != PETSC_BOOL3_UNKNOWN) {
9604     *set = PETSC_TRUE;
9605     *flg = PetscBool3ToBool(A->hermitian);
9606   } else {
9607     *set = PETSC_FALSE;
9608   }
9609   PetscFunctionReturn(PETSC_SUCCESS);
9610 }
9611 
9612 /*@
9613   MatIsStructurallySymmetric - Test whether a matrix is structurally symmetric
9614 
9615   Collective
9616 
9617   Input Parameter:
9618 . A - the matrix to test
9619 
9620   Output Parameter:
9621 . flg - the result
9622 
9623   Level: intermediate
9624 
9625   Notes:
9626   If the matrix does yet know it is structurally symmetric this can be an expensive operation, also available `MatIsStructurallySymmetricKnown()`
9627 
9628   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
9629   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9630 
9631 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MAT_STRUCTURAL_SYMMETRY_ETERNAL`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsSymmetric()`, `MatSetOption()`, `MatIsStructurallySymmetricKnown()`
9632 @*/
9633 PetscErrorCode MatIsStructurallySymmetric(Mat A, PetscBool *flg)
9634 {
9635   PetscFunctionBegin;
9636   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9637   PetscAssertPointer(flg, 2);
9638   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9639     *flg = PetscBool3ToBool(A->structurally_symmetric);
9640   } else {
9641     PetscUseTypeMethod(A, isstructurallysymmetric, flg);
9642     PetscCall(MatSetOption(A, MAT_STRUCTURALLY_SYMMETRIC, *flg));
9643   }
9644   PetscFunctionReturn(PETSC_SUCCESS);
9645 }
9646 
9647 /*@
9648   MatIsStructurallySymmetricKnown - Checks if a matrix knows if it is structurally symmetric or not and its structurally symmetric state
9649 
9650   Not Collective
9651 
9652   Input Parameter:
9653 . A - the matrix to check
9654 
9655   Output Parameters:
9656 + set - PETSC_TRUE if the matrix knows its structurally symmetric state (this tells you if the next flag is valid)
9657 - flg - the result (only valid if set is PETSC_TRUE)
9658 
9659   Level: advanced
9660 
9661   Notes:
9662   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
9663   symmetric after changes to the matrices values one can call `MatSetOption`(mat,`MAT_STRUCTURAL_SYMMETRY_ETERNAL`,`PETSC_TRUE`)
9664 
9665   Use `MatIsStructurallySymmetric()` to explicitly check if a matrix is structurally symmetric (this is an expensive operation)
9666 
9667 .seealso: [](ch_matrices), `Mat`, `MAT_STRUCTURALLY_SYMMETRIC`, `MatTranspose()`, `MatIsTranspose()`, `MatIsHermitian()`, `MatIsStructurallySymmetric()`, `MatSetOption()`, `MatIsSymmetric()`, `MatIsHermitianKnown()`
9668 @*/
9669 PetscErrorCode MatIsStructurallySymmetricKnown(Mat A, PetscBool *set, PetscBool *flg)
9670 {
9671   PetscFunctionBegin;
9672   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
9673   PetscAssertPointer(set, 2);
9674   PetscAssertPointer(flg, 3);
9675   if (A->structurally_symmetric != PETSC_BOOL3_UNKNOWN) {
9676     *set = PETSC_TRUE;
9677     *flg = PetscBool3ToBool(A->structurally_symmetric);
9678   } else {
9679     *set = PETSC_FALSE;
9680   }
9681   PetscFunctionReturn(PETSC_SUCCESS);
9682 }
9683 
9684 /*@
9685   MatStashGetInfo - Gets how many values are currently in the matrix stash, i.e. need
9686   to be communicated to other processors during the `MatAssemblyBegin()`/`MatAssemblyEnd()` process
9687 
9688   Not Collective
9689 
9690   Input Parameter:
9691 . mat - the matrix
9692 
9693   Output Parameters:
9694 + nstash    - the size of the stash
9695 . reallocs  - the number of additional mallocs incurred.
9696 . bnstash   - the size of the block stash
9697 - breallocs - the number of additional mallocs incurred.in the block stash
9698 
9699   Level: advanced
9700 
9701 .seealso: [](ch_matrices), `MatAssemblyBegin()`, `MatAssemblyEnd()`, `Mat`, `MatStashSetInitialSize()`
9702 @*/
9703 PetscErrorCode MatStashGetInfo(Mat mat, PetscInt *nstash, PetscInt *reallocs, PetscInt *bnstash, PetscInt *breallocs)
9704 {
9705   PetscFunctionBegin;
9706   PetscCall(MatStashGetInfo_Private(&mat->stash, nstash, reallocs));
9707   PetscCall(MatStashGetInfo_Private(&mat->bstash, bnstash, breallocs));
9708   PetscFunctionReturn(PETSC_SUCCESS);
9709 }
9710 
9711 /*@
9712   MatCreateVecs - Get vector(s) compatible with the matrix, i.e. with the same
9713   parallel layout, `PetscLayout` for rows and columns
9714 
9715   Collective
9716 
9717   Input Parameter:
9718 . mat - the matrix
9719 
9720   Output Parameters:
9721 + right - (optional) vector that the matrix can be multiplied against
9722 - left  - (optional) vector that the matrix vector product can be stored in
9723 
9724   Level: advanced
9725 
9726   Notes:
9727   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()`.
9728 
9729   These are new vectors which are not owned by the mat, they should be destroyed in `VecDestroy()` when no longer needed
9730 
9731 .seealso: [](ch_matrices), `Mat`, `Vec`, `VecCreate()`, `VecDestroy()`, `DMCreateGlobalVector()`
9732 @*/
9733 PetscErrorCode MatCreateVecs(Mat mat, Vec *right, Vec *left)
9734 {
9735   PetscFunctionBegin;
9736   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9737   PetscValidType(mat, 1);
9738   if (mat->ops->getvecs) {
9739     PetscUseTypeMethod(mat, getvecs, right, left);
9740   } else {
9741     if (right) {
9742       PetscCheck(mat->cmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for columns not yet setup");
9743       PetscCall(VecCreateWithLayout_Private(mat->cmap, right));
9744       PetscCall(VecSetType(*right, mat->defaultvectype));
9745 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9746       if (mat->boundtocpu && mat->bindingpropagates) {
9747         PetscCall(VecSetBindingPropagates(*right, PETSC_TRUE));
9748         PetscCall(VecBindToCPU(*right, PETSC_TRUE));
9749       }
9750 #endif
9751     }
9752     if (left) {
9753       PetscCheck(mat->rmap->n >= 0, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "PetscLayout for rows not yet setup");
9754       PetscCall(VecCreateWithLayout_Private(mat->rmap, left));
9755       PetscCall(VecSetType(*left, mat->defaultvectype));
9756 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
9757       if (mat->boundtocpu && mat->bindingpropagates) {
9758         PetscCall(VecSetBindingPropagates(*left, PETSC_TRUE));
9759         PetscCall(VecBindToCPU(*left, PETSC_TRUE));
9760       }
9761 #endif
9762     }
9763   }
9764   PetscFunctionReturn(PETSC_SUCCESS);
9765 }
9766 
9767 /*@
9768   MatFactorInfoInitialize - Initializes a `MatFactorInfo` data structure
9769   with default values.
9770 
9771   Not Collective
9772 
9773   Input Parameter:
9774 . info - the `MatFactorInfo` data structure
9775 
9776   Level: developer
9777 
9778   Notes:
9779   The solvers are generally used through the `KSP` and `PC` objects, for example
9780   `PCLU`, `PCILU`, `PCCHOLESKY`, `PCICC`
9781 
9782   Once the data structure is initialized one may change certain entries as desired for the particular factorization to be performed
9783 
9784 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorInfo`
9785 @*/
9786 PetscErrorCode MatFactorInfoInitialize(MatFactorInfo *info)
9787 {
9788   PetscFunctionBegin;
9789   PetscCall(PetscMemzero(info, sizeof(MatFactorInfo)));
9790   PetscFunctionReturn(PETSC_SUCCESS);
9791 }
9792 
9793 /*@
9794   MatFactorSetSchurIS - Set indices corresponding to the Schur complement you wish to have computed
9795 
9796   Collective
9797 
9798   Input Parameters:
9799 + mat - the factored matrix
9800 - is  - the index set defining the Schur indices (0-based)
9801 
9802   Level: advanced
9803 
9804   Notes:
9805   Call `MatFactorSolveSchurComplement()` or `MatFactorSolveSchurComplementTranspose()` after this call to solve a Schur complement system.
9806 
9807   You can call `MatFactorGetSchurComplement()` or `MatFactorCreateSchurComplement()` after this call.
9808 
9809   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9810 
9811 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorGetSchurComplement()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSolveSchurComplement()`,
9812           `MatFactorSolveSchurComplementTranspose()`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9813 @*/
9814 PetscErrorCode MatFactorSetSchurIS(Mat mat, IS is)
9815 {
9816   PetscErrorCode (*f)(Mat, IS);
9817 
9818   PetscFunctionBegin;
9819   PetscValidType(mat, 1);
9820   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
9821   PetscValidType(is, 2);
9822   PetscValidHeaderSpecific(is, IS_CLASSID, 2);
9823   PetscCheckSameComm(mat, 1, is, 2);
9824   PetscCheck(mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Only for factored matrix");
9825   PetscCall(PetscObjectQueryFunction((PetscObject)mat, "MatFactorSetSchurIS_C", &f));
9826   PetscCheck(f, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "The selected MatSolverType does not support Schur complement computation. You should use MATSOLVERMUMPS or MATSOLVERMKL_PARDISO");
9827   PetscCall(MatDestroy(&mat->schur));
9828   PetscCall((*f)(mat, is));
9829   PetscCheck(mat->schur, PetscObjectComm((PetscObject)mat), PETSC_ERR_PLIB, "Schur complement has not been created");
9830   PetscFunctionReturn(PETSC_SUCCESS);
9831 }
9832 
9833 /*@
9834   MatFactorCreateSchurComplement - Create a Schur complement matrix object using Schur data computed during the factorization step
9835 
9836   Logically Collective
9837 
9838   Input Parameters:
9839 + F      - the factored matrix obtained by calling `MatGetFactor()`
9840 . S      - location where to return the Schur complement, can be `NULL`
9841 - status - the status of the Schur complement matrix, can be `NULL`
9842 
9843   Level: advanced
9844 
9845   Notes:
9846   You must call `MatFactorSetSchurIS()` before calling this routine.
9847 
9848   This functionality is only supported for `MATSOLVERMUMPS` and `MATSOLVERMKL_PARDISO`
9849 
9850   The routine provides a copy of the Schur matrix stored within the solver data structures.
9851   The caller must destroy the object when it is no longer needed.
9852   If `MatFactorInvertSchurComplement()` has been called, the routine gets back the inverse.
9853 
9854   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)
9855 
9856   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9857 
9858   Developer Note:
9859   The reason this routine exists is because the representation of the Schur complement within the factor matrix may be different than a standard PETSc
9860   matrix representation and we normally do not want to use the time or memory to make a copy as a regular PETSc matrix.
9861 
9862 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorSchurStatus`, `MATSOLVERMUMPS`, `MATSOLVERMKL_PARDISO`
9863 @*/
9864 PetscErrorCode MatFactorCreateSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9865 {
9866   PetscFunctionBegin;
9867   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9868   if (S) PetscAssertPointer(S, 2);
9869   if (status) PetscAssertPointer(status, 3);
9870   if (S) {
9871     PetscErrorCode (*f)(Mat, Mat *);
9872 
9873     PetscCall(PetscObjectQueryFunction((PetscObject)F, "MatFactorCreateSchurComplement_C", &f));
9874     if (f) {
9875       PetscCall((*f)(F, S));
9876     } else {
9877       PetscCall(MatDuplicate(F->schur, MAT_COPY_VALUES, S));
9878     }
9879   }
9880   if (status) *status = F->schur_status;
9881   PetscFunctionReturn(PETSC_SUCCESS);
9882 }
9883 
9884 /*@
9885   MatFactorGetSchurComplement - Gets access to a Schur complement matrix using the current Schur data within a factored matrix
9886 
9887   Logically Collective
9888 
9889   Input Parameters:
9890 + F      - the factored matrix obtained by calling `MatGetFactor()`
9891 . S      - location where to return the Schur complement, can be `NULL`
9892 - status - the status of the Schur complement matrix, can be `NULL`
9893 
9894   Level: advanced
9895 
9896   Notes:
9897   You must call `MatFactorSetSchurIS()` before calling this routine.
9898 
9899   Schur complement mode is currently implemented for sequential matrices with factor type of `MATSOLVERMUMPS`
9900 
9901   The routine returns a the Schur Complement stored within the data structures of the solver.
9902 
9903   If `MatFactorInvertSchurComplement()` has previously been called, the returned matrix is actually the inverse of the Schur complement.
9904 
9905   The returned matrix should not be destroyed; the caller should call `MatFactorRestoreSchurComplement()` when the object is no longer needed.
9906 
9907   Use `MatFactorCreateSchurComplement()` to create a copy of the Schur complement matrix that is within a factored matrix
9908 
9909   See `MatCreateSchurComplement()` or `MatGetSchurComplement()` for ways to create virtual or approximate Schur complements.
9910 
9911 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorRestoreSchurComplement()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9912 @*/
9913 PetscErrorCode MatFactorGetSchurComplement(Mat F, Mat *S, MatFactorSchurStatus *status)
9914 {
9915   PetscFunctionBegin;
9916   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9917   if (S) {
9918     PetscAssertPointer(S, 2);
9919     *S = F->schur;
9920   }
9921   if (status) {
9922     PetscAssertPointer(status, 3);
9923     *status = F->schur_status;
9924   }
9925   PetscFunctionReturn(PETSC_SUCCESS);
9926 }
9927 
9928 static PetscErrorCode MatFactorUpdateSchurStatus_Private(Mat F)
9929 {
9930   Mat S = F->schur;
9931 
9932   PetscFunctionBegin;
9933   switch (F->schur_status) {
9934   case MAT_FACTOR_SCHUR_UNFACTORED: // fall-through
9935   case MAT_FACTOR_SCHUR_INVERTED:
9936     if (S) {
9937       S->ops->solve             = NULL;
9938       S->ops->matsolve          = NULL;
9939       S->ops->solvetranspose    = NULL;
9940       S->ops->matsolvetranspose = NULL;
9941       S->ops->solveadd          = NULL;
9942       S->ops->solvetransposeadd = NULL;
9943       S->factortype             = MAT_FACTOR_NONE;
9944       PetscCall(PetscFree(S->solvertype));
9945     }
9946   case MAT_FACTOR_SCHUR_FACTORED: // fall-through
9947     break;
9948   default:
9949     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
9950   }
9951   PetscFunctionReturn(PETSC_SUCCESS);
9952 }
9953 
9954 /*@
9955   MatFactorRestoreSchurComplement - Restore the Schur complement matrix object obtained from a call to `MatFactorGetSchurComplement()`
9956 
9957   Logically Collective
9958 
9959   Input Parameters:
9960 + F      - the factored matrix obtained by calling `MatGetFactor()`
9961 . S      - location where the Schur complement is stored
9962 - status - the status of the Schur complement matrix (see `MatFactorSchurStatus`)
9963 
9964   Level: advanced
9965 
9966 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorCreateSchurComplement()`, `MatFactorSchurStatus`
9967 @*/
9968 PetscErrorCode MatFactorRestoreSchurComplement(Mat F, Mat *S, MatFactorSchurStatus status)
9969 {
9970   PetscFunctionBegin;
9971   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
9972   if (S) {
9973     PetscValidHeaderSpecific(*S, MAT_CLASSID, 2);
9974     *S = NULL;
9975   }
9976   F->schur_status = status;
9977   PetscCall(MatFactorUpdateSchurStatus_Private(F));
9978   PetscFunctionReturn(PETSC_SUCCESS);
9979 }
9980 
9981 /*@
9982   MatFactorSolveSchurComplementTranspose - Solve the transpose of the Schur complement system computed during the factorization step
9983 
9984   Logically Collective
9985 
9986   Input Parameters:
9987 + F   - the factored matrix obtained by calling `MatGetFactor()`
9988 . rhs - location where the right-hand side of the Schur complement system is stored
9989 - sol - location where the solution of the Schur complement system has to be returned
9990 
9991   Level: advanced
9992 
9993   Notes:
9994   The sizes of the vectors should match the size of the Schur complement
9995 
9996   Must be called after `MatFactorSetSchurIS()`
9997 
9998 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplement()`
9999 @*/
10000 PetscErrorCode MatFactorSolveSchurComplementTranspose(Mat F, Vec rhs, Vec sol)
10001 {
10002   PetscFunctionBegin;
10003   PetscValidType(F, 1);
10004   PetscValidType(rhs, 2);
10005   PetscValidType(sol, 3);
10006   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
10007   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
10008   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
10009   PetscCheckSameComm(F, 1, rhs, 2);
10010   PetscCheckSameComm(F, 1, sol, 3);
10011   PetscCall(MatFactorFactorizeSchurComplement(F));
10012   switch (F->schur_status) {
10013   case MAT_FACTOR_SCHUR_FACTORED:
10014     PetscCall(MatSolveTranspose(F->schur, rhs, sol));
10015     break;
10016   case MAT_FACTOR_SCHUR_INVERTED:
10017     PetscCall(MatMultTranspose(F->schur, rhs, sol));
10018     break;
10019   default:
10020     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
10021   }
10022   PetscFunctionReturn(PETSC_SUCCESS);
10023 }
10024 
10025 /*@
10026   MatFactorSolveSchurComplement - Solve the Schur complement system computed during the factorization step
10027 
10028   Logically Collective
10029 
10030   Input Parameters:
10031 + F   - the factored matrix obtained by calling `MatGetFactor()`
10032 . rhs - location where the right-hand side of the Schur complement system is stored
10033 - sol - location where the solution of the Schur complement system has to be returned
10034 
10035   Level: advanced
10036 
10037   Notes:
10038   The sizes of the vectors should match the size of the Schur complement
10039 
10040   Must be called after `MatFactorSetSchurIS()`
10041 
10042 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorSolveSchurComplementTranspose()`
10043 @*/
10044 PetscErrorCode MatFactorSolveSchurComplement(Mat F, Vec rhs, Vec sol)
10045 {
10046   PetscFunctionBegin;
10047   PetscValidType(F, 1);
10048   PetscValidType(rhs, 2);
10049   PetscValidType(sol, 3);
10050   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
10051   PetscValidHeaderSpecific(rhs, VEC_CLASSID, 2);
10052   PetscValidHeaderSpecific(sol, VEC_CLASSID, 3);
10053   PetscCheckSameComm(F, 1, rhs, 2);
10054   PetscCheckSameComm(F, 1, sol, 3);
10055   PetscCall(MatFactorFactorizeSchurComplement(F));
10056   switch (F->schur_status) {
10057   case MAT_FACTOR_SCHUR_FACTORED:
10058     PetscCall(MatSolve(F->schur, rhs, sol));
10059     break;
10060   case MAT_FACTOR_SCHUR_INVERTED:
10061     PetscCall(MatMult(F->schur, rhs, sol));
10062     break;
10063   default:
10064     SETERRQ(PetscObjectComm((PetscObject)F), PETSC_ERR_SUP, "Unhandled MatFactorSchurStatus %d", F->schur_status);
10065   }
10066   PetscFunctionReturn(PETSC_SUCCESS);
10067 }
10068 
10069 PETSC_EXTERN PetscErrorCode MatSeqDenseInvertFactors_Private(Mat);
10070 #if PetscDefined(HAVE_CUDA)
10071 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode MatSeqDenseCUDAInvertFactors_Internal(Mat);
10072 #endif
10073 
10074 /* Schur status updated in the interface */
10075 static PetscErrorCode MatFactorInvertSchurComplement_Private(Mat F)
10076 {
10077   Mat S = F->schur;
10078 
10079   PetscFunctionBegin;
10080   if (S) {
10081     PetscMPIInt size;
10082     PetscBool   isdense, isdensecuda;
10083 
10084     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)S), &size));
10085     PetscCheck(size <= 1, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not yet implemented");
10086     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSE, &isdense));
10087     PetscCall(PetscObjectTypeCompare((PetscObject)S, MATSEQDENSECUDA, &isdensecuda));
10088     PetscCheck(isdense || isdensecuda, PetscObjectComm((PetscObject)S), PETSC_ERR_SUP, "Not implemented for type %s", ((PetscObject)S)->type_name);
10089     PetscCall(PetscLogEventBegin(MAT_FactorInvS, F, 0, 0, 0));
10090     if (isdense) {
10091       PetscCall(MatSeqDenseInvertFactors_Private(S));
10092     } else if (isdensecuda) {
10093 #if defined(PETSC_HAVE_CUDA)
10094       PetscCall(MatSeqDenseCUDAInvertFactors_Internal(S));
10095 #endif
10096     }
10097     // HIP??????????????
10098     PetscCall(PetscLogEventEnd(MAT_FactorInvS, F, 0, 0, 0));
10099   }
10100   PetscFunctionReturn(PETSC_SUCCESS);
10101 }
10102 
10103 /*@
10104   MatFactorInvertSchurComplement - Invert the Schur complement matrix computed during the factorization step
10105 
10106   Logically Collective
10107 
10108   Input Parameter:
10109 . F - the factored matrix obtained by calling `MatGetFactor()`
10110 
10111   Level: advanced
10112 
10113   Notes:
10114   Must be called after `MatFactorSetSchurIS()`.
10115 
10116   Call `MatFactorGetSchurComplement()` or  `MatFactorCreateSchurComplement()` AFTER this call to actually compute the inverse and get access to it.
10117 
10118 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorGetSchurComplement()`, `MatFactorCreateSchurComplement()`
10119 @*/
10120 PetscErrorCode MatFactorInvertSchurComplement(Mat F)
10121 {
10122   PetscFunctionBegin;
10123   PetscValidType(F, 1);
10124   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
10125   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED) PetscFunctionReturn(PETSC_SUCCESS);
10126   PetscCall(MatFactorFactorizeSchurComplement(F));
10127   PetscCall(MatFactorInvertSchurComplement_Private(F));
10128   F->schur_status = MAT_FACTOR_SCHUR_INVERTED;
10129   PetscFunctionReturn(PETSC_SUCCESS);
10130 }
10131 
10132 /*@
10133   MatFactorFactorizeSchurComplement - Factorize the Schur complement matrix computed during the factorization step
10134 
10135   Logically Collective
10136 
10137   Input Parameter:
10138 . F - the factored matrix obtained by calling `MatGetFactor()`
10139 
10140   Level: advanced
10141 
10142   Note:
10143   Must be called after `MatFactorSetSchurIS()`
10144 
10145 .seealso: [](ch_matrices), `Mat`, `MatGetFactor()`, `MatFactorSetSchurIS()`, `MatFactorInvertSchurComplement()`
10146 @*/
10147 PetscErrorCode MatFactorFactorizeSchurComplement(Mat F)
10148 {
10149   MatFactorInfo info;
10150 
10151   PetscFunctionBegin;
10152   PetscValidType(F, 1);
10153   PetscValidHeaderSpecific(F, MAT_CLASSID, 1);
10154   if (F->schur_status == MAT_FACTOR_SCHUR_INVERTED || F->schur_status == MAT_FACTOR_SCHUR_FACTORED) PetscFunctionReturn(PETSC_SUCCESS);
10155   PetscCall(PetscLogEventBegin(MAT_FactorFactS, F, 0, 0, 0));
10156   PetscCall(PetscMemzero(&info, sizeof(MatFactorInfo)));
10157   if (F->factortype == MAT_FACTOR_CHOLESKY) { /* LDL^t regarded as Cholesky */
10158     PetscCall(MatCholeskyFactor(F->schur, NULL, &info));
10159   } else {
10160     PetscCall(MatLUFactor(F->schur, NULL, NULL, &info));
10161   }
10162   PetscCall(PetscLogEventEnd(MAT_FactorFactS, F, 0, 0, 0));
10163   F->schur_status = MAT_FACTOR_SCHUR_FACTORED;
10164   PetscFunctionReturn(PETSC_SUCCESS);
10165 }
10166 
10167 /*@
10168   MatPtAP - Creates the matrix product $C = P^T * A * P$
10169 
10170   Neighbor-wise Collective
10171 
10172   Input Parameters:
10173 + A     - the matrix
10174 . P     - the projection matrix
10175 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10176 - 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
10177           if the result is a dense matrix this is irrelevant
10178 
10179   Output Parameter:
10180 . C - the product matrix
10181 
10182   Level: intermediate
10183 
10184   Notes:
10185   C will be created and must be destroyed by the user with `MatDestroy()`.
10186 
10187   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
10188 
10189   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10190 
10191   Developer Note:
10192   For matrix types without special implementation the function fallbacks to `MatMatMult()` followed by `MatTransposeMatMult()`.
10193 
10194 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatRARt()`
10195 @*/
10196 PetscErrorCode MatPtAP(Mat A, Mat P, MatReuse scall, PetscReal fill, Mat *C)
10197 {
10198   PetscFunctionBegin;
10199   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10200   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10201 
10202   if (scall == MAT_INITIAL_MATRIX) {
10203     PetscCall(MatProductCreate(A, P, NULL, C));
10204     PetscCall(MatProductSetType(*C, MATPRODUCT_PtAP));
10205     PetscCall(MatProductSetAlgorithm(*C, "default"));
10206     PetscCall(MatProductSetFill(*C, fill));
10207 
10208     (*C)->product->api_user = PETSC_TRUE;
10209     PetscCall(MatProductSetFromOptions(*C));
10210     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);
10211     PetscCall(MatProductSymbolic(*C));
10212   } else { /* scall == MAT_REUSE_MATRIX */
10213     PetscCall(MatProductReplaceMats(A, P, NULL, *C));
10214   }
10215 
10216   PetscCall(MatProductNumeric(*C));
10217   (*C)->symmetric = A->symmetric;
10218   (*C)->spd       = A->spd;
10219   PetscFunctionReturn(PETSC_SUCCESS);
10220 }
10221 
10222 /*@
10223   MatRARt - Creates the matrix product $C = R * A * R^T$
10224 
10225   Neighbor-wise Collective
10226 
10227   Input Parameters:
10228 + A     - the matrix
10229 . R     - the projection matrix
10230 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10231 - fill  - expected fill as ratio of nnz(C)/nnz(A), use `PETSC_DETERMINE` or `PETSC_CURRENT` if you do not have a good estimate
10232           if the result is a dense matrix this is irrelevant
10233 
10234   Output Parameter:
10235 . C - the product matrix
10236 
10237   Level: intermediate
10238 
10239   Notes:
10240   `C` will be created and must be destroyed by the user with `MatDestroy()`.
10241 
10242   An alternative approach to this function is to use `MatProductCreate()` and set the desired options before the computation is done
10243 
10244   This routine is currently only implemented for pairs of `MATAIJ` matrices and classes
10245   which inherit from `MATAIJ`. Due to PETSc sparse matrix block row distribution among processes,
10246   parallel `MatRARt()` is implemented via explicit transpose of `R`, which could be very expensive.
10247   We recommend using `MatPtAP()`.
10248 
10249   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10250 
10251 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MatMatMult()`, `MatPtAP()`
10252 @*/
10253 PetscErrorCode MatRARt(Mat A, Mat R, MatReuse scall, PetscReal fill, Mat *C)
10254 {
10255   PetscFunctionBegin;
10256   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*C, 5);
10257   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10258 
10259   if (scall == MAT_INITIAL_MATRIX) {
10260     PetscCall(MatProductCreate(A, R, NULL, C));
10261     PetscCall(MatProductSetType(*C, MATPRODUCT_RARt));
10262     PetscCall(MatProductSetAlgorithm(*C, "default"));
10263     PetscCall(MatProductSetFill(*C, fill));
10264 
10265     (*C)->product->api_user = PETSC_TRUE;
10266     PetscCall(MatProductSetFromOptions(*C));
10267     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);
10268     PetscCall(MatProductSymbolic(*C));
10269   } else { /* scall == MAT_REUSE_MATRIX */
10270     PetscCall(MatProductReplaceMats(A, R, NULL, *C));
10271   }
10272 
10273   PetscCall(MatProductNumeric(*C));
10274   if (A->symmetric == PETSC_BOOL3_TRUE) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10275   PetscFunctionReturn(PETSC_SUCCESS);
10276 }
10277 
10278 static PetscErrorCode MatProduct_Private(Mat A, Mat B, MatReuse scall, PetscReal fill, MatProductType ptype, Mat *C)
10279 {
10280   PetscBool flg = PETSC_TRUE;
10281 
10282   PetscFunctionBegin;
10283   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX product not supported");
10284   if (scall == MAT_INITIAL_MATRIX) {
10285     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_INITIAL_MATRIX and product type %s\n", MatProductTypes[ptype]));
10286     PetscCall(MatProductCreate(A, B, NULL, C));
10287     PetscCall(MatProductSetAlgorithm(*C, MATPRODUCTALGORITHMDEFAULT));
10288     PetscCall(MatProductSetFill(*C, fill));
10289   } else { /* scall == MAT_REUSE_MATRIX */
10290     Mat_Product *product = (*C)->product;
10291 
10292     PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)*C, &flg, MATSEQDENSE, MATMPIDENSE, ""));
10293     if (flg && product && product->type != ptype) {
10294       PetscCall(MatProductClear(*C));
10295       product = NULL;
10296     }
10297     PetscCall(PetscInfo(A, "Calling MatProduct API with MAT_REUSE_MATRIX %s product present and product type %s\n", product ? "with" : "without", MatProductTypes[ptype]));
10298     if (!product) { /* user provide the dense matrix *C without calling MatProductCreate() or reusing it from previous calls */
10299       PetscCheck(flg, PetscObjectComm((PetscObject)*C), PETSC_ERR_SUP, "Call MatProductCreate() first");
10300       PetscCall(MatProductCreate_Private(A, B, NULL, *C));
10301       product        = (*C)->product;
10302       product->fill  = fill;
10303       product->clear = PETSC_TRUE;
10304     } else { /* user may change input matrices A or B when MAT_REUSE_MATRIX */
10305       flg = PETSC_FALSE;
10306       PetscCall(MatProductReplaceMats(A, B, NULL, *C));
10307     }
10308   }
10309   if (flg) {
10310     (*C)->product->api_user = PETSC_TRUE;
10311     PetscCall(MatProductSetType(*C, ptype));
10312     PetscCall(MatProductSetFromOptions(*C));
10313     PetscCall(MatProductSymbolic(*C));
10314   }
10315   PetscCall(MatProductNumeric(*C));
10316   PetscFunctionReturn(PETSC_SUCCESS);
10317 }
10318 
10319 /*@
10320   MatMatMult - Performs matrix-matrix multiplication C=A*B.
10321 
10322   Neighbor-wise Collective
10323 
10324   Input Parameters:
10325 + A     - the left matrix
10326 . B     - the right matrix
10327 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10328 - 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
10329           if the result is a dense matrix this is irrelevant
10330 
10331   Output Parameter:
10332 . C - the product matrix
10333 
10334   Notes:
10335   Unless scall is `MAT_REUSE_MATRIX` C will be created.
10336 
10337   `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
10338   call to this function with `MAT_INITIAL_MATRIX`.
10339 
10340   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value actually needed.
10341 
10342   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`,
10343   rather than first having `MatMatMult()` create it for you. You can NEVER do this if the matrix `C` is sparse.
10344 
10345   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10346 
10347   Example of Usage:
10348 .vb
10349      MatProductCreate(A,B,NULL,&C);
10350      MatProductSetType(C,MATPRODUCT_AB);
10351      MatProductSymbolic(C);
10352      MatProductNumeric(C); // compute C=A * B
10353      MatProductReplaceMats(A1,B1,NULL,C); // compute C=A1 * B1
10354      MatProductNumeric(C);
10355      MatProductReplaceMats(A2,NULL,NULL,C); // compute C=A2 * B1
10356      MatProductNumeric(C);
10357 .ve
10358 
10359   Level: intermediate
10360 
10361 .seealso: [](ch_matrices), `Mat`, `MatProductType`, `MATPRODUCT_AB`, `MatTransposeMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`, `MatProductCreate()`, `MatProductSymbolic()`, `MatProductReplaceMats()`, `MatProductNumeric()`
10362 @*/
10363 PetscErrorCode MatMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10364 {
10365   PetscFunctionBegin;
10366   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AB, C));
10367   PetscFunctionReturn(PETSC_SUCCESS);
10368 }
10369 
10370 /*@
10371   MatMatTransposeMult - Performs matrix-matrix multiplication $C = A*B^T$.
10372 
10373   Neighbor-wise Collective
10374 
10375   Input Parameters:
10376 + A     - the left matrix
10377 . B     - the right matrix
10378 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10379 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10380 
10381   Output Parameter:
10382 . C - the product matrix
10383 
10384   Options Database Key:
10385 . -matmattransmult_mpidense_mpidense_via {allgatherv,cyclic} - Choose between algorithms for `MATMPIDENSE` matrices: the
10386               first redundantly copies the transposed `B` matrix on each process and requires O(log P) communication complexity;
10387               the second never stores more than one portion of the `B` matrix at a time but requires O(P) communication complexity.
10388 
10389   Level: intermediate
10390 
10391   Notes:
10392   C will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10393 
10394   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call
10395 
10396   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10397   actually needed.
10398 
10399   This routine is currently only implemented for pairs of `MATSEQAIJ` matrices, for the `MATSEQDENSE` class,
10400   and for pairs of `MATMPIDENSE` matrices.
10401 
10402   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABt`
10403 
10404   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10405 
10406 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABt`, `MatMatMult()`, `MatTransposeMatMult()` `MatPtAP()`, `MatProductAlgorithm`, `MatProductType`
10407 @*/
10408 PetscErrorCode MatMatTransposeMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10409 {
10410   PetscFunctionBegin;
10411   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_ABt, C));
10412   if (A == B) PetscCall(MatSetOption(*C, MAT_SYMMETRIC, PETSC_TRUE));
10413   PetscFunctionReturn(PETSC_SUCCESS);
10414 }
10415 
10416 /*@
10417   MatTransposeMatMult - Performs matrix-matrix multiplication $C = A^T*B$.
10418 
10419   Neighbor-wise Collective
10420 
10421   Input Parameters:
10422 + A     - the left matrix
10423 . B     - the right matrix
10424 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10425 - fill  - expected fill as ratio of nnz(C)/(nnz(A) + nnz(B)), use `PETSC_DETERMINE` or `PETSC_CURRENT` if not known
10426 
10427   Output Parameter:
10428 . C - the product matrix
10429 
10430   Level: intermediate
10431 
10432   Notes:
10433   `C` will be created if `MAT_INITIAL_MATRIX` and must be destroyed by the user with `MatDestroy()`.
10434 
10435   `MAT_REUSE_MATRIX` can only be used if the matrices A and B have the same nonzero pattern as in the previous call.
10436 
10437   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_AtB`
10438 
10439   To determine the correct fill value, run with -info and search for the string "Fill ratio" to see the value
10440   actually needed.
10441 
10442   This routine is currently implemented for pairs of `MATAIJ` matrices and pairs of `MATSEQDENSE` matrices and classes
10443   which inherit from `MATSEQAIJ`.  `C` will be of the same type as the input matrices.
10444 
10445   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10446 
10447 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_AtB`, `MatMatMult()`, `MatMatTransposeMult()`, `MatPtAP()`
10448 @*/
10449 PetscErrorCode MatTransposeMatMult(Mat A, Mat B, MatReuse scall, PetscReal fill, Mat *C)
10450 {
10451   PetscFunctionBegin;
10452   PetscCall(MatProduct_Private(A, B, scall, fill, MATPRODUCT_AtB, C));
10453   PetscFunctionReturn(PETSC_SUCCESS);
10454 }
10455 
10456 /*@
10457   MatMatMatMult - Performs matrix-matrix-matrix multiplication D=A*B*C.
10458 
10459   Neighbor-wise Collective
10460 
10461   Input Parameters:
10462 + A     - the left matrix
10463 . B     - the middle matrix
10464 . C     - the right matrix
10465 . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10466 - 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
10467           if the result is a dense matrix this is irrelevant
10468 
10469   Output Parameter:
10470 . D - the product matrix
10471 
10472   Level: intermediate
10473 
10474   Notes:
10475   Unless `scall` is `MAT_REUSE_MATRIX` `D` will be created.
10476 
10477   `MAT_REUSE_MATRIX` can only be used if the matrices `A`, `B`, and `C` have the same nonzero pattern as in the previous call
10478 
10479   This routine is shorthand for using `MatProductCreate()` with the `MatProductType` of `MATPRODUCT_ABC`
10480 
10481   To determine the correct fill value, run with `-info` and search for the string "Fill ratio" to see the value
10482   actually needed.
10483 
10484   If you have many matrices with the same non-zero structure to multiply, you
10485   should use `MAT_REUSE_MATRIX` in all calls but the first
10486 
10487   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
10488 
10489 .seealso: [](ch_matrices), `Mat`, `MatProductCreate()`, `MATPRODUCT_ABC`, `MatMatMult`, `MatPtAP()`, `MatMatTransposeMult()`, `MatTransposeMatMult()`
10490 @*/
10491 PetscErrorCode MatMatMatMult(Mat A, Mat B, Mat C, MatReuse scall, PetscReal fill, Mat *D)
10492 {
10493   PetscFunctionBegin;
10494   if (scall == MAT_REUSE_MATRIX) MatCheckProduct(*D, 6);
10495   PetscCheck(scall != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
10496 
10497   if (scall == MAT_INITIAL_MATRIX) {
10498     PetscCall(MatProductCreate(A, B, C, D));
10499     PetscCall(MatProductSetType(*D, MATPRODUCT_ABC));
10500     PetscCall(MatProductSetAlgorithm(*D, "default"));
10501     PetscCall(MatProductSetFill(*D, fill));
10502 
10503     (*D)->product->api_user = PETSC_TRUE;
10504     PetscCall(MatProductSetFromOptions(*D));
10505     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,
10506                ((PetscObject)C)->type_name);
10507     PetscCall(MatProductSymbolic(*D));
10508   } else { /* user may change input matrices when REUSE */
10509     PetscCall(MatProductReplaceMats(A, B, C, *D));
10510   }
10511   PetscCall(MatProductNumeric(*D));
10512   PetscFunctionReturn(PETSC_SUCCESS);
10513 }
10514 
10515 /*@
10516   MatCreateRedundantMatrix - Create redundant matrices and put them into processors of subcommunicators.
10517 
10518   Collective
10519 
10520   Input Parameters:
10521 + mat      - the matrix
10522 . nsubcomm - the number of subcommunicators (= number of redundant parallel or sequential matrices)
10523 . subcomm  - MPI communicator split from the communicator where mat resides in (or `MPI_COMM_NULL` if nsubcomm is used)
10524 - reuse    - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10525 
10526   Output Parameter:
10527 . matredundant - redundant matrix
10528 
10529   Level: advanced
10530 
10531   Notes:
10532   `MAT_REUSE_MATRIX` can only be used when the nonzero structure of the
10533   original matrix has not changed from that last call to `MatCreateRedundantMatrix()`.
10534 
10535   This routine creates the duplicated matrices in the subcommunicators; you should NOT create them before
10536   calling it.
10537 
10538   `PetscSubcommCreate()` can be used to manage the creation of the subcomm but need not be.
10539 
10540 .seealso: [](ch_matrices), `Mat`, `MatDestroy()`, `PetscSubcommCreate()`, `PetscSubcomm`
10541 @*/
10542 PetscErrorCode MatCreateRedundantMatrix(Mat mat, PetscInt nsubcomm, MPI_Comm subcomm, MatReuse reuse, Mat *matredundant)
10543 {
10544   MPI_Comm       comm;
10545   PetscMPIInt    size;
10546   PetscInt       mloc_sub, nloc_sub, rstart, rend, M = mat->rmap->N, N = mat->cmap->N, bs = mat->rmap->bs;
10547   Mat_Redundant *redund     = NULL;
10548   PetscSubcomm   psubcomm   = NULL;
10549   MPI_Comm       subcomm_in = subcomm;
10550   Mat           *matseq;
10551   IS             isrow, iscol;
10552   PetscBool      newsubcomm = PETSC_FALSE;
10553 
10554   PetscFunctionBegin;
10555   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10556   if (nsubcomm && reuse == MAT_REUSE_MATRIX) {
10557     PetscAssertPointer(*matredundant, 5);
10558     PetscValidHeaderSpecific(*matredundant, MAT_CLASSID, 5);
10559   }
10560 
10561   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
10562   if (size == 1 || nsubcomm == 1) {
10563     if (reuse == MAT_INITIAL_MATRIX) {
10564       PetscCall(MatDuplicate(mat, MAT_COPY_VALUES, matredundant));
10565     } else {
10566       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");
10567       PetscCall(MatCopy(mat, *matredundant, SAME_NONZERO_PATTERN));
10568     }
10569     PetscFunctionReturn(PETSC_SUCCESS);
10570   }
10571 
10572   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10573   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10574   MatCheckPreallocated(mat, 1);
10575 
10576   PetscCall(PetscLogEventBegin(MAT_RedundantMat, mat, 0, 0, 0));
10577   if (subcomm_in == MPI_COMM_NULL && reuse == MAT_INITIAL_MATRIX) { /* get subcomm if user does not provide subcomm */
10578     /* create psubcomm, then get subcomm */
10579     PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
10580     PetscCallMPI(MPI_Comm_size(comm, &size));
10581     PetscCheck(nsubcomm >= 1 && nsubcomm <= size, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "nsubcomm must between 1 and %d", size);
10582 
10583     PetscCall(PetscSubcommCreate(comm, &psubcomm));
10584     PetscCall(PetscSubcommSetNumber(psubcomm, nsubcomm));
10585     PetscCall(PetscSubcommSetType(psubcomm, PETSC_SUBCOMM_CONTIGUOUS));
10586     PetscCall(PetscSubcommSetFromOptions(psubcomm));
10587     PetscCall(PetscCommDuplicate(PetscSubcommChild(psubcomm), &subcomm, NULL));
10588     newsubcomm = PETSC_TRUE;
10589     PetscCall(PetscSubcommDestroy(&psubcomm));
10590   }
10591 
10592   /* get isrow, iscol and a local sequential matrix matseq[0] */
10593   if (reuse == MAT_INITIAL_MATRIX) {
10594     mloc_sub = PETSC_DECIDE;
10595     nloc_sub = PETSC_DECIDE;
10596     if (bs < 1) {
10597       PetscCall(PetscSplitOwnership(subcomm, &mloc_sub, &M));
10598       PetscCall(PetscSplitOwnership(subcomm, &nloc_sub, &N));
10599     } else {
10600       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &mloc_sub, &M));
10601       PetscCall(PetscSplitOwnershipBlock(subcomm, bs, &nloc_sub, &N));
10602     }
10603     PetscCallMPI(MPI_Scan(&mloc_sub, &rend, 1, MPIU_INT, MPI_SUM, subcomm));
10604     rstart = rend - mloc_sub;
10605     PetscCall(ISCreateStride(PETSC_COMM_SELF, mloc_sub, rstart, 1, &isrow));
10606     PetscCall(ISCreateStride(PETSC_COMM_SELF, N, 0, 1, &iscol));
10607     PetscCall(ISSetIdentity(iscol));
10608   } else { /* reuse == MAT_REUSE_MATRIX */
10609     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");
10610     /* retrieve subcomm */
10611     PetscCall(PetscObjectGetComm((PetscObject)*matredundant, &subcomm));
10612     redund = (*matredundant)->redundant;
10613     isrow  = redund->isrow;
10614     iscol  = redund->iscol;
10615     matseq = redund->matseq;
10616   }
10617   PetscCall(MatCreateSubMatrices(mat, 1, &isrow, &iscol, reuse, &matseq));
10618 
10619   /* get matredundant over subcomm */
10620   if (reuse == MAT_INITIAL_MATRIX) {
10621     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], nloc_sub, reuse, matredundant));
10622 
10623     /* create a supporting struct and attach it to C for reuse */
10624     PetscCall(PetscNew(&redund));
10625     (*matredundant)->redundant = redund;
10626     redund->isrow              = isrow;
10627     redund->iscol              = iscol;
10628     redund->matseq             = matseq;
10629     if (newsubcomm) {
10630       redund->subcomm = subcomm;
10631     } else {
10632       redund->subcomm = MPI_COMM_NULL;
10633     }
10634   } else {
10635     PetscCall(MatCreateMPIMatConcatenateSeqMat(subcomm, matseq[0], PETSC_DECIDE, reuse, matredundant));
10636   }
10637 #if defined(PETSC_HAVE_VIENNACL) || defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
10638   if (matseq[0]->boundtocpu && matseq[0]->bindingpropagates) {
10639     PetscCall(MatBindToCPU(*matredundant, PETSC_TRUE));
10640     PetscCall(MatSetBindingPropagates(*matredundant, PETSC_TRUE));
10641   }
10642 #endif
10643   PetscCall(PetscLogEventEnd(MAT_RedundantMat, mat, 0, 0, 0));
10644   PetscFunctionReturn(PETSC_SUCCESS);
10645 }
10646 
10647 /*@C
10648   MatGetMultiProcBlock - Create multiple 'parallel submatrices' from
10649   a given `Mat`. Each submatrix can span multiple procs.
10650 
10651   Collective
10652 
10653   Input Parameters:
10654 + mat     - the matrix
10655 . subComm - the sub communicator obtained as if by `MPI_Comm_split(PetscObjectComm((PetscObject)mat))`
10656 - scall   - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
10657 
10658   Output Parameter:
10659 . subMat - parallel sub-matrices each spanning a given `subcomm`
10660 
10661   Level: advanced
10662 
10663   Notes:
10664   The submatrix partition across processors is dictated by `subComm` a
10665   communicator obtained by `MPI_comm_split()` or via `PetscSubcommCreate()`. The `subComm`
10666   is not restricted to be grouped with consecutive original MPI processes.
10667 
10668   Due the `MPI_Comm_split()` usage, the parallel layout of the submatrices
10669   map directly to the layout of the original matrix [wrt the local
10670   row,col partitioning]. So the original 'DiagonalMat' naturally maps
10671   into the 'DiagonalMat' of the `subMat`, hence it is used directly from
10672   the `subMat`. However the offDiagMat looses some columns - and this is
10673   reconstructed with `MatSetValues()`
10674 
10675   This is used by `PCBJACOBI` when a single block spans multiple MPI processes.
10676 
10677 .seealso: [](ch_matrices), `Mat`, `MatCreateRedundantMatrix()`, `MatCreateSubMatrices()`, `PCBJACOBI`
10678 @*/
10679 PetscErrorCode MatGetMultiProcBlock(Mat mat, MPI_Comm subComm, MatReuse scall, Mat *subMat)
10680 {
10681   PetscMPIInt commsize, subCommSize;
10682 
10683   PetscFunctionBegin;
10684   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &commsize));
10685   PetscCallMPI(MPI_Comm_size(subComm, &subCommSize));
10686   PetscCheck(subCommSize <= commsize, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_OUTOFRANGE, "CommSize %d < SubCommZize %d", commsize, subCommSize);
10687 
10688   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");
10689   PetscCall(PetscLogEventBegin(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10690   PetscUseTypeMethod(mat, getmultiprocblock, subComm, scall, subMat);
10691   PetscCall(PetscLogEventEnd(MAT_GetMultiProcBlock, mat, 0, 0, 0));
10692   PetscFunctionReturn(PETSC_SUCCESS);
10693 }
10694 
10695 /*@
10696   MatGetLocalSubMatrix - Gets a reference to a submatrix specified in local numbering
10697 
10698   Not Collective
10699 
10700   Input Parameters:
10701 + mat   - matrix to extract local submatrix from
10702 . isrow - local row indices for submatrix
10703 - iscol - local column indices for submatrix
10704 
10705   Output Parameter:
10706 . submat - the submatrix
10707 
10708   Level: intermediate
10709 
10710   Notes:
10711   `submat` should be disposed of with `MatRestoreLocalSubMatrix()`.
10712 
10713   Depending on the format of `mat`, the returned `submat` may not implement `MatMult()`.  Its communicator may be
10714   the same as `mat`, it may be `PETSC_COMM_SELF`, or some other sub-communictor of `mat`'s.
10715 
10716   `submat` always implements `MatSetValuesLocal()`.  If `isrow` and `iscol` have the same block size, then
10717   `MatSetValuesBlockedLocal()` will also be implemented.
10718 
10719   `mat` must have had a `ISLocalToGlobalMapping` provided to it with `MatSetLocalToGlobalMapping()`.
10720   Matrices obtained with `DMCreateMatrix()` generally already have the local to global mapping provided.
10721 
10722 .seealso: [](ch_matrices), `Mat`, `MatRestoreLocalSubMatrix()`, `MatCreateLocalRef()`, `MatSetLocalToGlobalMapping()`
10723 @*/
10724 PetscErrorCode MatGetLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10725 {
10726   PetscFunctionBegin;
10727   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10728   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10729   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10730   PetscCheckSameComm(isrow, 2, iscol, 3);
10731   PetscAssertPointer(submat, 4);
10732   PetscCheck(mat->rmap->mapping, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Matrix must have local to global mapping provided before this call");
10733 
10734   if (mat->ops->getlocalsubmatrix) {
10735     PetscUseTypeMethod(mat, getlocalsubmatrix, isrow, iscol, submat);
10736   } else {
10737     PetscCall(MatCreateLocalRef(mat, isrow, iscol, submat));
10738   }
10739   PetscFunctionReturn(PETSC_SUCCESS);
10740 }
10741 
10742 /*@
10743   MatRestoreLocalSubMatrix - Restores a reference to a submatrix specified in local numbering obtained with `MatGetLocalSubMatrix()`
10744 
10745   Not Collective
10746 
10747   Input Parameters:
10748 + mat    - matrix to extract local submatrix from
10749 . isrow  - local row indices for submatrix
10750 . iscol  - local column indices for submatrix
10751 - submat - the submatrix
10752 
10753   Level: intermediate
10754 
10755 .seealso: [](ch_matrices), `Mat`, `MatGetLocalSubMatrix()`
10756 @*/
10757 PetscErrorCode MatRestoreLocalSubMatrix(Mat mat, IS isrow, IS iscol, Mat *submat)
10758 {
10759   PetscFunctionBegin;
10760   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10761   PetscValidHeaderSpecific(isrow, IS_CLASSID, 2);
10762   PetscValidHeaderSpecific(iscol, IS_CLASSID, 3);
10763   PetscCheckSameComm(isrow, 2, iscol, 3);
10764   PetscAssertPointer(submat, 4);
10765   if (*submat) PetscValidHeaderSpecific(*submat, MAT_CLASSID, 4);
10766 
10767   if (mat->ops->restorelocalsubmatrix) {
10768     PetscUseTypeMethod(mat, restorelocalsubmatrix, isrow, iscol, submat);
10769   } else {
10770     PetscCall(MatDestroy(submat));
10771   }
10772   *submat = NULL;
10773   PetscFunctionReturn(PETSC_SUCCESS);
10774 }
10775 
10776 /*@
10777   MatFindZeroDiagonals - Finds all the rows of a matrix that have zero or no diagonal entry in the matrix
10778 
10779   Collective
10780 
10781   Input Parameter:
10782 . mat - the matrix
10783 
10784   Output Parameter:
10785 . is - if any rows have zero diagonals this contains the list of them
10786 
10787   Level: developer
10788 
10789 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10790 @*/
10791 PetscErrorCode MatFindZeroDiagonals(Mat mat, IS *is)
10792 {
10793   PetscFunctionBegin;
10794   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10795   PetscValidType(mat, 1);
10796   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10797   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10798 
10799   if (!mat->ops->findzerodiagonals) {
10800     Vec                diag;
10801     const PetscScalar *a;
10802     PetscInt          *rows;
10803     PetscInt           rStart, rEnd, r, nrow = 0;
10804 
10805     PetscCall(MatCreateVecs(mat, &diag, NULL));
10806     PetscCall(MatGetDiagonal(mat, diag));
10807     PetscCall(MatGetOwnershipRange(mat, &rStart, &rEnd));
10808     PetscCall(VecGetArrayRead(diag, &a));
10809     for (r = 0; r < rEnd - rStart; ++r)
10810       if (a[r] == 0.0) ++nrow;
10811     PetscCall(PetscMalloc1(nrow, &rows));
10812     nrow = 0;
10813     for (r = 0; r < rEnd - rStart; ++r)
10814       if (a[r] == 0.0) rows[nrow++] = r + rStart;
10815     PetscCall(VecRestoreArrayRead(diag, &a));
10816     PetscCall(VecDestroy(&diag));
10817     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)mat), nrow, rows, PETSC_OWN_POINTER, is));
10818   } else {
10819     PetscUseTypeMethod(mat, findzerodiagonals, is);
10820   }
10821   PetscFunctionReturn(PETSC_SUCCESS);
10822 }
10823 
10824 /*@
10825   MatFindOffBlockDiagonalEntries - Finds all the rows of a matrix that have entries outside of the main diagonal block (defined by the matrix block size)
10826 
10827   Collective
10828 
10829   Input Parameter:
10830 . mat - the matrix
10831 
10832   Output Parameter:
10833 . is - contains the list of rows with off block diagonal entries
10834 
10835   Level: developer
10836 
10837 .seealso: [](ch_matrices), `Mat`, `MatMultTranspose()`, `MatMultAdd()`, `MatMultTransposeAdd()`
10838 @*/
10839 PetscErrorCode MatFindOffBlockDiagonalEntries(Mat mat, IS *is)
10840 {
10841   PetscFunctionBegin;
10842   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10843   PetscValidType(mat, 1);
10844   PetscCheck(mat->assembled, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10845   PetscCheck(!mat->factortype, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10846 
10847   PetscUseTypeMethod(mat, findoffblockdiagonalentries, is);
10848   PetscFunctionReturn(PETSC_SUCCESS);
10849 }
10850 
10851 /*@C
10852   MatInvertBlockDiagonal - Inverts the block diagonal entries.
10853 
10854   Collective; No Fortran Support
10855 
10856   Input Parameter:
10857 . mat - the matrix
10858 
10859   Output Parameter:
10860 . values - the block inverses in column major order (FORTRAN-like)
10861 
10862   Level: advanced
10863 
10864   Notes:
10865   The size of the blocks is determined by the block size of the matrix.
10866 
10867   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10868 
10869   The blocks all have the same size, use `MatInvertVariableBlockDiagonal()` for variable block size
10870 
10871 .seealso: [](ch_matrices), `Mat`, `MatInvertVariableBlockEnvelope()`, `MatInvertBlockDiagonalMat()`
10872 @*/
10873 PetscErrorCode MatInvertBlockDiagonal(Mat mat, const PetscScalar *values[])
10874 {
10875   PetscFunctionBegin;
10876   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10877   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10878   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10879   PetscUseTypeMethod(mat, invertblockdiagonal, values);
10880   PetscFunctionReturn(PETSC_SUCCESS);
10881 }
10882 
10883 /*@
10884   MatInvertVariableBlockDiagonal - Inverts the point block diagonal entries.
10885 
10886   Collective; No Fortran Support
10887 
10888   Input Parameters:
10889 + mat     - the matrix
10890 . nblocks - the number of blocks on the process, set with `MatSetVariableBlockSizes()`
10891 - bsizes  - the size of each block on the process, set with `MatSetVariableBlockSizes()`
10892 
10893   Output Parameter:
10894 . values - the block inverses in column major order (FORTRAN-like)
10895 
10896   Level: advanced
10897 
10898   Notes:
10899   Use `MatInvertBlockDiagonal()` if all blocks have the same size
10900 
10901   The blocks never overlap between two MPI processes, use `MatInvertVariableBlockEnvelope()` for that case
10902 
10903 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`, `MatSetVariableBlockSizes()`, `MatInvertVariableBlockEnvelope()`
10904 @*/
10905 PetscErrorCode MatInvertVariableBlockDiagonal(Mat mat, PetscInt nblocks, const PetscInt bsizes[], PetscScalar values[])
10906 {
10907   PetscFunctionBegin;
10908   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
10909   PetscCheck(mat->assembled, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
10910   PetscCheck(!mat->factortype, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
10911   PetscUseTypeMethod(mat, invertvariableblockdiagonal, nblocks, bsizes, values);
10912   PetscFunctionReturn(PETSC_SUCCESS);
10913 }
10914 
10915 /*@
10916   MatInvertBlockDiagonalMat - set the values of matrix C to be the inverted block diagonal of matrix A
10917 
10918   Collective
10919 
10920   Input Parameters:
10921 + A - the matrix
10922 - C - matrix with inverted block diagonal of `A`.  This matrix should be created and may have its type set.
10923 
10924   Level: advanced
10925 
10926   Note:
10927   The blocksize of the matrix is used to determine the blocks on the diagonal of `C`
10928 
10929 .seealso: [](ch_matrices), `Mat`, `MatInvertBlockDiagonal()`
10930 @*/
10931 PetscErrorCode MatInvertBlockDiagonalMat(Mat A, Mat C)
10932 {
10933   const PetscScalar *vals;
10934   PetscInt          *dnnz;
10935   PetscInt           m, rstart, rend, bs, i, j;
10936 
10937   PetscFunctionBegin;
10938   PetscCall(MatInvertBlockDiagonal(A, &vals));
10939   PetscCall(MatGetBlockSize(A, &bs));
10940   PetscCall(MatGetLocalSize(A, &m, NULL));
10941   PetscCall(MatSetLayouts(C, A->rmap, A->cmap));
10942   PetscCall(PetscMalloc1(m / bs, &dnnz));
10943   for (j = 0; j < m / bs; j++) dnnz[j] = 1;
10944   PetscCall(MatXAIJSetPreallocation(C, bs, dnnz, NULL, NULL, NULL));
10945   PetscCall(PetscFree(dnnz));
10946   PetscCall(MatGetOwnershipRange(C, &rstart, &rend));
10947   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_FALSE));
10948   for (i = rstart / bs; i < rend / bs; i++) PetscCall(MatSetValuesBlocked(C, 1, &i, 1, &i, &vals[(i - rstart / bs) * bs * bs], INSERT_VALUES));
10949   PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY));
10950   PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY));
10951   PetscCall(MatSetOption(C, MAT_ROW_ORIENTED, PETSC_TRUE));
10952   PetscFunctionReturn(PETSC_SUCCESS);
10953 }
10954 
10955 /*@
10956   MatTransposeColoringDestroy - Destroys a coloring context for matrix product $C = A*B^T$ that was created
10957   via `MatTransposeColoringCreate()`.
10958 
10959   Collective
10960 
10961   Input Parameter:
10962 . c - coloring context
10963 
10964   Level: intermediate
10965 
10966 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`
10967 @*/
10968 PetscErrorCode MatTransposeColoringDestroy(MatTransposeColoring *c)
10969 {
10970   MatTransposeColoring matcolor = *c;
10971 
10972   PetscFunctionBegin;
10973   if (!matcolor) PetscFunctionReturn(PETSC_SUCCESS);
10974   if (--((PetscObject)matcolor)->refct > 0) {
10975     matcolor = NULL;
10976     PetscFunctionReturn(PETSC_SUCCESS);
10977   }
10978 
10979   PetscCall(PetscFree3(matcolor->ncolumns, matcolor->nrows, matcolor->colorforrow));
10980   PetscCall(PetscFree(matcolor->rows));
10981   PetscCall(PetscFree(matcolor->den2sp));
10982   PetscCall(PetscFree(matcolor->colorforcol));
10983   PetscCall(PetscFree(matcolor->columns));
10984   if (matcolor->brows > 0) PetscCall(PetscFree(matcolor->lstart));
10985   PetscCall(PetscHeaderDestroy(c));
10986   PetscFunctionReturn(PETSC_SUCCESS);
10987 }
10988 
10989 /*@
10990   MatTransColoringApplySpToDen - Given a symbolic matrix product $C = A*B^T$ for which
10991   a `MatTransposeColoring` context has been created, computes a dense $B^T$ by applying
10992   `MatTransposeColoring` to sparse `B`.
10993 
10994   Collective
10995 
10996   Input Parameters:
10997 + coloring - coloring context created with `MatTransposeColoringCreate()`
10998 - B        - sparse matrix
10999 
11000   Output Parameter:
11001 . Btdense - dense matrix $B^T$
11002 
11003   Level: developer
11004 
11005   Note:
11006   These are used internally for some implementations of `MatRARt()`
11007 
11008 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplyDenToSp()`
11009 @*/
11010 PetscErrorCode MatTransColoringApplySpToDen(MatTransposeColoring coloring, Mat B, Mat Btdense)
11011 {
11012   PetscFunctionBegin;
11013   PetscValidHeaderSpecific(coloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
11014   PetscValidHeaderSpecific(B, MAT_CLASSID, 2);
11015   PetscValidHeaderSpecific(Btdense, MAT_CLASSID, 3);
11016 
11017   PetscCall((*B->ops->transcoloringapplysptoden)(coloring, B, Btdense));
11018   PetscFunctionReturn(PETSC_SUCCESS);
11019 }
11020 
11021 /*@
11022   MatTransColoringApplyDenToSp - Given a symbolic matrix product $C_{sp} = A*B^T$ for which
11023   a `MatTransposeColoring` context has been created and a dense matrix $C_{den} = A*B^T_{dense}$
11024   in which `B^T_{dens}` is obtained from `MatTransColoringApplySpToDen()`, recover sparse matrix
11025   $C_{sp}$ from $C_{den}$.
11026 
11027   Collective
11028 
11029   Input Parameters:
11030 + matcoloring - coloring context created with `MatTransposeColoringCreate()`
11031 - Cden        - matrix product of a sparse matrix and a dense matrix Btdense
11032 
11033   Output Parameter:
11034 . Csp - sparse matrix
11035 
11036   Level: developer
11037 
11038   Note:
11039   These are used internally for some implementations of `MatRARt()`
11040 
11041 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringCreate()`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`
11042 @*/
11043 PetscErrorCode MatTransColoringApplyDenToSp(MatTransposeColoring matcoloring, Mat Cden, Mat Csp)
11044 {
11045   PetscFunctionBegin;
11046   PetscValidHeaderSpecific(matcoloring, MAT_TRANSPOSECOLORING_CLASSID, 1);
11047   PetscValidHeaderSpecific(Cden, MAT_CLASSID, 2);
11048   PetscValidHeaderSpecific(Csp, MAT_CLASSID, 3);
11049 
11050   PetscCall((*Csp->ops->transcoloringapplydentosp)(matcoloring, Cden, Csp));
11051   PetscCall(MatAssemblyBegin(Csp, MAT_FINAL_ASSEMBLY));
11052   PetscCall(MatAssemblyEnd(Csp, MAT_FINAL_ASSEMBLY));
11053   PetscFunctionReturn(PETSC_SUCCESS);
11054 }
11055 
11056 /*@
11057   MatTransposeColoringCreate - Creates a matrix coloring context for the matrix product $C = A*B^T$.
11058 
11059   Collective
11060 
11061   Input Parameters:
11062 + mat        - the matrix product C
11063 - iscoloring - the coloring of the matrix; usually obtained with `MatColoringCreate()` or `DMCreateColoring()`
11064 
11065   Output Parameter:
11066 . color - the new coloring context
11067 
11068   Level: intermediate
11069 
11070 .seealso: [](ch_matrices), `Mat`, `MatTransposeColoringDestroy()`, `MatTransColoringApplySpToDen()`,
11071           `MatTransColoringApplyDenToSp()`
11072 @*/
11073 PetscErrorCode MatTransposeColoringCreate(Mat mat, ISColoring iscoloring, MatTransposeColoring *color)
11074 {
11075   MatTransposeColoring c;
11076   MPI_Comm             comm;
11077 
11078   PetscFunctionBegin;
11079   PetscAssertPointer(color, 3);
11080 
11081   PetscCall(PetscLogEventBegin(MAT_TransposeColoringCreate, mat, 0, 0, 0));
11082   PetscCall(PetscObjectGetComm((PetscObject)mat, &comm));
11083   PetscCall(PetscHeaderCreate(c, MAT_TRANSPOSECOLORING_CLASSID, "MatTransposeColoring", "Matrix product C=A*B^T via coloring", "Mat", comm, MatTransposeColoringDestroy, NULL));
11084   c->ctype = iscoloring->ctype;
11085   PetscUseTypeMethod(mat, transposecoloringcreate, iscoloring, c);
11086   *color = c;
11087   PetscCall(PetscLogEventEnd(MAT_TransposeColoringCreate, mat, 0, 0, 0));
11088   PetscFunctionReturn(PETSC_SUCCESS);
11089 }
11090 
11091 /*@
11092   MatGetNonzeroState - Returns a 64-bit integer representing the current state of nonzeros in the matrix. If the
11093   matrix has had new nonzero locations added to (or removed from) the matrix since the previous call, the value will be larger.
11094 
11095   Not Collective
11096 
11097   Input Parameter:
11098 . mat - the matrix
11099 
11100   Output Parameter:
11101 . state - the current state
11102 
11103   Level: intermediate
11104 
11105   Notes:
11106   You can only compare states from two different calls to the SAME matrix, you cannot compare calls between
11107   different matrices
11108 
11109   Use `PetscObjectStateGet()` to check for changes to the numerical values in a matrix
11110 
11111   Use the result of `PetscObjectGetId()` to compare if a previously checked matrix is the same as the current matrix, do not compare object pointers.
11112 
11113 .seealso: [](ch_matrices), `Mat`, `PetscObjectStateGet()`, `PetscObjectGetId()`
11114 @*/
11115 PetscErrorCode MatGetNonzeroState(Mat mat, PetscObjectState *state)
11116 {
11117   PetscFunctionBegin;
11118   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11119   *state = mat->nonzerostate;
11120   PetscFunctionReturn(PETSC_SUCCESS);
11121 }
11122 
11123 /*@
11124   MatCreateMPIMatConcatenateSeqMat - Creates a single large PETSc matrix by concatenating sequential
11125   matrices from each processor
11126 
11127   Collective
11128 
11129   Input Parameters:
11130 + comm   - the communicators the parallel matrix will live on
11131 . seqmat - the input sequential matrices
11132 . n      - number of local columns (or `PETSC_DECIDE`)
11133 - reuse  - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
11134 
11135   Output Parameter:
11136 . mpimat - the parallel matrix generated
11137 
11138   Level: developer
11139 
11140   Note:
11141   The number of columns of the matrix in EACH processor MUST be the same.
11142 
11143 .seealso: [](ch_matrices), `Mat`
11144 @*/
11145 PetscErrorCode MatCreateMPIMatConcatenateSeqMat(MPI_Comm comm, Mat seqmat, PetscInt n, MatReuse reuse, Mat *mpimat)
11146 {
11147   PetscMPIInt size;
11148 
11149   PetscFunctionBegin;
11150   PetscCallMPI(MPI_Comm_size(comm, &size));
11151   if (size == 1) {
11152     if (reuse == MAT_INITIAL_MATRIX) {
11153       PetscCall(MatDuplicate(seqmat, MAT_COPY_VALUES, mpimat));
11154     } else {
11155       PetscCall(MatCopy(seqmat, *mpimat, SAME_NONZERO_PATTERN));
11156     }
11157     PetscFunctionReturn(PETSC_SUCCESS);
11158   }
11159 
11160   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");
11161 
11162   PetscCall(PetscLogEventBegin(MAT_Merge, seqmat, 0, 0, 0));
11163   PetscCall((*seqmat->ops->creatempimatconcatenateseqmat)(comm, seqmat, n, reuse, mpimat));
11164   PetscCall(PetscLogEventEnd(MAT_Merge, seqmat, 0, 0, 0));
11165   PetscFunctionReturn(PETSC_SUCCESS);
11166 }
11167 
11168 /*@
11169   MatSubdomainsCreateCoalesce - Creates index subdomains by coalescing adjacent MPI processes' ownership ranges.
11170 
11171   Collective
11172 
11173   Input Parameters:
11174 + A - the matrix to create subdomains from
11175 - N - requested number of subdomains
11176 
11177   Output Parameters:
11178 + n   - number of subdomains resulting on this MPI process
11179 - iss - `IS` list with indices of subdomains on this MPI process
11180 
11181   Level: advanced
11182 
11183   Note:
11184   The number of subdomains must be smaller than the communicator size
11185 
11186 .seealso: [](ch_matrices), `Mat`, `IS`
11187 @*/
11188 PetscErrorCode MatSubdomainsCreateCoalesce(Mat A, PetscInt N, PetscInt *n, IS *iss[])
11189 {
11190   MPI_Comm    comm, subcomm;
11191   PetscMPIInt size, rank, color;
11192   PetscInt    rstart, rend, k;
11193 
11194   PetscFunctionBegin;
11195   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
11196   PetscCallMPI(MPI_Comm_size(comm, &size));
11197   PetscCallMPI(MPI_Comm_rank(comm, &rank));
11198   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);
11199   *n    = 1;
11200   k     = size / N + (size % N > 0); /* There are up to k ranks to a color */
11201   color = rank / k;
11202   PetscCallMPI(MPI_Comm_split(comm, color, rank, &subcomm));
11203   PetscCall(PetscMalloc1(1, iss));
11204   PetscCall(MatGetOwnershipRange(A, &rstart, &rend));
11205   PetscCall(ISCreateStride(subcomm, rend - rstart, rstart, 1, iss[0]));
11206   PetscCallMPI(MPI_Comm_free(&subcomm));
11207   PetscFunctionReturn(PETSC_SUCCESS);
11208 }
11209 
11210 /*@
11211   MatGalerkin - Constructs the coarse grid problem matrix via Galerkin projection.
11212 
11213   If the interpolation and restriction operators are the same, uses `MatPtAP()`.
11214   If they are not the same, uses `MatMatMatMult()`.
11215 
11216   Once the coarse grid problem is constructed, correct for interpolation operators
11217   that are not of full rank, which can legitimately happen in the case of non-nested
11218   geometric multigrid.
11219 
11220   Input Parameters:
11221 + restrct     - restriction operator
11222 . dA          - fine grid matrix
11223 . interpolate - interpolation operator
11224 . reuse       - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
11225 - fill        - expected fill, use `PETSC_DETERMINE` or `PETSC_DETERMINE` if you do not have a good estimate
11226 
11227   Output Parameter:
11228 . A - the Galerkin coarse matrix
11229 
11230   Options Database Key:
11231 . -pc_mg_galerkin <both,pmat,mat,none> - for what matrices the Galerkin process should be used
11232 
11233   Level: developer
11234 
11235   Note:
11236   The deprecated `PETSC_DEFAULT` in `fill` also means use the current value
11237 
11238 .seealso: [](ch_matrices), `Mat`, `MatPtAP()`, `MatMatMatMult()`
11239 @*/
11240 PetscErrorCode MatGalerkin(Mat restrct, Mat dA, Mat interpolate, MatReuse reuse, PetscReal fill, Mat *A)
11241 {
11242   IS  zerorows;
11243   Vec diag;
11244 
11245   PetscFunctionBegin;
11246   PetscCheck(reuse != MAT_INPLACE_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Inplace product not supported");
11247   /* Construct the coarse grid matrix */
11248   if (interpolate == restrct) {
11249     PetscCall(MatPtAP(dA, interpolate, reuse, fill, A));
11250   } else {
11251     PetscCall(MatMatMatMult(restrct, dA, interpolate, reuse, fill, A));
11252   }
11253 
11254   /* If the interpolation matrix is not of full rank, A will have zero rows.
11255      This can legitimately happen in the case of non-nested geometric multigrid.
11256      In that event, we set the rows of the matrix to the rows of the identity,
11257      ignoring the equations (as the RHS will also be zero). */
11258 
11259   PetscCall(MatFindZeroRows(*A, &zerorows));
11260 
11261   if (zerorows != NULL) { /* if there are any zero rows */
11262     PetscCall(MatCreateVecs(*A, &diag, NULL));
11263     PetscCall(MatGetDiagonal(*A, diag));
11264     PetscCall(VecISSet(diag, zerorows, 1.0));
11265     PetscCall(MatDiagonalSet(*A, diag, INSERT_VALUES));
11266     PetscCall(VecDestroy(&diag));
11267     PetscCall(ISDestroy(&zerorows));
11268   }
11269   PetscFunctionReturn(PETSC_SUCCESS);
11270 }
11271 
11272 /*@C
11273   MatSetOperation - Allows user to set a matrix operation for any matrix type
11274 
11275   Logically Collective
11276 
11277   Input Parameters:
11278 + mat - the matrix
11279 . op  - the name of the operation
11280 - f   - the function that provides the operation
11281 
11282   Level: developer
11283 
11284   Example Usage:
11285 .vb
11286   extern PetscErrorCode usermult(Mat, Vec, Vec);
11287 
11288   PetscCall(MatCreateXXX(comm, ..., &A));
11289   PetscCall(MatSetOperation(A, MATOP_MULT, (PetscVoidFn *)usermult));
11290 .ve
11291 
11292   Notes:
11293   See the file `include/petscmat.h` for a complete list of matrix
11294   operations, which all have the form MATOP_<OPERATION>, where
11295   <OPERATION> is the name (in all capital letters) of the
11296   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11297 
11298   All user-provided functions (except for `MATOP_DESTROY`) should have the same calling
11299   sequence as the usual matrix interface routines, since they
11300   are intended to be accessed via the usual matrix interface
11301   routines, e.g.,
11302 .vb
11303   MatMult(Mat, Vec, Vec) -> usermult(Mat, Vec, Vec)
11304 .ve
11305 
11306   In particular each function MUST return `PETSC_SUCCESS` on success and
11307   nonzero on failure.
11308 
11309   This routine is distinct from `MatShellSetOperation()` in that it can be called on any matrix type.
11310 
11311 .seealso: [](ch_matrices), `Mat`, `MatGetOperation()`, `MatCreateShell()`, `MatShellSetContext()`, `MatShellSetOperation()`
11312 @*/
11313 PetscErrorCode MatSetOperation(Mat mat, MatOperation op, void (*f)(void))
11314 {
11315   PetscFunctionBegin;
11316   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11317   if (op == MATOP_VIEW && !mat->ops->viewnative && f != (void (*)(void))mat->ops->view) mat->ops->viewnative = mat->ops->view;
11318   (((void (**)(void))mat->ops)[op]) = f;
11319   PetscFunctionReturn(PETSC_SUCCESS);
11320 }
11321 
11322 /*@C
11323   MatGetOperation - Gets a matrix operation for any matrix type.
11324 
11325   Not Collective
11326 
11327   Input Parameters:
11328 + mat - the matrix
11329 - op  - the name of the operation
11330 
11331   Output Parameter:
11332 . f - the function that provides the operation
11333 
11334   Level: developer
11335 
11336   Example Usage:
11337 .vb
11338   PetscErrorCode (*usermult)(Mat, Vec, Vec);
11339 
11340   MatGetOperation(A, MATOP_MULT, (void (**)(void))&usermult);
11341 .ve
11342 
11343   Notes:
11344   See the file include/petscmat.h for a complete list of matrix
11345   operations, which all have the form MATOP_<OPERATION>, where
11346   <OPERATION> is the name (in all capital letters) of the
11347   user interface routine (e.g., `MatMult()` -> `MATOP_MULT`).
11348 
11349   This routine is distinct from `MatShellGetOperation()` in that it can be called on any matrix type.
11350 
11351 .seealso: [](ch_matrices), `Mat`, `MatSetOperation()`, `MatCreateShell()`, `MatShellGetContext()`, `MatShellGetOperation()`
11352 @*/
11353 PetscErrorCode MatGetOperation(Mat mat, MatOperation op, void (**f)(void))
11354 {
11355   PetscFunctionBegin;
11356   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11357   *f = (((void (**)(void))mat->ops)[op]);
11358   PetscFunctionReturn(PETSC_SUCCESS);
11359 }
11360 
11361 /*@
11362   MatHasOperation - Determines whether the given matrix supports the particular operation.
11363 
11364   Not Collective
11365 
11366   Input Parameters:
11367 + mat - the matrix
11368 - op  - the operation, for example, `MATOP_GET_DIAGONAL`
11369 
11370   Output Parameter:
11371 . has - either `PETSC_TRUE` or `PETSC_FALSE`
11372 
11373   Level: advanced
11374 
11375   Note:
11376   See `MatSetOperation()` for additional discussion on naming convention and usage of `op`.
11377 
11378 .seealso: [](ch_matrices), `Mat`, `MatCreateShell()`, `MatGetOperation()`, `MatSetOperation()`
11379 @*/
11380 PetscErrorCode MatHasOperation(Mat mat, MatOperation op, PetscBool *has)
11381 {
11382   PetscFunctionBegin;
11383   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11384   PetscAssertPointer(has, 3);
11385   if (mat->ops->hasoperation) {
11386     PetscUseTypeMethod(mat, hasoperation, op, has);
11387   } else {
11388     if (((void **)mat->ops)[op]) *has = PETSC_TRUE;
11389     else {
11390       *has = PETSC_FALSE;
11391       if (op == MATOP_CREATE_SUBMATRIX) {
11392         PetscMPIInt size;
11393 
11394         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size));
11395         if (size == 1) PetscCall(MatHasOperation(mat, MATOP_CREATE_SUBMATRICES, has));
11396       }
11397     }
11398   }
11399   PetscFunctionReturn(PETSC_SUCCESS);
11400 }
11401 
11402 /*@
11403   MatHasCongruentLayouts - Determines whether the rows and columns layouts of the matrix are congruent
11404 
11405   Collective
11406 
11407   Input Parameter:
11408 . mat - the matrix
11409 
11410   Output Parameter:
11411 . cong - either `PETSC_TRUE` or `PETSC_FALSE`
11412 
11413   Level: beginner
11414 
11415 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatSetSizes()`, `PetscLayout`
11416 @*/
11417 PetscErrorCode MatHasCongruentLayouts(Mat mat, PetscBool *cong)
11418 {
11419   PetscFunctionBegin;
11420   PetscValidHeaderSpecific(mat, MAT_CLASSID, 1);
11421   PetscValidType(mat, 1);
11422   PetscAssertPointer(cong, 2);
11423   if (!mat->rmap || !mat->cmap) {
11424     *cong = mat->rmap == mat->cmap ? PETSC_TRUE : PETSC_FALSE;
11425     PetscFunctionReturn(PETSC_SUCCESS);
11426   }
11427   if (mat->congruentlayouts == PETSC_DECIDE) { /* first time we compare rows and cols layouts */
11428     PetscCall(PetscLayoutSetUp(mat->rmap));
11429     PetscCall(PetscLayoutSetUp(mat->cmap));
11430     PetscCall(PetscLayoutCompare(mat->rmap, mat->cmap, cong));
11431     if (*cong) mat->congruentlayouts = 1;
11432     else mat->congruentlayouts = 0;
11433   } else *cong = mat->congruentlayouts ? PETSC_TRUE : PETSC_FALSE;
11434   PetscFunctionReturn(PETSC_SUCCESS);
11435 }
11436 
11437 PetscErrorCode MatSetInf(Mat A)
11438 {
11439   PetscFunctionBegin;
11440   PetscUseTypeMethod(A, setinf);
11441   PetscFunctionReturn(PETSC_SUCCESS);
11442 }
11443 
11444 /*@
11445   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
11446   and possibly removes small values from the graph structure.
11447 
11448   Collective
11449 
11450   Input Parameters:
11451 + A       - the matrix
11452 . sym     - `PETSC_TRUE` indicates that the graph should be symmetrized
11453 . scale   - `PETSC_TRUE` indicates that the graph edge weights should be symmetrically scaled with the diagonal entry
11454 . filter  - filter value - < 0: does nothing; == 0: removes only 0.0 entries; otherwise: removes entries with abs(entries) <= value
11455 . num_idx - size of 'index' array
11456 - index   - array of block indices to use for graph strength of connection weight
11457 
11458   Output Parameter:
11459 . graph - the resulting graph
11460 
11461   Level: advanced
11462 
11463 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `PCGAMG`
11464 @*/
11465 PetscErrorCode MatCreateGraph(Mat A, PetscBool sym, PetscBool scale, PetscReal filter, PetscInt num_idx, PetscInt index[], Mat *graph)
11466 {
11467   PetscFunctionBegin;
11468   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11469   PetscValidType(A, 1);
11470   PetscValidLogicalCollectiveBool(A, scale, 3);
11471   PetscAssertPointer(graph, 7);
11472   PetscCall(PetscLogEventBegin(MAT_CreateGraph, A, 0, 0, 0));
11473   PetscUseTypeMethod(A, creategraph, sym, scale, filter, num_idx, index, graph);
11474   PetscCall(PetscLogEventEnd(MAT_CreateGraph, A, 0, 0, 0));
11475   PetscFunctionReturn(PETSC_SUCCESS);
11476 }
11477 
11478 /*@
11479   MatEliminateZeros - eliminate the nondiagonal zero entries in place from the nonzero structure of a sparse `Mat` in place,
11480   meaning the same memory is used for the matrix, and no new memory is allocated.
11481 
11482   Collective
11483 
11484   Input Parameters:
11485 + A    - the matrix
11486 - 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
11487 
11488   Level: intermediate
11489 
11490   Developer Note:
11491   The entries in the sparse matrix data structure are shifted to fill in the unneeded locations in the data. Thus the end
11492   of the arrays in the data structure are unneeded.
11493 
11494 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateGraph()`, `MatFilter()`
11495 @*/
11496 PetscErrorCode MatEliminateZeros(Mat A, PetscBool keep)
11497 {
11498   PetscFunctionBegin;
11499   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
11500   PetscUseTypeMethod(A, eliminatezeros, keep);
11501   PetscFunctionReturn(PETSC_SUCCESS);
11502 }
11503