Actual source code: matscalapack.c

  1: #include <petsc/private/petscscalapack.h>

  3: const char       ScaLAPACKCitation[] = "@BOOK{scalapack-user-guide,\n"
  4:                                        "       AUTHOR = {L. S. Blackford and J. Choi and A. Cleary and E. D'Azevedo and\n"
  5:                                        "                 J. Demmel and I. Dhillon and J. Dongarra and S. Hammarling and\n"
  6:                                        "                 G. Henry and A. Petitet and K. Stanley and D. Walker and R. C. Whaley},\n"
  7:                                        "       TITLE = {Sca{LAPACK} Users' Guide},\n"
  8:                                        "       PUBLISHER = {SIAM},\n"
  9:                                        "       ADDRESS = {Philadelphia, PA},\n"
 10:                                        "       YEAR = 1997\n"
 11:                                        "}\n";
 12: static PetscBool ScaLAPACKCite       = PETSC_FALSE;

 14: #define DEFAULT_BLOCKSIZE 64

 16: /*
 17:     The variable Petsc_ScaLAPACK_keyval is used to indicate an MPI attribute that
 18:   is attached to a communicator, in this case the attribute is a Mat_ScaLAPACK_Grid
 19: */
 20: static PetscMPIInt Petsc_ScaLAPACK_keyval = MPI_KEYVAL_INVALID;

 22: static PetscErrorCode Petsc_ScaLAPACK_keyval_free(void)
 23: {
 24:   PetscFunctionBegin;
 25:   PetscCall(PetscInfo(NULL, "Freeing Petsc_ScaLAPACK_keyval\n"));
 26:   PetscCallMPI(MPI_Comm_free_keyval(&Petsc_ScaLAPACK_keyval));
 27:   PetscFunctionReturn(PETSC_SUCCESS);
 28: }

 30: static PetscErrorCode MatView_ScaLAPACK(Mat A, PetscViewer viewer)
 31: {
 32:   Mat_ScaLAPACK    *a = (Mat_ScaLAPACK *)A->data;
 33:   PetscBool         isascii;
 34:   PetscViewerFormat format;
 35:   Mat               Adense;

 37:   PetscFunctionBegin;
 38:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
 39:   if (isascii) {
 40:     PetscCall(PetscViewerGetFormat(viewer, &format));
 41:     if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
 42:       PetscCall(PetscViewerASCIIPrintf(viewer, "block sizes: %d,%d\n", (int)a->mb, (int)a->nb));
 43:       PetscCall(PetscViewerASCIIPrintf(viewer, "grid height=%d, grid width=%d\n", (int)a->grid->nprow, (int)a->grid->npcol));
 44:       PetscCall(PetscViewerASCIIPrintf(viewer, "coordinates of process owning first row and column: (%d,%d)\n", (int)a->rsrc, (int)a->csrc));
 45:       PetscCall(PetscViewerASCIIPrintf(viewer, "dimension of largest local matrix: %d x %d\n", (int)a->locr, (int)a->locc));
 46:       PetscFunctionReturn(PETSC_SUCCESS);
 47:     } else if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
 48:       PetscFunctionReturn(PETSC_SUCCESS);
 49:     }
 50:   }
 51:   /* convert to dense format and call MatView() */
 52:   PetscCall(MatConvert(A, MATDENSE, MAT_INITIAL_MATRIX, &Adense));
 53:   PetscCall(MatView(Adense, viewer));
 54:   PetscCall(MatDestroy(&Adense));
 55:   PetscFunctionReturn(PETSC_SUCCESS);
 56: }

 58: static PetscErrorCode MatGetInfo_ScaLAPACK(Mat A, MatInfoType flag, MatInfo *info)
 59: {
 60:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data;
 61:   PetscLogDouble isend[2], irecv[2];

 63:   PetscFunctionBegin;
 64:   info->block_size = 1.0;

 66:   isend[0] = a->lld * a->locc;  /* locally allocated */
 67:   isend[1] = a->locr * a->locc; /* used submatrix */
 68:   if (flag == MAT_LOCAL || flag == MAT_GLOBAL_MAX) {
 69:     info->nz_allocated = isend[0];
 70:     info->nz_used      = isend[1];
 71:   } else if (flag == MAT_GLOBAL_MAX) {
 72:     PetscCallMPI(MPIU_Allreduce(isend, irecv, 2, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A)));
 73:     info->nz_allocated = irecv[0];
 74:     info->nz_used      = irecv[1];
 75:   } else if (flag == MAT_GLOBAL_SUM) {
 76:     PetscCallMPI(MPIU_Allreduce(isend, irecv, 2, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A)));
 77:     info->nz_allocated = irecv[0];
 78:     info->nz_used      = irecv[1];
 79:   }

 81:   info->nz_unneeded       = 0;
 82:   info->assemblies        = A->num_ass;
 83:   info->mallocs           = 0;
 84:   info->memory            = 0; /* REVIEW ME */
 85:   info->fill_ratio_given  = 0;
 86:   info->fill_ratio_needed = 0;
 87:   info->factor_mallocs    = 0;
 88:   PetscFunctionReturn(PETSC_SUCCESS);
 89: }

 91: static PetscErrorCode MatSetOption_ScaLAPACK(Mat A, MatOption op, PetscBool flg)
 92: {
 93:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data;

 95:   PetscFunctionBegin;
 96:   switch (op) {
 97:   case MAT_NEW_NONZERO_LOCATIONS:
 98:   case MAT_NEW_NONZERO_LOCATION_ERR:
 99:   case MAT_NEW_NONZERO_ALLOCATION_ERR:
100:   case MAT_SYMMETRIC:
101:   case MAT_SORTED_FULL:
102:   case MAT_HERMITIAN:
103:     break;
104:   case MAT_ROW_ORIENTED:
105:     a->roworiented = flg;
106:     break;
107:   default:
108:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported option %s", MatOptions[op]);
109:   }
110:   PetscFunctionReturn(PETSC_SUCCESS);
111: }

113: static PetscErrorCode MatSetValues_ScaLAPACK(Mat A, PetscInt nr, const PetscInt *rows, PetscInt nc, const PetscInt *cols, const PetscScalar *vals, InsertMode imode)
114: {
115:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data;
116:   PetscInt       j;
117:   PetscBLASInt   gridx, gcidx, lridx, lcidx, rsrc, csrc;
118:   PetscBool      roworiented = a->roworiented;

120:   PetscFunctionBegin;
121:   PetscCheck(imode == INSERT_VALUES || imode == ADD_VALUES, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "No support for InsertMode %d", (int)imode);
122:   for (PetscInt i = 0; i < nr; i++) {
123:     if (rows[i] < 0) continue;
124:     PetscCall(PetscBLASIntCast(rows[i] + 1, &gridx));
125:     for (j = 0; j < nc; j++) {
126:       if (cols[j] < 0) continue;
127:       PetscCall(PetscBLASIntCast(cols[j] + 1, &gcidx));
128:       PetscCallBLAS("SCALAPACKinfog2l", SCALAPACKinfog2l_(&gridx, &gcidx, a->desc, &a->grid->nprow, &a->grid->npcol, &a->grid->myrow, &a->grid->mycol, &lridx, &lcidx, &rsrc, &csrc));
129:       if (rsrc == a->grid->myrow && csrc == a->grid->mycol) {
130:         if (roworiented) {
131:           switch (imode) {
132:           case INSERT_VALUES:
133:             a->loc[lridx - 1 + (lcidx - 1) * a->lld] = vals[i * nc + j];
134:             break;
135:           default:
136:             a->loc[lridx - 1 + (lcidx - 1) * a->lld] += vals[i * nc + j];
137:             break;
138:           }
139:         } else {
140:           switch (imode) {
141:           case INSERT_VALUES:
142:             a->loc[lridx - 1 + (lcidx - 1) * a->lld] = vals[i + j * nr];
143:             break;
144:           default:
145:             a->loc[lridx - 1 + (lcidx - 1) * a->lld] += vals[i + j * nr];
146:             break;
147:           }
148:         }
149:       } else {
150:         PetscCheck(!A->nooffprocentries, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Setting off process entry even though MatSetOption(,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE) was set");
151:         A->assembled = PETSC_FALSE;
152:         PetscCall(MatStashValuesRow_Private(&A->stash, rows[i], 1, cols + j, roworiented ? vals + i * nc + j : vals + i + j * nr, (PetscBool)(imode == ADD_VALUES)));
153:       }
154:     }
155:   }
156:   PetscFunctionReturn(PETSC_SUCCESS);
157: }

159: static PetscErrorCode MatMultXXXYYY_ScaLAPACK(Mat A, PetscBool transpose, PetscBool hermitian, PetscScalar beta, const PetscScalar *x, PetscScalar *y)
160: {
161:   Mat_ScaLAPACK  *a = (Mat_ScaLAPACK *)A->data;
162:   PetscScalar    *x2d, *y2d, alpha = 1.0;
163:   const PetscInt *ranges;
164:   PetscBLASInt    xdesc[9], ydesc[9], x2desc[9], y2desc[9], mb, nb, lszx, lszy, zero = 0, one = 1, xlld, ylld;

166:   PetscFunctionBegin;
167:   if (transpose) {
168:     /* create ScaLAPACK descriptors for vectors (1d block distribution) */
169:     PetscCall(PetscLayoutGetRanges(A->rmap, &ranges));
170:     PetscCall(PetscBLASIntCast(ranges[1], &mb)); /* x block size */
171:     PetscCall(PetscBLASIntCast(PetscMax(1, A->rmap->n), &xlld));
172:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(xdesc, &a->M, &one, &mb, &one, &zero, &zero, &a->grid->ictxcol, &xlld, &info));
173:     PetscCall(PetscLayoutGetRanges(A->cmap, &ranges));
174:     PetscCall(PetscBLASIntCast(ranges[1], &nb)); /* y block size */
175:     ylld = 1;
176:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(ydesc, &one, &a->N, &one, &nb, &zero, &zero, &a->grid->ictxrow, &ylld, &info));

178:     /* allocate 2d vectors */
179:     lszx = SCALAPACKnumroc_(&a->M, &a->mb, &a->grid->myrow, &a->rsrc, &a->grid->nprow);
180:     lszy = SCALAPACKnumroc_(&a->N, &a->nb, &a->grid->mycol, &a->csrc, &a->grid->npcol);
181:     PetscCall(PetscMalloc2(lszx, &x2d, lszy, &y2d));
182:     PetscCall(PetscBLASIntCast(PetscMax(1, lszx), &xlld));

184:     /* create ScaLAPACK descriptors for vectors (2d block distribution) */
185:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(x2desc, &a->M, &one, &a->mb, &one, &zero, &zero, &a->grid->ictxt, &xlld, &info));
186:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(y2desc, &one, &a->N, &one, &a->nb, &zero, &zero, &a->grid->ictxt, &ylld, &info));

188:     /* redistribute x as a column of a 2d matrix */
189:     PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&a->M, &one, x, &one, &one, xdesc, x2d, &one, &one, x2desc, &a->grid->ictxcol));

191:     /* redistribute y as a row of a 2d matrix */
192:     if (beta != 0.0) PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&one, &a->N, y, &one, &one, ydesc, y2d, &one, &one, y2desc, &a->grid->ictxrow));

194:     /* call PBLAS subroutine */
195:     if (hermitian) PetscCallBLAS("PBLASgemv", PBLASgemv_("C", &a->M, &a->N, &alpha, a->loc, &one, &one, a->desc, x2d, &one, &one, x2desc, &one, &beta, y2d, &one, &one, y2desc, &one));
196:     else PetscCallBLAS("PBLASgemv", PBLASgemv_("T", &a->M, &a->N, &alpha, a->loc, &one, &one, a->desc, x2d, &one, &one, x2desc, &one, &beta, y2d, &one, &one, y2desc, &one));

198:     /* redistribute y from a row of a 2d matrix */
199:     PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&one, &a->N, y2d, &one, &one, y2desc, y, &one, &one, ydesc, &a->grid->ictxrow));

201:   } else { /* non-transpose */

203:     /* create ScaLAPACK descriptors for vectors (1d block distribution) */
204:     PetscCall(PetscLayoutGetRanges(A->cmap, &ranges));
205:     PetscCall(PetscBLASIntCast(ranges[1], &nb)); /* x block size */
206:     xlld = 1;
207:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(xdesc, &one, &a->N, &one, &nb, &zero, &zero, &a->grid->ictxrow, &xlld, &info));
208:     PetscCall(PetscLayoutGetRanges(A->rmap, &ranges));
209:     PetscCall(PetscBLASIntCast(ranges[1], &mb)); /* y block size */
210:     PetscCall(PetscBLASIntCast(PetscMax(1, A->rmap->n), &ylld));
211:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(ydesc, &a->M, &one, &mb, &one, &zero, &zero, &a->grid->ictxcol, &ylld, &info));

213:     /* allocate 2d vectors */
214:     lszy = SCALAPACKnumroc_(&a->M, &a->mb, &a->grid->myrow, &a->rsrc, &a->grid->nprow);
215:     lszx = SCALAPACKnumroc_(&a->N, &a->nb, &a->grid->mycol, &a->csrc, &a->grid->npcol);
216:     PetscCall(PetscMalloc2(lszx, &x2d, lszy, &y2d));
217:     PetscCall(PetscBLASIntCast(PetscMax(1, lszy), &ylld));

219:     /* create ScaLAPACK descriptors for vectors (2d block distribution) */
220:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(x2desc, &one, &a->N, &one, &a->nb, &zero, &zero, &a->grid->ictxt, &xlld, &info));
221:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(y2desc, &a->M, &one, &a->mb, &one, &zero, &zero, &a->grid->ictxt, &ylld, &info));

223:     /* redistribute x as a row of a 2d matrix */
224:     PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&one, &a->N, x, &one, &one, xdesc, x2d, &one, &one, x2desc, &a->grid->ictxrow));

226:     /* redistribute y as a column of a 2d matrix */
227:     if (beta != 0.0) PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&a->M, &one, y, &one, &one, ydesc, y2d, &one, &one, y2desc, &a->grid->ictxcol));

229:     /* call PBLAS subroutine */
230:     PetscCallBLAS("PBLASgemv", PBLASgemv_("N", &a->M, &a->N, &alpha, a->loc, &one, &one, a->desc, x2d, &one, &one, x2desc, &one, &beta, y2d, &one, &one, y2desc, &one));

232:     /* redistribute y from a column of a 2d matrix */
233:     PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&a->M, &one, y2d, &one, &one, y2desc, y, &one, &one, ydesc, &a->grid->ictxcol));
234:   }
235:   PetscCall(PetscFree2(x2d, y2d));
236:   PetscFunctionReturn(PETSC_SUCCESS);
237: }

239: static PetscErrorCode MatMult_ScaLAPACK(Mat A, Vec x, Vec y)
240: {
241:   const PetscScalar *xarray;
242:   PetscScalar       *yarray;

244:   PetscFunctionBegin;
245:   PetscCall(VecGetArrayRead(x, &xarray));
246:   PetscCall(VecGetArray(y, &yarray));
247:   PetscCall(MatMultXXXYYY_ScaLAPACK(A, PETSC_FALSE, PETSC_FALSE, 0.0, xarray, yarray));
248:   PetscCall(VecRestoreArrayRead(x, &xarray));
249:   PetscCall(VecRestoreArray(y, &yarray));
250:   PetscFunctionReturn(PETSC_SUCCESS);
251: }

253: static PetscErrorCode MatMultTranspose_ScaLAPACK(Mat A, Vec x, Vec y)
254: {
255:   const PetscScalar *xarray;
256:   PetscScalar       *yarray;

258:   PetscFunctionBegin;
259:   PetscCall(VecGetArrayRead(x, &xarray));
260:   PetscCall(VecGetArray(y, &yarray));
261:   PetscCall(MatMultXXXYYY_ScaLAPACK(A, PETSC_TRUE, PETSC_FALSE, 0.0, xarray, yarray));
262:   PetscCall(VecRestoreArrayRead(x, &xarray));
263:   PetscCall(VecRestoreArray(y, &yarray));
264:   PetscFunctionReturn(PETSC_SUCCESS);
265: }

267: static PetscErrorCode MatMultHermitianTranspose_ScaLAPACK(Mat A, Vec x, Vec y)
268: {
269:   const PetscScalar *xarray;
270:   PetscScalar       *yarray;

272:   PetscFunctionBegin;
273:   PetscCall(VecGetArrayRead(x, &xarray));
274:   PetscCall(VecGetArrayWrite(y, &yarray));
275:   PetscCall(MatMultXXXYYY_ScaLAPACK(A, PETSC_TRUE, PETSC_TRUE, 0.0, xarray, yarray));
276:   PetscCall(VecRestoreArrayRead(x, &xarray));
277:   PetscCall(VecRestoreArrayWrite(y, &yarray));
278:   PetscFunctionReturn(PETSC_SUCCESS);
279: }

281: static PetscErrorCode MatMultAdd_ScaLAPACK(Mat A, Vec x, Vec y, Vec z)
282: {
283:   const PetscScalar *xarray;
284:   PetscScalar       *zarray;

286:   PetscFunctionBegin;
287:   if (y != z) PetscCall(VecCopy(y, z));
288:   PetscCall(VecGetArrayRead(x, &xarray));
289:   PetscCall(VecGetArray(z, &zarray));
290:   PetscCall(MatMultXXXYYY_ScaLAPACK(A, PETSC_FALSE, PETSC_FALSE, 1.0, xarray, zarray));
291:   PetscCall(VecRestoreArrayRead(x, &xarray));
292:   PetscCall(VecRestoreArray(z, &zarray));
293:   PetscFunctionReturn(PETSC_SUCCESS);
294: }

296: static PetscErrorCode MatMultTransposeAdd_ScaLAPACK(Mat A, Vec x, Vec y, Vec z)
297: {
298:   const PetscScalar *xarray;
299:   PetscScalar       *zarray;

301:   PetscFunctionBegin;
302:   if (y != z) PetscCall(VecCopy(y, z));
303:   PetscCall(VecGetArrayRead(x, &xarray));
304:   PetscCall(VecGetArray(z, &zarray));
305:   PetscCall(MatMultXXXYYY_ScaLAPACK(A, PETSC_TRUE, PETSC_FALSE, 1.0, xarray, zarray));
306:   PetscCall(VecRestoreArrayRead(x, &xarray));
307:   PetscCall(VecRestoreArray(z, &zarray));
308:   PetscFunctionReturn(PETSC_SUCCESS);
309: }

311: static PetscErrorCode MatMultHermitianTransposeAdd_ScaLAPACK(Mat A, Vec x, Vec y, Vec z)
312: {
313:   const PetscScalar *xarray;
314:   PetscScalar       *zarray;

316:   PetscFunctionBegin;
317:   if (y != z) PetscCall(VecCopy(y, z));
318:   PetscCall(VecGetArrayRead(x, &xarray));
319:   PetscCall(VecGetArray(z, &zarray));
320:   PetscCall(MatMultXXXYYY_ScaLAPACK(A, PETSC_TRUE, PETSC_TRUE, 1.0, xarray, zarray));
321:   PetscCall(VecRestoreArrayRead(x, &xarray));
322:   PetscCall(VecRestoreArray(z, &zarray));
323:   PetscFunctionReturn(PETSC_SUCCESS);
324: }

326: PetscErrorCode MatMatMultNumeric_ScaLAPACK(Mat A, Mat B, Mat C)
327: {
328:   Mat_ScaLAPACK *a    = (Mat_ScaLAPACK *)A->data;
329:   Mat_ScaLAPACK *b    = (Mat_ScaLAPACK *)B->data;
330:   Mat_ScaLAPACK *c    = (Mat_ScaLAPACK *)C->data;
331:   PetscScalar    sone = 1.0, zero = 0.0;
332:   PetscBLASInt   one = 1;

334:   PetscFunctionBegin;
335:   PetscCallBLAS("PBLASgemm", PBLASgemm_("N", "N", &a->M, &b->N, &a->N, &sone, a->loc, &one, &one, a->desc, b->loc, &one, &one, b->desc, &zero, c->loc, &one, &one, c->desc));
336:   C->assembled = PETSC_TRUE;
337:   PetscFunctionReturn(PETSC_SUCCESS);
338: }

340: PetscErrorCode MatMatMultSymbolic_ScaLAPACK(Mat A, Mat B, PetscReal fill, Mat C)
341: {
342:   PetscFunctionBegin;
343:   PetscCall(MatSetSizes(C, A->rmap->n, B->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
344:   PetscCall(MatSetType(C, MATSCALAPACK));
345:   PetscCall(MatSetUp(C));
346:   C->ops->matmultnumeric = MatMatMultNumeric_ScaLAPACK;
347:   PetscFunctionReturn(PETSC_SUCCESS);
348: }

350: static PetscErrorCode MatTransposeMatMultNumeric_ScaLAPACK(Mat A, Mat B, Mat C)
351: {
352:   Mat_ScaLAPACK *a    = (Mat_ScaLAPACK *)A->data;
353:   Mat_ScaLAPACK *b    = (Mat_ScaLAPACK *)B->data;
354:   Mat_ScaLAPACK *c    = (Mat_ScaLAPACK *)C->data;
355:   PetscScalar    sone = 1.0, zero = 0.0;
356:   PetscBLASInt   one = 1;

358:   PetscFunctionBegin;
359:   PetscCallBLAS("PBLASgemm", PBLASgemm_("T", "N", &a->N, &b->N, &a->M, &sone, a->loc, &one, &one, a->desc, b->loc, &one, &one, b->desc, &zero, c->loc, &one, &one, c->desc));
360:   C->assembled = PETSC_TRUE;
361:   PetscFunctionReturn(PETSC_SUCCESS);
362: }

364: static PetscErrorCode MatTransposeMatMultSymbolic_ScaLAPACK(Mat A, Mat B, PetscReal fill, Mat C)
365: {
366:   PetscFunctionBegin;
367:   PetscCall(MatSetSizes(C, A->cmap->n, B->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
368:   PetscCall(MatSetType(C, MATSCALAPACK));
369:   PetscCall(MatSetUp(C));
370:   C->ops->transposematmultnumeric = MatTransposeMatMultNumeric_ScaLAPACK;
371:   PetscFunctionReturn(PETSC_SUCCESS);
372: }

374: static PetscErrorCode MatMatTransposeMultNumeric_ScaLAPACK(Mat A, Mat B, Mat C)
375: {
376:   Mat_ScaLAPACK *a    = (Mat_ScaLAPACK *)A->data;
377:   Mat_ScaLAPACK *b    = (Mat_ScaLAPACK *)B->data;
378:   Mat_ScaLAPACK *c    = (Mat_ScaLAPACK *)C->data;
379:   PetscScalar    sone = 1.0, zero = 0.0;
380:   PetscBLASInt   one = 1;

382:   PetscFunctionBegin;
383:   PetscCallBLAS("PBLASgemm", PBLASgemm_("N", "T", &a->M, &b->M, &a->N, &sone, a->loc, &one, &one, a->desc, b->loc, &one, &one, b->desc, &zero, c->loc, &one, &one, c->desc));
384:   C->assembled = PETSC_TRUE;
385:   PetscFunctionReturn(PETSC_SUCCESS);
386: }

388: static PetscErrorCode MatMatTransposeMultSymbolic_ScaLAPACK(Mat A, Mat B, PetscReal fill, Mat C)
389: {
390:   PetscFunctionBegin;
391:   PetscCall(MatSetSizes(C, A->rmap->n, B->rmap->n, PETSC_DECIDE, PETSC_DECIDE));
392:   PetscCall(MatSetType(C, MATSCALAPACK));
393:   PetscCall(MatSetUp(C));
394:   C->ops->mattransposemultnumeric = MatMatTransposeMultNumeric_ScaLAPACK;
395:   PetscFunctionReturn(PETSC_SUCCESS);
396: }

398: PETSC_INTERN PetscErrorCode MatProductSetFromOptions_ScaLAPACK(Mat C)
399: {
400:   Mat_Product *product = C->product;

402:   PetscFunctionBegin;
403:   switch (product->type) {
404:   case MATPRODUCT_AB:
405:     C->ops->matmultsymbolic = MatMatMultSymbolic_ScaLAPACK;
406:     C->ops->productsymbolic = MatProductSymbolic_AB;
407:     break;
408:   case MATPRODUCT_AtB:
409:     C->ops->transposematmultsymbolic = MatTransposeMatMultSymbolic_ScaLAPACK;
410:     C->ops->productsymbolic          = MatProductSymbolic_AtB;
411:     break;
412:   case MATPRODUCT_ABt:
413:     C->ops->mattransposemultsymbolic = MatMatTransposeMultSymbolic_ScaLAPACK;
414:     C->ops->productsymbolic          = MatProductSymbolic_ABt;
415:     break;
416:   default:
417:     SETERRQ(PetscObjectComm((PetscObject)C), PETSC_ERR_SUP, "MatProduct type %s is not supported for ScaLAPACK and ScaLAPACK matrices", MatProductTypes[product->type]);
418:   }
419:   PetscFunctionReturn(PETSC_SUCCESS);
420: }

422: static PetscErrorCode MatGetDiagonal_ScaLAPACK(Mat A, Vec D)
423: {
424:   Mat_ScaLAPACK  *a = (Mat_ScaLAPACK *)A->data;
425:   PetscScalar    *darray, *d2d, v;
426:   const PetscInt *ranges;
427:   PetscBLASInt    j, ddesc[9], d2desc[9], mb, nb, lszd, zero = 0, one = 1, dlld;

429:   PetscFunctionBegin;
430:   PetscCall(VecGetArray(D, &darray));

432:   if (A->rmap->N <= A->cmap->N) { /* row version */

434:     /* create ScaLAPACK descriptor for vector (1d block distribution) */
435:     PetscCall(PetscLayoutGetRanges(A->rmap, &ranges));
436:     PetscCall(PetscBLASIntCast(ranges[1], &mb)); /* D block size */
437:     PetscCall(PetscBLASIntCast(PetscMax(1, A->rmap->n), &dlld));
438:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(ddesc, &a->M, &one, &mb, &one, &zero, &zero, &a->grid->ictxcol, &dlld, &info));

440:     /* allocate 2d vector */
441:     lszd = SCALAPACKnumroc_(&a->M, &a->mb, &a->grid->myrow, &a->rsrc, &a->grid->nprow);
442:     PetscCall(PetscCalloc1(lszd, &d2d));
443:     PetscCall(PetscBLASIntCast(PetscMax(1, lszd), &dlld));

445:     /* create ScaLAPACK descriptor for vector (2d block distribution) */
446:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(d2desc, &a->M, &one, &a->mb, &one, &zero, &zero, &a->grid->ictxt, &dlld, &info));

448:     /* collect diagonal */
449:     for (j = 1; j <= a->M; j++) {
450:       PetscCallBLAS("SCALAPACKelget", SCALAPACKelget_("R", " ", &v, a->loc, &j, &j, a->desc));
451:       PetscCallBLAS("SCALAPACKelset", SCALAPACKelset_(d2d, &j, &one, d2desc, &v));
452:     }

454:     /* redistribute d from a column of a 2d matrix */
455:     PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&a->M, &one, d2d, &one, &one, d2desc, darray, &one, &one, ddesc, &a->grid->ictxcol));
456:     PetscCall(PetscFree(d2d));

458:   } else { /* column version */

460:     /* create ScaLAPACK descriptor for vector (1d block distribution) */
461:     PetscCall(PetscLayoutGetRanges(A->cmap, &ranges));
462:     PetscCall(PetscBLASIntCast(ranges[1], &nb)); /* D block size */
463:     dlld = 1;
464:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(ddesc, &one, &a->N, &one, &nb, &zero, &zero, &a->grid->ictxrow, &dlld, &info));

466:     /* allocate 2d vector */
467:     lszd = SCALAPACKnumroc_(&a->N, &a->nb, &a->grid->mycol, &a->csrc, &a->grid->npcol);
468:     PetscCall(PetscCalloc1(lszd, &d2d));

470:     /* create ScaLAPACK descriptor for vector (2d block distribution) */
471:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(d2desc, &one, &a->N, &one, &a->nb, &zero, &zero, &a->grid->ictxt, &dlld, &info));

473:     /* collect diagonal */
474:     for (j = 1; j <= a->N; j++) {
475:       PetscCallBLAS("SCALAPACKelget", SCALAPACKelget_("C", " ", &v, a->loc, &j, &j, a->desc));
476:       PetscCallBLAS("SCALAPACKelset", SCALAPACKelset_(d2d, &one, &j, d2desc, &v));
477:     }

479:     /* redistribute d from a row of a 2d matrix */
480:     PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&one, &a->N, d2d, &one, &one, d2desc, darray, &one, &one, ddesc, &a->grid->ictxrow));
481:     PetscCall(PetscFree(d2d));
482:   }

484:   PetscCall(VecRestoreArray(D, &darray));
485:   PetscCall(VecAssemblyBegin(D));
486:   PetscCall(VecAssemblyEnd(D));
487:   PetscFunctionReturn(PETSC_SUCCESS);
488: }

490: static PetscErrorCode MatDiagonalScale_ScaLAPACK(Mat A, Vec L, Vec R)
491: {
492:   Mat_ScaLAPACK     *a = (Mat_ScaLAPACK *)A->data;
493:   const PetscScalar *d;
494:   const PetscInt    *ranges;
495:   PetscScalar       *d2d;
496:   PetscBLASInt       i, j, ddesc[9], d2desc[9], mb, nb, lszd, zero = 0, one = 1, dlld;

498:   PetscFunctionBegin;
499:   if (R) {
500:     PetscCall(VecGetArrayRead(R, &d));
501:     /* create ScaLAPACK descriptor for vector (1d block distribution) */
502:     PetscCall(PetscLayoutGetRanges(A->cmap, &ranges));
503:     PetscCall(PetscBLASIntCast(ranges[1], &nb)); /* D block size */
504:     dlld = 1;
505:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(ddesc, &one, &a->N, &one, &nb, &zero, &zero, &a->grid->ictxrow, &dlld, &info));

507:     /* allocate 2d vector */
508:     lszd = SCALAPACKnumroc_(&a->N, &a->nb, &a->grid->mycol, &a->csrc, &a->grid->npcol);
509:     PetscCall(PetscCalloc1(lszd, &d2d));

511:     /* create ScaLAPACK descriptor for vector (2d block distribution) */
512:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(d2desc, &one, &a->N, &one, &a->nb, &zero, &zero, &a->grid->ictxt, &dlld, &info));

514:     /* redistribute d to a row of a 2d matrix */
515:     PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&one, &a->N, d, &one, &one, ddesc, d2d, &one, &one, d2desc, &a->grid->ictxrow));

517:     /* broadcast along process columns */
518:     if (!a->grid->myrow) Cdgebs2d(a->grid->ictxt, "C", " ", 1, lszd, d2d, dlld);
519:     else Cdgebr2d(a->grid->ictxt, "C", " ", 1, lszd, d2d, dlld, 0, a->grid->mycol);

521:     /* local scaling */
522:     for (j = 0; j < a->locc; j++)
523:       for (i = 0; i < a->locr; i++) a->loc[i + j * a->lld] *= d2d[j];

525:     PetscCall(PetscFree(d2d));
526:     PetscCall(VecRestoreArrayRead(R, &d));
527:   }
528:   if (L) {
529:     PetscCall(VecGetArrayRead(L, &d));
530:     /* create ScaLAPACK descriptor for vector (1d block distribution) */
531:     PetscCall(PetscLayoutGetRanges(A->rmap, &ranges));
532:     PetscCall(PetscBLASIntCast(ranges[1], &mb)); /* D block size */
533:     PetscCall(PetscBLASIntCast(PetscMax(1, A->rmap->n), &dlld));
534:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(ddesc, &a->M, &one, &mb, &one, &zero, &zero, &a->grid->ictxcol, &dlld, &info));

536:     /* allocate 2d vector */
537:     lszd = SCALAPACKnumroc_(&a->M, &a->mb, &a->grid->myrow, &a->rsrc, &a->grid->nprow);
538:     PetscCall(PetscCalloc1(lszd, &d2d));
539:     PetscCall(PetscBLASIntCast(PetscMax(1, lszd), &dlld));

541:     /* create ScaLAPACK descriptor for vector (2d block distribution) */
542:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(d2desc, &a->M, &one, &a->mb, &one, &zero, &zero, &a->grid->ictxt, &dlld, &info));

544:     /* redistribute d to a column of a 2d matrix */
545:     PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&a->M, &one, d, &one, &one, ddesc, d2d, &one, &one, d2desc, &a->grid->ictxcol));

547:     /* broadcast along process rows */
548:     if (!a->grid->mycol) Cdgebs2d(a->grid->ictxt, "R", " ", lszd, 1, d2d, dlld);
549:     else Cdgebr2d(a->grid->ictxt, "R", " ", lszd, 1, d2d, dlld, a->grid->myrow, 0);

551:     /* local scaling */
552:     for (i = 0; i < a->locr; i++)
553:       for (j = 0; j < a->locc; j++) a->loc[i + j * a->lld] *= d2d[i];

555:     PetscCall(PetscFree(d2d));
556:     PetscCall(VecRestoreArrayRead(L, &d));
557:   }
558:   PetscFunctionReturn(PETSC_SUCCESS);
559: }

561: static PetscErrorCode MatScale_ScaLAPACK(Mat X, PetscScalar a)
562: {
563:   Mat_ScaLAPACK *x = (Mat_ScaLAPACK *)X->data;
564:   PetscBLASInt   n, one = 1;

566:   PetscFunctionBegin;
567:   n = x->lld * x->locc;
568:   PetscCallBLAS("BLASscal", BLASscal_(&n, &a, x->loc, &one));
569:   PetscFunctionReturn(PETSC_SUCCESS);
570: }

572: static PetscErrorCode MatShift_ScaLAPACK(Mat X, PetscScalar alpha)
573: {
574:   Mat_ScaLAPACK *x = (Mat_ScaLAPACK *)X->data;
575:   PetscBLASInt   i, n;
576:   PetscScalar    v;

578:   PetscFunctionBegin;
579:   n = PetscMin(x->M, x->N);
580:   for (i = 1; i <= n; i++) {
581:     PetscCallBLAS("SCALAPACKelget", SCALAPACKelget_("-", " ", &v, x->loc, &i, &i, x->desc));
582:     v += alpha;
583:     PetscCallBLAS("SCALAPACKelset", SCALAPACKelset_(x->loc, &i, &i, x->desc, &v));
584:   }
585:   PetscFunctionReturn(PETSC_SUCCESS);
586: }

588: static PetscErrorCode MatAXPY_ScaLAPACK(Mat Y, PetscScalar alpha, Mat X, MatStructure str)
589: {
590:   Mat_ScaLAPACK *x    = (Mat_ScaLAPACK *)X->data;
591:   Mat_ScaLAPACK *y    = (Mat_ScaLAPACK *)Y->data;
592:   PetscBLASInt   one  = 1;
593:   PetscScalar    beta = 1.0;

595:   PetscFunctionBegin;
596:   MatScaLAPACKCheckDistribution(Y, 1, X, 3);
597:   PetscCallBLAS("SCALAPACKmatadd", SCALAPACKmatadd_(&x->M, &x->N, &alpha, x->loc, &one, &one, x->desc, &beta, y->loc, &one, &one, y->desc));
598:   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
599:   PetscFunctionReturn(PETSC_SUCCESS);
600: }

602: static PetscErrorCode MatCopy_ScaLAPACK(Mat A, Mat B, MatStructure str)
603: {
604:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data;
605:   Mat_ScaLAPACK *b = (Mat_ScaLAPACK *)B->data;

607:   PetscFunctionBegin;
608:   PetscCall(PetscArraycpy(b->loc, a->loc, a->lld * a->locc));
609:   PetscCall(PetscObjectStateIncrease((PetscObject)B));
610:   PetscFunctionReturn(PETSC_SUCCESS);
611: }

613: static PetscErrorCode MatDuplicate_ScaLAPACK(Mat A, MatDuplicateOption op, Mat *B)
614: {
615:   Mat            Bs;
616:   MPI_Comm       comm;
617:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data, *b;

619:   PetscFunctionBegin;
620:   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
621:   PetscCall(MatCreate(comm, &Bs));
622:   PetscCall(MatSetSizes(Bs, A->rmap->n, A->cmap->n, PETSC_DECIDE, PETSC_DECIDE));
623:   PetscCall(MatSetType(Bs, MATSCALAPACK));
624:   b       = (Mat_ScaLAPACK *)Bs->data;
625:   b->M    = a->M;
626:   b->N    = a->N;
627:   b->mb   = a->mb;
628:   b->nb   = a->nb;
629:   b->rsrc = a->rsrc;
630:   b->csrc = a->csrc;
631:   PetscCall(MatSetUp(Bs));
632:   *B = Bs;
633:   if (op == MAT_COPY_VALUES) PetscCall(PetscArraycpy(b->loc, a->loc, a->lld * a->locc));
634:   Bs->assembled = PETSC_TRUE;
635:   PetscFunctionReturn(PETSC_SUCCESS);
636: }

638: static PetscErrorCode MatTranspose_ScaLAPACK(Mat A, MatReuse reuse, Mat *B)
639: {
640:   Mat_ScaLAPACK *a    = (Mat_ScaLAPACK *)A->data, *b;
641:   Mat            Bs   = *B;
642:   PetscBLASInt   one  = 1;
643:   PetscScalar    sone = 1.0, zero = 0.0;
644: #if defined(PETSC_USE_COMPLEX)
645:   PetscInt i;
646: #endif

648:   PetscFunctionBegin;
649:   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B));
650:   PetscCheck(reuse == MAT_INITIAL_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Only MAT_INITIAL_MATRIX supported");
651:   PetscCall(MatCreateScaLAPACK(PetscObjectComm((PetscObject)A), a->nb, a->mb, a->N, a->M, a->csrc, a->rsrc, &Bs));
652:   *B = Bs;
653:   b  = (Mat_ScaLAPACK *)Bs->data;
654:   PetscCallBLAS("PBLAStran", PBLAStran_(&a->N, &a->M, &sone, a->loc, &one, &one, a->desc, &zero, b->loc, &one, &one, b->desc));
655: #if defined(PETSC_USE_COMPLEX)
656:   /* undo conjugation */
657:   for (i = 0; i < b->locr; i++)
658:     for (PetscInt j = 0; j < b->locc; j++) b->loc[i + j * b->lld] = PetscConj(b->loc[i + j * b->lld]);
659: #endif
660:   Bs->assembled = PETSC_TRUE;
661:   PetscFunctionReturn(PETSC_SUCCESS);
662: }

664: static PetscErrorCode MatConjugate_ScaLAPACK(Mat A)
665: {
666:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data;
667:   PetscInt       i;

669:   PetscFunctionBegin;
670:   for (i = 0; i < a->locr; i++)
671:     for (PetscInt j = 0; j < a->locc; j++) a->loc[i + j * a->lld] = PetscConj(a->loc[i + j * a->lld]);
672:   PetscFunctionReturn(PETSC_SUCCESS);
673: }

675: static PetscErrorCode MatHermitianTranspose_ScaLAPACK(Mat A, MatReuse reuse, Mat *B)
676: {
677:   Mat_ScaLAPACK *a    = (Mat_ScaLAPACK *)A->data, *b;
678:   Mat            Bs   = *B;
679:   PetscBLASInt   one  = 1;
680:   PetscScalar    sone = 1.0, zero = 0.0;

682:   PetscFunctionBegin;
683:   PetscCheck(reuse == MAT_INITIAL_MATRIX, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Only MAT_INITIAL_MATRIX supported");
684:   PetscCall(MatCreateScaLAPACK(PetscObjectComm((PetscObject)A), a->nb, a->mb, a->N, a->M, a->csrc, a->rsrc, &Bs));
685:   *B = Bs;
686:   b  = (Mat_ScaLAPACK *)Bs->data;
687:   PetscCallBLAS("PBLAStran", PBLAStran_(&a->N, &a->M, &sone, a->loc, &one, &one, a->desc, &zero, b->loc, &one, &one, b->desc));
688:   Bs->assembled = PETSC_TRUE;
689:   PetscFunctionReturn(PETSC_SUCCESS);
690: }

692: static PetscErrorCode MatSolve_ScaLAPACK(Mat A, Vec B, Vec X)
693: {
694:   Mat_ScaLAPACK  *a = (Mat_ScaLAPACK *)A->data;
695:   PetscScalar    *x, *x2d;
696:   const PetscInt *ranges;
697:   PetscBLASInt    xdesc[9], x2desc[9], mb, lszx, zero = 0, one = 1, xlld, nrhs = 1;

699:   PetscFunctionBegin;
700:   PetscCall(VecCopy(B, X));
701:   PetscCall(VecGetArray(X, &x));

703:   /* create ScaLAPACK descriptor for a vector (1d block distribution) */
704:   PetscCall(PetscLayoutGetRanges(A->rmap, &ranges));
705:   PetscCall(PetscBLASIntCast(ranges[1], &mb)); /* x block size */
706:   PetscCall(PetscBLASIntCast(PetscMax(1, A->rmap->n), &xlld));
707:   PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(xdesc, &a->M, &one, &mb, &one, &zero, &zero, &a->grid->ictxcol, &xlld, &info));

709:   /* allocate 2d vector */
710:   lszx = SCALAPACKnumroc_(&a->M, &a->mb, &a->grid->myrow, &a->rsrc, &a->grid->nprow);
711:   PetscCall(PetscMalloc1(lszx, &x2d));
712:   PetscCall(PetscBLASIntCast(PetscMax(1, lszx), &xlld));

714:   /* create ScaLAPACK descriptor for a vector (2d block distribution) */
715:   PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(x2desc, &a->M, &one, &a->mb, &one, &zero, &zero, &a->grid->ictxt, &xlld, &info));

717:   /* redistribute x as a column of a 2d matrix */
718:   PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&a->M, &one, x, &one, &one, xdesc, x2d, &one, &one, x2desc, &a->grid->ictxcol));

720:   /* call ScaLAPACK subroutine */
721:   switch (A->factortype) {
722:   case MAT_FACTOR_LU:
723:     PetscCallScaLAPACKInfo("getrs", SCALAPACKgetrs_("N", &a->M, &nrhs, a->loc, &one, &one, a->desc, a->pivots, x2d, &one, &one, x2desc, &info));
724:     break;
725:   case MAT_FACTOR_CHOLESKY:
726:     PetscCallScaLAPACKInfo("potrs", SCALAPACKpotrs_("L", &a->M, &nrhs, a->loc, &one, &one, a->desc, x2d, &one, &one, x2desc, &info));
727:     break;
728:   default:
729:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unfactored Matrix or Unsupported MatFactorType");
730:   }

732:   /* redistribute x from a column of a 2d matrix */
733:   PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&a->M, &one, x2d, &one, &one, x2desc, x, &one, &one, xdesc, &a->grid->ictxcol));

735:   PetscCall(PetscFree(x2d));
736:   PetscCall(VecRestoreArray(X, &x));
737:   PetscFunctionReturn(PETSC_SUCCESS);
738: }

740: static PetscErrorCode MatSolveAdd_ScaLAPACK(Mat A, Vec B, Vec Y, Vec X)
741: {
742:   PetscFunctionBegin;
743:   PetscCall(MatSolve_ScaLAPACK(A, B, X));
744:   PetscCall(VecAXPY(X, 1, Y));
745:   PetscFunctionReturn(PETSC_SUCCESS);
746: }

748: static PetscErrorCode MatMatSolve_ScaLAPACK(Mat A, Mat B, Mat X)
749: {
750:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data, *x;
751:   PetscBool      flg1, flg2;
752:   PetscBLASInt   one = 1;
753:   Mat            C;
754:   MatType        type;

756:   PetscFunctionBegin;
757:   PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSCALAPACK, &flg1));
758:   PetscCall(PetscObjectTypeCompare((PetscObject)X, MATSCALAPACK, &flg2));
759:   if (flg1 && flg2) MatScaLAPACKCheckDistribution(B, 2, X, 3);
760:   if (flg2) {
761:     if (flg1) PetscCall(MatCopy(B, X, SAME_NONZERO_PATTERN));
762:     else PetscCall(MatConvert(B, MATSCALAPACK, MAT_REUSE_MATRIX, &X));
763:     C = X;
764:   } else {
765:     PetscCall(MatConvert(B, MATSCALAPACK, MAT_INITIAL_MATRIX, &C));
766:   }
767:   x = (Mat_ScaLAPACK *)C->data;

769:   switch (A->factortype) {
770:   case MAT_FACTOR_LU:
771:     PetscCallScaLAPACKInfo("getrs", SCALAPACKgetrs_("N", &a->M, &x->N, a->loc, &one, &one, a->desc, a->pivots, x->loc, &one, &one, x->desc, &info));
772:     break;
773:   case MAT_FACTOR_CHOLESKY:
774:     PetscCallScaLAPACKInfo("potrs", SCALAPACKpotrs_("L", &a->M, &x->N, a->loc, &one, &one, a->desc, x->loc, &one, &one, x->desc, &info));
775:     break;
776:   default:
777:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unfactored Matrix or Unsupported MatFactorType");
778:   }
779:   if (!flg2) {
780:     PetscCall(MatGetType(X, &type));
781:     PetscCall(MatConvert(C, type, MAT_REUSE_MATRIX, &X));
782:     PetscCall(MatDestroy(&C));
783:   }
784:   PetscFunctionReturn(PETSC_SUCCESS);
785: }

787: static PetscErrorCode MatLUFactor_ScaLAPACK(Mat A, IS row, IS col, const MatFactorInfo *factorinfo)
788: {
789:   Mat_ScaLAPACK *a   = (Mat_ScaLAPACK *)A->data;
790:   PetscBLASInt   one = 1;

792:   PetscFunctionBegin;
793:   if (!a->pivots) PetscCall(PetscMalloc1(a->locr + a->mb, &a->pivots));
794:   PetscCallScaLAPACKInfo("getrf", SCALAPACKgetrf_(&a->M, &a->N, a->loc, &one, &one, a->desc, a->pivots, &info));
795:   A->factortype = MAT_FACTOR_LU;
796:   A->assembled  = PETSC_TRUE;

798:   PetscCall(PetscFree(A->solvertype));
799:   PetscCall(PetscStrallocpy(MATSOLVERSCALAPACK, &A->solvertype));
800:   PetscFunctionReturn(PETSC_SUCCESS);
801: }

803: static PetscErrorCode MatLUFactorNumeric_ScaLAPACK(Mat F, Mat A, const MatFactorInfo *info)
804: {
805:   PetscFunctionBegin;
806:   PetscCall(MatCopy(A, F, SAME_NONZERO_PATTERN));
807:   PetscCall(MatLUFactor_ScaLAPACK(F, 0, 0, info));
808:   PetscFunctionReturn(PETSC_SUCCESS);
809: }

811: static PetscErrorCode MatLUFactorSymbolic_ScaLAPACK(Mat F, Mat A, IS r, IS c, const MatFactorInfo *info)
812: {
813:   PetscFunctionBegin;
814:   /* F is created and allocated by MatGetFactor_scalapack_petsc(), skip this routine. */
815:   PetscFunctionReturn(PETSC_SUCCESS);
816: }

818: static PetscErrorCode MatCholeskyFactor_ScaLAPACK(Mat A, IS perm, const MatFactorInfo *factorinfo)
819: {
820:   Mat_ScaLAPACK *a   = (Mat_ScaLAPACK *)A->data;
821:   PetscBLASInt   one = 1;

823:   PetscFunctionBegin;
824:   PetscCallScaLAPACKInfo("potrf", SCALAPACKpotrf_("L", &a->M, a->loc, &one, &one, a->desc, &info));
825:   A->factortype = MAT_FACTOR_CHOLESKY;
826:   A->assembled  = PETSC_TRUE;

828:   PetscCall(PetscFree(A->solvertype));
829:   PetscCall(PetscStrallocpy(MATSOLVERSCALAPACK, &A->solvertype));
830:   PetscFunctionReturn(PETSC_SUCCESS);
831: }

833: static PetscErrorCode MatCholeskyFactorNumeric_ScaLAPACK(Mat F, Mat A, const MatFactorInfo *info)
834: {
835:   PetscFunctionBegin;
836:   PetscCall(MatCopy(A, F, SAME_NONZERO_PATTERN));
837:   PetscCall(MatCholeskyFactor_ScaLAPACK(F, 0, info));
838:   PetscFunctionReturn(PETSC_SUCCESS);
839: }

841: static PetscErrorCode MatCholeskyFactorSymbolic_ScaLAPACK(Mat F, Mat A, IS perm, const MatFactorInfo *info)
842: {
843:   PetscFunctionBegin;
844:   /* F is created and allocated by MatGetFactor_scalapack_petsc(), skip this routine. */
845:   PetscFunctionReturn(PETSC_SUCCESS);
846: }

848: static PetscErrorCode MatFactorGetSolverType_scalapack_scalapack(Mat A, MatSolverType *type)
849: {
850:   PetscFunctionBegin;
851:   *type = MATSOLVERSCALAPACK;
852:   PetscFunctionReturn(PETSC_SUCCESS);
853: }

855: static PetscErrorCode MatGetFactor_scalapack_scalapack(Mat A, MatFactorType ftype, Mat *F)
856: {
857:   Mat            B;
858:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data;

860:   PetscFunctionBegin;
861:   /* Create the factorization matrix */
862:   PetscCall(MatCreateScaLAPACK(PetscObjectComm((PetscObject)A), a->mb, a->nb, a->M, a->N, a->rsrc, a->csrc, &B));
863:   B->trivialsymbolic = PETSC_TRUE;
864:   B->factortype      = ftype;
865:   PetscCall(PetscFree(B->solvertype));
866:   PetscCall(PetscStrallocpy(MATSOLVERSCALAPACK, &B->solvertype));

868:   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatFactorGetSolverType_C", MatFactorGetSolverType_scalapack_scalapack));
869:   *F = B;
870:   PetscFunctionReturn(PETSC_SUCCESS);
871: }

873: PETSC_INTERN PetscErrorCode MatSolverTypeRegister_ScaLAPACK(void)
874: {
875:   PetscFunctionBegin;
876:   PetscCall(MatSolverTypeRegister(MATSOLVERSCALAPACK, MATSCALAPACK, MAT_FACTOR_LU, MatGetFactor_scalapack_scalapack));
877:   PetscCall(MatSolverTypeRegister(MATSOLVERSCALAPACK, MATSCALAPACK, MAT_FACTOR_CHOLESKY, MatGetFactor_scalapack_scalapack));
878:   PetscFunctionReturn(PETSC_SUCCESS);
879: }

881: static PetscErrorCode MatNorm_ScaLAPACK(Mat A, NormType type, PetscReal *nrm)
882: {
883:   Mat_ScaLAPACK *a   = (Mat_ScaLAPACK *)A->data;
884:   PetscBLASInt   one = 1, lwork = 0;
885:   const char    *ntype;
886:   PetscScalar   *work = NULL, dummy;

888:   PetscFunctionBegin;
889:   switch (type) {
890:   case NORM_1:
891:     ntype = "1";
892:     lwork = PetscMax(a->locr, a->locc);
893:     break;
894:   case NORM_FROBENIUS:
895:     ntype = "F";
896:     work  = &dummy;
897:     break;
898:   case NORM_INFINITY:
899:     ntype = "I";
900:     lwork = PetscMax(a->locr, a->locc);
901:     break;
902:   default:
903:     SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Unsupported norm type");
904:   }
905:   if (lwork) PetscCall(PetscMalloc1(lwork, &work));
906:   *nrm = SCALAPACKlange_(ntype, &a->M, &a->N, a->loc, &one, &one, a->desc, work);
907:   if (lwork) PetscCall(PetscFree(work));
908:   PetscFunctionReturn(PETSC_SUCCESS);
909: }

911: static PetscErrorCode MatZeroEntries_ScaLAPACK(Mat A)
912: {
913:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data;

915:   PetscFunctionBegin;
916:   PetscCall(PetscArrayzero(a->loc, a->lld * a->locc));
917:   PetscFunctionReturn(PETSC_SUCCESS);
918: }

920: static PetscErrorCode MatGetOwnershipIS_ScaLAPACK(Mat A, IS *rows, IS *cols)
921: {
922:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data;
923:   PetscInt       i, n, nb, isrc, nproc, iproc, *idx;

925:   PetscFunctionBegin;
926:   if (rows) {
927:     n     = a->locr;
928:     nb    = a->mb;
929:     isrc  = a->rsrc;
930:     nproc = a->grid->nprow;
931:     iproc = a->grid->myrow;
932:     PetscCall(PetscMalloc1(n, &idx));
933:     for (i = 0; i < n; i++) idx[i] = nproc * nb * (i / nb) + i % nb + ((nproc + iproc - isrc) % nproc) * nb;
934:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, idx, PETSC_OWN_POINTER, rows));
935:   }
936:   if (cols) {
937:     n     = a->locc;
938:     nb    = a->nb;
939:     isrc  = a->csrc;
940:     nproc = a->grid->npcol;
941:     iproc = a->grid->mycol;
942:     PetscCall(PetscMalloc1(n, &idx));
943:     for (i = 0; i < n; i++) idx[i] = nproc * nb * (i / nb) + i % nb + ((nproc + iproc - isrc) % nproc) * nb;
944:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, n, idx, PETSC_OWN_POINTER, cols));
945:   }
946:   PetscFunctionReturn(PETSC_SUCCESS);
947: }

949: static PetscErrorCode MatConvert_ScaLAPACK_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *B)
950: {
951:   Mat_ScaLAPACK     *a = (Mat_ScaLAPACK *)A->data;
952:   Mat                Bmpi;
953:   MPI_Comm           comm;
954:   PetscInt           i, M = A->rmap->N, N = A->cmap->N, m, n, rstart, rend, nz, ldb;
955:   const PetscInt    *ranges, *branges, *cwork;
956:   const PetscScalar *vwork;
957:   PetscBLASInt       bdesc[9], bmb, zero = 0, one = 1, lld;
958:   PetscScalar       *barray;
959:   PetscBool          differ = PETSC_FALSE;
960:   PetscMPIInt        size;

962:   PetscFunctionBegin;
963:   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));
964:   PetscCall(PetscLayoutGetRanges(A->rmap, &ranges));

966:   if (reuse == MAT_REUSE_MATRIX) { /* check if local sizes differ in A and B */
967:     PetscCallMPI(MPI_Comm_size(comm, &size));
968:     PetscCall(PetscLayoutGetRanges((*B)->rmap, &branges));
969:     for (i = 0; i < size; i++)
970:       if (ranges[i + 1] != branges[i + 1]) {
971:         differ = PETSC_TRUE;
972:         break;
973:       }
974:   }

976:   if (reuse == MAT_REUSE_MATRIX && differ) { /* special case, use auxiliary dense matrix */
977:     PetscCall(MatCreate(comm, &Bmpi));
978:     m = PETSC_DECIDE;
979:     PetscCall(PetscSplitOwnershipEqual(comm, &m, &M));
980:     n = PETSC_DECIDE;
981:     PetscCall(PetscSplitOwnershipEqual(comm, &n, &N));
982:     PetscCall(MatSetSizes(Bmpi, m, n, M, N));
983:     PetscCall(MatSetType(Bmpi, MATDENSE));
984:     PetscCall(MatSetUp(Bmpi));

986:     /* create ScaLAPACK descriptor for B (1d block distribution) */
987:     PetscCall(PetscBLASIntCast(ranges[1], &bmb)); /* row block size */
988:     PetscCall(MatDenseGetLDA(Bmpi, &ldb));
989:     PetscCall(PetscBLASIntCast(PetscMax(ldb, 1), &lld)); /* local leading dimension */
990:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(bdesc, &a->M, &a->N, &bmb, &a->N, &zero, &zero, &a->grid->ictxcol, &lld, &info));

992:     /* redistribute matrix */
993:     PetscCall(MatDenseGetArray(Bmpi, &barray));
994:     PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&a->M, &a->N, a->loc, &one, &one, a->desc, barray, &one, &one, bdesc, &a->grid->ictxcol));
995:     PetscCall(MatDenseRestoreArray(Bmpi, &barray));
996:     PetscCall(MatAssemblyBegin(Bmpi, MAT_FINAL_ASSEMBLY));
997:     PetscCall(MatAssemblyEnd(Bmpi, MAT_FINAL_ASSEMBLY));

999:     /* transfer rows of auxiliary matrix to the final matrix B */
1000:     PetscCall(MatGetOwnershipRange(Bmpi, &rstart, &rend));
1001:     for (i = rstart; i < rend; i++) {
1002:       PetscCall(MatGetRow(Bmpi, i, &nz, &cwork, &vwork));
1003:       PetscCall(MatSetValues(*B, 1, &i, nz, cwork, vwork, INSERT_VALUES));
1004:       PetscCall(MatRestoreRow(Bmpi, i, &nz, &cwork, &vwork));
1005:     }
1006:     PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY));
1007:     PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY));
1008:     PetscCall(MatDestroy(&Bmpi));

1010:   } else { /* normal cases */

1012:     if (reuse == MAT_REUSE_MATRIX) Bmpi = *B;
1013:     else {
1014:       PetscCall(MatCreate(comm, &Bmpi));
1015:       m = PETSC_DECIDE;
1016:       PetscCall(PetscSplitOwnershipEqual(comm, &m, &M));
1017:       n = PETSC_DECIDE;
1018:       PetscCall(PetscSplitOwnershipEqual(comm, &n, &N));
1019:       PetscCall(MatSetSizes(Bmpi, m, n, M, N));
1020:       PetscCall(MatSetType(Bmpi, MATDENSE));
1021:       PetscCall(MatSetUp(Bmpi));
1022:     }

1024:     /* create ScaLAPACK descriptor for B (1d block distribution) */
1025:     PetscCall(PetscBLASIntCast(ranges[1], &bmb)); /* row block size */
1026:     PetscCall(MatDenseGetLDA(Bmpi, &ldb));
1027:     PetscCall(PetscBLASIntCast(PetscMax(ldb, 1), &lld)); /* local leading dimension */
1028:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(bdesc, &a->M, &a->N, &bmb, &a->N, &zero, &zero, &a->grid->ictxcol, &lld, &info));

1030:     /* redistribute matrix */
1031:     PetscCall(MatDenseGetArray(Bmpi, &barray));
1032:     PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&a->M, &a->N, a->loc, &one, &one, a->desc, barray, &one, &one, bdesc, &a->grid->ictxcol));
1033:     PetscCall(MatDenseRestoreArray(Bmpi, &barray));

1035:     PetscCall(MatAssemblyBegin(Bmpi, MAT_FINAL_ASSEMBLY));
1036:     PetscCall(MatAssemblyEnd(Bmpi, MAT_FINAL_ASSEMBLY));
1037:     if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &Bmpi));
1038:     else *B = Bmpi;
1039:   }
1040:   PetscFunctionReturn(PETSC_SUCCESS);
1041: }

1043: static inline PetscErrorCode MatScaLAPACKCheckLayout(PetscLayout map, PetscBool *correct)
1044: {
1045:   const PetscInt *ranges;
1046:   PetscMPIInt     size;
1047:   PetscInt        i, n;

1049:   PetscFunctionBegin;
1050:   *correct = PETSC_TRUE;
1051:   PetscCallMPI(MPI_Comm_size(map->comm, &size));
1052:   if (size > 1) {
1053:     PetscCall(PetscLayoutGetRanges(map, &ranges));
1054:     n = ranges[1] - ranges[0];
1055:     for (i = 1; i < size; i++)
1056:       if (ranges[i + 1] - ranges[i] != n) break;
1057:     *correct = (PetscBool)(i == size || (i == size - 1 && ranges[i + 1] - ranges[i] <= n));
1058:   }
1059:   PetscFunctionReturn(PETSC_SUCCESS);
1060: }

1062: PETSC_INTERN PetscErrorCode MatConvert_Dense_ScaLAPACK(Mat A, MatType newtype, MatReuse reuse, Mat *B)
1063: {
1064:   Mat_ScaLAPACK     *b;
1065:   Mat                Bmpi;
1066:   MPI_Comm           comm;
1067:   PetscInt           M = A->rmap->N, N = A->cmap->N, m, n;
1068:   const PetscInt    *ranges, *rows, *cols;
1069:   PetscBLASInt       adesc[9], amb, zero = 0, one = 1, lld;
1070:   const PetscScalar *aarray;
1071:   IS                 ir, ic;
1072:   PetscInt           lda;
1073:   PetscBool          flg;

1075:   PetscFunctionBegin;
1076:   PetscCall(PetscObjectGetComm((PetscObject)A, &comm));

1078:   if (reuse == MAT_REUSE_MATRIX) Bmpi = *B;
1079:   else {
1080:     PetscCall(MatCreate(comm, &Bmpi));
1081:     m = PETSC_DECIDE;
1082:     PetscCall(PetscSplitOwnershipEqual(comm, &m, &M));
1083:     n = PETSC_DECIDE;
1084:     PetscCall(PetscSplitOwnershipEqual(comm, &n, &N));
1085:     PetscCall(MatSetSizes(Bmpi, m, n, M, N));
1086:     PetscCall(MatSetType(Bmpi, MATSCALAPACK));
1087:     PetscCall(MatSetUp(Bmpi));
1088:   }
1089:   b = (Mat_ScaLAPACK *)Bmpi->data;

1091:   PetscCall(MatDenseGetLDA(A, &lda));
1092:   PetscCall(MatDenseGetArrayRead(A, &aarray));
1093:   PetscCall(MatScaLAPACKCheckLayout(A->rmap, &flg));
1094:   if (flg) PetscCall(MatScaLAPACKCheckLayout(A->cmap, &flg));
1095:   if (flg) { /* if the input Mat has a ScaLAPACK-compatible layout, use ScaLAPACK for the redistribution */
1096:     /* create ScaLAPACK descriptor for A (1d block distribution) */
1097:     PetscCall(PetscLayoutGetRanges(A->rmap, &ranges));
1098:     PetscCall(PetscBLASIntCast(ranges[1], &amb));        /* row block size */
1099:     PetscCall(PetscBLASIntCast(PetscMax(lda, 1), &lld)); /* local leading dimension */
1100:     PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(adesc, &b->M, &b->N, &amb, &b->N, &zero, &zero, &b->grid->ictxcol, &lld, &info));

1102:     /* redistribute matrix */
1103:     PetscCallBLAS("SCALAPACKgemr2d", SCALAPACKgemr2d_(&b->M, &b->N, aarray, &one, &one, adesc, b->loc, &one, &one, b->desc, &b->grid->ictxcol));
1104:     Bmpi->nooffprocentries = PETSC_TRUE;
1105:   } else { /* if the input Mat has a ScaLAPACK-incompatible layout, redistribute via MatSetValues() */
1106:     PetscCheck(lda == A->rmap->n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Leading dimension (%" PetscInt_FMT ") different than local number of rows (%" PetscInt_FMT ")", lda, A->rmap->n);
1107:     b->roworiented = PETSC_FALSE;
1108:     PetscCall(MatGetOwnershipIS(A, &ir, &ic));
1109:     PetscCall(ISGetIndices(ir, &rows));
1110:     PetscCall(ISGetIndices(ic, &cols));
1111:     PetscCall(MatSetValues(Bmpi, A->rmap->n, rows, A->cmap->N, cols, aarray, INSERT_VALUES));
1112:     PetscCall(ISRestoreIndices(ir, &rows));
1113:     PetscCall(ISRestoreIndices(ic, &cols));
1114:     PetscCall(ISDestroy(&ic));
1115:     PetscCall(ISDestroy(&ir));
1116:   }
1117:   PetscCall(MatDenseRestoreArrayRead(A, &aarray));
1118:   PetscCall(MatAssemblyBegin(Bmpi, MAT_FINAL_ASSEMBLY));
1119:   PetscCall(MatAssemblyEnd(Bmpi, MAT_FINAL_ASSEMBLY));
1120:   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &Bmpi));
1121:   else *B = Bmpi;
1122:   PetscFunctionReturn(PETSC_SUCCESS);
1123: }

1125: PETSC_INTERN PetscErrorCode MatConvert_AIJ_ScaLAPACK(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1126: {
1127:   Mat                mat_scal;
1128:   PetscInt           M = A->rmap->N, N = A->cmap->N, rstart = A->rmap->rstart, rend = A->rmap->rend, m, n, row, ncols;
1129:   const PetscInt    *cols;
1130:   const PetscScalar *vals;

1132:   PetscFunctionBegin;
1133:   if (reuse == MAT_REUSE_MATRIX) {
1134:     mat_scal = *newmat;
1135:     PetscCall(MatZeroEntries(mat_scal));
1136:   } else {
1137:     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &mat_scal));
1138:     m = PETSC_DECIDE;
1139:     PetscCall(PetscSplitOwnershipEqual(PetscObjectComm((PetscObject)A), &m, &M));
1140:     n = PETSC_DECIDE;
1141:     PetscCall(PetscSplitOwnershipEqual(PetscObjectComm((PetscObject)A), &n, &N));
1142:     PetscCall(MatSetSizes(mat_scal, m, n, M, N));
1143:     PetscCall(MatSetType(mat_scal, MATSCALAPACK));
1144:     PetscCall(MatSetUp(mat_scal));
1145:   }
1146:   for (row = rstart; row < rend; row++) {
1147:     PetscCall(MatGetRow(A, row, &ncols, &cols, &vals));
1148:     PetscCall(MatSetValues(mat_scal, 1, &row, ncols, cols, vals, INSERT_VALUES));
1149:     PetscCall(MatRestoreRow(A, row, &ncols, &cols, &vals));
1150:   }
1151:   PetscCall(MatAssemblyBegin(mat_scal, MAT_FINAL_ASSEMBLY));
1152:   PetscCall(MatAssemblyEnd(mat_scal, MAT_FINAL_ASSEMBLY));

1154:   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &mat_scal));
1155:   else *newmat = mat_scal;
1156:   PetscFunctionReturn(PETSC_SUCCESS);
1157: }

1159: PETSC_INTERN PetscErrorCode MatConvert_SBAIJ_ScaLAPACK(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1160: {
1161:   Mat                mat_scal;
1162:   PetscInt           M = A->rmap->N, N = A->cmap->N, m, n, row, ncols, j, rstart = A->rmap->rstart, rend = A->rmap->rend;
1163:   const PetscInt    *cols;
1164:   const PetscScalar *vals;
1165:   PetscScalar        v;

1167:   PetscFunctionBegin;
1168:   if (reuse == MAT_REUSE_MATRIX) {
1169:     mat_scal = *newmat;
1170:     PetscCall(MatZeroEntries(mat_scal));
1171:   } else {
1172:     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &mat_scal));
1173:     m = PETSC_DECIDE;
1174:     PetscCall(PetscSplitOwnershipEqual(PetscObjectComm((PetscObject)A), &m, &M));
1175:     n = PETSC_DECIDE;
1176:     PetscCall(PetscSplitOwnershipEqual(PetscObjectComm((PetscObject)A), &n, &N));
1177:     PetscCall(MatSetSizes(mat_scal, m, n, M, N));
1178:     PetscCall(MatSetType(mat_scal, MATSCALAPACK));
1179:     PetscCall(MatSetUp(mat_scal));
1180:   }
1181:   PetscCall(MatGetRowUpperTriangular(A));
1182:   for (row = rstart; row < rend; row++) {
1183:     PetscCall(MatGetRow(A, row, &ncols, &cols, &vals));
1184:     PetscCall(MatSetValues(mat_scal, 1, &row, ncols, cols, vals, ADD_VALUES));
1185:     for (j = 0; j < ncols; j++) { /* lower triangular part */
1186:       if (cols[j] == row) continue;
1187:       v = A->hermitian == PETSC_BOOL3_TRUE ? PetscConj(vals[j]) : vals[j];
1188:       PetscCall(MatSetValues(mat_scal, 1, &cols[j], 1, &row, &v, ADD_VALUES));
1189:     }
1190:     PetscCall(MatRestoreRow(A, row, &ncols, &cols, &vals));
1191:   }
1192:   PetscCall(MatRestoreRowUpperTriangular(A));
1193:   PetscCall(MatAssemblyBegin(mat_scal, MAT_FINAL_ASSEMBLY));
1194:   PetscCall(MatAssemblyEnd(mat_scal, MAT_FINAL_ASSEMBLY));

1196:   if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &mat_scal));
1197:   else *newmat = mat_scal;
1198:   PetscFunctionReturn(PETSC_SUCCESS);
1199: }

1201: static PetscErrorCode MatScaLAPACKSetPreallocation(Mat A)
1202: {
1203:   Mat_ScaLAPACK *a  = (Mat_ScaLAPACK *)A->data;
1204:   PetscInt       sz = 0;

1206:   PetscFunctionBegin;
1207:   PetscCall(PetscLayoutSetUp(A->rmap));
1208:   PetscCall(PetscLayoutSetUp(A->cmap));
1209:   if (!a->lld) a->lld = a->locr;

1211:   PetscCall(PetscFree(a->loc));
1212:   PetscCall(PetscIntMultError(a->lld, a->locc, &sz));
1213:   PetscCall(PetscCalloc1(sz, &a->loc));

1215:   A->preallocated = PETSC_TRUE;
1216:   PetscFunctionReturn(PETSC_SUCCESS);
1217: }

1219: static PetscErrorCode MatDestroy_ScaLAPACK(Mat A)
1220: {
1221:   Mat_ScaLAPACK      *a = (Mat_ScaLAPACK *)A->data;
1222:   Mat_ScaLAPACK_Grid *grid;
1223:   PetscMPIInt         iflg;
1224:   MPI_Comm            icomm;

1226:   PetscFunctionBegin;
1227:   PetscCall(MatStashDestroy_Private(&A->stash));
1228:   PetscCall(PetscFree(a->loc));
1229:   PetscCall(PetscFree(a->pivots));
1230:   PetscCall(PetscCommDuplicate(PetscObjectComm((PetscObject)A), &icomm, NULL));
1231:   PetscCallMPI(MPI_Comm_get_attr(icomm, Petsc_ScaLAPACK_keyval, (void **)&grid, &iflg));
1232:   if (--grid->grid_refct == 0) {
1233:     Cblacs_gridexit(grid->ictxt);
1234:     Cblacs_gridexit(grid->ictxrow);
1235:     Cblacs_gridexit(grid->ictxcol);
1236:     PetscCall(PetscFree(grid));
1237:     PetscCallMPI(MPI_Comm_delete_attr(icomm, Petsc_ScaLAPACK_keyval));
1238:   }
1239:   PetscCall(PetscCommDestroy(&icomm));
1240:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatGetOwnershipIS_C", NULL));
1241:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatFactorGetSolverType_C", NULL));
1242:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatScaLAPACKSetBlockSizes_C", NULL));
1243:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatScaLAPACKGetBlockSizes_C", NULL));
1244:   PetscCall(PetscFree(A->data));
1245:   PetscFunctionReturn(PETSC_SUCCESS);
1246: }

1248: static PetscErrorCode MatSetUp_ScaLAPACK(Mat A)
1249: {
1250:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data;
1251:   PetscBool      flg;

1253:   PetscFunctionBegin;
1254:   PetscCall(PetscLayoutSetUp(A->rmap));
1255:   PetscCall(PetscLayoutSetUp(A->cmap));

1257:   /* check that the layout is as enforced by MatCreateScaLAPACK() */
1258:   PetscCall(MatScaLAPACKCheckLayout(A->rmap, &flg));
1259:   PetscCheck(flg, A->rmap->comm, PETSC_ERR_SUP, "MATSCALAPACK must have equal local row sizes in all processes (except possibly the last one), consider using MatCreateScaLAPACK");
1260:   PetscCall(MatScaLAPACKCheckLayout(A->cmap, &flg));
1261:   PetscCheck(flg, A->cmap->comm, PETSC_ERR_SUP, "MATSCALAPACK must have equal local column sizes in all processes (except possibly the last one), consider using MatCreateScaLAPACK");

1263:   /* compute local sizes */
1264:   PetscCall(PetscBLASIntCast(A->rmap->N, &a->M));
1265:   PetscCall(PetscBLASIntCast(A->cmap->N, &a->N));
1266:   a->locr = SCALAPACKnumroc_(&a->M, &a->mb, &a->grid->myrow, &a->rsrc, &a->grid->nprow);
1267:   a->locc = SCALAPACKnumroc_(&a->N, &a->nb, &a->grid->mycol, &a->csrc, &a->grid->npcol);
1268:   a->lld  = PetscMax(1, a->locr);

1270:   /* allocate local array */
1271:   PetscCall(MatScaLAPACKSetPreallocation(A));

1273:   /* set up ScaLAPACK descriptor */
1274:   PetscCallScaLAPACKInfo("descinit", SCALAPACKdescinit_(a->desc, &a->M, &a->N, &a->mb, &a->nb, &a->rsrc, &a->csrc, &a->grid->ictxt, &a->lld, &info));
1275:   PetscFunctionReturn(PETSC_SUCCESS);
1276: }

1278: static PetscErrorCode MatAssemblyBegin_ScaLAPACK(Mat A, MatAssemblyType type)
1279: {
1280:   PetscInt nstash, reallocs;

1282:   PetscFunctionBegin;
1283:   if (A->nooffprocentries) PetscFunctionReturn(PETSC_SUCCESS);
1284:   PetscCall(MatStashScatterBegin_Private(A, &A->stash, NULL));
1285:   PetscCall(MatStashGetInfo_Private(&A->stash, &nstash, &reallocs));
1286:   PetscCall(PetscInfo(A, "Stash has %" PetscInt_FMT " entries, uses %" PetscInt_FMT " mallocs.\n", nstash, reallocs));
1287:   PetscFunctionReturn(PETSC_SUCCESS);
1288: }

1290: static PetscErrorCode MatAssemblyEnd_ScaLAPACK(Mat A, MatAssemblyType type)
1291: {
1292:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data;
1293:   PetscMPIInt    n;
1294:   PetscInt       i, flg, *row, *col;
1295:   PetscScalar   *val;
1296:   PetscBLASInt   gridx, gcidx, lridx, lcidx, rsrc, csrc;

1298:   PetscFunctionBegin;
1299:   if (A->nooffprocentries) PetscFunctionReturn(PETSC_SUCCESS);
1300:   while (1) {
1301:     PetscCall(MatStashScatterGetMesg_Private(&A->stash, &n, &row, &col, &val, &flg));
1302:     if (!flg) break;
1303:     for (i = 0; i < n; i++) {
1304:       PetscCall(PetscBLASIntCast(row[i] + 1, &gridx));
1305:       PetscCall(PetscBLASIntCast(col[i] + 1, &gcidx));
1306:       PetscCallBLAS("SCALAPACKinfog2l", SCALAPACKinfog2l_(&gridx, &gcidx, a->desc, &a->grid->nprow, &a->grid->npcol, &a->grid->myrow, &a->grid->mycol, &lridx, &lcidx, &rsrc, &csrc));
1307:       PetscCheck(rsrc == a->grid->myrow && csrc == a->grid->mycol, PetscObjectComm((PetscObject)A), PETSC_ERR_LIB, "Something went wrong, received value does not belong to this process");
1308:       switch (A->insertmode) {
1309:       case INSERT_VALUES:
1310:         a->loc[lridx - 1 + (lcidx - 1) * a->lld] = val[i];
1311:         break;
1312:       case ADD_VALUES:
1313:         a->loc[lridx - 1 + (lcidx - 1) * a->lld] += val[i];
1314:         break;
1315:       default:
1316:         SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "No support for InsertMode %d", (int)A->insertmode);
1317:       }
1318:     }
1319:   }
1320:   PetscCall(MatStashScatterEnd_Private(&A->stash));
1321:   PetscFunctionReturn(PETSC_SUCCESS);
1322: }

1324: static PetscErrorCode MatLoad_ScaLAPACK(Mat newMat, PetscViewer viewer)
1325: {
1326:   Mat      Adense, As;
1327:   MPI_Comm comm;

1329:   PetscFunctionBegin;
1330:   PetscCall(PetscObjectGetComm((PetscObject)newMat, &comm));
1331:   PetscCall(MatCreate(comm, &Adense));
1332:   PetscCall(MatSetType(Adense, MATDENSE));
1333:   PetscCall(MatLoad(Adense, viewer));
1334:   PetscCall(MatConvert(Adense, MATSCALAPACK, MAT_INITIAL_MATRIX, &As));
1335:   PetscCall(MatDestroy(&Adense));
1336:   PetscCall(MatHeaderReplace(newMat, &As));
1337:   PetscFunctionReturn(PETSC_SUCCESS);
1338: }

1340: static struct _MatOps MatOps_Values = {MatSetValues_ScaLAPACK,
1341:                                        NULL,
1342:                                        NULL,
1343:                                        MatMult_ScaLAPACK,
1344:                                        /* 4*/ MatMultAdd_ScaLAPACK,
1345:                                        MatMultTranspose_ScaLAPACK,
1346:                                        MatMultTransposeAdd_ScaLAPACK,
1347:                                        MatSolve_ScaLAPACK,
1348:                                        MatSolveAdd_ScaLAPACK,
1349:                                        NULL,
1350:                                        /*10*/ NULL,
1351:                                        MatLUFactor_ScaLAPACK,
1352:                                        MatCholeskyFactor_ScaLAPACK,
1353:                                        NULL,
1354:                                        MatTranspose_ScaLAPACK,
1355:                                        /*15*/ MatGetInfo_ScaLAPACK,
1356:                                        NULL,
1357:                                        MatGetDiagonal_ScaLAPACK,
1358:                                        MatDiagonalScale_ScaLAPACK,
1359:                                        MatNorm_ScaLAPACK,
1360:                                        /*20*/ MatAssemblyBegin_ScaLAPACK,
1361:                                        MatAssemblyEnd_ScaLAPACK,
1362:                                        MatSetOption_ScaLAPACK,
1363:                                        MatZeroEntries_ScaLAPACK,
1364:                                        /*24*/ NULL,
1365:                                        MatLUFactorSymbolic_ScaLAPACK,
1366:                                        MatLUFactorNumeric_ScaLAPACK,
1367:                                        MatCholeskyFactorSymbolic_ScaLAPACK,
1368:                                        MatCholeskyFactorNumeric_ScaLAPACK,
1369:                                        /*29*/ MatSetUp_ScaLAPACK,
1370:                                        NULL,
1371:                                        NULL,
1372:                                        NULL,
1373:                                        NULL,
1374:                                        /*34*/ MatDuplicate_ScaLAPACK,
1375:                                        NULL,
1376:                                        NULL,
1377:                                        NULL,
1378:                                        NULL,
1379:                                        /*39*/ MatAXPY_ScaLAPACK,
1380:                                        NULL,
1381:                                        NULL,
1382:                                        NULL,
1383:                                        MatCopy_ScaLAPACK,
1384:                                        /*44*/ NULL,
1385:                                        MatScale_ScaLAPACK,
1386:                                        MatShift_ScaLAPACK,
1387:                                        NULL,
1388:                                        NULL,
1389:                                        /*49*/ NULL,
1390:                                        NULL,
1391:                                        NULL,
1392:                                        NULL,
1393:                                        NULL,
1394:                                        /*54*/ NULL,
1395:                                        NULL,
1396:                                        NULL,
1397:                                        NULL,
1398:                                        NULL,
1399:                                        /*59*/ NULL,
1400:                                        MatDestroy_ScaLAPACK,
1401:                                        MatView_ScaLAPACK,
1402:                                        NULL,
1403:                                        NULL,
1404:                                        /*64*/ NULL,
1405:                                        NULL,
1406:                                        NULL,
1407:                                        NULL,
1408:                                        NULL,
1409:                                        /*69*/ NULL,
1410:                                        MatConvert_ScaLAPACK_Dense,
1411:                                        NULL,
1412:                                        NULL,
1413:                                        NULL,
1414:                                        /*74*/ NULL,
1415:                                        NULL,
1416:                                        NULL,
1417:                                        NULL,
1418:                                        MatLoad_ScaLAPACK,
1419:                                        /*79*/ NULL,
1420:                                        NULL,
1421:                                        NULL,
1422:                                        NULL,
1423:                                        NULL,
1424:                                        /*84*/ NULL,
1425:                                        MatMatMultNumeric_ScaLAPACK,
1426:                                        NULL,
1427:                                        NULL,
1428:                                        MatMatTransposeMultNumeric_ScaLAPACK,
1429:                                        /*89*/ NULL,
1430:                                        MatProductSetFromOptions_ScaLAPACK,
1431:                                        NULL,
1432:                                        NULL,
1433:                                        MatConjugate_ScaLAPACK,
1434:                                        /*94*/ NULL,
1435:                                        NULL,
1436:                                        NULL,
1437:                                        NULL,
1438:                                        NULL,
1439:                                        /*99*/ NULL,
1440:                                        MatMatSolve_ScaLAPACK,
1441:                                        NULL,
1442:                                        NULL,
1443:                                        NULL,
1444:                                        /*104*/ NULL,
1445:                                        NULL,
1446:                                        NULL,
1447:                                        NULL,
1448:                                        NULL,
1449:                                        /*109*/ NULL,
1450:                                        MatHermitianTranspose_ScaLAPACK,
1451:                                        MatMultHermitianTranspose_ScaLAPACK,
1452:                                        MatMultHermitianTransposeAdd_ScaLAPACK,
1453:                                        NULL,
1454:                                        /*114*/ NULL,
1455:                                        NULL,
1456:                                        NULL,
1457:                                        NULL,
1458:                                        NULL,
1459:                                        /*119*/ NULL,
1460:                                        MatTransposeMatMultNumeric_ScaLAPACK,
1461:                                        NULL,
1462:                                        NULL,
1463:                                        /*124*/ NULL,
1464:                                        NULL,
1465:                                        NULL,
1466:                                        NULL,
1467:                                        NULL,
1468:                                        /*129*/ NULL,
1469:                                        NULL,
1470:                                        NULL,
1471:                                        NULL,
1472:                                        NULL,
1473:                                        /*134*/ NULL,
1474:                                        NULL,
1475:                                        NULL,
1476:                                        NULL,
1477:                                        NULL,
1478:                                        NULL,
1479:                                        /*140*/ NULL,
1480:                                        NULL,
1481:                                        NULL,
1482:                                        NULL,
1483:                                        MatADot_Default,
1484:                                        /*144*/ MatANorm_Default,
1485:                                        NULL,
1486:                                        NULL,
1487:                                        NULL};

1489: static PetscErrorCode MatStashScatterBegin_ScaLAPACK(Mat mat, MatStash *stash, PetscInt *owners)
1490: {
1491:   PetscInt          *owner, *startv, *starti, bs2;
1492:   PetscInt           size = stash->size, nsends;
1493:   PetscInt          *sindices, **rindices, j, l;
1494:   PetscScalar      **rvalues, *svalues;
1495:   MPI_Comm           comm = stash->comm;
1496:   MPI_Request       *send_waits, *recv_waits, *recv_waits1, *recv_waits2;
1497:   PetscMPIInt        tag1 = stash->tag1, tag2 = stash->tag2, *sizes, *nlengths, nreceives, insends, ii;
1498:   PetscInt          *sp_idx, *sp_idy;
1499:   PetscScalar       *sp_val;
1500:   PetscMatStashSpace space, space_next;
1501:   PetscBLASInt       gridx, gcidx, lridx, lcidx, rsrc, csrc;
1502:   Mat_ScaLAPACK     *a = (Mat_ScaLAPACK *)mat->data;

1504:   PetscFunctionBegin;
1505:   { /* make sure all processors are either in INSERTMODE or ADDMODE */
1506:     InsertMode addv;
1507:     PetscCallMPI(MPIU_Allreduce((PetscEnum *)&mat->insertmode, (PetscEnum *)&addv, 1, MPIU_ENUM, MPI_BOR, PetscObjectComm((PetscObject)mat)));
1508:     PetscCheck(addv != (ADD_VALUES | INSERT_VALUES), PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONGSTATE, "Some processors inserted others added");
1509:     mat->insertmode = addv; /* in case this processor had no cache */
1510:   }

1512:   bs2 = stash->bs * stash->bs;

1514:   /*  first count number of contributors to each processor */
1515:   PetscCall(PetscCalloc1(size, &nlengths));
1516:   PetscCall(PetscMalloc1(stash->n + 1, &owner));

1518:   ii = j = 0;
1519:   space  = stash->space_head;
1520:   while (space) {
1521:     space_next = space->next;
1522:     for (l = 0; l < space->local_used; l++) {
1523:       PetscCall(PetscBLASIntCast(space->idx[l] + 1, &gridx));
1524:       PetscCall(PetscBLASIntCast(space->idy[l] + 1, &gcidx));
1525:       PetscCallBLAS("SCALAPACKinfog2l", SCALAPACKinfog2l_(&gridx, &gcidx, a->desc, &a->grid->nprow, &a->grid->npcol, &a->grid->myrow, &a->grid->mycol, &lridx, &lcidx, &rsrc, &csrc));
1526:       j = Cblacs_pnum(a->grid->ictxt, rsrc, csrc);
1527:       nlengths[j]++;
1528:       owner[ii] = j;
1529:       ii++;
1530:     }
1531:     space = space_next;
1532:   }

1534:   /* Now check what procs get messages - and compute nsends. */
1535:   PetscCall(PetscCalloc1(size, &sizes));
1536:   nsends = 0;
1537:   for (PetscMPIInt i = 0; i < size; i++) {
1538:     if (nlengths[i]) {
1539:       sizes[i] = 1;
1540:       nsends++;
1541:     }
1542:   }

1544:   {
1545:     PetscMPIInt *onodes, *olengths;

1547:     /* Determine the number of messages to expect, their lengths, from from-ids */
1548:     PetscCall(PetscGatherNumberOfMessages(comm, sizes, nlengths, &nreceives));
1549:     PetscCall(PetscMPIIntCast(nsends, &insends));
1550:     PetscCall(PetscGatherMessageLengths(comm, insends, nreceives, nlengths, &onodes, &olengths));
1551:     /* since clubbing row,col - lengths are multiplied by 2 */
1552:     for (PetscMPIInt i = 0; i < nreceives; i++) olengths[i] *= 2;
1553:     PetscCall(PetscPostIrecvInt(comm, tag1, nreceives, onodes, olengths, &rindices, &recv_waits1));
1554:     /* values are size 'bs2' lengths (and remove earlier factor 2 */
1555:     for (PetscMPIInt i = 0; i < nreceives; i++) olengths[i] = (PetscMPIInt)(olengths[i] * bs2 / 2);
1556:     PetscCall(PetscPostIrecvScalar(comm, tag2, nreceives, onodes, olengths, &rvalues, &recv_waits2));
1557:     PetscCall(PetscFree(onodes));
1558:     PetscCall(PetscFree(olengths));
1559:   }

1561:   /* do sends:
1562:       1) starts[i] gives the starting index in svalues for stuff going to
1563:          the ith processor
1564:   */
1565:   PetscCall(PetscMalloc2(bs2 * stash->n, &svalues, 2 * (stash->n + 1), &sindices));
1566:   PetscCall(PetscMalloc1(2 * nsends, &send_waits));
1567:   PetscCall(PetscMalloc2(size, &startv, size, &starti));
1568:   /* use 2 sends the first with all_a, the next with all_i and all_j */
1569:   startv[0] = 0;
1570:   starti[0] = 0;
1571:   for (PetscMPIInt i = 1; i < size; i++) {
1572:     startv[i] = startv[i - 1] + nlengths[i - 1];
1573:     starti[i] = starti[i - 1] + 2 * nlengths[i - 1];
1574:   }

1576:   ii    = 0;
1577:   space = stash->space_head;
1578:   while (space) {
1579:     space_next = space->next;
1580:     sp_idx     = space->idx;
1581:     sp_idy     = space->idy;
1582:     sp_val     = space->val;
1583:     for (l = 0; l < space->local_used; l++) {
1584:       j = owner[ii];
1585:       if (bs2 == 1) {
1586:         svalues[startv[j]] = sp_val[l];
1587:       } else {
1588:         PetscScalar *buf1, *buf2;
1589:         buf1 = svalues + bs2 * startv[j];
1590:         buf2 = space->val + bs2 * l;
1591:         for (PetscInt k = 0; k < bs2; k++) buf1[k] = buf2[k];
1592:       }
1593:       sindices[starti[j]]               = sp_idx[l];
1594:       sindices[starti[j] + nlengths[j]] = sp_idy[l];
1595:       startv[j]++;
1596:       starti[j]++;
1597:       ii++;
1598:     }
1599:     space = space_next;
1600:   }
1601:   startv[0] = 0;
1602:   for (PetscMPIInt i = 1; i < size; i++) startv[i] = startv[i - 1] + nlengths[i - 1];

1604:   for (PetscMPIInt i = 0, count = 0; i < size; i++) {
1605:     if (sizes[i]) {
1606:       PetscCallMPI(MPIU_Isend(sindices + 2 * startv[i], 2 * nlengths[i], MPIU_INT, i, tag1, comm, send_waits + count++));
1607:       PetscCallMPI(MPIU_Isend(svalues + bs2 * startv[i], bs2 * nlengths[i], MPIU_SCALAR, i, tag2, comm, send_waits + count++));
1608:     }
1609:   }
1610: #if defined(PETSC_USE_INFO)
1611:   PetscCall(PetscInfo(NULL, "No of messages: %" PetscInt_FMT "\n", nsends));
1612:   for (PetscMPIInt i = 0; i < size; i++) {
1613:     if (sizes[i]) PetscCall(PetscInfo(NULL, "Mesg_to: %d: size: %zu bytes\n", i, (size_t)(nlengths[i] * (bs2 * sizeof(PetscScalar) + 2 * sizeof(PetscInt)))));
1614:   }
1615: #endif
1616:   PetscCall(PetscFree(nlengths));
1617:   PetscCall(PetscFree(owner));
1618:   PetscCall(PetscFree2(startv, starti));
1619:   PetscCall(PetscFree(sizes));

1621:   /* recv_waits need to be contiguous for MatStashScatterGetMesg_Private() */
1622:   PetscCall(PetscMalloc1(2 * nreceives, &recv_waits));

1624:   for (PetscMPIInt i = 0; i < nreceives; i++) {
1625:     recv_waits[2 * i]     = recv_waits1[i];
1626:     recv_waits[2 * i + 1] = recv_waits2[i];
1627:   }
1628:   stash->recv_waits = recv_waits;

1630:   PetscCall(PetscFree(recv_waits1));
1631:   PetscCall(PetscFree(recv_waits2));

1633:   stash->svalues         = svalues;
1634:   stash->sindices        = sindices;
1635:   stash->rvalues         = rvalues;
1636:   stash->rindices        = rindices;
1637:   stash->send_waits      = send_waits;
1638:   stash->nsends          = (PetscMPIInt)nsends;
1639:   stash->nrecvs          = nreceives;
1640:   stash->reproduce_count = 0;
1641:   PetscFunctionReturn(PETSC_SUCCESS);
1642: }

1644: static PetscErrorCode MatScaLAPACKSetBlockSizes_ScaLAPACK(Mat A, PetscInt mb, PetscInt nb)
1645: {
1646:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data;

1648:   PetscFunctionBegin;
1649:   PetscCheck(!A->preallocated, PETSC_COMM_SELF, PETSC_ERR_ORDER, "Cannot change block sizes after MatSetUp");
1650:   PetscCheck(mb >= 1 || mb == PETSC_DECIDE, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "mb %" PetscInt_FMT " must be at least 1", mb);
1651:   PetscCheck(nb >= 1 || nb == PETSC_DECIDE, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "nb %" PetscInt_FMT " must be at least 1", nb);
1652:   PetscCall(PetscBLASIntCast((mb == PETSC_DECIDE) ? DEFAULT_BLOCKSIZE : mb, &a->mb));
1653:   PetscCall(PetscBLASIntCast((nb == PETSC_DECIDE) ? a->mb : nb, &a->nb));
1654:   PetscFunctionReturn(PETSC_SUCCESS);
1655: }

1657: /*@
1658:   MatScaLAPACKSetBlockSizes - Sets the block sizes to be used for the distribution of
1659:   the `MATSCALAPACK` matrix

1661:   Logically Collective

1663:   Input Parameters:
1664: + A  - a `MATSCALAPACK` matrix
1665: . mb - the row block size
1666: - nb - the column block size

1668:   Level: intermediate

1670:   Note:
1671:   This block size has a different meaning from the block size associated with `MatSetBlockSize()` used for sparse matrices

1673: .seealso: [](ch_matrices), `Mat`, `MATSCALAPACK`, `MatCreateScaLAPACK()`, `MatScaLAPACKGetBlockSizes()`
1674: @*/
1675: PetscErrorCode MatScaLAPACKSetBlockSizes(Mat A, PetscInt mb, PetscInt nb)
1676: {
1677:   PetscFunctionBegin;
1681:   PetscTryMethod(A, "MatScaLAPACKSetBlockSizes_C", (Mat, PetscInt, PetscInt), (A, mb, nb));
1682:   PetscFunctionReturn(PETSC_SUCCESS);
1683: }

1685: static PetscErrorCode MatScaLAPACKGetBlockSizes_ScaLAPACK(Mat A, PetscInt *mb, PetscInt *nb)
1686: {
1687:   Mat_ScaLAPACK *a = (Mat_ScaLAPACK *)A->data;

1689:   PetscFunctionBegin;
1690:   if (mb) *mb = a->mb;
1691:   if (nb) *nb = a->nb;
1692:   PetscFunctionReturn(PETSC_SUCCESS);
1693: }

1695: /*@
1696:   MatScaLAPACKGetBlockSizes - Gets the block sizes used in the distribution of
1697:   the `MATSCALAPACK` matrix

1699:   Not Collective

1701:   Input Parameter:
1702: . A - a `MATSCALAPACK` matrix

1704:   Output Parameters:
1705: + mb - the row block size
1706: - nb - the column block size

1708:   Level: intermediate

1710:   Note:
1711:   This block size has a different meaning from the block size associated with `MatSetBlockSize()` used for sparse matrices

1713: .seealso: [](ch_matrices), `Mat`, `MATSCALAPACK`, `MatCreateScaLAPACK()`, `MatScaLAPACKSetBlockSizes()`
1714: @*/
1715: PetscErrorCode MatScaLAPACKGetBlockSizes(Mat A, PetscInt *mb, PetscInt *nb)
1716: {
1717:   PetscFunctionBegin;
1719:   PetscUseMethod(A, "MatScaLAPACKGetBlockSizes_C", (Mat, PetscInt *, PetscInt *), (A, mb, nb));
1720:   PetscFunctionReturn(PETSC_SUCCESS);
1721: }

1723: PETSC_INTERN PetscErrorCode MatStashScatterGetMesg_Ref(MatStash *, PetscMPIInt *, PetscInt **, PetscInt **, PetscScalar **, PetscInt *);
1724: PETSC_INTERN PetscErrorCode MatStashScatterEnd_Ref(MatStash *);

1726: /*MC
1727:    MATSCALAPACK = "scalapack" - A matrix type for dense matrices using the ScaLAPACK package

1729:    Use `./configure --download-scalapack` to install PETSc to use ScaLAPACK

1731:    Options Database Keys:
1732: +  -mat_type scalapack                  - sets the matrix type to `MATSCALAPACK`
1733: .  -pc_factor_mat_solver_type scalapack - to use this direct solver with the option `-pc_type lu`
1734: .  -mat_scalapack_grid_height           - sets Grid Height for 2D cyclic ordering of internal matrix
1735: -  -mat_scalapack_block_sizes           - size of the blocks to use (one or two integers separated by comma)

1737:    Level: intermediate

1739:   Note:
1740:    Note unlike most matrix formats, this format does not store all the matrix entries for a contiguous
1741:    range of rows on an MPI rank. Use `MatGetOwnershipIS()` to determine what values are stored on
1742:    the given rank.

1744: .seealso: [](ch_matrices), `Mat`, `MATSCALAPACK`, `MATDENSE`, `MATELEMENTAL`, `MatGetOwnershipIS()`, `MatCreateScaLAPACK()`
1745: M*/

1747: PETSC_EXTERN PetscErrorCode MatCreate_ScaLAPACK(Mat A)
1748: {
1749:   Mat_ScaLAPACK      *a;
1750:   PetscBool           flg;
1751:   PetscMPIInt         iflg;
1752:   Mat_ScaLAPACK_Grid *grid;
1753:   MPI_Comm            icomm;
1754:   PetscBLASInt        nprow, npcol, myrow, mycol;
1755:   PetscInt            optv1, k = 2, array[2] = {0, 0};
1756:   PetscMPIInt         size;

1758:   PetscFunctionBegin;
1759:   A->ops[0]     = MatOps_Values;
1760:   A->insertmode = NOT_SET_VALUES;

1762:   PetscCall(MatStashCreate_Private(PetscObjectComm((PetscObject)A), 1, &A->stash));
1763:   A->stash.ScatterBegin   = MatStashScatterBegin_ScaLAPACK;
1764:   A->stash.ScatterGetMesg = MatStashScatterGetMesg_Ref;
1765:   A->stash.ScatterEnd     = MatStashScatterEnd_Ref;
1766:   A->stash.ScatterDestroy = NULL;

1768:   PetscCall(PetscNew(&a));
1769:   A->data = (void *)a;

1771:   /* Grid needs to be shared between multiple Mats on the same communicator, implement by attribute caching on the MPI_Comm */
1772:   if (Petsc_ScaLAPACK_keyval == MPI_KEYVAL_INVALID) {
1773:     PetscCallMPI(MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, MPI_COMM_NULL_DELETE_FN, &Petsc_ScaLAPACK_keyval, NULL));
1774:     PetscCall(PetscRegisterFinalize(Petsc_ScaLAPACK_keyval_free));
1775:     PetscCall(PetscCitationsRegister(ScaLAPACKCitation, &ScaLAPACKCite));
1776:   }
1777:   PetscCall(PetscCommDuplicate(PetscObjectComm((PetscObject)A), &icomm, NULL));
1778:   PetscCallMPI(MPI_Comm_get_attr(icomm, Petsc_ScaLAPACK_keyval, (void **)&grid, &iflg));
1779:   if (!iflg) {
1780:     PetscCall(PetscNew(&grid));

1782:     PetscCallMPI(MPI_Comm_size(icomm, &size));
1783:     PetscCall(PetscBLASIntCast(PetscSqrtReal((PetscReal)size) + 0.001, &grid->nprow));

1785:     PetscOptionsBegin(PetscObjectComm((PetscObject)A), ((PetscObject)A)->prefix, "ScaLAPACK Grid Options", "Mat");
1786:     PetscCall(PetscOptionsInt("-mat_scalapack_grid_height", "Grid Height", "None", grid->nprow, &optv1, &flg));
1787:     if (flg) {
1788:       PetscCheck(size % optv1 == 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Grid Height %" PetscInt_FMT " must evenly divide CommSize %d", optv1, size);
1789:       PetscCall(PetscBLASIntCast(optv1, &grid->nprow));
1790:     }
1791:     PetscOptionsEnd();

1793:     if (size % grid->nprow) grid->nprow = 1; /* cannot use a squarish grid, use a 1d grid */
1794:     grid->npcol = size / grid->nprow;
1795:     PetscCall(PetscBLASIntCast(grid->nprow, &nprow));
1796:     PetscCall(PetscBLASIntCast(grid->npcol, &npcol));
1797:     grid->ictxt = Csys2blacs_handle(icomm);
1798:     Cblacs_gridinit(&grid->ictxt, "R", nprow, npcol);
1799:     Cblacs_gridinfo(grid->ictxt, &nprow, &npcol, &myrow, &mycol);
1800:     grid->grid_refct = 1;
1801:     grid->nprow      = nprow;
1802:     grid->npcol      = npcol;
1803:     grid->myrow      = myrow;
1804:     grid->mycol      = mycol;
1805:     /* auxiliary 1d BLACS contexts for 1xsize and sizex1 grids */
1806:     grid->ictxrow = Csys2blacs_handle(icomm);
1807:     Cblacs_gridinit(&grid->ictxrow, "R", 1, size);
1808:     grid->ictxcol = Csys2blacs_handle(icomm);
1809:     Cblacs_gridinit(&grid->ictxcol, "R", size, 1);
1810:     PetscCallMPI(MPI_Comm_set_attr(icomm, Petsc_ScaLAPACK_keyval, (void *)grid));

1812:   } else grid->grid_refct++;
1813:   PetscCall(PetscCommDestroy(&icomm));
1814:   a->grid = grid;
1815:   a->mb   = DEFAULT_BLOCKSIZE;
1816:   a->nb   = DEFAULT_BLOCKSIZE;

1818:   PetscOptionsBegin(PetscObjectComm((PetscObject)A), NULL, "ScaLAPACK Options", "Mat");
1819:   PetscCall(PetscOptionsIntArray("-mat_scalapack_block_sizes", "Size of the blocks to use (one or two comma-separated integers)", "MatCreateScaLAPACK", array, &k, &flg));
1820:   if (flg) {
1821:     a->mb = (PetscMPIInt)array[0];
1822:     a->nb = (k > 1) ? (PetscMPIInt)array[1] : a->mb;
1823:   }
1824:   PetscOptionsEnd();

1826:   a->roworiented = PETSC_TRUE;
1827:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatGetOwnershipIS_C", MatGetOwnershipIS_ScaLAPACK));
1828:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatScaLAPACKSetBlockSizes_C", MatScaLAPACKSetBlockSizes_ScaLAPACK));
1829:   PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatScaLAPACKGetBlockSizes_C", MatScaLAPACKGetBlockSizes_ScaLAPACK));
1830:   PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATSCALAPACK));
1831:   PetscFunctionReturn(PETSC_SUCCESS);
1832: }

1834: /*@C
1835:   MatCreateScaLAPACK - Creates a dense parallel matrix in ScaLAPACK format
1836:   (2D block cyclic distribution) for a `MATSCALAPACK` matrix

1838:   Collective

1840:   Input Parameters:
1841: + comm - MPI communicator
1842: . mb   - row block size (or `PETSC_DECIDE` to have it set)
1843: . nb   - column block size (or `PETSC_DECIDE` to have it set)
1844: . M    - number of global rows
1845: . N    - number of global columns
1846: . rsrc - coordinate of process that owns the first row of the distributed matrix
1847: - csrc - coordinate of process that owns the first column of the distributed matrix

1849:   Output Parameter:
1850: . A - the matrix

1852:   Options Database Key:
1853: . -mat_scalapack_block_sizes - size of the blocks to use (one or two integers separated by comma)

1855:   Level: intermediate

1857:   Notes:
1858:   If `PETSC_DECIDE` is used for the block sizes, then an appropriate value is chosen

1860:   It is recommended that one use the `MatCreate()`, `MatSetType()` and/or `MatSetFromOptions()`,
1861:   MatXXXXSetPreallocation() paradigm instead of this routine directly.
1862:   [MatXXXXSetPreallocation() is, for example, `MatSeqAIJSetPreallocation()`]

1864:   Storage is completely managed by ScaLAPACK, so this requires PETSc to be
1865:   configured with ScaLAPACK. In particular, PETSc's local sizes lose
1866:   significance and are thus ignored. The block sizes refer to the values
1867:   used for the distributed matrix, not the same meaning as in `MATBAIJ`.

1869: .seealso: [](ch_matrices), `Mat`, `MATSCALAPACK`, `MATDENSE`, `MATELEMENTAL`, `MatCreate()`, `MatCreateDense()`, `MatSetValues()`
1870: @*/
1871: PetscErrorCode MatCreateScaLAPACK(MPI_Comm comm, PetscInt mb, PetscInt nb, PetscInt M, PetscInt N, PetscInt rsrc, PetscInt csrc, Mat *A)
1872: {
1873:   Mat_ScaLAPACK *a;
1874:   PetscInt       m, n;

1876:   PetscFunctionBegin;
1877:   PetscCall(MatCreate(comm, A));
1878:   PetscCall(MatSetType(*A, MATSCALAPACK));
1879:   PetscCheck(M != PETSC_DECIDE && N != PETSC_DECIDE, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot use PETSC_DECIDE for matrix dimensions");
1880:   /* rows and columns are NOT distributed according to PetscSplitOwnership */
1881:   m = PETSC_DECIDE;
1882:   PetscCall(PetscSplitOwnershipEqual(comm, &m, &M));
1883:   n = PETSC_DECIDE;
1884:   PetscCall(PetscSplitOwnershipEqual(comm, &n, &N));
1885:   PetscCall(MatSetSizes(*A, m, n, M, N));
1886:   a = (Mat_ScaLAPACK *)(*A)->data;
1887:   PetscCall(PetscBLASIntCast(M, &a->M));
1888:   PetscCall(PetscBLASIntCast(N, &a->N));
1889:   PetscCall(PetscBLASIntCast((mb == PETSC_DECIDE) ? DEFAULT_BLOCKSIZE : mb, &a->mb));
1890:   PetscCall(PetscBLASIntCast((nb == PETSC_DECIDE) ? a->mb : nb, &a->nb));
1891:   PetscCall(PetscBLASIntCast(rsrc, &a->rsrc));
1892:   PetscCall(PetscBLASIntCast(csrc, &a->csrc));
1893:   PetscCall(MatSetUp(*A));
1894:   PetscFunctionReturn(PETSC_SUCCESS);
1895: }