Actual source code: mpidense.c

  1: /*
  2:    Basic functions for basic parallel dense matrices.
  3:    Portions of this code are under:
  4:    Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
  5: */

  7: #include <../src/mat/impls/dense/mpi/mpidense.h>
  8: #include <../src/mat/impls/aij/mpi/mpiaij.h>
  9: #include <petscblaslapack.h>
 10: #include <petsc/private/vecimpl.h>
 11: #include <petsc/private/deviceimpl.h>
 12: #include <petsc/private/sfimpl.h>

 14: /*@
 15:   MatDenseGetLocalMatrix - For a `MATMPIDENSE` or `MATSEQDENSE` matrix returns the sequential
 16:   matrix that represents the operator. For sequential matrices it returns itself.

 18:   Input Parameter:
 19: . A - the sequential or MPI `MATDENSE` matrix

 21:   Output Parameter:
 22: . B - the inner matrix

 24:   Level: intermediate

 26: .seealso: [](ch_matrices), `Mat`, `MATDENSE`, `MATMPIDENSE`, `MATSEQDENSE`
 27: @*/
 28: PetscErrorCode MatDenseGetLocalMatrix(Mat A, Mat *B)
 29: {
 30:   Mat_MPIDense *mat = (Mat_MPIDense *)A->data;
 31:   PetscBool     flg;

 33:   PetscFunctionBegin;
 35:   PetscAssertPointer(B, 2);
 36:   PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIDENSE, &flg));
 37:   if (flg) *B = mat->A;
 38:   else {
 39:     PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATSEQDENSE, &flg));
 40:     PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)A)->type_name);
 41:     *B = A;
 42:   }
 43:   PetscFunctionReturn(PETSC_SUCCESS);
 44: }

 46: static PetscErrorCode MatCopy_MPIDense(Mat A, Mat B, MatStructure s)
 47: {
 48:   Mat_MPIDense *Amat = (Mat_MPIDense *)A->data;
 49:   Mat_MPIDense *Bmat = (Mat_MPIDense *)B->data;

 51:   PetscFunctionBegin;
 52:   /* If the two matrices don't have the same copy implementation, they aren't compatible for fast copy. */
 53:   if (A->ops->copy != B->ops->copy) {
 54:     PetscCall(MatCopy_Basic(A, B, s));
 55:     PetscFunctionReturn(PETSC_SUCCESS);
 56:   }
 57:   PetscCall(MatCopy(Amat->A, Bmat->A, s));
 58:   PetscFunctionReturn(PETSC_SUCCESS);
 59: }

 61: PetscErrorCode MatShift_MPIDense(Mat A, PetscScalar alpha)
 62: {
 63:   Mat_MPIDense *mat = (Mat_MPIDense *)A->data;
 64:   PetscInt      j, lda, rstart = A->rmap->rstart, rend = A->rmap->rend, rend2;
 65:   PetscScalar  *v;

 67:   PetscFunctionBegin;
 68:   PetscCall(MatDenseGetArray(mat->A, &v));
 69:   PetscCall(MatDenseGetLDA(mat->A, &lda));
 70:   rend2 = PetscMin(rend, A->cmap->N);
 71:   if (rend2 > rstart) {
 72:     for (j = rstart; j < rend2; j++) v[j - rstart + j * lda] += alpha;
 73:     PetscCall(PetscLogFlops(rend2 - rstart));
 74:   }
 75:   PetscCall(MatDenseRestoreArray(mat->A, &v));
 76:   PetscFunctionReturn(PETSC_SUCCESS);
 77: }

 79: static PetscErrorCode MatGetRow_MPIDense(Mat A, PetscInt row, PetscInt *nz, PetscInt **idx, PetscScalar **v)
 80: {
 81:   Mat_MPIDense *mat = (Mat_MPIDense *)A->data;
 82:   PetscInt      lrow, rstart = A->rmap->rstart, rend = A->rmap->rend;

 84:   PetscFunctionBegin;
 85:   PetscCheck(row >= rstart && row < rend, PETSC_COMM_SELF, PETSC_ERR_SUP, "only local rows");
 86:   lrow = row - rstart;
 87:   PetscCall(MatGetRow(mat->A, lrow, nz, (const PetscInt **)idx, (const PetscScalar **)v));
 88:   PetscFunctionReturn(PETSC_SUCCESS);
 89: }

 91: static PetscErrorCode MatRestoreRow_MPIDense(Mat A, PetscInt row, PetscInt *nz, PetscInt **idx, PetscScalar **v)
 92: {
 93:   Mat_MPIDense *mat = (Mat_MPIDense *)A->data;
 94:   PetscInt      lrow, rstart = A->rmap->rstart, rend = A->rmap->rend;

 96:   PetscFunctionBegin;
 97:   PetscCheck(row >= rstart && row < rend, PETSC_COMM_SELF, PETSC_ERR_SUP, "only local rows");
 98:   lrow = row - rstart;
 99:   PetscCall(MatRestoreRow(mat->A, lrow, nz, (const PetscInt **)idx, (const PetscScalar **)v));
100:   PetscFunctionReturn(PETSC_SUCCESS);
101: }

103: static PetscErrorCode MatGetDiagonalBlock_MPIDense(Mat A, Mat *a)
104: {
105:   Mat_MPIDense *mdn = (Mat_MPIDense *)A->data;
106:   PetscInt      m = A->rmap->n, rstart = A->rmap->rstart;
107:   PetscScalar  *array;
108:   MPI_Comm      comm;
109:   PetscBool     flg;
110:   Mat           B;

112:   PetscFunctionBegin;
113:   PetscCall(MatHasCongruentLayouts(A, &flg));
114:   PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only square matrices supported.");
115:   PetscCall(PetscObjectQuery((PetscObject)A, "DiagonalBlock", (PetscObject *)&B));
116:   if (!B) { /* This should use MatDenseGetSubMatrix (not create), but we would need a call like MatRestoreDiagonalBlock */
117: #if PetscDefined(HAVE_CUDA)
118:     PetscCall(PetscObjectTypeCompare((PetscObject)mdn->A, MATSEQDENSECUDA, &flg));
119:     PetscCheck(!flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not coded for %s. Send an email to petsc-dev@mcs.anl.gov to request this feature", MATSEQDENSECUDA);
120: #elif PetscDefined(HAVE_HIP)
121:     PetscCall(PetscObjectTypeCompare((PetscObject)mdn->A, MATSEQDENSEHIP, &flg));
122:     PetscCheck(!flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not coded for %s. Send an email to petsc-dev@mcs.anl.gov to request this feature", MATSEQDENSEHIP);
123: #endif
124:     PetscCall(PetscObjectGetComm((PetscObject)mdn->A, &comm));
125:     PetscCall(MatCreate(comm, &B));
126:     PetscCall(MatSetSizes(B, m, m, m, m));
127:     PetscCall(MatSetType(B, ((PetscObject)mdn->A)->type_name));
128:     PetscCall(MatDenseGetArrayRead(mdn->A, (const PetscScalar **)&array));
129:     PetscCall(MatSeqDenseSetPreallocation(B, PetscSafePointerPlusOffset(array, m * rstart)));
130:     PetscCall(MatDenseRestoreArrayRead(mdn->A, (const PetscScalar **)&array));
131:     PetscCall(PetscObjectCompose((PetscObject)A, "DiagonalBlock", (PetscObject)B));
132:     *a = B;
133:     PetscCall(MatDestroy(&B));
134:   } else *a = B;
135:   PetscFunctionReturn(PETSC_SUCCESS);
136: }

138: static PetscErrorCode MatSetValues_MPIDense(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar v[], InsertMode addv)
139: {
140:   Mat_MPIDense *A = (Mat_MPIDense *)mat->data;
141:   PetscInt      i, j, rstart = mat->rmap->rstart, rend = mat->rmap->rend, row;
142:   PetscBool     roworiented = A->roworiented;

144:   PetscFunctionBegin;
145:   for (i = 0; i < m; i++) {
146:     if (idxm[i] < 0) continue;
147:     PetscCheck(idxm[i] < mat->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large");
148:     if (idxm[i] >= rstart && idxm[i] < rend) {
149:       row = idxm[i] - rstart;
150:       if (roworiented) {
151:         PetscCall(MatSetValues(A->A, 1, &row, n, idxn, PetscSafePointerPlusOffset(v, i * n), addv));
152:       } else {
153:         for (j = 0; j < n; j++) {
154:           if (idxn[j] < 0) continue;
155:           PetscCheck(idxn[j] < mat->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large");
156:           PetscCall(MatSetValues(A->A, 1, &row, 1, &idxn[j], PetscSafePointerPlusOffset(v, i + j * m), addv));
157:         }
158:       }
159:     } else if (!A->donotstash) {
160:       mat->assembled = PETSC_FALSE;
161:       if (roworiented) {
162:         PetscCall(MatStashValuesRow_Private(&mat->stash, idxm[i], n, idxn, PetscSafePointerPlusOffset(v, i * n), PETSC_FALSE));
163:       } else {
164:         PetscCall(MatStashValuesCol_Private(&mat->stash, idxm[i], n, idxn, PetscSafePointerPlusOffset(v, i), m, PETSC_FALSE));
165:       }
166:     }
167:   }
168:   PetscFunctionReturn(PETSC_SUCCESS);
169: }

171: static PetscErrorCode MatGetValues_MPIDense(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], PetscScalar v[])
172: {
173:   Mat_MPIDense *mdn = (Mat_MPIDense *)mat->data;
174:   PetscInt      i, j, rstart = mat->rmap->rstart, rend = mat->rmap->rend, row;
175:   PetscBool     roworiented = mdn->roworiented;
176:   PetscScalar  *value;

178:   PetscFunctionBegin;
179:   for (i = 0; i < m; i++) {
180:     if (idxm[i] < 0) continue; /* negative row */
181:     PetscCheck(idxm[i] < mat->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large");
182:     PetscCheck(idxm[i] >= rstart && idxm[i] < rend, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only local values currently supported");
183:     row = idxm[i] - rstart;
184:     for (j = 0; j < n; j++) {
185:       if (idxn[j] < 0) continue; /* negative column */
186:       PetscCheck(idxn[j] < mat->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large");
187:       value = roworiented ? &v[j + i * n] : &v[i + j * m];
188:       PetscCall(MatGetValues(mdn->A, 1, &row, 1, &idxn[j], value));
189:     }
190:   }
191:   PetscFunctionReturn(PETSC_SUCCESS);
192: }

194: static PetscErrorCode MatDenseGetLDA_MPIDense(Mat A, PetscInt *lda)
195: {
196:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

198:   PetscFunctionBegin;
199:   PetscCall(MatDenseGetLDA(a->A, lda));
200:   PetscFunctionReturn(PETSC_SUCCESS);
201: }

203: static PetscErrorCode MatDenseSetLDA_MPIDense(Mat A, PetscInt lda)
204: {
205:   Mat_MPIDense *a     = (Mat_MPIDense *)A->data;
206:   MatType       mtype = MATSEQDENSE;

208:   PetscFunctionBegin;
209:   if (!a->A) {
210:     PetscCheck(!a->matinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
211:     PetscCall(PetscLayoutSetUp(A->rmap));
212:     PetscCall(PetscLayoutSetUp(A->cmap));
213:     PetscCall(MatCreate(PETSC_COMM_SELF, &a->A));
214:     PetscCall(MatSetSizes(a->A, A->rmap->n, A->cmap->N, A->rmap->n, A->cmap->N));
215: #if PetscDefined(HAVE_CUDA)
216:     PetscBool iscuda;
217:     PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPIDENSECUDA, &iscuda));
218:     if (iscuda) mtype = MATSEQDENSECUDA;
219: #elif PetscDefined(HAVE_HIP)
220:     PetscBool iship;
221:     PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPIDENSEHIP, &iship));
222:     if (iship) mtype = MATSEQDENSEHIP;
223: #endif
224:     PetscCall(MatSetType(a->A, mtype));
225:   }
226:   PetscCall(MatDenseSetLDA(a->A, lda));
227:   PetscFunctionReturn(PETSC_SUCCESS);
228: }

230: static PetscErrorCode MatDenseGetArray_MPIDense(Mat A, PetscScalar **array)
231: {
232:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

234:   PetscFunctionBegin;
235:   PetscCheck(!a->matinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
236:   PetscCall(MatDenseGetArray(a->A, array));
237:   PetscFunctionReturn(PETSC_SUCCESS);
238: }

240: static PetscErrorCode MatDenseGetArrayRead_MPIDense(Mat A, PetscScalar **array)
241: {
242:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

244:   PetscFunctionBegin;
245:   PetscCheck(!a->matinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
246:   PetscCall(MatDenseGetArrayRead(a->A, (const PetscScalar **)array));
247:   PetscFunctionReturn(PETSC_SUCCESS);
248: }

250: static PetscErrorCode MatDenseGetArrayWrite_MPIDense(Mat A, PetscScalar **array)
251: {
252:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

254:   PetscFunctionBegin;
255:   PetscCheck(!a->matinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
256:   PetscCall(MatDenseGetArrayWrite(a->A, array));
257:   PetscFunctionReturn(PETSC_SUCCESS);
258: }

260: static PetscErrorCode MatDensePlaceArray_MPIDense(Mat A, const PetscScalar *array)
261: {
262:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

264:   PetscFunctionBegin;
265:   PetscCheck(!a->vecinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreColumnVec() first");
266:   PetscCheck(!a->matinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
267:   PetscCall(MatDensePlaceArray(a->A, array));
268:   PetscFunctionReturn(PETSC_SUCCESS);
269: }

271: static PetscErrorCode MatDenseResetArray_MPIDense(Mat A)
272: {
273:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

275:   PetscFunctionBegin;
276:   PetscCheck(!a->vecinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreColumnVec() first");
277:   PetscCheck(!a->matinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
278:   PetscCall(MatDenseResetArray(a->A));
279:   PetscFunctionReturn(PETSC_SUCCESS);
280: }

282: static PetscErrorCode MatDenseReplaceArray_MPIDense(Mat A, const PetscScalar *array)
283: {
284:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

286:   PetscFunctionBegin;
287:   PetscCheck(!a->vecinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreColumnVec() first");
288:   PetscCheck(!a->matinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
289:   PetscCall(MatDenseReplaceArray(a->A, array));
290:   PetscFunctionReturn(PETSC_SUCCESS);
291: }

293: static PetscErrorCode MatCreateSubMatrix_MPIDense(Mat A, IS isrow, IS iscol, MatReuse scall, Mat *B)
294: {
295:   Mat_MPIDense      *mat = (Mat_MPIDense *)A->data;
296:   PetscInt           lda, i, j, rstart, rend, nrows, ncols, Ncols, nlrows, nlcols;
297:   const PetscInt    *irow, *icol;
298:   const PetscScalar *v;
299:   PetscScalar       *bv;
300:   Mat                newmat;
301:   IS                 iscol_local;
302:   MPI_Comm           comm_is, comm_mat;

304:   PetscFunctionBegin;
305:   PetscCall(PetscObjectGetComm((PetscObject)A, &comm_mat));
306:   PetscCall(PetscObjectGetComm((PetscObject)iscol, &comm_is));
307:   PetscCheck(comm_mat == comm_is, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "IS communicator must match matrix communicator");

309:   PetscCall(ISAllGather(iscol, &iscol_local));
310:   PetscCall(ISGetIndices(isrow, &irow));
311:   PetscCall(ISGetIndices(iscol_local, &icol));
312:   PetscCall(ISGetLocalSize(isrow, &nrows));
313:   PetscCall(ISGetLocalSize(iscol, &ncols));
314:   PetscCall(ISGetSize(iscol, &Ncols)); /* global number of columns, size of iscol_local */

316:   /* No parallel redistribution currently supported! Should really check each index set
317:      to confirm that it is OK.  ... Currently supports only submatrix same partitioning as
318:      original matrix! */

320:   PetscCall(MatGetLocalSize(A, &nlrows, &nlcols));
321:   PetscCall(MatGetOwnershipRange(A, &rstart, &rend));

323:   /* Check submatrix call */
324:   if (scall == MAT_REUSE_MATRIX) {
325:     /* SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Reused submatrix wrong size"); */
326:     /* Really need to test rows and column sizes! */
327:     newmat = *B;
328:   } else {
329:     /* Create and fill new matrix */
330:     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &newmat));
331:     PetscCall(MatSetSizes(newmat, nrows, ncols, PETSC_DECIDE, Ncols));
332:     PetscCall(MatSetType(newmat, ((PetscObject)A)->type_name));
333:     PetscCall(MatMPIDenseSetPreallocation(newmat, NULL));
334:   }

336:   /* Now extract the data pointers and do the copy, column at a time */
337:   PetscCall(MatDenseGetArray(newmat, &bv));
338:   PetscCall(MatDenseGetArrayRead(mat->A, &v));
339:   PetscCall(MatDenseGetLDA(mat->A, &lda));
340:   for (i = 0; i < Ncols; i++) {
341:     const PetscScalar *av = v + lda * icol[i];
342:     for (j = 0; j < nrows; j++) *bv++ = av[irow[j] - rstart];
343:   }
344:   PetscCall(MatDenseRestoreArrayRead(mat->A, &v));
345:   PetscCall(MatDenseRestoreArray(newmat, &bv));

347:   /* Free work space */
348:   PetscCall(ISRestoreIndices(isrow, &irow));
349:   PetscCall(ISRestoreIndices(iscol_local, &icol));
350:   PetscCall(ISDestroy(&iscol_local));
351:   *B = newmat;
352:   PetscFunctionReturn(PETSC_SUCCESS);
353: }

355: static PetscErrorCode MatDenseRestoreArray_MPIDense(Mat A, PetscScalar **array)
356: {
357:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

359:   PetscFunctionBegin;
360:   PetscCall(MatDenseRestoreArray(a->A, array));
361:   PetscFunctionReturn(PETSC_SUCCESS);
362: }

364: static PetscErrorCode MatDenseRestoreArrayRead_MPIDense(Mat A, PetscScalar **array)
365: {
366:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

368:   PetscFunctionBegin;
369:   PetscCall(MatDenseRestoreArrayRead(a->A, (const PetscScalar **)array));
370:   PetscFunctionReturn(PETSC_SUCCESS);
371: }

373: static PetscErrorCode MatDenseRestoreArrayWrite_MPIDense(Mat A, PetscScalar **array)
374: {
375:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

377:   PetscFunctionBegin;
378:   PetscCall(MatDenseRestoreArrayWrite(a->A, array));
379:   PetscFunctionReturn(PETSC_SUCCESS);
380: }

382: static PetscErrorCode MatAssemblyBegin_MPIDense(Mat mat, MatAssemblyType mode)
383: {
384:   Mat_MPIDense *mdn = (Mat_MPIDense *)mat->data;
385:   PetscInt      nstash, reallocs;

387:   PetscFunctionBegin;
388:   if (mdn->donotstash || mat->nooffprocentries) PetscFunctionReturn(PETSC_SUCCESS);

390:   PetscCall(MatStashScatterBegin_Private(mat, &mat->stash, mat->rmap->range));
391:   PetscCall(MatStashGetInfo_Private(&mat->stash, &nstash, &reallocs));
392:   PetscCall(PetscInfo(mdn->A, "Stash has %" PetscInt_FMT " entries, uses %" PetscInt_FMT " mallocs.\n", nstash, reallocs));
393:   PetscFunctionReturn(PETSC_SUCCESS);
394: }

396: static PetscErrorCode MatAssemblyEnd_MPIDense(Mat mat, MatAssemblyType mode)
397: {
398:   Mat_MPIDense *mdn = (Mat_MPIDense *)mat->data;
399:   PetscInt      i, *row, *col, flg, j, rstart, ncols;
400:   PetscMPIInt   n;
401:   PetscScalar  *val;

403:   PetscFunctionBegin;
404:   if (!mdn->donotstash && !mat->nooffprocentries) {
405:     /*  wait on receives */
406:     while (1) {
407:       PetscCall(MatStashScatterGetMesg_Private(&mat->stash, &n, &row, &col, &val, &flg));
408:       if (!flg) break;

410:       for (i = 0; i < n;) {
411:         /* Now identify the consecutive vals belonging to the same row */
412:         for (j = i, rstart = row[j]; j < n; j++) {
413:           if (row[j] != rstart) break;
414:         }
415:         if (j < n) ncols = j - i;
416:         else ncols = n - i;
417:         /* Now assemble all these values with a single function call */
418:         PetscCall(MatSetValues_MPIDense(mat, 1, row + i, ncols, col + i, val + i, mat->insertmode));
419:         i = j;
420:       }
421:     }
422:     PetscCall(MatStashScatterEnd_Private(&mat->stash));
423:   }

425:   PetscCall(MatAssemblyBegin(mdn->A, mode));
426:   PetscCall(MatAssemblyEnd(mdn->A, mode));
427:   PetscFunctionReturn(PETSC_SUCCESS);
428: }

430: static PetscErrorCode MatZeroEntries_MPIDense(Mat A)
431: {
432:   Mat_MPIDense *l = (Mat_MPIDense *)A->data;

434:   PetscFunctionBegin;
435:   PetscCall(MatZeroEntries(l->A));
436:   PetscFunctionReturn(PETSC_SUCCESS);
437: }

439: static PetscErrorCode MatSetInf_MPIDense(Mat A)
440: {
441:   Mat_MPIDense *l = (Mat_MPIDense *)A->data;

443:   PetscFunctionBegin;
444:   PetscCall(MatFlag(l->A, 1));
445:   PetscFunctionReturn(PETSC_SUCCESS);
446: }

448: static PetscErrorCode MatZeroRows_MPIDense(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
449: {
450:   Mat_MPIDense *l = (Mat_MPIDense *)A->data;
451:   PetscInt      i, len, *lrows;

453:   PetscFunctionBegin;
454:   /* get locally owned rows */
455:   PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL));
456:   /* fix right-hand side if needed */
457:   if (x && b) {
458:     const PetscScalar *xx;
459:     PetscScalar       *bb;

461:     PetscCall(VecGetArrayRead(x, &xx));
462:     PetscCall(VecGetArrayWrite(b, &bb));
463:     for (i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]];
464:     PetscCall(VecRestoreArrayRead(x, &xx));
465:     PetscCall(VecRestoreArrayWrite(b, &bb));
466:   }
467:   PetscCall(MatZeroRows(l->A, len, lrows, 0.0, NULL, NULL));
468:   if (diag != 0.0) {
469:     Vec d;

471:     PetscCall(MatCreateVecs(A, NULL, &d));
472:     PetscCall(VecSet(d, diag));
473:     PetscCall(MatDiagonalSet(A, d, INSERT_VALUES));
474:     PetscCall(VecDestroy(&d));
475:   }
476:   PetscCall(PetscFree(lrows));
477:   PetscFunctionReturn(PETSC_SUCCESS);
478: }

480: PETSC_INTERN PetscErrorCode MatMult_SeqDense(Mat, Vec, Vec);
481: PETSC_INTERN PetscErrorCode MatMultAdd_SeqDense(Mat, Vec, Vec, Vec);
482: PETSC_INTERN PetscErrorCode MatMultTranspose_SeqDense(Mat, Vec, Vec);
483: PETSC_INTERN PetscErrorCode MatMultTransposeAdd_SeqDense(Mat, Vec, Vec, Vec);

485: static PetscErrorCode MatMultColumnRange_MPIDense(Mat mat, Vec xx, Vec yy, PetscInt c_start, PetscInt c_end)
486: {
487:   Mat_MPIDense      *mdn = (Mat_MPIDense *)mat->data;
488:   const PetscScalar *ax;
489:   PetscScalar       *ay;
490:   PetscMemType       axmtype, aymtype;

492:   PetscFunctionBegin;
493:   if (!mdn->Mvctx) PetscCall(MatSetUpMultiply_MPIDense(mat));
494:   PetscCall(VecGetArrayReadAndMemType(xx, &ax, &axmtype));
495:   PetscCall(VecGetArrayWriteAndMemType(mdn->lvec, &ay, &aymtype));
496:   PetscCall(PetscSFBcastWithMemTypeBegin(mdn->Mvctx, MPIU_SCALAR, axmtype, ax, aymtype, ay, MPI_REPLACE));
497:   PetscCall(PetscSFBcastEnd(mdn->Mvctx, MPIU_SCALAR, ax, ay, MPI_REPLACE));
498:   PetscCall(VecRestoreArrayWriteAndMemType(mdn->lvec, &ay));
499:   PetscCall(VecRestoreArrayReadAndMemType(xx, &ax));
500:   PetscUseMethod(mdn->A, "MatMultColumnRange_C", (Mat, Vec, Vec, PetscInt, PetscInt), (mdn->A, mdn->lvec, yy, c_start, c_end));
501:   PetscFunctionReturn(PETSC_SUCCESS);
502: }

504: static PetscErrorCode MatMult_MPIDense(Mat mat, Vec xx, Vec yy)
505: {
506:   Mat_MPIDense      *mdn = (Mat_MPIDense *)mat->data;
507:   const PetscScalar *ax;
508:   PetscScalar       *ay;
509:   PetscMemType       axmtype, aymtype;

511:   PetscFunctionBegin;
512:   if (!mdn->Mvctx) PetscCall(MatSetUpMultiply_MPIDense(mat));
513:   PetscCall(VecGetArrayReadAndMemType(xx, &ax, &axmtype));
514:   PetscCall(VecGetArrayWriteAndMemType(mdn->lvec, &ay, &aymtype));
515:   PetscCall(PetscSFBcastWithMemTypeBegin(mdn->Mvctx, MPIU_SCALAR, axmtype, ax, aymtype, ay, MPI_REPLACE));
516:   PetscCall(PetscSFBcastEnd(mdn->Mvctx, MPIU_SCALAR, ax, ay, MPI_REPLACE));
517:   PetscCall(VecRestoreArrayWriteAndMemType(mdn->lvec, &ay));
518:   PetscCall(VecRestoreArrayReadAndMemType(xx, &ax));
519:   PetscUseTypeMethod(mdn->A, mult, mdn->lvec, yy);
520:   PetscFunctionReturn(PETSC_SUCCESS);
521: }

523: static PetscErrorCode MatGetMultPetscSF_MPIDense(Mat A, PetscSF *sf)
524: {
525:   Mat_MPIDense *mdn = (Mat_MPIDense *)A->data;

527:   PetscFunctionBegin;
528:   *sf = mdn->Mvctx;
529:   PetscFunctionReturn(PETSC_SUCCESS);
530: }

532: static PetscErrorCode MatMultAddColumnRange_MPIDense(Mat mat, Vec xx, Vec yy, Vec zz, PetscInt c_start, PetscInt c_end)
533: {
534:   Mat_MPIDense      *mdn = (Mat_MPIDense *)mat->data;
535:   const PetscScalar *ax;
536:   PetscScalar       *ay;
537:   PetscMemType       axmtype, aymtype;

539:   PetscFunctionBegin;
540:   if (!mdn->Mvctx) PetscCall(MatSetUpMultiply_MPIDense(mat));
541:   PetscCall(VecGetArrayReadAndMemType(xx, &ax, &axmtype));
542:   PetscCall(VecGetArrayAndMemType(mdn->lvec, &ay, &aymtype));
543:   PetscCall(PetscSFBcastWithMemTypeBegin(mdn->Mvctx, MPIU_SCALAR, axmtype, ax, aymtype, ay, MPI_REPLACE));
544:   PetscCall(PetscSFBcastEnd(mdn->Mvctx, MPIU_SCALAR, ax, ay, MPI_REPLACE));
545:   PetscCall(VecRestoreArrayAndMemType(mdn->lvec, &ay));
546:   PetscCall(VecRestoreArrayReadAndMemType(xx, &ax));
547:   PetscUseMethod(mdn->A, "MatMultAddColumnRange_C", (Mat, Vec, Vec, Vec, PetscInt, PetscInt), (mdn->A, mdn->lvec, yy, zz, c_start, c_end));
548:   PetscFunctionReturn(PETSC_SUCCESS);
549: }

551: static PetscErrorCode MatMultAdd_MPIDense(Mat mat, Vec xx, Vec yy, Vec zz)
552: {
553:   Mat_MPIDense      *mdn = (Mat_MPIDense *)mat->data;
554:   const PetscScalar *ax;
555:   PetscScalar       *ay;
556:   PetscMemType       axmtype, aymtype;

558:   PetscFunctionBegin;
559:   if (!mdn->Mvctx) PetscCall(MatSetUpMultiply_MPIDense(mat));
560:   PetscCall(VecGetArrayReadAndMemType(xx, &ax, &axmtype));
561:   PetscCall(VecGetArrayAndMemType(mdn->lvec, &ay, &aymtype));
562:   PetscCall(PetscSFBcastWithMemTypeBegin(mdn->Mvctx, MPIU_SCALAR, axmtype, ax, aymtype, ay, MPI_REPLACE));
563:   PetscCall(PetscSFBcastEnd(mdn->Mvctx, MPIU_SCALAR, ax, ay, MPI_REPLACE));
564:   PetscCall(VecRestoreArrayAndMemType(mdn->lvec, &ay));
565:   PetscCall(VecRestoreArrayReadAndMemType(xx, &ax));
566:   PetscUseTypeMethod(mdn->A, multadd, mdn->lvec, yy, zz);
567:   PetscFunctionReturn(PETSC_SUCCESS);
568: }

570: static PetscErrorCode MatMultHermitianTransposeColumnRange_MPIDense(Mat A, Vec xx, Vec yy, PetscInt c_start, PetscInt c_end)
571: {
572:   Mat_MPIDense      *a = (Mat_MPIDense *)A->data;
573:   const PetscScalar *ax;
574:   PetscScalar       *ay;
575:   PetscMemType       axmtype, aymtype;
576:   PetscInt           r_start, r_end;
577:   PetscInt           c_start_local, c_end_local;

579:   PetscFunctionBegin;
580:   if (!a->Mvctx) PetscCall(MatSetUpMultiply_MPIDense(A));
581:   PetscCall(VecZeroEntries(a->lvec));
582:   PetscCall(VecGetOwnershipRange(yy, &r_start, &r_end));
583:   c_start_local = PetscMax(c_start, r_start);
584:   c_end_local   = PetscMin(c_end, r_end);
585:   PetscCall(VecGetArrayAndMemType(yy, &ay, &aymtype));
586:   if (c_end_local > c_start_local) {
587:     if (PetscMemTypeHost(aymtype)) {
588:       PetscCall(PetscArrayzero(&ay[c_start_local], (size_t)(c_end_local - c_start_local)));
589:     } else {
590:       PetscCall(PetscDeviceRegisterMemory(ay, aymtype, sizeof(*ay) * ((size_t)(r_end - r_start))));
591:       PetscCall(PetscDeviceArrayZero(NULL, &ay[c_start_local], (size_t)(c_end_local - c_start_local)));
592:     }
593:   }
594:   PetscUseMethod(a->A, "MatMultHermitianTransposeColumnRange_C", (Mat, Vec, Vec, PetscInt, PetscInt), (a->A, xx, a->lvec, c_start, c_end));
595:   PetscCall(VecGetArrayReadAndMemType(a->lvec, &ax, &axmtype));
596:   PetscCall(PetscSFReduceWithMemTypeBegin(a->Mvctx, MPIU_SCALAR, axmtype, ax, aymtype, ay, MPIU_SUM));
597:   PetscCall(PetscSFReduceEnd(a->Mvctx, MPIU_SCALAR, ax, ay, MPIU_SUM));
598:   PetscCall(VecRestoreArrayReadAndMemType(a->lvec, &ax));
599:   PetscCall(VecRestoreArrayAndMemType(yy, &ay));
600:   PetscFunctionReturn(PETSC_SUCCESS);
601: }

603: static PetscErrorCode MatMultTransposeKernel_MPIDense(Mat A, Vec xx, Vec yy, PetscBool herm)
604: {
605:   Mat_MPIDense      *a = (Mat_MPIDense *)A->data;
606:   const PetscScalar *ax;
607:   PetscScalar       *ay;
608:   PetscMemType       axmtype, aymtype;

610:   PetscFunctionBegin;
611:   if (!a->Mvctx) PetscCall(MatSetUpMultiply_MPIDense(A));
612:   PetscCall(VecSet(yy, 0.0));
613:   if (herm) PetscUseTypeMethod(a->A, multhermitiantranspose, xx, a->lvec);
614:   else PetscUseTypeMethod(a->A, multtranspose, xx, a->lvec);
615:   PetscCall(VecGetArrayReadAndMemType(a->lvec, &ax, &axmtype));
616:   PetscCall(VecGetArrayAndMemType(yy, &ay, &aymtype));
617:   PetscCall(PetscSFReduceWithMemTypeBegin(a->Mvctx, MPIU_SCALAR, axmtype, ax, aymtype, ay, MPIU_SUM));
618:   PetscCall(PetscSFReduceEnd(a->Mvctx, MPIU_SCALAR, ax, ay, MPIU_SUM));
619:   PetscCall(VecRestoreArrayReadAndMemType(a->lvec, &ax));
620:   PetscCall(VecRestoreArrayAndMemType(yy, &ay));
621:   PetscFunctionReturn(PETSC_SUCCESS);
622: }

624: static PetscErrorCode MatMultHermitianTransposeAddColumnRange_MPIDense(Mat A, Vec xx, Vec yy, Vec zz, PetscInt c_start, PetscInt c_end)
625: {
626:   Mat_MPIDense      *a = (Mat_MPIDense *)A->data;
627:   const PetscScalar *ax;
628:   PetscScalar       *ay;
629:   PetscMemType       axmtype, aymtype;

631:   PetscFunctionBegin;
632:   if (!a->Mvctx) PetscCall(MatSetUpMultiply_MPIDense(A));
633:   PetscCall(VecCopy(yy, zz));
634:   PetscCall(VecZeroEntries(a->lvec));
635:   PetscUseMethod(a->A, "MatMultHermitianTransposeColumnRange_C", (Mat, Vec, Vec, PetscInt, PetscInt), (a->A, xx, a->lvec, c_start, c_end));
636:   PetscCall(VecGetArrayReadAndMemType(a->lvec, &ax, &axmtype));
637:   PetscCall(VecGetArrayAndMemType(zz, &ay, &aymtype));
638:   PetscCall(PetscSFReduceWithMemTypeBegin(a->Mvctx, MPIU_SCALAR, axmtype, ax, aymtype, ay, MPIU_SUM));
639:   PetscCall(PetscSFReduceEnd(a->Mvctx, MPIU_SCALAR, ax, ay, MPIU_SUM));
640:   PetscCall(VecRestoreArrayReadAndMemType(a->lvec, &ax));
641:   PetscCall(VecRestoreArrayAndMemType(zz, &ay));
642:   PetscFunctionReturn(PETSC_SUCCESS);
643: }

645: static PetscErrorCode MatMultTransposeAddKernel_MPIDense(Mat A, Vec xx, Vec yy, Vec zz, PetscBool herm)
646: {
647:   Mat_MPIDense      *a = (Mat_MPIDense *)A->data;
648:   const PetscScalar *ax;
649:   PetscScalar       *ay;
650:   PetscMemType       axmtype, aymtype;

652:   PetscFunctionBegin;
653:   if (!a->Mvctx) PetscCall(MatSetUpMultiply_MPIDense(A));
654:   PetscCall(VecCopy(yy, zz));
655:   if (herm) PetscUseTypeMethod(a->A, multhermitiantranspose, xx, a->lvec);
656:   else PetscUseTypeMethod(a->A, multtranspose, xx, a->lvec);
657:   PetscCall(VecGetArrayReadAndMemType(a->lvec, &ax, &axmtype));
658:   PetscCall(VecGetArrayAndMemType(zz, &ay, &aymtype));
659:   PetscCall(PetscSFReduceWithMemTypeBegin(a->Mvctx, MPIU_SCALAR, axmtype, ax, aymtype, ay, MPIU_SUM));
660:   PetscCall(PetscSFReduceEnd(a->Mvctx, MPIU_SCALAR, ax, ay, MPIU_SUM));
661:   PetscCall(VecRestoreArrayReadAndMemType(a->lvec, &ax));
662:   PetscCall(VecRestoreArrayAndMemType(zz, &ay));
663:   PetscFunctionReturn(PETSC_SUCCESS);
664: }

666: static PetscErrorCode MatMultTranspose_MPIDense(Mat A, Vec xx, Vec yy)
667: {
668:   PetscFunctionBegin;
669:   PetscCall(MatMultTransposeKernel_MPIDense(A, xx, yy, PETSC_FALSE));
670:   PetscFunctionReturn(PETSC_SUCCESS);
671: }

673: static PetscErrorCode MatMultTransposeAdd_MPIDense(Mat A, Vec xx, Vec yy, Vec zz)
674: {
675:   PetscFunctionBegin;
676:   PetscCall(MatMultTransposeAddKernel_MPIDense(A, xx, yy, zz, PETSC_FALSE));
677:   PetscFunctionReturn(PETSC_SUCCESS);
678: }

680: static PetscErrorCode MatMultHermitianTranspose_MPIDense(Mat A, Vec xx, Vec yy)
681: {
682:   PetscFunctionBegin;
683:   PetscCall(MatMultTransposeKernel_MPIDense(A, xx, yy, PETSC_TRUE));
684:   PetscFunctionReturn(PETSC_SUCCESS);
685: }

687: static PetscErrorCode MatMultHermitianTransposeAdd_MPIDense(Mat A, Vec xx, Vec yy, Vec zz)
688: {
689:   PetscFunctionBegin;
690:   PetscCall(MatMultTransposeAddKernel_MPIDense(A, xx, yy, zz, PETSC_TRUE));
691:   PetscFunctionReturn(PETSC_SUCCESS);
692: }

694: PetscErrorCode MatGetDiagonal_MPIDense(Mat A, Vec v)
695: {
696:   Mat_MPIDense      *a = (Mat_MPIDense *)A->data;
697:   PetscInt           lda, len, i, nl, ng, m = A->rmap->n, radd;
698:   PetscScalar       *x;
699:   const PetscScalar *av;

701:   PetscFunctionBegin;
702:   PetscCall(VecGetArray(v, &x));
703:   PetscCall(VecGetSize(v, &ng));
704:   PetscCheck(ng == A->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Nonconforming mat and vec");
705:   PetscCall(VecGetLocalSize(v, &nl));
706:   len  = PetscMin(a->A->rmap->n, a->A->cmap->n);
707:   radd = A->rmap->rstart * m;
708:   PetscCall(MatDenseGetArrayRead(a->A, &av));
709:   PetscCall(MatDenseGetLDA(a->A, &lda));
710:   for (i = 0; i < len; i++) x[i] = av[radd + i * lda + i];
711:   PetscCall(MatDenseRestoreArrayRead(a->A, &av));
712:   if (nl - i > 0) PetscCall(PetscArrayzero(x + i, nl - i));
713:   PetscCall(VecRestoreArray(v, &x));
714:   PetscFunctionReturn(PETSC_SUCCESS);
715: }

717: static PetscErrorCode MatDestroy_MPIDense(Mat mat)
718: {
719:   Mat_MPIDense *mdn = (Mat_MPIDense *)mat->data;

721:   PetscFunctionBegin;
722:   PetscCall(PetscLogObjectState((PetscObject)mat, "Rows=%" PetscInt_FMT ", Cols=%" PetscInt_FMT, mat->rmap->N, mat->cmap->N));
723:   PetscCall(MatStashDestroy_Private(&mat->stash));
724:   PetscCheck(!mdn->vecinuse, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Need to call MatDenseRestoreColumnVec() first");
725:   PetscCheck(!mdn->matinuse, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
726:   PetscCall(MatDestroy(&mdn->A));
727:   PetscCall(VecDestroy(&mdn->lvec));
728:   PetscCall(PetscSFDestroy(&mdn->Mvctx));
729:   PetscCall(VecDestroy(&mdn->cvec));
730:   PetscCall(MatDestroy(&mdn->cmat));

732:   PetscCall(PetscFree(mat->data));
733:   PetscCall(PetscObjectChangeTypeName((PetscObject)mat, NULL));

735:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetLDA_C", NULL));
736:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseSetLDA_C", NULL));
737:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetArray_C", NULL));
738:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreArray_C", NULL));
739:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetArrayRead_C", NULL));
740:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreArrayRead_C", NULL));
741:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetArrayWrite_C", NULL));
742:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreArrayWrite_C", NULL));
743:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDensePlaceArray_C", NULL));
744:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseResetArray_C", NULL));
745:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseReplaceArray_C", NULL));
746:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpiaij_mpidense_C", NULL));
747:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpidense_mpiaij_C", NULL));
748: #if PetscDefined(HAVE_ELEMENTAL)
749:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpidense_elemental_C", NULL));
750: #endif
751: #if PetscDefined(HAVE_SCALAPACK) && (PetscDefined(USE_REAL_SINGLE) || PetscDefined(USE_REAL_DOUBLE))
752:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpidense_scalapack_C", NULL));
753: #endif
754:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMPIDenseSetPreallocation_C", NULL));
755:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpiaij_mpidense_C", NULL));
756:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpidense_mpiaij_C", NULL));
757: #if PetscDefined(HAVE_CUDA)
758:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpiaijcusparse_mpidense_C", NULL));
759:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpidense_mpiaijcusparse_C", NULL));
760:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpidense_mpidensecuda_C", NULL));
761:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpidensecuda_mpidense_C", NULL));
762:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpiaij_mpidensecuda_C", NULL));
763:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpiaijcusparse_mpidensecuda_C", NULL));
764:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpidensecuda_mpiaij_C", NULL));
765:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpidensecuda_mpiaijcusparse_C", NULL));
766:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseCUDAGetArray_C", NULL));
767:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseCUDAGetArrayRead_C", NULL));
768:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseCUDAGetArrayWrite_C", NULL));
769:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseCUDARestoreArray_C", NULL));
770:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseCUDARestoreArrayRead_C", NULL));
771:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseCUDARestoreArrayWrite_C", NULL));
772:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseCUDAPlaceArray_C", NULL));
773:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseCUDAResetArray_C", NULL));
774:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseCUDAReplaceArray_C", NULL));
775:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseCUDASetPreallocation_C", NULL));
776: #endif
777: #if PetscDefined(HAVE_HIP)
778:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpiaijhipsparse_mpidense_C", NULL));
779:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpidense_mpiaijhipsparse_C", NULL));
780:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpidense_mpidensehip_C", NULL));
781:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpidensehip_mpidense_C", NULL));
782:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpiaij_mpidensehip_C", NULL));
783:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpiaijhipsparse_mpidensehip_C", NULL));
784:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpidensehip_mpiaij_C", NULL));
785:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpidensehip_mpiaijhipsparse_C", NULL));
786:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseHIPGetArray_C", NULL));
787:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseHIPGetArrayRead_C", NULL));
788:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseHIPGetArrayWrite_C", NULL));
789:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseHIPRestoreArray_C", NULL));
790:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseHIPRestoreArrayRead_C", NULL));
791:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseHIPRestoreArrayWrite_C", NULL));
792:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseHIPPlaceArray_C", NULL));
793:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseHIPResetArray_C", NULL));
794:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseHIPReplaceArray_C", NULL));
795:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseHIPSetPreallocation_C", NULL));
796: #endif
797:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetColumn_C", NULL));
798:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreColumn_C", NULL));
799:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetColumnVec_C", NULL));
800:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreColumnVec_C", NULL));
801:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetColumnVecRead_C", NULL));
802:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreColumnVecRead_C", NULL));
803:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetColumnVecWrite_C", NULL));
804:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreColumnVecWrite_C", NULL));
805:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetSubMatrix_C", NULL));
806:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreSubMatrix_C", NULL));
807:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMultColumnRange_C", NULL));
808:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMultAddColumnRange_C", NULL));
809:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMultHermitianTransposeColumnRange_C", NULL));
810:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMultHermitianTransposeAddColumnRange_C", NULL));
811:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatGetMultPetscSF_C", NULL));
812:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseUpdateColumnLayout_C", NULL));

814:   PetscCall(PetscObjectCompose((PetscObject)mat, "DiagonalBlock", NULL));
815:   PetscFunctionReturn(PETSC_SUCCESS);
816: }

818: #include <petscdraw.h>
819: static PetscErrorCode MatView_MPIDense_ASCIIorDraworSocket(Mat mat, PetscViewer viewer)
820: {
821:   Mat_MPIDense     *mdn = (Mat_MPIDense *)mat->data;
822:   PetscMPIInt       rank;
823:   PetscViewerType   vtype;
824:   PetscBool         isascii, isdraw;
825:   PetscViewer       sviewer;
826:   PetscViewerFormat format;

828:   PetscFunctionBegin;
829:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank));
830:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
831:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
832:   if (isascii) {
833:     PetscCall(PetscViewerGetType(viewer, &vtype));
834:     PetscCall(PetscViewerGetFormat(viewer, &format));
835:     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
836:       MatInfo info;
837:       PetscCall(MatGetInfo(mat, MAT_LOCAL, &info));
838:       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
839:       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  [%d] local rows %" PetscInt_FMT " nz %" PetscInt_FMT " nz alloced %" PetscInt_FMT " mem %" PetscInt_FMT " \n", rank, mat->rmap->n, (PetscInt)info.nz_used, (PetscInt)info.nz_allocated,
840:                                                    (PetscInt)info.memory));
841:       PetscCall(PetscViewerFlush(viewer));
842:       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
843:       if (mdn->Mvctx) PetscCall(PetscSFView(mdn->Mvctx, viewer));
844:       PetscFunctionReturn(PETSC_SUCCESS);
845:     } else if (format == PETSC_VIEWER_ASCII_INFO) {
846:       PetscFunctionReturn(PETSC_SUCCESS);
847:     }
848:   } else if (isdraw) {
849:     PetscDraw draw;
850:     PetscBool isnull;

852:     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
853:     PetscCall(PetscDrawIsNull(draw, &isnull));
854:     if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
855:   }

857:   {
858:     /* assemble the entire matrix onto first processor. */
859:     Mat          A;
860:     PetscInt     M = mat->rmap->N, N = mat->cmap->N, m, row, i, nz;
861:     PetscInt    *cols;
862:     PetscScalar *vals;

864:     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &A));
865:     if (rank == 0) {
866:       PetscCall(MatSetSizes(A, M, N, M, N));
867:     } else {
868:       PetscCall(MatSetSizes(A, 0, 0, M, N));
869:     }
870:     /* Since this is a temporary matrix, MATMPIDENSE instead of ((PetscObject)A)->type_name here is probably acceptable. */
871:     PetscCall(MatSetType(A, MATMPIDENSE));
872:     PetscCall(MatMPIDenseSetPreallocation(A, NULL));

874:     /* Copy the matrix ... This isn't the most efficient means,
875:        but it's quick for now */
876:     A->insertmode = INSERT_VALUES;

878:     row = mat->rmap->rstart;
879:     m   = mdn->A->rmap->n;
880:     for (i = 0; i < m; i++) {
881:       PetscCall(MatGetRow_MPIDense(mat, row, &nz, &cols, &vals));
882:       PetscCall(MatSetValues_MPIDense(A, 1, &row, nz, cols, vals, INSERT_VALUES));
883:       PetscCall(MatRestoreRow_MPIDense(mat, row, &nz, &cols, &vals));
884:       row++;
885:     }

887:     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
888:     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
889:     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
890:     if (rank == 0) {
891:       PetscCall(PetscObjectSetName((PetscObject)((Mat_MPIDense *)A->data)->A, ((PetscObject)mat)->name));
892:       PetscCall(MatView_SeqDense(((Mat_MPIDense *)A->data)->A, sviewer));
893:     }
894:     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
895:     PetscCall(MatDestroy(&A));
896:   }
897:   PetscFunctionReturn(PETSC_SUCCESS);
898: }

900: static PetscErrorCode MatView_MPIDense(Mat mat, PetscViewer viewer)
901: {
902:   PetscBool isascii, isbinary, isdraw, issocket;

904:   PetscFunctionBegin;
905:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
906:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
907:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSOCKET, &issocket));
908:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));

910:   if (isascii || issocket || isdraw) PetscCall(MatView_MPIDense_ASCIIorDraworSocket(mat, viewer));
911:   else if (isbinary) PetscCall(MatView_Dense_Binary(mat, viewer));
912:   PetscFunctionReturn(PETSC_SUCCESS);
913: }

915: static PetscErrorCode MatGetInfo_MPIDense(Mat A, MatInfoType flag, MatInfo *info)
916: {
917:   Mat_MPIDense  *mat = (Mat_MPIDense *)A->data;
918:   Mat            mdn = mat->A;
919:   PetscLogDouble irecv[5];

921:   PetscFunctionBegin;
922:   info->block_size = 1.0;

924:   PetscCall(MatGetInfo(mdn, MAT_LOCAL, info));

926:   irecv[0] = info->nz_used;
927:   irecv[1] = info->nz_allocated;
928:   irecv[2] = info->nz_unneeded;
929:   irecv[3] = info->memory;
930:   irecv[4] = info->mallocs;
931:   if (flag == MAT_LOCAL) {
932:     info->nz_used      = irecv[0];
933:     info->nz_allocated = irecv[1];
934:     info->nz_unneeded  = irecv[2];
935:     info->memory       = irecv[3];
936:     info->mallocs      = irecv[4];
937:   } else if (flag == MAT_GLOBAL_MAX) {
938:     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A)));

940:     info->nz_used      = irecv[0];
941:     info->nz_allocated = irecv[1];
942:     info->nz_unneeded  = irecv[2];
943:     info->memory       = irecv[3];
944:     info->mallocs      = irecv[4];
945:   } else if (flag == MAT_GLOBAL_SUM) {
946:     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A)));

948:     info->nz_used      = irecv[0];
949:     info->nz_allocated = irecv[1];
950:     info->nz_unneeded  = irecv[2];
951:     info->memory       = irecv[3];
952:     info->mallocs      = irecv[4];
953:   }
954:   info->fill_ratio_given  = 0; /* no parallel LU/ILU/Cholesky */
955:   info->fill_ratio_needed = 0;
956:   info->factor_mallocs    = 0;
957:   PetscFunctionReturn(PETSC_SUCCESS);
958: }

960: static PetscErrorCode MatSetOption_MPIDense(Mat A, MatOption op, PetscBool flg)
961: {
962:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

964:   PetscFunctionBegin;
965:   switch (op) {
966:   case MAT_NEW_NONZERO_LOCATIONS:
967:   case MAT_NEW_NONZERO_LOCATION_ERR:
968:   case MAT_NEW_NONZERO_ALLOCATION_ERR:
969:     MatCheckPreallocated(A, 1);
970:     PetscCall(MatSetOption(a->A, op, flg));
971:     break;
972:   case MAT_ROW_ORIENTED:
973:     MatCheckPreallocated(A, 1);
974:     a->roworiented = flg;
975:     PetscCall(MatSetOption(a->A, op, flg));
976:     break;
977:   case MAT_IGNORE_OFF_PROC_ENTRIES:
978:     a->donotstash = flg;
979:     break;
980:   case MAT_SYMMETRIC:
981:   case MAT_STRUCTURALLY_SYMMETRIC:
982:   case MAT_HERMITIAN:
983:   case MAT_SYMMETRY_ETERNAL:
984:   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
985:   case MAT_SPD:
986:   case MAT_SPD_ETERNAL:
987:     /* if the diagonal matrix is square it inherits some of the properties above */
988:     if (a->A && A->rmap->n == A->cmap->n) PetscCall(MatSetOption(a->A, op, flg));
989:     break;
990:   default:
991:     break;
992:   }
993:   PetscFunctionReturn(PETSC_SUCCESS);
994: }

996: static PetscErrorCode MatDiagonalScale_MPIDense(Mat A, Vec ll, Vec rr)
997: {
998:   Mat_MPIDense *mdn = (Mat_MPIDense *)A->data;
999:   PetscInt      s1, s2, s3;

1001:   PetscFunctionBegin;
1002:   PetscCall(MatGetLocalSize(A, &s2, &s3));
1003:   if (ll) {
1004:     PetscCall(VecGetLocalSize(ll, &s1));
1005:     PetscCheck(s1 == s2, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Left scaling vector non-conforming local size, %" PetscInt_FMT " != %" PetscInt_FMT, s1, s2);
1006:   }
1007:   if (rr) {
1008:     PetscCall(VecGetLocalSize(rr, &s1));
1009:     PetscCheck(s1 == s3, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Right scaling vector non-conforming local size, %" PetscInt_FMT " != %" PetscInt_FMT, s1, s3);
1010:     /* gather the right scaling into the local column layout, staying on the device when the Vecs live there */
1011:     if (!mdn->Mvctx) PetscCall(MatSetUpMultiply_MPIDense(A));
1012:     PetscCall(VecScatterBegin(mdn->Mvctx, rr, mdn->lvec, INSERT_VALUES, SCATTER_FORWARD));
1013:     PetscCall(VecScatterEnd(mdn->Mvctx, rr, mdn->lvec, INSERT_VALUES, SCATTER_FORWARD));
1014:   }
1015:   /* the local matrix holds exactly the local rows and all the columns, so the local part of ll applies to it directly;
1016:      the operation is called rather than MatDiagonalScale() because ll is the parallel Vec and the interface checks that
1017:      it shares the communicator of the sequential matrix, as in MatDiagonalScale_MPIAIJ() */
1018:   PetscUseTypeMethod(mdn->A, diagonalscale, ll, rr ? mdn->lvec : NULL);
1019:   PetscCall(PetscObjectStateIncrease((PetscObject)mdn->A));
1020:   PetscFunctionReturn(PETSC_SUCCESS);
1021: }

1023: static PetscErrorCode MatNorm_MPIDense(Mat A, NormType type, PetscReal *nrm)
1024: {
1025:   Mat_MPIDense      *mdn = (Mat_MPIDense *)A->data;
1026:   PetscInt           i, j, lda;
1027:   PetscMPIInt        size;
1028:   const PetscScalar *av;

1030:   PetscFunctionBegin;
1031:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size));
1032:   if (size == 1) {
1033:     PetscCall(MatNorm(mdn->A, type, nrm));
1034:   } else {
1035:     if (type == NORM_FROBENIUS) {
1036:       PetscCall(MatNorm(mdn->A, NORM_FROBENIUS, nrm));
1037:       *nrm *= *nrm;
1038:       PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, nrm, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)A)));
1039:       *nrm = PetscSqrtReal(*nrm);
1040:     } else if (type == NORM_1) {
1041:       PetscReal *tmp;

1043:       PetscCall(PetscCalloc1(A->cmap->N, &tmp));
1044:       *nrm = 0.0;
1045:       PetscCall(MatDenseGetArrayRead(mdn->A, &av));
1046:       PetscCall(MatDenseGetLDA(mdn->A, &lda));
1047:       for (j = 0; j < mdn->A->cmap->n; j++) {
1048:         for (i = 0; i < mdn->A->rmap->n; i++) tmp[j] += PetscAbsScalar(av[i + j * lda]);
1049:       }
1050:       PetscCall(MatDenseRestoreArrayRead(mdn->A, &av));
1051:       PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, tmp, A->cmap->N, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)A)));
1052:       for (j = 0; j < A->cmap->N; j++) {
1053:         if (tmp[j] > *nrm) *nrm = tmp[j];
1054:       }
1055:       PetscCall(PetscFree(tmp));
1056:       PetscCall(PetscLogFlops(A->cmap->n * A->rmap->n));
1057:     } else if (type == NORM_INFINITY) { /* max row norm */
1058:       PetscCall(MatNorm(mdn->A, type, nrm));
1059:       PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, nrm, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)A)));
1060:     } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Unsupported norm type %s", NormTypes[type]);
1061:   }
1062:   PetscFunctionReturn(PETSC_SUCCESS);
1063: }

1065: static PetscErrorCode MatTranspose_MPIDense(Mat A, MatReuse reuse, Mat *matout)
1066: {
1067:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;
1068:   Mat           B;
1069:   PetscInt      M = A->rmap->N, N = A->cmap->N, m, n, *rwork, rstart = A->rmap->rstart;
1070:   PetscInt      j, i, lda;
1071:   PetscScalar  *v;

1073:   PetscFunctionBegin;
1074:   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *matout));
1075:   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
1076:     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
1077:     PetscCall(MatSetSizes(B, A->cmap->n, A->rmap->n, N, M));
1078:     PetscCall(MatSetType(B, ((PetscObject)A)->type_name));
1079:     PetscCall(MatMPIDenseSetPreallocation(B, NULL));
1080:   } else B = *matout;

1082:   m = a->A->rmap->n;
1083:   n = a->A->cmap->n;
1084:   PetscCall(MatDenseGetArrayRead(a->A, (const PetscScalar **)&v));
1085:   PetscCall(MatDenseGetLDA(a->A, &lda));
1086:   PetscCall(PetscMalloc1(m, &rwork));
1087:   for (i = 0; i < m; i++) rwork[i] = rstart + i;
1088:   for (j = 0; j < n; j++) {
1089:     PetscCall(MatSetValues(B, 1, &j, m, rwork, v, INSERT_VALUES));
1090:     v = PetscSafePointerPlusOffset(v, lda);
1091:   }
1092:   PetscCall(MatDenseRestoreArrayRead(a->A, (const PetscScalar **)&v));
1093:   PetscCall(PetscFree(rwork));
1094:   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
1095:   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
1096:   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
1097:     *matout = B;
1098:   } else {
1099:     PetscCall(MatHeaderMerge(A, &B));
1100:   }
1101:   PetscFunctionReturn(PETSC_SUCCESS);
1102: }

1104: static PetscErrorCode       MatDuplicate_MPIDense(Mat, MatDuplicateOption, Mat *);
1105: PETSC_INTERN PetscErrorCode MatScale_MPIDense(Mat, PetscScalar);

1107: static PetscErrorCode MatSetUp_MPIDense(Mat A)
1108: {
1109:   PetscFunctionBegin;
1110:   PetscCall(PetscLayoutSetUp(A->rmap));
1111:   PetscCall(PetscLayoutSetUp(A->cmap));
1112:   if (!A->preallocated) PetscCall(MatMPIDenseSetPreallocation(A, NULL));
1113:   PetscFunctionReturn(PETSC_SUCCESS);
1114: }

1116: static PetscErrorCode MatAXPY_MPIDense(Mat Y, PetscScalar alpha, Mat X, MatStructure str)
1117: {
1118:   Mat_MPIDense *A = (Mat_MPIDense *)Y->data, *B = (Mat_MPIDense *)X->data;

1120:   PetscFunctionBegin;
1121:   PetscCall(MatAXPY(A->A, alpha, B->A, str));
1122:   PetscFunctionReturn(PETSC_SUCCESS);
1123: }

1125: static PetscErrorCode MatConjugate_MPIDense(Mat mat)
1126: {
1127:   Mat_MPIDense *a = (Mat_MPIDense *)mat->data;

1129:   PetscFunctionBegin;
1130:   PetscCall(MatConjugate(a->A));
1131:   PetscFunctionReturn(PETSC_SUCCESS);
1132: }

1134: static PetscErrorCode MatRealPart_MPIDense(Mat A)
1135: {
1136:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

1138:   PetscFunctionBegin;
1139:   PetscCall(MatRealPart(a->A));
1140:   PetscFunctionReturn(PETSC_SUCCESS);
1141: }

1143: static PetscErrorCode MatImaginaryPart_MPIDense(Mat A)
1144: {
1145:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

1147:   PetscFunctionBegin;
1148:   PetscCall(MatImaginaryPart(a->A));
1149:   PetscFunctionReturn(PETSC_SUCCESS);
1150: }

1152: static PetscErrorCode MatGetColumnVector_MPIDense(Mat A, Vec v, PetscInt col)
1153: {
1154:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

1156:   PetscFunctionBegin;
1157:   PetscCheck(a->A, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Missing local matrix");
1158:   PetscCheck(a->A->ops->getcolumnvector, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Missing get column operation");
1159:   PetscUseTypeMethod(a->A, getcolumnvector, v, col);
1160:   PetscFunctionReturn(PETSC_SUCCESS);
1161: }

1163: PETSC_INTERN PetscErrorCode MatGetColumnReductions_SeqDense(Mat, PetscInt, PetscReal *);

1165: static PetscErrorCode MatGetColumnReductions_MPIDense(Mat A, PetscInt type, PetscReal *reductions)
1166: {
1167:   PetscInt      i, m, n;
1168:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

1170:   PetscFunctionBegin;
1171:   PetscCall(MatGetSize(A, &m, &n));
1172:   if (type == REDUCTION_MEAN_REALPART) {
1173:     PetscCall(MatGetColumnReductions_SeqDense(a->A, (PetscInt)REDUCTION_SUM_REALPART, reductions));
1174:   } else if (type == REDUCTION_MEAN_IMAGINARYPART) {
1175:     PetscCall(MatGetColumnReductions_SeqDense(a->A, (PetscInt)REDUCTION_SUM_IMAGINARYPART, reductions));
1176:   } else {
1177:     PetscCall(MatGetColumnReductions_SeqDense(a->A, type, reductions));
1178:   }
1179:   if (type == NORM_2) {
1180:     for (i = 0; i < n; i++) reductions[i] *= reductions[i];
1181:   }
1182:   if (type == NORM_INFINITY) {
1183:     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, reductions, n, MPIU_REAL, MPIU_MAX, A->hdr.comm));
1184:   } else {
1185:     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, reductions, n, MPIU_REAL, MPIU_SUM, A->hdr.comm));
1186:   }
1187:   if (type == NORM_2) {
1188:     for (i = 0; i < n; i++) reductions[i] = PetscSqrtReal(reductions[i]);
1189:   } else if (type == REDUCTION_MEAN_REALPART || type == REDUCTION_MEAN_IMAGINARYPART) {
1190:     for (i = 0; i < n; i++) reductions[i] /= m;
1191:   }
1192:   PetscFunctionReturn(PETSC_SUCCESS);
1193: }

1195: static PetscErrorCode MatSetRandom_MPIDense(Mat x, PetscRandom rctx)
1196: {
1197:   Mat_MPIDense *d = (Mat_MPIDense *)x->data;

1199:   PetscFunctionBegin;
1200:   PetscCall(MatSetRandom(d->A, rctx));
1201: #if PetscDefined(HAVE_DEVICE)
1202:   x->offloadmask = d->A->offloadmask;
1203: #endif
1204:   PetscCall(PetscObjectStateIncrease((PetscObject)x));
1205:   PetscFunctionReturn(PETSC_SUCCESS);
1206: }

1208: static PetscErrorCode MatMatTransposeMultSymbolic_MPIDense_MPIDense(Mat, Mat, PetscReal, Mat);
1209: static PetscErrorCode MatMatTransposeMultNumeric_MPIDense_MPIDense(Mat, Mat, Mat);
1210: static PetscErrorCode MatTransposeMatMultSymbolic_MPIDense_MPIDense(Mat, Mat, PetscReal, Mat);
1211: static PetscErrorCode MatTransposeMatMultNumeric_MPIDense_MPIDense(Mat, Mat, Mat);
1212: static PetscErrorCode MatEqual_MPIDense(Mat, Mat, PetscBool *);
1213: static PetscErrorCode MatLoad_MPIDense(Mat, PetscViewer);
1214: static PetscErrorCode MatProductSetFromOptions_MPIDense(Mat);

1216: static struct _MatOps MatOps_Values = {MatSetValues_MPIDense,
1217:                                        MatGetRow_MPIDense,
1218:                                        MatRestoreRow_MPIDense,
1219:                                        MatMult_MPIDense,
1220:                                        /*  4*/ MatMultAdd_MPIDense,
1221:                                        MatMultTranspose_MPIDense,
1222:                                        MatMultTransposeAdd_MPIDense,
1223:                                        NULL,
1224:                                        NULL,
1225:                                        NULL,
1226:                                        /* 10*/ NULL,
1227:                                        NULL,
1228:                                        NULL,
1229:                                        NULL,
1230:                                        MatTranspose_MPIDense,
1231:                                        /* 15*/ MatGetInfo_MPIDense,
1232:                                        MatEqual_MPIDense,
1233:                                        MatGetDiagonal_MPIDense,
1234:                                        MatDiagonalScale_MPIDense,
1235:                                        MatNorm_MPIDense,
1236:                                        /* 20*/ MatAssemblyBegin_MPIDense,
1237:                                        MatAssemblyEnd_MPIDense,
1238:                                        MatSetOption_MPIDense,
1239:                                        MatZeroEntries_MPIDense,
1240:                                        /* 24*/ MatZeroRows_MPIDense,
1241:                                        NULL,
1242:                                        NULL,
1243:                                        NULL,
1244:                                        NULL,
1245:                                        /* 29*/ MatSetUp_MPIDense,
1246:                                        NULL,
1247:                                        NULL,
1248:                                        MatGetDiagonalBlock_MPIDense,
1249:                                        MatSetInf_MPIDense,
1250:                                        /* 34*/ MatDuplicate_MPIDense,
1251:                                        NULL,
1252:                                        NULL,
1253:                                        NULL,
1254:                                        NULL,
1255:                                        /* 39*/ MatAXPY_MPIDense,
1256:                                        MatCreateSubMatrices_MPIDense,
1257:                                        NULL,
1258:                                        MatGetValues_MPIDense,
1259:                                        MatCopy_MPIDense,
1260:                                        /* 44*/ NULL,
1261:                                        MatScale_MPIDense,
1262:                                        MatShift_MPIDense,
1263:                                        NULL,
1264:                                        NULL,
1265:                                        /* 49*/ MatSetRandom_MPIDense,
1266:                                        NULL,
1267:                                        NULL,
1268:                                        NULL,
1269:                                        NULL,
1270:                                        /* 54*/ NULL,
1271:                                        NULL,
1272:                                        NULL,
1273:                                        NULL,
1274:                                        NULL,
1275:                                        /* 59*/ MatCreateSubMatrix_MPIDense,
1276:                                        MatDestroy_MPIDense,
1277:                                        MatView_MPIDense,
1278:                                        NULL,
1279:                                        NULL,
1280:                                        /* 64*/ NULL,
1281:                                        NULL,
1282:                                        NULL,
1283:                                        NULL,
1284:                                        NULL,
1285:                                        /* 69*/ NULL,
1286:                                        NULL,
1287:                                        NULL,
1288:                                        NULL,
1289:                                        NULL,
1290:                                        /* 74*/ NULL,
1291:                                        NULL,
1292:                                        NULL,
1293:                                        NULL,
1294:                                        MatLoad_MPIDense,
1295:                                        /* 79*/ NULL,
1296:                                        NULL,
1297:                                        NULL,
1298:                                        NULL,
1299:                                        /* 83*/ NULL,
1300:                                        NULL,
1301:                                        NULL,
1302:                                        NULL,
1303:                                        MatMatTransposeMultSymbolic_MPIDense_MPIDense,
1304:                                        MatMatTransposeMultNumeric_MPIDense_MPIDense,
1305:                                        /* 89*/ NULL,
1306:                                        MatProductSetFromOptions_MPIDense,
1307:                                        NULL,
1308:                                        NULL,
1309:                                        MatConjugate_MPIDense,
1310:                                        /* 94*/ NULL,
1311:                                        NULL,
1312:                                        MatRealPart_MPIDense,
1313:                                        MatImaginaryPart_MPIDense,
1314:                                        NULL,
1315:                                        /*99*/ NULL,
1316:                                        NULL,
1317:                                        NULL,
1318:                                        NULL,
1319:                                        MatGetColumnVector_MPIDense,
1320:                                        /*104*/ NULL,
1321:                                        NULL,
1322:                                        NULL,
1323:                                        NULL,
1324:                                        NULL,
1325:                                        /*109*/ NULL,
1326:                                        NULL,
1327:                                        MatMultHermitianTranspose_MPIDense,
1328:                                        MatMultHermitianTransposeAdd_MPIDense,
1329:                                        NULL,
1330:                                        /*114*/ NULL,
1331:                                        MatGetColumnReductions_MPIDense,
1332:                                        NULL,
1333:                                        NULL,
1334:                                        NULL,
1335:                                        /*120*/ MatTransposeMatMultSymbolic_MPIDense_MPIDense,
1336:                                        MatTransposeMatMultNumeric_MPIDense_MPIDense,
1337:                                        NULL,
1338:                                        NULL,
1339:                                        /*124*/ NULL,
1340:                                        NULL,
1341:                                        NULL,
1342:                                        NULL,
1343:                                        NULL,
1344:                                        /*129*/ NULL,
1345:                                        MatCreateMPIMatConcatenateSeqMat_MPIDense,
1346:                                        NULL,
1347:                                        NULL,
1348:                                        NULL,
1349:                                        /*134*/ NULL,
1350:                                        NULL,
1351:                                        NULL,
1352:                                        NULL,
1353:                                        NULL,
1354:                                        /*139*/ NULL,
1355:                                        NULL,
1356:                                        NULL,
1357:                                        NULL,
1358:                                        NULL,
1359:                                        NULL,
1360:                                        /*144*/ NULL,
1361:                                        NULL,
1362:                                        NULL,
1363:                                        NULL};

1365: static PetscErrorCode MatMPIDenseSetPreallocation_MPIDense(Mat mat, PetscScalar *data)
1366: {
1367:   Mat_MPIDense *a     = (Mat_MPIDense *)mat->data;
1368:   MatType       mtype = MATSEQDENSE;

1370:   PetscFunctionBegin;
1371:   PetscCheck(!a->matinuse, PetscObjectComm((PetscObject)mat), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
1372:   PetscCall(PetscLayoutSetUp(mat->rmap));
1373:   PetscCall(PetscLayoutSetUp(mat->cmap));
1374:   if (!a->A) {
1375:     PetscCall(MatCreate(PETSC_COMM_SELF, &a->A));
1376:     PetscCall(MatSetSizes(a->A, mat->rmap->n, mat->cmap->N, mat->rmap->n, mat->cmap->N));
1377:   }
1378: #if PetscDefined(HAVE_CUDA)
1379:   PetscBool iscuda;
1380:   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATMPIDENSECUDA, &iscuda));
1381:   if (iscuda) mtype = MATSEQDENSECUDA;
1382: #endif
1383: #if PetscDefined(HAVE_HIP)
1384:   PetscBool iship;
1385:   PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATMPIDENSEHIP, &iship));
1386:   if (iship) mtype = MATSEQDENSEHIP;
1387: #endif
1388:   PetscCall(MatSetType(a->A, mtype));
1389:   PetscCall(MatSeqDenseSetPreallocation(a->A, data));
1390: #if PetscDefined(HAVE_CUDA) || PetscDefined(HAVE_HIP)
1391:   mat->offloadmask = a->A->offloadmask;
1392: #endif
1393:   mat->preallocated = PETSC_TRUE;
1394:   mat->assembled    = PETSC_TRUE;
1395:   PetscFunctionReturn(PETSC_SUCCESS);
1396: }

1398: PETSC_INTERN PetscErrorCode MatConvert_MPIAIJ_MPIDense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1399: {
1400:   Mat B, C;

1402:   PetscFunctionBegin;
1403:   PetscCall(MatMPIAIJGetLocalMat(A, MAT_INITIAL_MATRIX, &C));
1404:   PetscCall(MatConvert_SeqAIJ_SeqDense(C, MATSEQDENSE, MAT_INITIAL_MATRIX, &B));
1405:   PetscCall(MatDestroy(&C));
1406:   if (reuse == MAT_REUSE_MATRIX) {
1407:     C = *newmat;
1408:   } else C = NULL;
1409:   PetscCall(MatCreateMPIMatConcatenateSeqMat(PetscObjectComm((PetscObject)A), B, A->cmap->n, !C ? MAT_INITIAL_MATRIX : MAT_REUSE_MATRIX, &C));
1410:   PetscCall(MatDestroy(&B));
1411:   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &C));
1412:   else if (reuse == MAT_INITIAL_MATRIX) *newmat = C;
1413:   PetscFunctionReturn(PETSC_SUCCESS);
1414: }

1416: static PetscErrorCode MatConvert_MPIDense_MPIAIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1417: {
1418:   Mat B, C;

1420:   PetscFunctionBegin;
1421:   PetscCall(MatDenseGetLocalMatrix(A, &C));
1422:   PetscCall(MatConvert_SeqDense_SeqAIJ(C, MATSEQAIJ, MAT_INITIAL_MATRIX, &B));
1423:   if (reuse == MAT_REUSE_MATRIX) {
1424:     C = *newmat;
1425:   } else C = NULL;
1426:   PetscCall(MatCreateMPIMatConcatenateSeqMat(PetscObjectComm((PetscObject)A), B, A->cmap->n, !C ? MAT_INITIAL_MATRIX : MAT_REUSE_MATRIX, &C));
1427:   PetscCall(MatDestroy(&B));
1428:   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &C));
1429:   else if (reuse == MAT_INITIAL_MATRIX) *newmat = C;
1430:   PetscFunctionReturn(PETSC_SUCCESS);
1431: }

1433: #if PetscDefined(HAVE_ELEMENTAL)
1434: PETSC_INTERN PetscErrorCode MatConvert_MPIDense_Elemental(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1435: {
1436:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;
1437:   Mat           mat_elemental;
1438:   PetscScalar  *v;
1439:   PetscInt      m = A->rmap->n, N = A->cmap->N, rstart = A->rmap->rstart, i, *rows, *cols, lda;

1441:   PetscFunctionBegin;
1442:   if (reuse == MAT_REUSE_MATRIX) {
1443:     mat_elemental = *newmat;
1444:     PetscCall(MatZeroEntries(*newmat));
1445:   } else {
1446:     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental));
1447:     PetscCall(MatSetSizes(mat_elemental, PETSC_DECIDE, PETSC_DECIDE, A->rmap->N, A->cmap->N));
1448:     PetscCall(MatSetType(mat_elemental, MATELEMENTAL));
1449:     PetscCall(MatSetUp(mat_elemental));
1450:     PetscCall(MatSetOption(mat_elemental, MAT_ROW_ORIENTED, PETSC_FALSE));
1451:   }

1453:   PetscCall(PetscMalloc2(m, &rows, N, &cols));
1454:   for (i = 0; i < N; i++) cols[i] = i;
1455:   for (i = 0; i < m; i++) rows[i] = rstart + i;

1457:   /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */
1458:   PetscCall(MatDenseGetArray(A, &v));
1459:   PetscCall(MatDenseGetLDA(a->A, &lda));
1460:   if (lda == m) PetscCall(MatSetValues(mat_elemental, m, rows, N, cols, v, ADD_VALUES));
1461:   else {
1462:     for (i = 0; i < N; i++) PetscCall(MatSetValues(mat_elemental, m, rows, 1, &i, v + lda * i, ADD_VALUES));
1463:   }
1464:   PetscCall(MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY));
1465:   PetscCall(MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY));
1466:   PetscCall(MatDenseRestoreArray(A, &v));
1467:   PetscCall(PetscFree2(rows, cols));

1469:   if (reuse == MAT_INPLACE_MATRIX) {
1470:     PetscCall(MatHeaderReplace(A, &mat_elemental));
1471:   } else {
1472:     *newmat = mat_elemental;
1473:   }
1474:   PetscFunctionReturn(PETSC_SUCCESS);
1475: }
1476: #endif

1478: static PetscErrorCode MatDenseGetColumn_MPIDense(Mat A, PetscInt col, PetscScalar **vals)
1479: {
1480:   Mat_MPIDense *mat = (Mat_MPIDense *)A->data;

1482:   PetscFunctionBegin;
1483:   PetscCall(MatDenseGetColumn(mat->A, col, vals));
1484:   PetscFunctionReturn(PETSC_SUCCESS);
1485: }

1487: static PetscErrorCode MatDenseRestoreColumn_MPIDense(Mat A, PetscScalar **vals)
1488: {
1489:   Mat_MPIDense *mat = (Mat_MPIDense *)A->data;

1491:   PetscFunctionBegin;
1492:   PetscCall(MatDenseRestoreColumn(mat->A, vals));
1493:   PetscFunctionReturn(PETSC_SUCCESS);
1494: }

1496: PetscErrorCode MatCreateMPIMatConcatenateSeqMat_MPIDense(MPI_Comm comm, Mat inmat, PetscInt n, MatReuse scall, Mat *outmat)
1497: {
1498:   Mat_MPIDense *mat;
1499:   PetscInt      m, nloc, N;

1501:   PetscFunctionBegin;
1502:   PetscCall(MatGetSize(inmat, &m, &N));
1503:   PetscCall(MatGetLocalSize(inmat, NULL, &nloc));
1504:   if (scall == MAT_INITIAL_MATRIX) { /* symbolic phase */
1505:     PetscInt sum;

1507:     if (n == PETSC_DECIDE) PetscCall(PetscSplitOwnership(comm, &n, &N));
1508:     /* Check sum(n) = N */
1509:     PetscCallMPI(MPIU_Allreduce(&n, &sum, 1, MPIU_INT, MPI_SUM, comm));
1510:     PetscCheck(sum == N, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Sum of local columns %" PetscInt_FMT " != global columns %" PetscInt_FMT, sum, N);

1512:     PetscCall(MatCreateDense(comm, m, n, PETSC_DETERMINE, N, NULL, outmat));
1513:     PetscCall(MatSetOption(*outmat, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
1514:   }

1516:   /* numeric phase */
1517:   mat = (Mat_MPIDense *)(*outmat)->data;
1518:   PetscCall(MatCopy(inmat, mat->A, SAME_NONZERO_PATTERN));
1519:   PetscFunctionReturn(PETSC_SUCCESS);
1520: }

1522: PetscErrorCode MatDenseGetColumnVec_MPIDense(Mat A, PetscInt col, Vec *v)
1523: {
1524:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;
1525:   PetscInt      lda;

1527:   PetscFunctionBegin;
1528:   PetscCheck(!a->vecinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreColumnVec() first");
1529:   PetscCheck(!a->matinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
1530:   if (!a->cvec) PetscCall(MatDenseCreateColumnVec_Private(A, &a->cvec));
1531:   a->vecinuse = col + 1;
1532:   PetscCall(MatDenseGetLDA(a->A, &lda));
1533:   PetscCall(MatDenseGetArray(a->A, (PetscScalar **)&a->ptrinuse));
1534:   PetscCall(VecPlaceArray(a->cvec, PetscSafePointerPlusOffset(a->ptrinuse, (size_t)col * (size_t)lda)));
1535:   *v = a->cvec;
1536:   PetscFunctionReturn(PETSC_SUCCESS);
1537: }

1539: PetscErrorCode MatDenseRestoreColumnVec_MPIDense(Mat A, PetscInt col, Vec *v)
1540: {
1541:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

1543:   PetscFunctionBegin;
1544:   PetscCheck(a->vecinuse, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Need to call MatDenseGetColumnVec() first");
1545:   PetscCheck(a->cvec, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing internal column vector");
1546:   VecCheckAssembled(a->cvec);
1547:   a->vecinuse = 0;
1548:   PetscCall(MatDenseRestoreArray(a->A, (PetscScalar **)&a->ptrinuse));
1549:   PetscCall(VecResetArray(a->cvec));
1550:   if (v) *v = NULL;
1551:   PetscFunctionReturn(PETSC_SUCCESS);
1552: }

1554: PetscErrorCode MatDenseGetColumnVecRead_MPIDense(Mat A, PetscInt col, Vec *v)
1555: {
1556:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;
1557:   PetscInt      lda;

1559:   PetscFunctionBegin;
1560:   PetscCheck(!a->vecinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreColumnVec() first");
1561:   PetscCheck(!a->matinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
1562:   if (!a->cvec) PetscCall(MatDenseCreateColumnVec_Private(A, &a->cvec));
1563:   a->vecinuse = col + 1;
1564:   PetscCall(MatDenseGetLDA(a->A, &lda));
1565:   PetscCall(MatDenseGetArrayRead(a->A, &a->ptrinuse));
1566:   PetscCall(VecPlaceArray(a->cvec, PetscSafePointerPlusOffset(a->ptrinuse, (size_t)col * (size_t)lda)));
1567:   PetscCall(VecLockReadPush(a->cvec));
1568:   *v = a->cvec;
1569:   PetscFunctionReturn(PETSC_SUCCESS);
1570: }

1572: PetscErrorCode MatDenseRestoreColumnVecRead_MPIDense(Mat A, PetscInt col, Vec *v)
1573: {
1574:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

1576:   PetscFunctionBegin;
1577:   PetscCheck(a->vecinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseGetColumnVec() first");
1578:   PetscCheck(a->cvec, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing internal column vector");
1579:   VecCheckAssembled(a->cvec);
1580:   a->vecinuse = 0;
1581:   PetscCall(MatDenseRestoreArrayRead(a->A, &a->ptrinuse));
1582:   PetscCall(VecLockReadPop(a->cvec));
1583:   PetscCall(VecResetArray(a->cvec));
1584:   if (v) *v = NULL;
1585:   PetscFunctionReturn(PETSC_SUCCESS);
1586: }

1588: PetscErrorCode MatDenseGetColumnVecWrite_MPIDense(Mat A, PetscInt col, Vec *v)
1589: {
1590:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;
1591:   PetscInt      lda;

1593:   PetscFunctionBegin;
1594:   PetscCheck(!a->vecinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreColumnVec() first");
1595:   PetscCheck(!a->matinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
1596:   if (!a->cvec) PetscCall(MatDenseCreateColumnVec_Private(A, &a->cvec));
1597:   a->vecinuse = col + 1;
1598:   PetscCall(MatDenseGetLDA(a->A, &lda));
1599:   PetscCall(MatDenseGetArrayWrite(a->A, (PetscScalar **)&a->ptrinuse));
1600:   PetscCall(VecPlaceArray(a->cvec, PetscSafePointerPlusOffset(a->ptrinuse, (size_t)col * (size_t)lda)));
1601:   *v = a->cvec;
1602:   PetscFunctionReturn(PETSC_SUCCESS);
1603: }

1605: PetscErrorCode MatDenseRestoreColumnVecWrite_MPIDense(Mat A, PetscInt col, Vec *v)
1606: {
1607:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

1609:   PetscFunctionBegin;
1610:   PetscCheck(a->vecinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseGetColumnVec() first");
1611:   PetscCheck(a->cvec, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing internal column vector");
1612:   VecCheckAssembled(a->cvec);
1613:   a->vecinuse = 0;
1614:   PetscCall(MatDenseRestoreArrayWrite(a->A, (PetscScalar **)&a->ptrinuse));
1615:   PetscCall(VecResetArray(a->cvec));
1616:   if (v) *v = NULL;
1617:   PetscFunctionReturn(PETSC_SUCCESS);
1618: }

1620: static PetscErrorCode MatDenseGetSubMatrix_MPIDense(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *v)
1621: {
1622:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;
1623:   Mat_MPIDense *c;
1624:   MPI_Comm      comm;
1625:   PetscInt      prbegin, prend, pcbegin, pcend;

1627:   PetscFunctionBegin;
1628:   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
1629:   PetscCheck(!a->vecinuse, comm, PETSC_ERR_ORDER, "Need to call MatDenseRestoreColumnVec() first");
1630:   PetscCheck(!a->matinuse, comm, PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
1631:   prbegin = PetscMax(0, PetscMin(A->rmap->rend, rbegin) - A->rmap->rstart);
1632:   prend   = PetscMin(A->rmap->n, PetscMax(0, rend - A->rmap->rstart));
1633:   pcbegin = PetscMax(0, PetscMin(A->cmap->rend, cbegin) - A->cmap->rstart);
1634:   pcend   = PetscMin(A->cmap->n, PetscMax(0, cend - A->cmap->rstart));
1635:   if (!a->cmat) {
1636:     PetscCall(MatCreate(comm, &a->cmat));
1637:     PetscCall(MatSetType(a->cmat, ((PetscObject)A)->type_name));
1638:     PetscCall(MatSetVecType(a->cmat, A->defaultvectype));
1639:     if (rend - rbegin == A->rmap->N) PetscCall(PetscLayoutReference(A->rmap, &a->cmat->rmap));
1640:     else {
1641:       PetscCall(PetscLayoutSetLocalSize(a->cmat->rmap, prend - prbegin));
1642:       PetscCall(PetscLayoutSetSize(a->cmat->rmap, rend - rbegin));
1643:       PetscCall(PetscLayoutSetUp(a->cmat->rmap));
1644:     }
1645:     if (cend - cbegin == A->cmap->N) PetscCall(PetscLayoutReference(A->cmap, &a->cmat->cmap));
1646:     else {
1647:       PetscCall(PetscLayoutSetLocalSize(a->cmat->cmap, pcend - pcbegin));
1648:       PetscCall(PetscLayoutSetSize(a->cmat->cmap, cend - cbegin));
1649:       PetscCall(PetscLayoutSetUp(a->cmat->cmap));
1650:     }
1651:     c             = (Mat_MPIDense *)a->cmat->data;
1652:     c->sub_rbegin = rbegin;
1653:     c->sub_rend   = rend;
1654:     c->sub_cbegin = cbegin;
1655:     c->sub_cend   = cend;
1656:   }
1657:   c = (Mat_MPIDense *)a->cmat->data;
1658:   if (c->sub_rbegin != rbegin || c->sub_rend != rend) {
1659:     PetscCall(PetscLayoutDestroy(&a->cmat->rmap));
1660:     PetscCall(PetscLayoutCreate(comm, &a->cmat->rmap));
1661:     PetscCall(PetscLayoutSetLocalSize(a->cmat->rmap, prend - prbegin));
1662:     PetscCall(PetscLayoutSetSize(a->cmat->rmap, rend - rbegin));
1663:     PetscCall(PetscLayoutSetUp(a->cmat->rmap));
1664:     c->sub_rbegin = rbegin;
1665:     c->sub_rend   = rend;
1666:   }
1667:   if (c->sub_cbegin != cbegin || c->sub_cend != cend) {
1668:     // special optimization: check if all columns are owned by rank 0, in which case no communication is necessary
1669:     if (cend - cbegin != a->cmat->cmap->N || A->cmap->range[1] != A->cmap->N) {
1670:       PetscCall(PetscLayoutDestroy(&a->cmat->cmap));
1671:       PetscCall(PetscLayoutCreate(comm, &a->cmat->cmap));
1672:       PetscCall(PetscLayoutSetLocalSize(a->cmat->cmap, pcend - pcbegin));
1673:       PetscCall(PetscLayoutSetSize(a->cmat->cmap, cend - cbegin));
1674:       PetscCall(PetscLayoutSetUp(a->cmat->cmap));
1675:       PetscCall(VecDestroy(&c->lvec));
1676:       PetscCall(PetscSFDestroy(&c->Mvctx));
1677:     }
1678:     c->sub_cbegin = cbegin;
1679:     c->sub_cend   = cend;
1680:   }
1681:   PetscCheck(!c->A, comm, PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
1682:   PetscCall(MatDenseGetSubMatrix(a->A, prbegin, prend, cbegin, cend, &c->A));

1684:   a->cmat->preallocated = PETSC_TRUE;
1685:   a->cmat->assembled    = PETSC_TRUE;
1686: #if PetscDefined(HAVE_DEVICE)
1687:   a->cmat->offloadmask = c->A->offloadmask;
1688: #endif
1689:   a->matinuse = cbegin + 1;
1690:   *v          = a->cmat;
1691:   PetscFunctionReturn(PETSC_SUCCESS);
1692: }

1694: static PetscErrorCode MatDenseRestoreSubMatrix_MPIDense(Mat A, Mat *v)
1695: {
1696:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;
1697:   Mat_MPIDense *c;

1699:   PetscFunctionBegin;
1700:   PetscCheck(a->matinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseGetSubMatrix() first");
1701:   PetscCheck(a->cmat, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing internal matrix");
1702:   PetscCheck(*v == a->cmat, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not the matrix obtained from MatDenseGetSubMatrix()");
1703:   a->matinuse = 0;
1704:   c           = (Mat_MPIDense *)a->cmat->data;
1705:   PetscCall(MatDenseRestoreSubMatrix(a->A, &c->A));
1706:   *v = NULL;
1707: #if PetscDefined(HAVE_DEVICE)
1708:   A->offloadmask = a->A->offloadmask;
1709: #endif
1710:   PetscFunctionReturn(PETSC_SUCCESS);
1711: }

1713: static PetscErrorCode MatDenseUpdateColumnLayout_MPIDense(Mat A, PetscLayout clayout)
1714: {
1715:   Mat_MPIDense *a = (Mat_MPIDense *)A->data;

1717:   PetscFunctionBegin;
1718:   if (A->cmap == clayout) PetscFunctionReturn(PETSC_SUCCESS);
1719:   PetscCheck(!a->matinuse, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to call MatDenseRestoreSubMatrix() first");
1720:   PetscCall(PetscLayoutReference(clayout, &A->cmap));
1721:   PetscCall(MatDestroy(&a->cmat));
1722:   PetscCall(PetscSFDestroy(&a->Mvctx));
1723:   PetscFunctionReturn(PETSC_SUCCESS);
1724: }

1726: /*MC
1727:    MATMPIDENSE - MATMPIDENSE = "mpidense" - A matrix type to be used for distributed dense matrices.

1729:    Options Database Key:
1730: . -mat_type mpidense - sets the matrix type to `MATMPIDENSE` during a call to `MatSetFromOptions()`

1732:   Level: beginner

1734: .seealso: [](ch_matrices), `Mat`, `MatCreateDense()`, `MATSEQDENSE`, `MATDENSE`
1735: M*/
1736: PetscErrorCode MatCreate_MPIDense(Mat mat)
1737: {
1738:   Mat_MPIDense *a;

1740:   PetscFunctionBegin;
1741:   PetscCall(PetscNew(&a));
1742:   mat->data   = (void *)a;
1743:   mat->ops[0] = MatOps_Values;

1745:   mat->insertmode = NOT_SET_VALUES;

1747:   /* build cache for off array entries formed */
1748:   a->donotstash = PETSC_FALSE;

1750:   PetscCall(MatStashCreate_Private(PetscObjectComm((PetscObject)mat), 1, &mat->stash));

1752:   /* stuff used for matrix vector multiply */
1753:   a->lvec        = NULL;
1754:   a->Mvctx       = NULL;
1755:   a->roworiented = PETSC_TRUE;

1757:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetLDA_C", MatDenseGetLDA_MPIDense));
1758:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseSetLDA_C", MatDenseSetLDA_MPIDense));
1759:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetArray_C", MatDenseGetArray_MPIDense));
1760:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreArray_C", MatDenseRestoreArray_MPIDense));
1761:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetArrayRead_C", MatDenseGetArrayRead_MPIDense));
1762:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreArrayRead_C", MatDenseRestoreArrayRead_MPIDense));
1763:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetArrayWrite_C", MatDenseGetArrayWrite_MPIDense));
1764:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreArrayWrite_C", MatDenseRestoreArrayWrite_MPIDense));
1765:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDensePlaceArray_C", MatDensePlaceArray_MPIDense));
1766:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseResetArray_C", MatDenseResetArray_MPIDense));
1767:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseReplaceArray_C", MatDenseReplaceArray_MPIDense));
1768:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetColumnVec_C", MatDenseGetColumnVec_MPIDense));
1769:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreColumnVec_C", MatDenseRestoreColumnVec_MPIDense));
1770:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetColumnVecRead_C", MatDenseGetColumnVecRead_MPIDense));
1771:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreColumnVecRead_C", MatDenseRestoreColumnVecRead_MPIDense));
1772:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetColumnVecWrite_C", MatDenseGetColumnVecWrite_MPIDense));
1773:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreColumnVecWrite_C", MatDenseRestoreColumnVecWrite_MPIDense));
1774:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetSubMatrix_C", MatDenseGetSubMatrix_MPIDense));
1775:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreSubMatrix_C", MatDenseRestoreSubMatrix_MPIDense));
1776:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpiaij_mpidense_C", MatConvert_MPIAIJ_MPIDense));
1777:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpidense_mpiaij_C", MatConvert_MPIDense_MPIAIJ));
1778: #if PetscDefined(HAVE_ELEMENTAL)
1779:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpidense_elemental_C", MatConvert_MPIDense_Elemental));
1780: #endif
1781: #if PetscDefined(HAVE_SCALAPACK) && (PetscDefined(USE_REAL_SINGLE) || PetscDefined(USE_REAL_DOUBLE))
1782:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpidense_scalapack_C", MatConvert_Dense_ScaLAPACK));
1783: #endif
1784: #if PetscDefined(HAVE_CUDA)
1785:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpidense_mpidensecuda_C", MatConvert_MPIDense_MPIDenseCUDA));
1786: #endif
1787:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMPIDenseSetPreallocation_C", MatMPIDenseSetPreallocation_MPIDense));
1788:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpiaij_mpidense_C", MatProductSetFromOptions_MPIAIJ_MPIDense));
1789:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpidense_mpiaij_C", MatProductSetFromOptions_MPIDense_MPIAIJ));
1790: #if PetscDefined(HAVE_CUDA)
1791:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpiaijcusparse_mpidense_C", MatProductSetFromOptions_MPIAIJ_MPIDense));
1792:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpidense_mpiaijcusparse_C", MatProductSetFromOptions_MPIDense_MPIAIJ));
1793: #endif
1794: #if PetscDefined(HAVE_HIP)
1795:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpidense_mpidensehip_C", MatConvert_MPIDense_MPIDenseHIP));
1796:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpiaijhipsparse_mpidense_C", MatProductSetFromOptions_MPIAIJ_MPIDense));
1797:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatProductSetFromOptions_mpidense_mpiaijhipsparse_C", MatProductSetFromOptions_MPIDense_MPIAIJ));
1798: #endif
1799:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseGetColumn_C", MatDenseGetColumn_MPIDense));
1800:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseRestoreColumn_C", MatDenseRestoreColumn_MPIDense));
1801:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMultColumnRange_C", MatMultColumnRange_MPIDense));
1802:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMultAddColumnRange_C", MatMultAddColumnRange_MPIDense));
1803:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMultHermitianTransposeColumnRange_C", MatMultHermitianTransposeColumnRange_MPIDense));
1804:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMultHermitianTransposeAddColumnRange_C", MatMultHermitianTransposeAddColumnRange_MPIDense));
1805:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatGetMultPetscSF_C", MatGetMultPetscSF_MPIDense));
1806:   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDenseUpdateColumnLayout_C", MatDenseUpdateColumnLayout_MPIDense));
1807:   PetscCall(PetscObjectChangeTypeName((PetscObject)mat, MATMPIDENSE));
1808:   PetscFunctionReturn(PETSC_SUCCESS);
1809: }

1811: /*MC
1812:    MATDENSE - MATDENSE = "dense" - A matrix type to be used for dense matrices.

1814:    This matrix type is identical to `MATSEQDENSE` when constructed with a single process communicator,
1815:    and `MATMPIDENSE` otherwise.

1817:    Options Database Key:
1818: . -mat_type dense - sets the matrix type to `MATDENSE` during a call to `MatSetFromOptions()`

1820:   Level: beginner

1822: .seealso: [](ch_matrices), `Mat`, `MATSEQDENSE`, `MATMPIDENSE`, `MATDENSECUDA`, `MATDENSEHIP`
1823: M*/

1825: /*@
1826:   MatMPIDenseSetPreallocation - Sets the array used to store the matrix entries

1828:   Collective

1830:   Input Parameters:
1831: + B    - the matrix
1832: - data - optional location of matrix data.  Set to `NULL` for PETSc
1833:          to control all matrix memory allocation.

1835:   Level: intermediate

1837:   Notes:
1838:   The dense format is fully compatible with standard Fortran
1839:   storage by columns.

1841:   The data input variable is intended primarily for Fortran programmers
1842:   who wish to allocate their own matrix memory space.  Most users should
1843:   set `data` to `NULL`.

1845: .seealso: [](ch_matrices), `Mat`, `MATMPIDENSE`, `MatCreate()`, `MatCreateSeqDense()`, `MatSetValues()`
1846: @*/
1847: PetscErrorCode MatMPIDenseSetPreallocation(Mat B, PetscScalar *data)
1848: {
1849:   PetscFunctionBegin;
1851:   PetscTryMethod(B, "MatMPIDenseSetPreallocation_C", (Mat, PetscScalar *), (B, data));
1852:   PetscFunctionReturn(PETSC_SUCCESS);
1853: }

1855: /*@
1856:   MatDensePlaceArray - Allows one to replace the array in a `MATDENSE` matrix with an
1857:   array provided by the user. This is useful to avoid copying an array
1858:   into a matrix

1860:   Not Collective

1862:   Input Parameters:
1863: + mat   - the matrix
1864: - array - the array in column major order

1866:   Level: developer

1868:   Note:
1869:   Adding `const` to `array` was an oversight, see notes in `VecPlaceArray()`.

1871:   You can return to the original array with a call to `MatDenseResetArray()`. The user is responsible for freeing this array; it will not be
1872:   freed when the matrix is destroyed.

1874: .seealso: [](ch_matrices), `Mat`, `MATDENSE`, `MatDenseGetArray()`, `MatDenseResetArray()`, `VecPlaceArray()`, `VecGetArray()`, `VecRestoreArray()`, `VecReplaceArray()`, `VecResetArray()`,
1875:           `MatDenseReplaceArray()`
1876: @*/
1877: PetscErrorCode MatDensePlaceArray(Mat mat, const PetscScalar *array)
1878: {
1879:   PetscFunctionBegin;
1881:   PetscUseMethod(mat, "MatDensePlaceArray_C", (Mat, const PetscScalar *), (mat, array));
1882:   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
1883: #if PetscDefined(HAVE_CUDA) || PetscDefined(HAVE_HIP)
1884:   mat->offloadmask = PETSC_OFFLOAD_CPU;
1885: #endif
1886:   PetscFunctionReturn(PETSC_SUCCESS);
1887: }

1889: /*@
1890:   MatDenseResetArray - Resets the matrix array to that it previously had before the call to `MatDensePlaceArray()`

1892:   Not Collective

1894:   Input Parameter:
1895: . mat - the matrix

1897:   Level: developer

1899:   Note:
1900:   You can only call this after a call to `MatDensePlaceArray()`

1902: .seealso: [](ch_matrices), `Mat`, `MATDENSE`, `MatDenseGetArray()`, `MatDensePlaceArray()`, `VecPlaceArray()`, `VecGetArray()`, `VecRestoreArray()`, `VecReplaceArray()`, `VecResetArray()`
1903: @*/
1904: PetscErrorCode MatDenseResetArray(Mat mat)
1905: {
1906:   PetscFunctionBegin;
1908:   PetscUseMethod(mat, "MatDenseResetArray_C", (Mat), (mat));
1909:   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
1910:   PetscFunctionReturn(PETSC_SUCCESS);
1911: }

1913: /*@
1914:   MatDenseReplaceArray - Allows one to replace the array in a dense matrix with an
1915:   array provided by the user. This is useful to avoid copying an array
1916:   into a matrix

1918:   Not Collective

1920:   Input Parameters:
1921: + mat   - the matrix
1922: - array - the array in column major order

1924:   Level: developer

1926:   Note:
1927:   Adding `const` to `array` was an oversight, see notes in `VecPlaceArray()`.

1929:   The memory passed in MUST be obtained with `PetscMalloc()` and CANNOT be
1930:   freed by the user. It will be freed when the matrix is destroyed.

1932: .seealso: [](ch_matrices), `Mat`, `MatDensePlaceArray()`, `MatDenseGetArray()`, `VecReplaceArray()`
1933: @*/
1934: PetscErrorCode MatDenseReplaceArray(Mat mat, const PetscScalar *array)
1935: {
1936:   PetscFunctionBegin;
1938:   PetscUseMethod(mat, "MatDenseReplaceArray_C", (Mat, const PetscScalar *), (mat, array));
1939:   PetscCall(PetscObjectStateIncrease((PetscObject)mat));
1940: #if PetscDefined(HAVE_CUDA) || PetscDefined(HAVE_HIP)
1941:   mat->offloadmask = PETSC_OFFLOAD_CPU;
1942: #endif
1943:   PetscFunctionReturn(PETSC_SUCCESS);
1944: }

1946: /*@
1947:   MatCreateDense - Creates a matrix in `MATDENSE` format.

1949:   Collective

1951:   Input Parameters:
1952: + comm - MPI communicator
1953: . m    - number of local rows (or `PETSC_DECIDE` to have calculated if `M` is given)
1954: . n    - number of local columns (or `PETSC_DECIDE` to have calculated if `N` is given)
1955: . M    - number of global rows (or `PETSC_DECIDE` to have calculated if `m` is given)
1956: . N    - number of global columns (or `PETSC_DECIDE` to have calculated if `n` is given)
1957: - data - optional location of matrix data.  Set data to `NULL` (`PETSC_NULL_SCALAR_ARRAY` for Fortran users) for PETSc
1958:    to control all matrix memory allocation.

1960:   Output Parameter:
1961: . A - the matrix

1963:   Level: intermediate

1965:   Notes:
1966:   The dense format is fully compatible with standard Fortran
1967:   storage by columns.

1969:   Although local portions of the matrix are stored in column-major
1970:   order, the matrix is partitioned across MPI ranks by row.

1972:   The data input variable is intended primarily for Fortran programmers
1973:   who wish to allocate their own matrix memory space.  Most users should
1974:   set `data` to `NULL` (`PETSC_NULL_SCALAR_ARRAY` for Fortran users).

1976:   The user MUST specify either the local or global matrix dimensions
1977:   (possibly both).

1979: .seealso: [](ch_matrices), `Mat`, `MATDENSE`, `MatCreate()`, `MatCreateSeqDense()`, `MatSetValues()`
1980: @*/
1981: PetscErrorCode MatCreateDense(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, PetscScalar data[], Mat *A)
1982: {
1983:   PetscFunctionBegin;
1984:   PetscCall(MatCreate(comm, A));
1985:   PetscCall(MatSetSizes(*A, m, n, M, N));
1986:   PetscCall(MatSetType(*A, MATDENSE));
1987:   PetscCall(MatSeqDenseSetPreallocation(*A, data));
1988:   PetscCall(MatMPIDenseSetPreallocation(*A, data));
1989:   PetscFunctionReturn(PETSC_SUCCESS);
1990: }

1992: static PetscErrorCode MatDuplicate_MPIDense(Mat A, MatDuplicateOption cpvalues, Mat *newmat)
1993: {
1994:   Mat           mat;
1995:   Mat_MPIDense *a, *oldmat = (Mat_MPIDense *)A->data;

1997:   PetscFunctionBegin;
1998:   *newmat = NULL;
1999:   PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &mat));
2000:   PetscCall(MatSetSizes(mat, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
2001:   PetscCall(MatSetType(mat, ((PetscObject)A)->type_name));
2002:   a = (Mat_MPIDense *)mat->data;

2004:   mat->factortype   = A->factortype;
2005:   mat->assembled    = PETSC_TRUE;
2006:   mat->preallocated = PETSC_TRUE;

2008:   mat->insertmode = NOT_SET_VALUES;
2009:   a->donotstash   = oldmat->donotstash;

2011:   PetscCall(PetscLayoutReference(A->rmap, &mat->rmap));
2012:   PetscCall(PetscLayoutReference(A->cmap, &mat->cmap));

2014:   PetscCall(MatDuplicate(oldmat->A, cpvalues, &a->A));

2016:   *newmat = mat;
2017:   PetscFunctionReturn(PETSC_SUCCESS);
2018: }

2020: static PetscErrorCode MatLoad_MPIDense(Mat newMat, PetscViewer viewer)
2021: {
2022:   PetscBool isbinary;
2023: #if PetscDefined(HAVE_HDF5)
2024:   PetscBool ishdf5;
2025: #endif

2027:   PetscFunctionBegin;
2030:   /* force binary viewer to load .info file if it has not yet done so */
2031:   PetscCall(PetscViewerSetUp(viewer));
2032:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
2033: #if PetscDefined(HAVE_HDF5)
2034:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
2035: #endif
2036:   if (isbinary) {
2037:     PetscCall(MatLoad_Dense_Binary(newMat, viewer));
2038: #if PetscDefined(HAVE_HDF5)
2039:   } else if (ishdf5) {
2040:     PetscCall(MatLoad_Dense_HDF5(newMat, viewer));
2041: #endif
2042:   } else SETERRQ(PetscObjectComm((PetscObject)newMat), PETSC_ERR_SUP, "Viewer type %s not yet supported for reading %s matrices", ((PetscObject)viewer)->type_name, ((PetscObject)newMat)->type_name);
2043:   PetscFunctionReturn(PETSC_SUCCESS);
2044: }

2046: static PetscErrorCode MatEqual_MPIDense(Mat A, Mat B, PetscBool *flag)
2047: {
2048:   Mat_MPIDense *matB = (Mat_MPIDense *)B->data, *matA = (Mat_MPIDense *)A->data;
2049:   Mat           a, b;

2051:   PetscFunctionBegin;
2052:   a = matA->A;
2053:   b = matB->A;
2054:   PetscCall(MatEqual(a, b, flag));
2055:   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, flag, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
2056:   PetscFunctionReturn(PETSC_SUCCESS);
2057: }

2059: static PetscErrorCode MatProductCtxDestroy_MatTransMatMult_MPIDense_MPIDense(PetscCtxRt data)
2060: {
2061:   MatProductCtx_TransMatMultDense *atb = *(MatProductCtx_TransMatMultDense **)data;

2063:   PetscFunctionBegin;
2064:   PetscCall(PetscFree2(atb->sendbuf, atb->recvcounts));
2065:   PetscCall(MatDestroy(&atb->atb));
2066:   PetscCall(PetscFree(atb));
2067:   PetscFunctionReturn(PETSC_SUCCESS);
2068: }

2070: static PetscErrorCode MatProductCtxDestroy_MatMatTransMult_MPIDense_MPIDense(PetscCtxRt data)
2071: {
2072:   MatProductCtx_MatTransMultDense *abt = *(MatProductCtx_MatTransMultDense **)data;

2074:   PetscFunctionBegin;
2075:   PetscCall(PetscFree2(abt->buf[0], abt->buf[1]));
2076:   PetscCall(PetscFree2(abt->recvcounts, abt->recvdispls));
2077:   PetscCall(PetscFree(abt));
2078:   PetscFunctionReturn(PETSC_SUCCESS);
2079: }

2081: static PetscErrorCode MatTransposeMatMultNumeric_MPIDense_MPIDense(Mat A, Mat B, Mat C)
2082: {
2083:   Mat_MPIDense                    *a = (Mat_MPIDense *)A->data, *b = (Mat_MPIDense *)B->data, *c = (Mat_MPIDense *)C->data;
2084:   MatProductCtx_TransMatMultDense *atb;
2085:   MPI_Comm                         comm;
2086:   PetscMPIInt                      size, *recvcounts;
2087:   PetscScalar                     *carray, *sendbuf;
2088:   const PetscScalar               *atbarray;
2089:   PetscInt                         i, cN = C->cmap->N, proc, k, j, lda;
2090:   const PetscInt                  *ranges;

2092:   PetscFunctionBegin;
2093:   MatCheckProduct(C, 3);
2094:   PetscCheck(C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty");
2095:   atb        = (MatProductCtx_TransMatMultDense *)C->product->data;
2096:   recvcounts = atb->recvcounts;
2097:   sendbuf    = atb->sendbuf;

2099:   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
2100:   PetscCallMPI(MPI_Comm_size(comm, &size));

2102:   /* compute atbarray = aseq^T * bseq */
2103:   PetscCall(MatTransposeMatMult(a->A, b->A, atb->atb ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, PETSC_DETERMINE, &atb->atb));

2105:   PetscCall(MatGetOwnershipRanges(C, &ranges));

2107:   if (ranges[1] == C->rmap->N) {
2108:     /* all of the values are being reduced to rank 0: optimize this case to use MPI_Reduce and GPU aware MPI if available */
2109:     PetscInt           atb_lda, c_lda;
2110:     Mat                atb_local = atb->atb;
2111:     Mat                atb_alloc = NULL;
2112:     Mat                c_local   = c->A;
2113:     Mat                c_alloc   = NULL;
2114:     PetscMemType       atb_memtype, c_memtype;
2115:     const PetscScalar *atb_array = NULL;
2116:     MPI_Datatype       vector_type;
2117:     PetscScalar       *c_array = NULL;
2118:     PetscMPIInt        rank;

2120:     PetscCallMPI(MPI_Comm_rank(comm, &rank));

2122:     PetscCall(MatDenseGetLDA(atb_local, &atb_lda));
2123:     if (atb_lda != C->rmap->N) {
2124:       // copy atb to a matrix that will have lda == the number of rows
2125:       PetscCall(MatDuplicate(atb_local, MAT_DO_NOT_COPY_VALUES, &atb_alloc));
2126:       PetscCall(MatCopy(atb_local, atb_alloc, DIFFERENT_NONZERO_PATTERN));
2127:       atb_local = atb_alloc;
2128:     }

2130:     if (rank == 0) {
2131:       PetscCall(MatDenseGetLDA(c_local, &c_lda));
2132:       if (c_lda != C->rmap->N) {
2133:         // copy c to a matrix that will have lda == the number of rows
2134:         PetscCall(MatDuplicate(c_local, MAT_DO_NOT_COPY_VALUES, &c_alloc));
2135:         c_local = c_alloc;
2136:       }
2137:       PetscCall(MatZeroEntries(c_local));
2138:     }
2139:     /* atb_local and c_local have nrows = lda = A->cmap->N and ncols =
2140:      * B->cmap->N: use the a->Mvctx to use the best reduction method */
2141:     if (!a->Mvctx) PetscCall(MatSetUpMultiply_MPIDense(A));
2142:     vector_type = MPIU_SCALAR;
2143:     if (B->cmap->N > 1) {
2144:       PetscMPIInt mpi_N;

2146:       PetscCall(PetscMPIIntCast(B->cmap->N, &mpi_N));
2147:       PetscCallMPI(MPI_Type_contiguous(mpi_N, MPIU_SCALAR, &vector_type));
2148:       PetscCallMPI(MPI_Type_commit(&vector_type));
2149:     }
2150:     PetscCall(MatDenseGetArrayReadAndMemType(atb_local, &atb_array, &atb_memtype));
2151:     PetscCall(MatDenseGetArrayWriteAndMemType(c_local, &c_array, &c_memtype));
2152:     PetscCall(PetscSFReduceWithMemTypeBegin(a->Mvctx, vector_type, atb_memtype, atb_array, c_memtype, c_array, MPIU_SUM));
2153:     PetscCall(PetscSFReduceEnd(a->Mvctx, vector_type, atb_array, c_array, MPIU_SUM));
2154:     PetscCall(MatDenseRestoreArrayWriteAndMemType(c_local, &c_array));
2155:     PetscCall(MatDenseRestoreArrayReadAndMemType(atb_local, &atb_array));
2156:     if (rank == 0 && c_local != c->A) PetscCall(MatCopy(c_local, c->A, DIFFERENT_NONZERO_PATTERN));
2157:     if (B->cmap->N > 1) PetscCallMPI(MPI_Type_free(&vector_type));
2158:     PetscCall(MatDestroy(&atb_alloc));
2159:     PetscCall(MatDestroy(&c_alloc));
2160:     PetscFunctionReturn(PETSC_SUCCESS);
2161:   }

2163:   /* arrange atbarray into sendbuf */
2164:   PetscCall(MatDenseGetArrayRead(atb->atb, &atbarray));
2165:   PetscCall(MatDenseGetLDA(atb->atb, &lda));
2166:   for (proc = 0, k = 0; proc < size; proc++) {
2167:     for (j = 0; j < cN; j++) {
2168:       for (i = ranges[proc]; i < ranges[proc + 1]; i++) sendbuf[k++] = atbarray[i + j * lda];
2169:     }
2170:   }
2171:   PetscCall(MatDenseRestoreArrayRead(atb->atb, &atbarray));

2173:   /* sum all atbarray to local values of C */
2174:   PetscCall(MatDenseGetLDA(c->A, &lda));
2175:   PetscCall(MatDenseGetArrayWrite(c->A, &carray));
2176:   if (lda > C->rmap->n && cN > 1 && C->rmap->n) {
2177:     PetscScalar *recvbuf;

2179:     /* the local product is no longer needed after packing sendbuf; reuse its storage for the contiguous reduction */
2180:     PetscCall(MatDenseGetArrayWrite(atb->atb, &recvbuf));
2181:     PetscCallMPI(MPI_Reduce_scatter(sendbuf, recvbuf, recvcounts, MPIU_SCALAR, MPIU_SUM, comm));
2182:     for (j = 0; j < cN; j++) PetscCall(PetscArraycpy(carray + (size_t)j * lda, recvbuf + (size_t)j * C->rmap->n, C->rmap->n));
2183:     PetscCall(MatDenseRestoreArrayWrite(atb->atb, &recvbuf));
2184:   } else PetscCallMPI(MPI_Reduce_scatter(sendbuf, carray, recvcounts, MPIU_SCALAR, MPIU_SUM, comm));
2185:   PetscCall(MatDenseRestoreArrayWrite(c->A, &carray));
2186:   PetscFunctionReturn(PETSC_SUCCESS);
2187: }

2189: static PetscErrorCode MatTransposeMatMultSymbolic_MPIDense_MPIDense(Mat A, Mat B, PetscReal fill, Mat C)
2190: {
2191:   MPI_Comm                         comm;
2192:   PetscMPIInt                      size;
2193:   PetscInt                         cm = A->cmap->n, cM, cN = B->cmap->N;
2194:   MatProductCtx_TransMatMultDense *atb;
2195:   PetscBool                        cisdense = PETSC_FALSE;
2196:   const PetscInt                  *ranges;

2198:   PetscFunctionBegin;
2199:   MatCheckProduct(C, 4);
2200:   PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
2201:   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
2202:   PetscCheck(A->rmap->rstart == B->rmap->rstart && A->rmap->rend == B->rmap->rend, comm, PETSC_ERR_ARG_SIZ, "Matrix local dimensions are incompatible, A (%" PetscInt_FMT ", %" PetscInt_FMT ") != B (%" PetscInt_FMT ",%" PetscInt_FMT ")", A->rmap->rstart,
2203:              A->rmap->rend, B->rmap->rstart, B->rmap->rend);

2205:   /* create matrix product C */
2206:   PetscCall(MatSetSizes(C, cm, B->cmap->n, A->cmap->N, B->cmap->N));
2207: #if PetscDefined(HAVE_CUDA)
2208:   PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATMPIDENSE, MATMPIDENSECUDA, ""));
2209: #endif
2210: #if PetscDefined(HAVE_HIP)
2211:   PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATMPIDENSE, MATMPIDENSEHIP, ""));
2212: #endif
2213:   if (!cisdense) {
2214:     PetscCall(MatSetType(C, ((PetscObject)A)->type_name));
2215:     PetscCall(MatSetVecType(C, A->defaultvectype));
2216:   }
2217:   PetscCall(MatSetUp(C));

2219:   /* create data structure for reuse C */
2220:   PetscCallMPI(MPI_Comm_size(comm, &size));
2221:   PetscCall(PetscNew(&atb));
2222:   cM = C->rmap->N;
2223:   PetscCall(PetscMalloc2(cM * cN, &atb->sendbuf, size, &atb->recvcounts));
2224:   PetscCall(MatGetOwnershipRanges(C, &ranges));
2225:   for (PetscMPIInt i = 0; i < size; i++) PetscCall(PetscMPIIntCast((ranges[i + 1] - ranges[i]) * cN, &atb->recvcounts[i]));
2226:   C->product->data    = atb;
2227:   C->product->destroy = MatProductCtxDestroy_MatTransMatMult_MPIDense_MPIDense;
2228:   PetscFunctionReturn(PETSC_SUCCESS);
2229: }

2231: static PetscErrorCode MatMatTransposeMultSymbolic_MPIDense_MPIDense(Mat A, Mat B, PetscReal fill, Mat C)
2232: {
2233:   MPI_Comm                         comm;
2234:   PetscMPIInt                      i, size;
2235:   PetscInt                         maxRows, bufsiz;
2236:   PetscMPIInt                      tag;
2237:   PetscInt                         alg;
2238:   MatProductCtx_MatTransMultDense *abt;
2239:   Mat_Product                     *product = C->product;
2240:   PetscBool                        flg;

2242:   PetscFunctionBegin;
2243:   MatCheckProduct(C, 4);
2244:   PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
2245:   /* check local size of A and B */
2246:   PetscCheck(A->cmap->n == B->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Matrix local column dimensions are incompatible, A (%" PetscInt_FMT ") != B (%" PetscInt_FMT ")", A->cmap->n, B->cmap->n);

2248:   PetscCall(PetscStrcmp(product->alg, "allgatherv", &flg));
2249:   alg = flg ? 0 : 1;

2251:   /* setup matrix product C */
2252:   PetscCall(MatSetSizes(C, A->rmap->n, B->rmap->n, A->rmap->N, B->rmap->N));
2253:   PetscCall(MatSetType(C, MATMPIDENSE));
2254:   /* keep the VecType of A, e.g. VECKOKKOS from MatCreateDenseFromVecType(), but only if A is a MATMPIDENSE like C, since the VecType of a MATMPIDENSECUDA or MATMPIDENSEHIP A, e.g. VECCUDA, is not valid for C */
2255:   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPIDENSE, &flg));
2256:   if (flg) PetscCall(MatSetVecType(C, A->defaultvectype));
2257:   PetscCall(MatSetUp(C));
2258:   PetscCall(PetscObjectGetNewTag((PetscObject)C, &tag));

2260:   /* create data structure for reuse C */
2261:   PetscCall(PetscObjectGetComm((PetscObject)C, &comm));
2262:   PetscCallMPI(MPI_Comm_size(comm, &size));
2263:   PetscCall(PetscNew(&abt));
2264:   abt->tag = tag;
2265:   abt->alg = alg;
2266:   switch (alg) {
2267:   case 1: /* alg: "cyclic" */
2268:     for (maxRows = 0, i = 0; i < size; i++) maxRows = PetscMax(maxRows, B->rmap->range[i + 1] - B->rmap->range[i]);
2269:     bufsiz = A->cmap->N * maxRows;
2270:     PetscCall(PetscMalloc2(bufsiz, &abt->buf[0], bufsiz, &abt->buf[1]));
2271:     break;
2272:   default: /* alg: "allgatherv" */
2273:     PetscCall(PetscMalloc2(B->rmap->n * B->cmap->N, &abt->buf[0], B->rmap->N * B->cmap->N, &abt->buf[1]));
2274:     PetscCall(PetscMalloc2(size, &abt->recvcounts, size + 1, &abt->recvdispls));
2275:     for (i = 0; i <= size; i++) PetscCall(PetscMPIIntCast(B->rmap->range[i] * A->cmap->N, &abt->recvdispls[i]));
2276:     for (i = 0; i < size; i++) PetscCall(PetscMPIIntCast(abt->recvdispls[i + 1] - abt->recvdispls[i], &abt->recvcounts[i]));
2277:     break;
2278:   }

2280:   C->product->data                = abt;
2281:   C->product->destroy             = MatProductCtxDestroy_MatMatTransMult_MPIDense_MPIDense;
2282:   C->ops->mattransposemultnumeric = MatMatTransposeMultNumeric_MPIDense_MPIDense;
2283:   PetscFunctionReturn(PETSC_SUCCESS);
2284: }

2286: static PetscErrorCode MatMatTransposeMultNumeric_MPIDense_MPIDense_Cyclic(Mat A, Mat B, Mat C)
2287: {
2288:   Mat_MPIDense                    *a = (Mat_MPIDense *)A->data, *b = (Mat_MPIDense *)B->data, *c = (Mat_MPIDense *)C->data;
2289:   MatProductCtx_MatTransMultDense *abt;
2290:   MPI_Comm                         comm;
2291:   PetscMPIInt                      rank, size, sendto, recvfrom, recvisfrom;
2292:   PetscScalar                     *sendbuf, *recvbuf = NULL, *cv;
2293:   PetscInt                         i, cK             = A->cmap->N, sendsiz, recvsiz, k, j, bn;
2294:   PetscScalar                      _DOne = 1.0, _DZero = 0.0;
2295:   const PetscScalar               *av, *bv;
2296:   PetscBLASInt                     cm, cn, ck, alda, blda = 0, clda;
2297:   MPI_Request                      reqs[2];
2298:   const PetscInt                  *ranges;

2300:   PetscFunctionBegin;
2301:   MatCheckProduct(C, 3);
2302:   PetscCheck(C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty");
2303:   abt = (MatProductCtx_MatTransMultDense *)C->product->data;
2304:   PetscCall(PetscObjectGetComm((PetscObject)C, &comm));
2305:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
2306:   PetscCallMPI(MPI_Comm_size(comm, &size));
2307:   PetscCall(MatDenseGetArrayRead(a->A, &av));
2308:   PetscCall(MatDenseGetArrayRead(b->A, &bv));
2309:   PetscCall(MatDenseGetArrayWrite(c->A, &cv));
2310:   PetscCall(MatDenseGetLDA(a->A, &i));
2311:   PetscCall(PetscBLASIntCast(i, &alda));
2312:   PetscCall(MatDenseGetLDA(b->A, &i));
2313:   PetscCall(PetscBLASIntCast(i, &blda));
2314:   PetscCall(MatDenseGetLDA(c->A, &i));
2315:   PetscCall(PetscBLASIntCast(i, &clda));
2316:   PetscCall(MatGetOwnershipRanges(B, &ranges));
2317:   bn = B->rmap->n;
2318:   if (blda == bn) {
2319:     sendbuf = (PetscScalar *)bv;
2320:   } else {
2321:     sendbuf = abt->buf[0];
2322:     for (k = 0, i = 0; i < cK; i++) {
2323:       for (j = 0; j < bn; j++, k++) sendbuf[k] = bv[i * blda + j];
2324:     }
2325:   }
2326:   if (size > 1) {
2327:     sendto   = (rank + size - 1) % size;
2328:     recvfrom = (rank + size + 1) % size;
2329:   } else {
2330:     sendto = recvfrom = 0;
2331:   }
2332:   PetscCall(PetscBLASIntCast(cK, &ck));
2333:   PetscCall(PetscBLASIntCast(c->A->rmap->n, &cm));
2334:   recvisfrom = rank;
2335:   for (i = 0; i < size; i++) {
2336:     /* we have finished receiving in sending, bufs can be read/modified */
2337:     PetscMPIInt nextrecvisfrom = (recvisfrom + 1) % size; /* which process the next recvbuf will originate on */
2338:     PetscInt    nextbn         = ranges[nextrecvisfrom + 1] - ranges[nextrecvisfrom];

2340:     if (nextrecvisfrom != rank) {
2341:       /* start the cyclic sends from sendbuf, to recvbuf (which will switch to sendbuf) */
2342:       sendsiz = cK * bn;
2343:       recvsiz = cK * nextbn;
2344:       recvbuf = (i & 1) ? abt->buf[0] : abt->buf[1];
2345:       PetscCallMPI(MPIU_Isend(sendbuf, sendsiz, MPIU_SCALAR, sendto, abt->tag, comm, &reqs[0]));
2346:       PetscCallMPI(MPIU_Irecv(recvbuf, recvsiz, MPIU_SCALAR, recvfrom, abt->tag, comm, &reqs[1]));
2347:     }

2349:     /* local aseq * sendbuf^T */
2350:     PetscCall(PetscBLASIntCast(ranges[recvisfrom + 1] - ranges[recvisfrom], &cn));
2351:     if (cm && cn && ck) PetscCallBLAS("BLASgemm", BLASgemm_("N", "T", &cm, &cn, &ck, &_DOne, av, &alda, sendbuf, &cn, &_DZero, cv + clda * ranges[recvisfrom], &clda));

2353:     if (nextrecvisfrom != rank) {
2354:       /* wait for the sends and receives to complete, swap sendbuf and recvbuf */
2355:       PetscCallMPI(MPI_Waitall(2, reqs, MPI_STATUSES_IGNORE));
2356:     }
2357:     bn         = nextbn;
2358:     recvisfrom = nextrecvisfrom;
2359:     sendbuf    = recvbuf;
2360:   }
2361:   PetscCall(MatDenseRestoreArrayRead(a->A, &av));
2362:   PetscCall(MatDenseRestoreArrayRead(b->A, &bv));
2363:   PetscCall(MatDenseRestoreArrayWrite(c->A, &cv));
2364:   PetscFunctionReturn(PETSC_SUCCESS);
2365: }

2367: static PetscErrorCode MatMatTransposeMultNumeric_MPIDense_MPIDense_Allgatherv(Mat A, Mat B, Mat C)
2368: {
2369:   Mat_MPIDense                    *a = (Mat_MPIDense *)A->data, *b = (Mat_MPIDense *)B->data, *c = (Mat_MPIDense *)C->data;
2370:   MatProductCtx_MatTransMultDense *abt;
2371:   MPI_Comm                         comm;
2372:   PetscMPIInt                      size, ibn;
2373:   PetscScalar                     *cv, *sendbuf, *recvbuf;
2374:   const PetscScalar               *av, *bv;
2375:   PetscInt                         blda, i, cK = A->cmap->N, k, j, bn;
2376:   PetscScalar                      _DOne = 1.0, _DZero = 0.0;
2377:   PetscBLASInt                     cm, cn, ck, alda, clda;

2379:   PetscFunctionBegin;
2380:   MatCheckProduct(C, 3);
2381:   PetscCheck(C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty");
2382:   abt = (MatProductCtx_MatTransMultDense *)C->product->data;
2383:   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
2384:   PetscCallMPI(MPI_Comm_size(comm, &size));
2385:   PetscCall(MatDenseGetArrayRead(a->A, &av));
2386:   PetscCall(MatDenseGetArrayRead(b->A, &bv));
2387:   PetscCall(MatDenseGetArrayWrite(c->A, &cv));
2388:   PetscCall(MatDenseGetLDA(a->A, &i));
2389:   PetscCall(PetscBLASIntCast(i, &alda));
2390:   PetscCall(MatDenseGetLDA(b->A, &blda));
2391:   PetscCall(MatDenseGetLDA(c->A, &i));
2392:   PetscCall(PetscBLASIntCast(i, &clda));
2393:   /* copy transpose of B into buf[0] */
2394:   bn      = B->rmap->n;
2395:   sendbuf = abt->buf[0];
2396:   recvbuf = abt->buf[1];
2397:   for (k = 0, j = 0; j < bn; j++) {
2398:     for (i = 0; i < cK; i++, k++) sendbuf[k] = bv[i * blda + j];
2399:   }
2400:   PetscCall(MatDenseRestoreArrayRead(b->A, &bv));
2401:   PetscCall(PetscMPIIntCast(bn * cK, &ibn));
2402:   PetscCallMPI(MPI_Allgatherv(sendbuf, ibn, MPIU_SCALAR, recvbuf, abt->recvcounts, abt->recvdispls, MPIU_SCALAR, comm));
2403:   PetscCall(PetscBLASIntCast(cK, &ck));
2404:   PetscCall(PetscBLASIntCast(c->A->rmap->n, &cm));
2405:   PetscCall(PetscBLASIntCast(c->A->cmap->n, &cn));
2406:   if (cm && cn && ck) PetscCallBLAS("BLASgemm", BLASgemm_("N", "N", &cm, &cn, &ck, &_DOne, av, &alda, recvbuf, &ck, &_DZero, cv, &clda));
2407:   PetscCall(MatDenseRestoreArrayRead(a->A, &av));
2408:   PetscCall(MatDenseRestoreArrayRead(b->A, &bv));
2409:   PetscCall(MatDenseRestoreArrayWrite(c->A, &cv));
2410:   PetscFunctionReturn(PETSC_SUCCESS);
2411: }

2413: static PetscErrorCode MatMatTransposeMultNumeric_MPIDense_MPIDense(Mat A, Mat B, Mat C)
2414: {
2415:   MatProductCtx_MatTransMultDense *abt;

2417:   PetscFunctionBegin;
2418:   MatCheckProduct(C, 3);
2419:   PetscCheck(C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty");
2420:   abt = (MatProductCtx_MatTransMultDense *)C->product->data;
2421:   switch (abt->alg) {
2422:   case 1:
2423:     PetscCall(MatMatTransposeMultNumeric_MPIDense_MPIDense_Cyclic(A, B, C));
2424:     break;
2425:   default:
2426:     PetscCall(MatMatTransposeMultNumeric_MPIDense_MPIDense_Allgatherv(A, B, C));
2427:     break;
2428:   }
2429:   PetscFunctionReturn(PETSC_SUCCESS);
2430: }

2432: static PetscErrorCode MatProductCtxDestroy_MatMatMult_MPIDense_MPIDense(PetscCtxRt data)
2433: {
2434:   MatProductCtx_MatMultDense *ab = *(MatProductCtx_MatMultDense **)data;

2436:   PetscFunctionBegin;
2437:   PetscCall(MatDestroy(&ab->Ce));
2438:   PetscCall(MatDestroy(&ab->Ae));
2439:   PetscCall(MatDestroy(&ab->Be));
2440:   PetscCall(PetscFree(ab));
2441:   PetscFunctionReturn(PETSC_SUCCESS);
2442: }

2444: static PetscErrorCode MatMatMultNumeric_MPIDense_MPIDense(Mat A, Mat B, Mat C)
2445: {
2446:   MatProductCtx_MatMultDense *ab;
2447:   Mat_MPIDense               *mdn = (Mat_MPIDense *)A->data;
2448:   Mat_MPIDense               *b   = (Mat_MPIDense *)B->data;

2450:   PetscFunctionBegin;
2451:   MatCheckProduct(C, 3);
2452:   PetscCheck(C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Missing product data");
2453:   ab = (MatProductCtx_MatMultDense *)C->product->data;
2454:   if (ab->Ae && ab->Ce) {
2455: #if PetscDefined(HAVE_ELEMENTAL)
2456:     PetscCall(MatConvert_MPIDense_Elemental(A, MATELEMENTAL, MAT_REUSE_MATRIX, &ab->Ae));
2457:     PetscCall(MatConvert_MPIDense_Elemental(B, MATELEMENTAL, MAT_REUSE_MATRIX, &ab->Be));
2458:     PetscCall(MatMatMultNumeric_Elemental(ab->Ae, ab->Be, ab->Ce));
2459:     PetscCall(MatConvert(ab->Ce, MATMPIDENSE, MAT_REUSE_MATRIX, &C));
2460: #else
2461:     SETERRQ(PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "PETSC_HAVE_ELEMENTAL not defined");
2462: #endif
2463:   } else {
2464:     MPI_Comm        comm;
2465:     Mat             clocal;
2466:     const PetscInt *ranges;
2467:     PetscMPIInt     size;

2469:     if (!mdn->Mvctx) PetscCall(MatSetUpMultiply_MPIDense(A)); /* cannot be done during the symbolic phase because of possible calls to MatProductReplaceMats() */
2470:     comm = PetscObjectComm((PetscObject)B);
2471:     PetscCallMPI(MPI_Comm_size(comm, &size));
2472:     PetscCall(PetscLayoutGetRanges(B->rmap, &ranges));
2473:     if (ranges[1] == ranges[size]) {
2474:       // optimize for the case where the B matrix is broadcast from rank 0
2475:       PetscInt           b_lda, be_lda;
2476:       Mat                b_local  = b->A;
2477:       Mat                b_alloc  = NULL;
2478:       Mat                be_local = ab->Be;
2479:       Mat                be_alloc = NULL;
2480:       PetscMemType       b_memtype, be_memtype;
2481:       const PetscScalar *b_array = NULL;
2482:       MPI_Datatype       vector_type;
2483:       PetscScalar       *be_array = NULL;
2484:       PetscMPIInt        rank;

2486:       PetscCallMPI(MPI_Comm_rank(comm, &rank));
2487:       PetscCall(MatDenseGetLDA(be_local, &be_lda));
2488:       if (be_lda != B->rmap->N) {
2489:         PetscCall(MatDuplicate(be_local, MAT_DO_NOT_COPY_VALUES, &be_alloc));
2490:         be_local = be_alloc;
2491:       }

2493:       if (rank == 0) {
2494:         PetscCall(MatDenseGetLDA(b_local, &b_lda));
2495:         if (b_lda != B->rmap->N) {
2496:           PetscCall(MatDuplicate(b_local, MAT_DO_NOT_COPY_VALUES, &b_alloc));
2497:           PetscCall(MatCopy(b_local, b_alloc, DIFFERENT_NONZERO_PATTERN));
2498:           b_local = b_alloc;
2499:         }
2500:       }
2501:       vector_type = MPIU_SCALAR;
2502:       if (B->cmap->N > 1) {
2503:         PetscMPIInt mpi_N;

2505:         PetscCall(PetscMPIIntCast(B->cmap->N, &mpi_N));
2506:         PetscCallMPI(MPI_Type_contiguous(mpi_N, MPIU_SCALAR, &vector_type));
2507:         PetscCallMPI(MPI_Type_commit(&vector_type));
2508:       }
2509:       PetscCall(MatDenseGetArrayReadAndMemType(b_local, &b_array, &b_memtype));
2510:       PetscCall(MatDenseGetArrayWriteAndMemType(be_local, &be_array, &be_memtype));
2511:       PetscCall(PetscSFBcastWithMemTypeBegin(mdn->Mvctx, vector_type, b_memtype, b_array, be_memtype, be_array, MPI_REPLACE));
2512:       PetscCall(PetscSFBcastEnd(mdn->Mvctx, vector_type, b_array, be_array, MPI_REPLACE));
2513:       PetscCall(MatDenseRestoreArrayWriteAndMemType(be_local, &be_array));
2514:       PetscCall(MatDenseRestoreArrayReadAndMemType(b_local, &b_array));
2515:       if (be_local != ab->Be) PetscCall(MatCopy(be_local, ab->Be, DIFFERENT_NONZERO_PATTERN));
2516:       if (B->cmap->N > 1) PetscCallMPI(MPI_Type_free(&vector_type));
2517:       PetscCall(MatDestroy(&be_alloc));
2518:       PetscCall(MatDestroy(&b_alloc));
2519:     } else PetscCall(MatDenseScatter_Private(mdn->Mvctx, B, ab->Be, INSERT_VALUES, SCATTER_FORWARD));
2520:     PetscCall(MatDenseGetLocalMatrix(C, &clocal));
2521:     PetscCall((*clocal->ops->matmultnumeric)(mdn->A, ab->Be, clocal));
2522:   }
2523:   PetscFunctionReturn(PETSC_SUCCESS);
2524: }

2526: static PetscErrorCode MatMatMultSymbolic_MPIDense_MPIDense(Mat A, Mat B, PetscReal fill, Mat C)
2527: {
2528:   Mat_Product                *product = C->product;
2529:   PetscInt                    alg;
2530:   MatProductCtx_MatMultDense *ab;
2531:   PetscBool                   flg;
2532:   VecType                     vtype;

2534:   PetscFunctionBegin;
2535:   MatCheckProduct(C, 4);
2536:   PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty");
2537:   /* check local size of A and B */
2538:   PetscCheck(A->cmap->rstart == B->rmap->rstart && A->cmap->rend == B->rmap->rend, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Matrix local dimensions are incompatible, A (%" PetscInt_FMT ", %" PetscInt_FMT ") != B (%" PetscInt_FMT ", %" PetscInt_FMT ")",
2539:              A->rmap->rstart, A->rmap->rend, B->rmap->rstart, B->rmap->rend);

2541:   PetscCall(PetscStrcmp(product->alg, "petsc", &flg));
2542:   alg = flg ? 0 : 1;

2544:   /* setup C */
2545:   PetscCall(MatSetSizes(C, A->rmap->n, B->cmap->n, A->rmap->N, B->cmap->N));
2546:   PetscCall(PetscObjectBaseTypeCompare((PetscObject)C, MATMPIDENSE, &flg));
2547:   if (!flg) {
2548:     PetscCall(PetscObjectTypeCompare((PetscObject)B, ((PetscObject)A)->type_name, &flg));
2549:     PetscCall(MatSetType(C, flg ? ((PetscObject)A)->type_name : MATMPIDENSE));
2550:   }
2551:   /* preserve a supplied dense result and its storage; copy the VecType only from a matching MatType */
2552:   PetscCall(PetscObjectTypeCompare((PetscObject)A, ((PetscObject)C)->type_name, &flg));
2553:   if (flg) PetscCall(MatSetVecType(C, A->defaultvectype));
2554:   PetscCall(MatSetUp(C));

2556:   /* create data structure for reuse Cdense */
2557:   PetscCall(PetscNew(&ab));

2559:   switch (alg) {
2560:   case 1: /* alg: "elemental" */
2561: #if PetscDefined(HAVE_ELEMENTAL)
2562:     /* create elemental matrices Ae and Be */
2563:     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &ab->Ae));
2564:     PetscCall(MatSetSizes(ab->Ae, PETSC_DECIDE, PETSC_DECIDE, A->rmap->N, A->cmap->N));
2565:     PetscCall(MatSetType(ab->Ae, MATELEMENTAL));
2566:     PetscCall(MatSetUp(ab->Ae));
2567:     PetscCall(MatSetOption(ab->Ae, MAT_ROW_ORIENTED, PETSC_FALSE));

2569:     PetscCall(MatCreate(PetscObjectComm((PetscObject)B), &ab->Be));
2570:     PetscCall(MatSetSizes(ab->Be, PETSC_DECIDE, PETSC_DECIDE, B->rmap->N, B->cmap->N));
2571:     PetscCall(MatSetType(ab->Be, MATELEMENTAL));
2572:     PetscCall(MatSetUp(ab->Be));
2573:     PetscCall(MatSetOption(ab->Be, MAT_ROW_ORIENTED, PETSC_FALSE));

2575:     /* compute symbolic Ce = Ae*Be */
2576:     PetscCall(MatCreate(PetscObjectComm((PetscObject)C), &ab->Ce));
2577:     PetscCall(MatMatMultSymbolic_Elemental(ab->Ae, ab->Be, fill, ab->Ce));
2578: #else
2579:     SETERRQ(PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "PETSC_HAVE_ELEMENTAL not defined");
2580: #endif
2581:     break;
2582:   default: /* alg: "petsc" */
2583:     ab->Ae = NULL;
2584:     PetscCall(MatGetVecType(C, &vtype));
2585:     PetscCall(MatCreateDenseFromVecType(PETSC_COMM_SELF, vtype, A->cmap->N, B->cmap->N, A->cmap->N, B->cmap->N, PETSC_DECIDE, NULL, &ab->Be));
2586:     ab->Ce = NULL;
2587:     break;
2588:   }

2590:   C->product->data       = ab;
2591:   C->product->destroy    = MatProductCtxDestroy_MatMatMult_MPIDense_MPIDense;
2592:   C->ops->matmultnumeric = MatMatMultNumeric_MPIDense_MPIDense;
2593:   PetscFunctionReturn(PETSC_SUCCESS);
2594: }

2596: static PetscErrorCode MatProductSetFromOptions_MPIDense_AB(Mat C)
2597: {
2598:   Mat_Product *product     = C->product;
2599:   const char  *algTypes[2] = {"petsc", "elemental"};
2600:   PetscInt     alg, nalg = PetscDefined(HAVE_ELEMENTAL) ? 2 : 1;
2601:   PetscBool    flg = PETSC_FALSE;

2603:   PetscFunctionBegin;
2604:   /* Set default algorithm */
2605:   alg = 0; /* default is PETSc */
2606:   PetscCall(PetscStrcmp(product->alg, "default", &flg));
2607:   if (flg) PetscCall(MatProductSetAlgorithm(C, algTypes[alg]));

2609:   /* Get runtime option */
2610:   PetscOptionsBegin(PetscObjectComm((PetscObject)C), ((PetscObject)C)->prefix, "MatProduct_AB", "Mat");
2611:   PetscCall(PetscOptionsEList("-mat_product_algorithm", "Algorithmic approach", "MatProduct_AB", algTypes, nalg, algTypes[alg], &alg, &flg));
2612:   PetscOptionsEnd();
2613:   if (flg) PetscCall(MatProductSetAlgorithm(C, algTypes[alg]));

2615:   C->ops->matmultsymbolic = MatMatMultSymbolic_MPIDense_MPIDense;
2616:   C->ops->productsymbolic = MatProductSymbolic_AB;
2617:   PetscFunctionReturn(PETSC_SUCCESS);
2618: }

2620: static PetscErrorCode MatProductSetFromOptions_MPIDense_AtB(Mat C)
2621: {
2622:   Mat_Product *product = C->product;
2623:   Mat          A = product->A, B = product->B;

2625:   PetscFunctionBegin;
2626:   PetscCheck(A->rmap->rstart == B->rmap->rstart && A->rmap->rend == B->rmap->rend, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Matrix local dimensions are incompatible, (%" PetscInt_FMT ", %" PetscInt_FMT ") != (%" PetscInt_FMT ",%" PetscInt_FMT ")",
2627:              A->rmap->rstart, A->rmap->rend, B->rmap->rstart, B->rmap->rend);
2628:   C->ops->transposematmultsymbolic = MatTransposeMatMultSymbolic_MPIDense_MPIDense;
2629:   C->ops->productsymbolic          = MatProductSymbolic_AtB;
2630:   PetscFunctionReturn(PETSC_SUCCESS);
2631: }

2633: static PetscErrorCode MatProductSetFromOptions_MPIDense_ABt(Mat C)
2634: {
2635:   Mat_Product *product     = C->product;
2636:   const char  *algTypes[2] = {"allgatherv", "cyclic"};
2637:   PetscInt     alg, nalg = 2;
2638:   PetscBool    flg = PETSC_FALSE;

2640:   PetscFunctionBegin;
2641:   /* Set default algorithm */
2642:   alg = 0; /* default is allgatherv */
2643:   PetscCall(PetscStrcmp(product->alg, "default", &flg));
2644:   if (flg) PetscCall(MatProductSetAlgorithm(C, algTypes[alg]));

2646:   /* Get runtime option */
2647:   if (product->api_user) {
2648:     PetscOptionsBegin(PetscObjectComm((PetscObject)C), ((PetscObject)C)->prefix, "MatMatTransposeMult", "Mat");
2649:     PetscCall(PetscOptionsEList("-matmattransmult_mpidense_mpidense_via", "Algorithmic approach", "MatMatTransposeMult", algTypes, nalg, algTypes[alg], &alg, &flg));
2650:     PetscOptionsEnd();
2651:   } else {
2652:     PetscOptionsBegin(PetscObjectComm((PetscObject)C), ((PetscObject)C)->prefix, "MatProduct_ABt", "Mat");
2653:     PetscCall(PetscOptionsEList("-mat_product_algorithm", "Algorithmic approach", "MatProduct_ABt", algTypes, nalg, algTypes[alg], &alg, &flg));
2654:     PetscOptionsEnd();
2655:   }
2656:   if (flg) PetscCall(MatProductSetAlgorithm(C, algTypes[alg]));

2658:   C->ops->mattransposemultsymbolic = MatMatTransposeMultSymbolic_MPIDense_MPIDense;
2659:   C->ops->productsymbolic          = MatProductSymbolic_ABt;
2660:   PetscFunctionReturn(PETSC_SUCCESS);
2661: }

2663: static PetscErrorCode MatProductSetFromOptions_MPIDense(Mat C)
2664: {
2665:   Mat_Product *product = C->product;

2667:   PetscFunctionBegin;
2668:   switch (product->type) {
2669:   case MATPRODUCT_AB:
2670:     PetscCall(MatProductSetFromOptions_MPIDense_AB(C));
2671:     break;
2672:   case MATPRODUCT_AtB:
2673:     PetscCall(MatProductSetFromOptions_MPIDense_AtB(C));
2674:     break;
2675:   case MATPRODUCT_ABt:
2676:     PetscCall(MatProductSetFromOptions_MPIDense_ABt(C));
2677:     break;
2678:   default:
2679:     break;
2680:   }
2681:   PetscFunctionReturn(PETSC_SUCCESS);
2682: }

2684: typedef struct {
2685:   PetscSF  sf;
2686:   PetscInt N, rld, lld, nr, nl;
2687: } MatDenseScatterCtx;

2689: static PetscErrorCode MatDenseScatterCtxDestroy_Private(PetscCtxRt ptr)
2690: {
2691:   MatDenseScatterCtx **ctx = (MatDenseScatterCtx **)ptr;

2693:   PetscFunctionBegin;
2694:   PetscCall(PetscSFDestroy(&(*ctx)->sf));
2695:   PetscCall(PetscFree(*ctx));
2696:   PetscFunctionReturn(PETSC_SUCCESS);
2697: }

2699: // The communication of MatDenseScatter_Private(), for a caller that already has a PetscSF for the layouts of X and Y
2700: PetscErrorCode MatDenseScatterWithSF_Private(PetscSF vsf, Mat X, Mat Y, MPI_Op op, ScatterMode smode, PetscBool writeonly)
2701: {
2702:   const PetscScalar *in;
2703:   PetscScalar       *out;
2704:   PetscMemType       mtype[2];

2706:   PetscFunctionBegin;
2707:   PetscCall(MatDenseGetArrayReadAndMemType(X, &in, &mtype[0]));
2708:   if (writeonly == PETSC_TRUE) PetscCall(MatDenseGetArrayWriteAndMemType(Y, &out, &mtype[1]));
2709:   else PetscCall(MatDenseGetArrayAndMemType(Y, &out, &mtype[1]));
2710:   if (smode == SCATTER_FORWARD) {
2711:     PetscCall(PetscSFBcastWithMemTypeBegin(vsf, vsf->vscat.unit, mtype[0], in, mtype[1], out, op));
2712:     PetscCall(PetscSFBcastEnd(vsf, vsf->vscat.unit, in, out, op));
2713:   } else {
2714:     PetscCall(PetscSFReduceWithMemTypeBegin(vsf, vsf->vscat.unit, mtype[0], in, mtype[1], out, op));
2715:     PetscCall(PetscSFReduceEnd(vsf, vsf->vscat.unit, in, out, op));
2716:   }
2717:   if (writeonly == PETSC_TRUE) PetscCall(MatDenseRestoreArrayWriteAndMemType(Y, &out));
2718:   else PetscCall(MatDenseRestoreArrayAndMemType(Y, &out));
2719:   PetscCall(MatDenseRestoreArrayReadAndMemType(X, &in));
2720:   PetscFunctionReturn(PETSC_SUCCESS);
2721: }

2723: /* MatDenseScatter_Private - Scatters the columns of the dense matrix X into the dense matrix Y

2725:    Collective

2727:    Input Parameters:
2728: +  sf    - the PetscSF for one column
2729: .  X     - the matrix to read
2730: .  Y     - the matrix to update
2731: .  mode  - INSERT_VALUES, ADD_VALUES, MAX_VALUES, or MIN_VALUES
2732: -  smode - SCATTER_FORWARD for a broadcast from X to Y, or SCATTER_REVERSE for a reduction from X to Y

2734:    Level: developer

2736:    Note:
2737:    With more than one column, a strided PetscSF is cached on sf. It is rebuilt if the number of columns changes.
2738:    Any other change of layout, such as another leading dimension, is an error unless the cache is first cleared
2739:    on all processes with PetscObjectCompose((PetscObject)sf, "_MatDenseScatter_StridedSF", NULL).

2741: .seealso: `MatDenseScatterWithSF_Private()`, `PetscSFCreateStridedSF()`
2742: */
2743: PetscErrorCode MatDenseScatter_Private(PetscSF sf, Mat X, Mat Y, InsertMode mode, ScatterMode smode)
2744: {
2745:   PetscSF   vsf;
2746:   PetscInt  N, ny, rld, lld;
2747:   MPI_Op    op        = MPI_OP_NULL;
2748:   PetscBool writeonly = PETSC_FALSE;

2750:   PetscFunctionBegin;
2754:   if (mode == INSERT_VALUES) op = MPI_REPLACE;
2755:   else if (mode == ADD_VALUES) op = MPIU_SUM;
2756:   else if (mode == MAX_VALUES) op = MPIU_MAX;
2757:   else if (mode == MIN_VALUES) op = MPIU_MIN;
2758:   PetscCheck(op != MPI_OP_NULL, PetscObjectComm((PetscObject)sf), PETSC_ERR_SUP, "Unsupported InsertMode %d in MatDenseScatter_Private()", mode);
2759:   PetscCheck(smode == SCATTER_FORWARD || smode == SCATTER_REVERSE, PetscObjectComm((PetscObject)sf), PETSC_ERR_SUP, "Unsupported ScatterMode %d in MatDenseScatter_Private()", smode);
2760:   PetscCall(MatGetSize(X, NULL, &N));
2761:   PetscCall(MatGetSize(Y, NULL, &ny));
2762:   PetscCheck(N == ny, PetscObjectComm((PetscObject)sf), PETSC_ERR_ARG_SIZ, "Matrix column sizes must match: %" PetscInt_FMT " != %" PetscInt_FMT, N, ny);
2763:   if (!N) PetscFunctionReturn(PETSC_SUCCESS);
2764:   PetscCall(MatDenseGetLDA(smode == SCATTER_FORWARD ? X : Y, &rld));
2765:   PetscCall(MatDenseGetLDA(smode == SCATTER_FORWARD ? Y : X, &lld));
2766:   /* get cached or create new strided PetscSF when the number of columns is greater than one */
2767:   if (N > 1) {
2768:     MatDenseScatterCtx *ctx;
2769:     PetscInt            nr, nl;

2771:     PetscCall(PetscSFGetGraph(sf, &nr, &nl, NULL, NULL));
2772:     PetscCall(PetscObjectContainerQuery((PetscObject)sf, "_MatDenseScatter_StridedSF", &ctx));
2773:     if (ctx && ctx->N != N) {
2774:       PetscCall(PetscObjectCompose((PetscObject)sf, "_MatDenseScatter_StridedSF", NULL));
2775:       ctx = NULL;
2776:     }
2777:     /* callers must clear the cache on all processes before changing the layout (which happens, e.g., with matrices with different leading dimensions) on any rank */
2778:     PetscCheck(ctx == NULL || (ctx->rld == rld && ctx->lld == lld && ctx->nr == nr && ctx->nl == nl), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "The cached strided SF has a different layout; the calling function must destroy it first on all processes with PetscObjectCompose((PetscObject)sf, \"_MatDenseScatter_StridedSF\", NULL)");
2779:     if (ctx == NULL) {
2780:       PetscCall(PetscNew(&ctx));
2781:       PetscCall(PetscSFCreateStridedSF(sf, N, rld, lld, &ctx->sf));
2782:       ctx->N   = N;
2783:       ctx->rld = rld;
2784:       ctx->lld = lld;
2785:       ctx->nr  = nr;
2786:       ctx->nl  = nl;
2787:       PetscCall(PetscObjectContainerCompose((PetscObject)sf, "_MatDenseScatter_StridedSF", ctx, MatDenseScatterCtxDestroy_Private));
2788:     }
2789:     vsf = ctx->sf;
2790:   } else vsf = sf;
2791:   if (mode == INSERT_VALUES && smode == SCATTER_FORWARD) {
2792:     const PetscInt *ilocal;
2793:     PetscInt        nl;

2795:     PetscCall(PetscSFGetGraph(sf, NULL, &nl, &ilocal, NULL));
2796:     PetscCall(MatGetLocalSize(Y, &ny, NULL));
2797:     // preserve untouched rows and padding; contiguous leaves cover every row only in this case
2798:     writeonly = (PetscBool)(ilocal == NULL && (PetscCount)nl * PetscMax(sf->vscat.bs, 1) == ny && lld == ny);
2799:   }
2800:   PetscCall(MatDenseScatterWithSF_Private(vsf, X, Y, op, smode, writeonly));
2801:   PetscFunctionReturn(PETSC_SUCCESS);
2802: }