Actual source code: mpisell.c
1: #include <../src/mat/impls/aij/mpi/mpiaij.h>
2: #include <../src/mat/impls/sell/mpi/mpisell.h>
3: #include <petsc/private/vecimpl.h>
4: #include <petsc/private/isimpl.h>
5: #include <petscblaslapack.h>
6: #include <petscsf.h>
8: /*MC
9: MATSELL - MATSELL = "sell" - A matrix type to be used for sparse matrices.
11: This matrix type is identical to `MATSEQSELL` when constructed with a single process communicator,
12: and `MATMPISELL` otherwise. As a result, for single process communicators,
13: `MatSeqSELLSetPreallocation()` is supported, and similarly `MatMPISELLSetPreallocation()` is supported
14: for communicators controlling multiple processes. It is recommended that you call both of
15: the above preallocation routines for simplicity.
17: Options Database Keys:
18: . -mat_type sell - sets the matrix type to `MATSELL` during a call to `MatSetFromOptions()`
20: Level: beginner
22: .seealso: `Mat`, `MATAIJ`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSELL()`, `MatCreateSeqSELL()`, `MATSEQSELL`, `MATMPISELL`
23: M*/
25: static PetscErrorCode MatDiagonalSet_MPISELL(Mat Y, Vec D, InsertMode is)
26: {
27: Mat_MPISELL *sell = (Mat_MPISELL *)Y->data;
29: PetscFunctionBegin;
30: if (Y->assembled && Y->rmap->rstart == Y->cmap->rstart && Y->rmap->rend == Y->cmap->rend) {
31: PetscCall(MatDiagonalSet(sell->A, D, is));
32: } else {
33: PetscCall(MatDiagonalSet_Default(Y, D, is));
34: }
35: PetscFunctionReturn(PETSC_SUCCESS);
36: }
38: /*
39: Local utility routine that creates a mapping from the global column
40: number to the local number in the off-diagonal part of the local
41: storage of the matrix. When PETSC_USE_CTABLE is used this is scalable at
42: a slightly higher hash table cost; without it it is not scalable (each processor
43: has an order N integer array but is fast to access.
44: */
45: PetscErrorCode MatCreateColmap_MPISELL_Private(Mat mat)
46: {
47: Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
48: PetscInt n = sell->B->cmap->n, i;
50: PetscFunctionBegin;
51: PetscCheck(sell->garray, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MPISELL Matrix was assembled but is missing garray");
52: #if defined(PETSC_USE_CTABLE)
53: PetscCall(PetscHMapICreateWithSize(n, &sell->colmap));
54: for (i = 0; i < n; i++) PetscCall(PetscHMapISet(sell->colmap, sell->garray[i] + 1, i + 1));
55: #else
56: PetscCall(PetscCalloc1(mat->cmap->N + 1, &sell->colmap));
57: for (i = 0; i < n; i++) sell->colmap[sell->garray[i]] = i + 1;
58: #endif
59: PetscFunctionReturn(PETSC_SUCCESS);
60: }
62: #define MatSetValues_SeqSELL_A_Private(row, col, value, addv, orow, ocol) \
63: { \
64: if (col <= lastcol1) low1 = 0; \
65: else high1 = nrow1; \
66: lastcol1 = col; \
67: while (high1 - low1 > 5) { \
68: t = (low1 + high1) / 2; \
69: if (cp1[sliceheight * t] > col) high1 = t; \
70: else low1 = t; \
71: } \
72: for (_i = low1; _i < high1; _i++) { \
73: if (cp1[sliceheight * _i] > col) break; \
74: if (cp1[sliceheight * _i] == col) { \
75: if (addv == ADD_VALUES) vp1[sliceheight * _i] += value; \
76: else vp1[sliceheight * _i] = value; \
77: inserted = PETSC_TRUE; \
78: goto a_noinsert; \
79: } \
80: } \
81: if (value == 0.0 && ignorezeroentries) { \
82: low1 = 0; \
83: high1 = nrow1; \
84: goto a_noinsert; \
85: } \
86: if (nonew == 1) { \
87: low1 = 0; \
88: high1 = nrow1; \
89: goto a_noinsert; \
90: } \
91: PetscCheck(nonew != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero at global row/column (%" PetscInt_FMT ", %" PetscInt_FMT ") into matrix", orow, ocol); \
92: MatSeqXSELLReallocateSELL(A, am, 1, nrow1, a->sliidx, a->sliceheight, row / sliceheight, row, col, a->colidx, a->val, cp1, vp1, nonew, MatScalar); \
93: /* shift up all the later entries in this row */ \
94: for (ii = nrow1 - 1; ii >= _i; ii--) { \
95: cp1[sliceheight * (ii + 1)] = cp1[sliceheight * ii]; \
96: vp1[sliceheight * (ii + 1)] = vp1[sliceheight * ii]; \
97: } \
98: cp1[sliceheight * _i] = col; \
99: vp1[sliceheight * _i] = value; \
100: a->nz++; \
101: nrow1++; \
102: a_noinsert:; \
103: a->rlen[row] = nrow1; \
104: }
106: #define MatSetValues_SeqSELL_B_Private(row, col, value, addv, orow, ocol) \
107: { \
108: if (col <= lastcol2) low2 = 0; \
109: else high2 = nrow2; \
110: lastcol2 = col; \
111: while (high2 - low2 > 5) { \
112: t = (low2 + high2) / 2; \
113: if (cp2[sliceheight * t] > col) high2 = t; \
114: else low2 = t; \
115: } \
116: for (_i = low2; _i < high2; _i++) { \
117: if (cp2[sliceheight * _i] > col) break; \
118: if (cp2[sliceheight * _i] == col) { \
119: if (addv == ADD_VALUES) vp2[sliceheight * _i] += value; \
120: else vp2[sliceheight * _i] = value; \
121: inserted = PETSC_TRUE; \
122: goto b_noinsert; \
123: } \
124: } \
125: if (value == 0.0 && ignorezeroentries) { \
126: low2 = 0; \
127: high2 = nrow2; \
128: goto b_noinsert; \
129: } \
130: if (nonew == 1) { \
131: low2 = 0; \
132: high2 = nrow2; \
133: goto b_noinsert; \
134: } \
135: PetscCheck(nonew != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero at global row/column (%" PetscInt_FMT ", %" PetscInt_FMT ") into matrix", orow, ocol); \
136: MatSeqXSELLReallocateSELL(B, bm, 1, nrow2, b->sliidx, b->sliceheight, row / sliceheight, row, col, b->colidx, b->val, cp2, vp2, nonew, MatScalar); \
137: /* shift up all the later entries in this row */ \
138: for (ii = nrow2 - 1; ii >= _i; ii--) { \
139: cp2[sliceheight * (ii + 1)] = cp2[sliceheight * ii]; \
140: vp2[sliceheight * (ii + 1)] = vp2[sliceheight * ii]; \
141: } \
142: cp2[sliceheight * _i] = col; \
143: vp2[sliceheight * _i] = value; \
144: b->nz++; \
145: nrow2++; \
146: b_noinsert:; \
147: b->rlen[row] = nrow2; \
148: }
150: static PetscErrorCode MatSetValues_MPISELL(Mat mat, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode addv)
151: {
152: Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
153: PetscScalar value;
154: PetscInt i, j, rstart = mat->rmap->rstart, rend = mat->rmap->rend, shift1, shift2;
155: PetscInt cstart = mat->cmap->rstart, cend = mat->cmap->rend, row, col;
156: PetscBool roworiented = sell->roworiented;
158: /* Some Variables required in the macro */
159: Mat A = sell->A;
160: Mat_SeqSELL *a = (Mat_SeqSELL *)A->data;
161: PetscBool ignorezeroentries = a->ignorezeroentries, found;
162: Mat B = sell->B;
163: Mat_SeqSELL *b = (Mat_SeqSELL *)B->data;
164: PetscInt *cp1, *cp2, ii, _i, nrow1, nrow2, low1, high1, low2, high2, t, lastcol1, lastcol2, sliceheight = a->sliceheight;
165: MatScalar *vp1, *vp2;
167: PetscFunctionBegin;
168: for (i = 0; i < m; i++) {
169: if (im[i] < 0) continue;
170: PetscCheck(im[i] < mat->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, im[i], mat->rmap->N - 1);
171: if (im[i] >= rstart && im[i] < rend) {
172: row = im[i] - rstart;
173: lastcol1 = -1;
174: shift1 = a->sliidx[row / sliceheight] + (row % sliceheight); /* starting index of the row */
175: cp1 = PetscSafePointerPlusOffset(a->colidx, shift1);
176: vp1 = PetscSafePointerPlusOffset(a->val, shift1);
177: nrow1 = a->rlen[row];
178: low1 = 0;
179: high1 = nrow1;
180: lastcol2 = -1;
181: shift2 = b->sliidx[row / sliceheight] + (row % sliceheight); /* starting index of the row */
182: cp2 = PetscSafePointerPlusOffset(b->colidx, shift2);
183: vp2 = PetscSafePointerPlusOffset(b->val, shift2);
184: nrow2 = b->rlen[row];
185: low2 = 0;
186: high2 = nrow2;
188: for (j = 0; j < n; j++) {
189: if (roworiented) value = v[i * n + j];
190: else value = v[i + j * m];
191: if (ignorezeroentries && value == 0.0 && (addv == ADD_VALUES)) continue;
192: if (in[j] >= cstart && in[j] < cend) {
193: col = in[j] - cstart;
194: MatSetValue_SeqSELL_Private(A, row, col, value, addv, im[i], in[j], cp1, vp1, lastcol1, low1, high1); /* set one value */
195: #if defined(PETSC_HAVE_CUDA)
196: if (A->offloadmask != PETSC_OFFLOAD_UNALLOCATED && found) A->offloadmask = PETSC_OFFLOAD_CPU;
197: #endif
198: } else if (in[j] < 0) {
199: continue;
200: } else {
201: PetscCheck(in[j] < mat->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, in[j], mat->cmap->N - 1);
202: if (mat->was_assembled) {
203: if (!sell->colmap) PetscCall(MatCreateColmap_MPISELL_Private(mat));
204: #if defined(PETSC_USE_CTABLE)
205: PetscCall(PetscHMapIGetWithDefault(sell->colmap, in[j] + 1, 0, &col));
206: col--;
207: #else
208: col = sell->colmap[in[j]] - 1;
209: #endif
210: if (col < 0 && !((Mat_SeqSELL *)sell->B->data)->nonew) {
211: PetscCall(MatDisAssemble_MPISELL(mat));
212: col = in[j];
213: /* Reinitialize the variables required by MatSetValues_SeqSELL_B_Private() */
214: B = sell->B;
215: b = (Mat_SeqSELL *)B->data;
216: shift2 = b->sliidx[row / sliceheight] + (row % sliceheight); /* starting index of the row */
217: cp2 = b->colidx + shift2;
218: vp2 = b->val + shift2;
219: nrow2 = b->rlen[row];
220: low2 = 0;
221: high2 = nrow2;
222: found = PETSC_FALSE;
223: } else {
224: PetscCheck(col >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Inserting a new nonzero at global row/column (%" PetscInt_FMT ", %" PetscInt_FMT ") into matrix", im[i], in[j]);
225: }
226: } else col = in[j];
227: MatSetValue_SeqSELL_Private(B, row, col, value, addv, im[i], in[j], cp2, vp2, lastcol2, low2, high2); /* set one value */
228: #if defined(PETSC_HAVE_CUDA)
229: if (B->offloadmask != PETSC_OFFLOAD_UNALLOCATED && found) B->offloadmask = PETSC_OFFLOAD_CPU;
230: #endif
231: }
232: }
233: } else {
234: PetscCheck(!mat->nooffprocentries, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Setting off process row %" PetscInt_FMT " even though MatSetOption(,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE) was set", im[i]);
235: if (!sell->donotstash) {
236: mat->assembled = PETSC_FALSE;
237: if (roworiented) {
238: PetscCall(MatStashValuesRow_Private(&mat->stash, im[i], n, in, v + i * n, (PetscBool)(ignorezeroentries && (addv == ADD_VALUES))));
239: } else {
240: PetscCall(MatStashValuesCol_Private(&mat->stash, im[i], n, in, v + i, m, (PetscBool)(ignorezeroentries && (addv == ADD_VALUES))));
241: }
242: }
243: }
244: }
245: PetscFunctionReturn(PETSC_SUCCESS);
246: }
248: static PetscErrorCode MatGetValues_MPISELL(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], PetscScalar v[])
249: {
250: Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
251: PetscInt i, j, rstart = mat->rmap->rstart, rend = mat->rmap->rend;
252: PetscInt cstart = mat->cmap->rstart, cend = mat->cmap->rend, row, col;
254: PetscFunctionBegin;
255: for (i = 0; i < m; i++) {
256: if (idxm[i] < 0) continue; /* negative row */
257: PetscCheck(idxm[i] < mat->rmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm[i], mat->rmap->N - 1);
258: PetscCheck(idxm[i] >= rstart && idxm[i] < rend, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only local values currently supported");
259: row = idxm[i] - rstart;
260: for (j = 0; j < n; j++) {
261: if (idxn[j] < 0) continue; /* negative column */
262: PetscCheck(idxn[j] < mat->cmap->N, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Column too large: col %" PetscInt_FMT " max %" PetscInt_FMT, idxn[j], mat->cmap->N - 1);
263: if (idxn[j] >= cstart && idxn[j] < cend) {
264: col = idxn[j] - cstart;
265: PetscCall(MatGetValues(sell->A, 1, &row, 1, &col, v + i * n + j));
266: } else {
267: if (!sell->colmap) PetscCall(MatCreateColmap_MPISELL_Private(mat));
268: #if defined(PETSC_USE_CTABLE)
269: PetscCall(PetscHMapIGetWithDefault(sell->colmap, idxn[j] + 1, 0, &col));
270: col--;
271: #else
272: col = sell->colmap[idxn[j]] - 1;
273: #endif
274: if (col < 0 || sell->garray[col] != idxn[j]) *(v + i * n + j) = 0.0;
275: else PetscCall(MatGetValues(sell->B, 1, &row, 1, &col, v + i * n + j));
276: }
277: }
278: }
279: PetscFunctionReturn(PETSC_SUCCESS);
280: }
282: static PetscErrorCode MatAssemblyBegin_MPISELL(Mat mat, MatAssemblyType mode)
283: {
284: Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
285: PetscInt nstash, reallocs;
287: PetscFunctionBegin;
288: if (sell->donotstash || mat->nooffprocentries) PetscFunctionReturn(PETSC_SUCCESS);
290: PetscCall(MatStashScatterBegin_Private(mat, &mat->stash, mat->rmap->range));
291: PetscCall(MatStashGetInfo_Private(&mat->stash, &nstash, &reallocs));
292: PetscCall(PetscInfo(sell->A, "Stash has %" PetscInt_FMT " entries, uses %" PetscInt_FMT " mallocs.\n", nstash, reallocs));
293: PetscFunctionReturn(PETSC_SUCCESS);
294: }
296: PetscErrorCode MatAssemblyEnd_MPISELL(Mat mat, MatAssemblyType mode)
297: {
298: Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
299: PetscMPIInt n;
300: PetscInt i, flg;
301: PetscInt *row, *col;
302: PetscScalar *val;
303: PetscBool all_assembled;
304: /* do not use 'b = (Mat_SeqSELL*)sell->B->data' as B can be reset in disassembly */
305: PetscFunctionBegin;
306: if (!sell->donotstash && !mat->nooffprocentries) {
307: while (1) {
308: PetscCall(MatStashScatterGetMesg_Private(&mat->stash, &n, &row, &col, &val, &flg));
309: if (!flg) break;
311: for (i = 0; i < n; i++) { /* assemble one by one */
312: PetscCall(MatSetValues_MPISELL(mat, 1, row + i, 1, col + i, val + i, mat->insertmode));
313: }
314: }
315: PetscCall(MatStashScatterEnd_Private(&mat->stash));
316: }
317: #if defined(PETSC_HAVE_CUDA)
318: if (mat->offloadmask == PETSC_OFFLOAD_CPU) sell->A->offloadmask = PETSC_OFFLOAD_CPU;
319: #endif
320: PetscCall(MatAssemblyBegin(sell->A, mode));
321: PetscCall(MatAssemblyEnd(sell->A, mode));
323: /*
324: determine if any process has disassembled, if so we must
325: also disassemble ourselves, in order that we may reassemble.
326: */
327: /*
328: if nonzero structure of submatrix B cannot change then we know that
329: no process disassembled thus we can skip this stuff
330: */
331: if (!((Mat_SeqSELL *)sell->B->data)->nonew) {
332: PetscCallMPI(MPIU_Allreduce(&mat->was_assembled, &all_assembled, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
333: if (mat->was_assembled && !all_assembled) PetscCall(MatDisAssemble_MPISELL(mat));
334: }
335: if (!mat->was_assembled && mode == MAT_FINAL_ASSEMBLY) PetscCall(MatSetUpMultiply_MPISELL(mat));
336: #if defined(PETSC_HAVE_CUDA)
337: if (mat->offloadmask == PETSC_OFFLOAD_CPU && sell->B->offloadmask != PETSC_OFFLOAD_UNALLOCATED) sell->B->offloadmask = PETSC_OFFLOAD_CPU;
338: #endif
339: PetscCall(MatAssemblyBegin(sell->B, mode));
340: PetscCall(MatAssemblyEnd(sell->B, mode));
341: PetscCall(PetscFree2(sell->rowvalues, sell->rowindices));
342: sell->rowvalues = NULL;
343: PetscCall(VecDestroy(&sell->diag));
345: /* if no new nonzero locations are allowed in matrix then only set the matrix state the first time through */
346: if ((!mat->was_assembled && mode == MAT_FINAL_ASSEMBLY) || !((Mat_SeqSELL *)sell->A->data)->nonew) {
347: PetscObjectState state = sell->A->nonzerostate + sell->B->nonzerostate;
348: PetscCallMPI(MPIU_Allreduce(&state, &mat->nonzerostate, 1, MPIU_INT64, MPI_SUM, PetscObjectComm((PetscObject)mat)));
349: }
350: #if defined(PETSC_HAVE_CUDA)
351: mat->offloadmask = PETSC_OFFLOAD_BOTH;
352: #endif
353: PetscFunctionReturn(PETSC_SUCCESS);
354: }
356: static PetscErrorCode MatZeroEntries_MPISELL(Mat A)
357: {
358: Mat_MPISELL *l = (Mat_MPISELL *)A->data;
360: PetscFunctionBegin;
361: PetscCall(MatZeroEntries(l->A));
362: PetscCall(MatZeroEntries(l->B));
363: PetscFunctionReturn(PETSC_SUCCESS);
364: }
366: static PetscErrorCode MatMult_MPISELL(Mat A, Vec xx, Vec yy)
367: {
368: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
369: PetscInt nt;
371: PetscFunctionBegin;
372: PetscCall(VecGetLocalSize(xx, &nt));
373: PetscCheck(nt == A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Incompatible partition of A (%" PetscInt_FMT ") and xx (%" PetscInt_FMT ")", A->cmap->n, nt);
374: PetscCall(VecScatterBegin(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
375: PetscUseTypeMethod(a->A, mult, xx, yy);
376: PetscCall(VecScatterEnd(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
377: PetscUseTypeMethod(a->B, multadd, a->lvec, yy, yy);
378: PetscFunctionReturn(PETSC_SUCCESS);
379: }
381: static PetscErrorCode MatGetMultPetscSF_MPISELL(Mat A, PetscSF *sf)
382: {
383: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
385: PetscFunctionBegin;
386: *sf = a->Mvctx;
387: PetscFunctionReturn(PETSC_SUCCESS);
388: }
390: static PetscErrorCode MatMultDiagonalBlock_MPISELL(Mat A, Vec bb, Vec xx)
391: {
392: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
394: PetscFunctionBegin;
395: PetscCall(MatMultDiagonalBlock(a->A, bb, xx));
396: PetscFunctionReturn(PETSC_SUCCESS);
397: }
399: static PetscErrorCode MatMultAdd_MPISELL(Mat A, Vec xx, Vec yy, Vec zz)
400: {
401: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
403: PetscFunctionBegin;
404: PetscCall(VecScatterBegin(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
405: PetscUseTypeMethod(a->A, multadd, xx, yy, zz);
406: PetscCall(VecScatterEnd(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
407: PetscUseTypeMethod(a->B, multadd, a->lvec, zz, zz);
408: PetscFunctionReturn(PETSC_SUCCESS);
409: }
411: static PetscErrorCode MatMultTranspose_MPISELL(Mat A, Vec xx, Vec yy)
412: {
413: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
415: PetscFunctionBegin;
416: /* do nondiagonal part */
417: PetscUseTypeMethod(a->B, multtranspose, xx, a->lvec);
418: /* do local part */
419: PetscUseTypeMethod(a->A, multtranspose, xx, yy);
420: /* add partial results together */
421: PetscCall(VecScatterBegin(a->Mvctx, a->lvec, yy, ADD_VALUES, SCATTER_REVERSE));
422: PetscCall(VecScatterEnd(a->Mvctx, a->lvec, yy, ADD_VALUES, SCATTER_REVERSE));
423: PetscFunctionReturn(PETSC_SUCCESS);
424: }
426: static PetscErrorCode MatIsTranspose_MPISELL(Mat Amat, Mat Bmat, PetscReal tol, PetscBool *f)
427: {
428: MPI_Comm comm;
429: Mat_MPISELL *Asell = (Mat_MPISELL *)Amat->data, *Bsell;
430: Mat Adia = Asell->A, Bdia, Aoff, Boff, *Aoffs, *Boffs;
431: IS Me, Notme;
432: PetscInt M, N, first, last, *notme, i;
433: PetscMPIInt size;
435: PetscFunctionBegin;
436: /* Easy test: symmetric diagonal block */
437: Bsell = (Mat_MPISELL *)Bmat->data;
438: Bdia = Bsell->A;
439: PetscCall(MatIsTranspose(Adia, Bdia, tol, f));
440: if (!*f) PetscFunctionReturn(PETSC_SUCCESS);
441: PetscCall(PetscObjectGetComm((PetscObject)Amat, &comm));
442: PetscCallMPI(MPI_Comm_size(comm, &size));
443: if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
445: /* Hard test: off-diagonal block. This takes a MatCreateSubMatrix. */
446: PetscCall(MatGetSize(Amat, &M, &N));
447: PetscCall(MatGetOwnershipRange(Amat, &first, &last));
448: PetscCall(PetscMalloc1(N - last + first, ¬me));
449: for (i = 0; i < first; i++) notme[i] = i;
450: for (i = last; i < M; i++) notme[i - last + first] = i;
451: PetscCall(ISCreateGeneral(MPI_COMM_SELF, N - last + first, notme, PETSC_COPY_VALUES, &Notme));
452: PetscCall(ISCreateStride(MPI_COMM_SELF, last - first, first, 1, &Me));
453: PetscCall(MatCreateSubMatrices(Amat, 1, &Me, &Notme, MAT_INITIAL_MATRIX, &Aoffs));
454: Aoff = Aoffs[0];
455: PetscCall(MatCreateSubMatrices(Bmat, 1, &Notme, &Me, MAT_INITIAL_MATRIX, &Boffs));
456: Boff = Boffs[0];
457: PetscCall(MatIsTranspose(Aoff, Boff, tol, f));
458: PetscCall(MatDestroyMatrices(1, &Aoffs));
459: PetscCall(MatDestroyMatrices(1, &Boffs));
460: PetscCall(ISDestroy(&Me));
461: PetscCall(ISDestroy(&Notme));
462: PetscCall(PetscFree(notme));
463: PetscFunctionReturn(PETSC_SUCCESS);
464: }
466: static PetscErrorCode MatMultTransposeAdd_MPISELL(Mat A, Vec xx, Vec yy, Vec zz)
467: {
468: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
470: PetscFunctionBegin;
471: /* do nondiagonal part */
472: PetscUseTypeMethod(a->B, multtranspose, xx, a->lvec);
473: /* do local part */
474: PetscUseTypeMethod(a->A, multtransposeadd, xx, yy, zz);
475: /* add partial results together */
476: PetscCall(VecScatterBegin(a->Mvctx, a->lvec, zz, ADD_VALUES, SCATTER_REVERSE));
477: PetscCall(VecScatterEnd(a->Mvctx, a->lvec, zz, ADD_VALUES, SCATTER_REVERSE));
478: PetscFunctionReturn(PETSC_SUCCESS);
479: }
481: /*
482: This only works correctly for square matrices where the subblock A->A is the
483: diagonal block
484: */
485: static PetscErrorCode MatGetDiagonal_MPISELL(Mat A, Vec v)
486: {
487: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
489: PetscFunctionBegin;
490: PetscCheck(A->rmap->N == A->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Supports only square matrix where A->A is diag block");
491: PetscCheck(A->rmap->rstart == A->cmap->rstart && A->rmap->rend == A->cmap->rend, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "row partition must equal col partition");
492: PetscCall(MatGetDiagonal(a->A, v));
493: PetscFunctionReturn(PETSC_SUCCESS);
494: }
496: static PetscErrorCode MatScale_MPISELL(Mat A, PetscScalar aa)
497: {
498: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
500: PetscFunctionBegin;
501: PetscCall(MatScale(a->A, aa));
502: PetscCall(MatScale(a->B, aa));
503: PetscFunctionReturn(PETSC_SUCCESS);
504: }
506: PetscErrorCode MatDestroy_MPISELL(Mat mat)
507: {
508: Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
510: PetscFunctionBegin;
511: PetscCall(PetscLogObjectState((PetscObject)mat, "Rows=%" PetscInt_FMT ", Cols=%" PetscInt_FMT, mat->rmap->N, mat->cmap->N));
512: PetscCall(MatStashDestroy_Private(&mat->stash));
513: PetscCall(VecDestroy(&sell->diag));
514: PetscCall(MatDestroy(&sell->A));
515: PetscCall(MatDestroy(&sell->B));
516: #if defined(PETSC_USE_CTABLE)
517: PetscCall(PetscHMapIDestroy(&sell->colmap));
518: #else
519: PetscCall(PetscFree(sell->colmap));
520: #endif
521: PetscCall(PetscFree(sell->garray));
522: PetscCall(VecDestroy(&sell->lvec));
523: PetscCall(VecScatterDestroy(&sell->Mvctx));
524: PetscCall(PetscFree2(sell->rowvalues, sell->rowindices));
525: PetscCall(PetscFree(sell->ld));
526: PetscCall(PetscFree(mat->data));
528: PetscCall(PetscObjectChangeTypeName((PetscObject)mat, NULL));
529: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatStoreValues_C", NULL));
530: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatRetrieveValues_C", NULL));
531: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatIsTranspose_C", NULL));
532: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMPISELLSetPreallocation_C", NULL));
533: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpisell_mpiaij_C", NULL));
534: #if defined(PETSC_HAVE_CUDA)
535: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpisell_mpisellcuda_C", NULL));
536: #endif
537: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalScaleLocal_C", NULL));
538: PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatGetMultPetscSF_C", NULL));
539: PetscFunctionReturn(PETSC_SUCCESS);
540: }
542: #include <petscdraw.h>
543: static PetscErrorCode MatView_MPISELL_ASCIIorDraworSocket(Mat mat, PetscViewer viewer)
544: {
545: Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
546: PetscMPIInt rank = sell->rank, size = sell->size;
547: PetscBool isdraw, isascii, isbinary;
548: PetscViewer sviewer;
549: PetscViewerFormat format;
551: PetscFunctionBegin;
552: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
553: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
554: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
555: if (isascii) {
556: PetscCall(PetscViewerGetFormat(viewer, &format));
557: if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
558: MatInfo info;
559: PetscInt *inodes;
561: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank));
562: PetscCall(MatGetInfo(mat, MAT_LOCAL, &info));
563: PetscCall(MatInodeGetInodeSizes(sell->A, NULL, &inodes, NULL));
564: PetscCall(PetscViewerASCIIPushSynchronized(viewer));
565: if (!inodes) {
566: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Local rows %" PetscInt_FMT " nz %" PetscInt_FMT " nz alloced %" PetscInt_FMT " mem %" PetscInt_FMT ", not using I-node routines\n", rank, mat->rmap->n, (PetscInt)info.nz_used,
567: (PetscInt)info.nz_allocated, (PetscInt)info.memory));
568: } else {
569: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Local rows %" PetscInt_FMT " nz %" PetscInt_FMT " nz alloced %" PetscInt_FMT " mem %" PetscInt_FMT ", using I-node routines\n", rank, mat->rmap->n, (PetscInt)info.nz_used,
570: (PetscInt)info.nz_allocated, (PetscInt)info.memory));
571: }
572: PetscCall(MatGetInfo(sell->A, MAT_LOCAL, &info));
573: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] on-diagonal part: nz %" PetscInt_FMT " \n", rank, (PetscInt)info.nz_used));
574: PetscCall(MatGetInfo(sell->B, MAT_LOCAL, &info));
575: PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] off-diagonal part: nz %" PetscInt_FMT " \n", rank, (PetscInt)info.nz_used));
576: PetscCall(PetscViewerFlush(viewer));
577: PetscCall(PetscViewerASCIIPopSynchronized(viewer));
578: PetscCall(PetscViewerASCIIPrintf(viewer, "Information on VecScatter used in matrix-vector product: \n"));
579: PetscCall(VecScatterView(sell->Mvctx, viewer));
580: PetscFunctionReturn(PETSC_SUCCESS);
581: } else if (format == PETSC_VIEWER_ASCII_INFO) {
582: PetscInt inodecount, inodelimit, *inodes;
583: PetscCall(MatInodeGetInodeSizes(sell->A, &inodecount, &inodes, &inodelimit));
584: if (inodes) {
585: PetscCall(PetscViewerASCIIPrintf(viewer, "using I-node (on process 0) routines: found %" PetscInt_FMT " nodes, limit used is %" PetscInt_FMT "\n", inodecount, inodelimit));
586: } else {
587: PetscCall(PetscViewerASCIIPrintf(viewer, "not using I-node (on process 0) routines\n"));
588: }
589: PetscFunctionReturn(PETSC_SUCCESS);
590: } else if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
591: PetscFunctionReturn(PETSC_SUCCESS);
592: }
593: } else if (isbinary) {
594: if (size == 1) {
595: PetscCall(PetscObjectSetName((PetscObject)sell->A, ((PetscObject)mat)->name));
596: PetscCall(MatView(sell->A, viewer));
597: } else {
598: /* PetscCall(MatView_MPISELL_Binary(mat,viewer)); */
599: }
600: PetscFunctionReturn(PETSC_SUCCESS);
601: } else if (isdraw) {
602: PetscDraw draw;
603: PetscBool isnull;
604: PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
605: PetscCall(PetscDrawIsNull(draw, &isnull));
606: if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
607: }
609: {
610: /* assemble the entire matrix onto first processor. */
611: Mat A;
612: Mat_SeqSELL *Aloc;
613: PetscInt M = mat->rmap->N, N = mat->cmap->N, *acolidx, row, col, i, j;
614: MatScalar *aval;
615: PetscBool isnonzero;
617: PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &A));
618: if (rank == 0) {
619: PetscCall(MatSetSizes(A, M, N, M, N));
620: } else {
621: PetscCall(MatSetSizes(A, 0, 0, M, N));
622: }
623: /* This is just a temporary matrix, so explicitly using MATMPISELL is probably best */
624: PetscCall(MatSetType(A, MATMPISELL));
625: PetscCall(MatMPISELLSetPreallocation(A, 0, NULL, 0, NULL));
626: PetscCall(MatSetOption(A, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
628: /* copy over the A part */
629: Aloc = (Mat_SeqSELL *)sell->A->data;
630: acolidx = Aloc->colidx;
631: aval = Aloc->val;
632: for (i = 0; i < Aloc->totalslices; i++) { /* loop over slices */
633: for (j = Aloc->sliidx[i]; j < Aloc->sliidx[i + 1]; j++) {
634: isnonzero = (PetscBool)((j - Aloc->sliidx[i]) / Aloc->sliceheight < Aloc->rlen[i * Aloc->sliceheight + j % Aloc->sliceheight]);
635: if (isnonzero) { /* check the mask bit */
636: row = i * Aloc->sliceheight + j % Aloc->sliceheight + mat->rmap->rstart;
637: col = *acolidx + mat->rmap->rstart;
638: PetscCall(MatSetValues(A, 1, &row, 1, &col, aval, INSERT_VALUES));
639: }
640: aval++;
641: acolidx++;
642: }
643: }
645: /* copy over the B part */
646: Aloc = (Mat_SeqSELL *)sell->B->data;
647: acolidx = Aloc->colidx;
648: aval = Aloc->val;
649: for (i = 0; i < Aloc->totalslices; i++) {
650: for (j = Aloc->sliidx[i]; j < Aloc->sliidx[i + 1]; j++) {
651: isnonzero = (PetscBool)((j - Aloc->sliidx[i]) / Aloc->sliceheight < Aloc->rlen[i * Aloc->sliceheight + j % Aloc->sliceheight]);
652: if (isnonzero) {
653: row = i * Aloc->sliceheight + j % Aloc->sliceheight + mat->rmap->rstart;
654: col = sell->garray[*acolidx];
655: PetscCall(MatSetValues(A, 1, &row, 1, &col, aval, INSERT_VALUES));
656: }
657: aval++;
658: acolidx++;
659: }
660: }
662: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
663: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
664: /*
665: Everyone has to call to draw the matrix since the graphics waits are
666: synchronized across all processors that share the PetscDraw object
667: */
668: PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
669: if (rank == 0) {
670: PetscCall(PetscObjectSetName((PetscObject)((Mat_MPISELL *)A->data)->A, ((PetscObject)mat)->name));
671: PetscCall(MatView_SeqSELL(((Mat_MPISELL *)A->data)->A, sviewer));
672: }
673: PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
674: PetscCall(MatDestroy(&A));
675: }
676: PetscFunctionReturn(PETSC_SUCCESS);
677: }
679: static PetscErrorCode MatView_MPISELL(Mat mat, PetscViewer viewer)
680: {
681: PetscBool isascii, isdraw, issocket, isbinary;
683: PetscFunctionBegin;
684: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
685: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
686: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
687: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSOCKET, &issocket));
688: if (isascii || isdraw || isbinary || issocket) PetscCall(MatView_MPISELL_ASCIIorDraworSocket(mat, viewer));
689: PetscFunctionReturn(PETSC_SUCCESS);
690: }
692: static PetscErrorCode MatGetGhosts_MPISELL(Mat mat, PetscInt *nghosts, const PetscInt *ghosts[])
693: {
694: Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
696: PetscFunctionBegin;
697: PetscCall(MatGetSize(sell->B, NULL, nghosts));
698: if (ghosts) *ghosts = sell->garray;
699: PetscFunctionReturn(PETSC_SUCCESS);
700: }
702: static PetscErrorCode MatGetInfo_MPISELL(Mat matin, MatInfoType flag, MatInfo *info)
703: {
704: Mat_MPISELL *mat = (Mat_MPISELL *)matin->data;
705: Mat A = mat->A, B = mat->B;
706: PetscLogDouble isend[5], irecv[5];
708: PetscFunctionBegin;
709: info->block_size = 1.0;
710: PetscCall(MatGetInfo(A, MAT_LOCAL, info));
712: isend[0] = info->nz_used;
713: isend[1] = info->nz_allocated;
714: isend[2] = info->nz_unneeded;
715: isend[3] = info->memory;
716: isend[4] = info->mallocs;
718: PetscCall(MatGetInfo(B, MAT_LOCAL, info));
720: isend[0] += info->nz_used;
721: isend[1] += info->nz_allocated;
722: isend[2] += info->nz_unneeded;
723: isend[3] += info->memory;
724: isend[4] += info->mallocs;
725: if (flag == MAT_LOCAL) {
726: info->nz_used = isend[0];
727: info->nz_allocated = isend[1];
728: info->nz_unneeded = isend[2];
729: info->memory = isend[3];
730: info->mallocs = isend[4];
731: } else if (flag == MAT_GLOBAL_MAX) {
732: PetscCallMPI(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)matin)));
734: info->nz_used = irecv[0];
735: info->nz_allocated = irecv[1];
736: info->nz_unneeded = irecv[2];
737: info->memory = irecv[3];
738: info->mallocs = irecv[4];
739: } else if (flag == MAT_GLOBAL_SUM) {
740: PetscCallMPI(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)matin)));
742: info->nz_used = irecv[0];
743: info->nz_allocated = irecv[1];
744: info->nz_unneeded = irecv[2];
745: info->memory = irecv[3];
746: info->mallocs = irecv[4];
747: }
748: info->fill_ratio_given = 0; /* no parallel LU/ILU/Cholesky */
749: info->fill_ratio_needed = 0;
750: info->factor_mallocs = 0;
751: PetscFunctionReturn(PETSC_SUCCESS);
752: }
754: static PetscErrorCode MatSetOption_MPISELL(Mat A, MatOption op, PetscBool flg)
755: {
756: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
758: PetscFunctionBegin;
759: switch (op) {
760: case MAT_NEW_NONZERO_LOCATIONS:
761: case MAT_NEW_NONZERO_ALLOCATION_ERR:
762: case MAT_UNUSED_NONZERO_LOCATION_ERR:
763: case MAT_KEEP_NONZERO_PATTERN:
764: case MAT_NEW_NONZERO_LOCATION_ERR:
765: case MAT_USE_INODES:
766: case MAT_IGNORE_ZERO_ENTRIES:
767: MatCheckPreallocated(A, 1);
768: PetscCall(MatSetOption(a->A, op, flg));
769: PetscCall(MatSetOption(a->B, op, flg));
770: break;
771: case MAT_ROW_ORIENTED:
772: MatCheckPreallocated(A, 1);
773: a->roworiented = flg;
775: PetscCall(MatSetOption(a->A, op, flg));
776: PetscCall(MatSetOption(a->B, op, flg));
777: break;
778: case MAT_IGNORE_OFF_PROC_ENTRIES:
779: a->donotstash = flg;
780: break;
781: case MAT_SYMMETRIC:
782: MatCheckPreallocated(A, 1);
783: PetscCall(MatSetOption(a->A, op, flg));
784: break;
785: case MAT_STRUCTURALLY_SYMMETRIC:
786: MatCheckPreallocated(A, 1);
787: PetscCall(MatSetOption(a->A, op, flg));
788: break;
789: case MAT_HERMITIAN:
790: MatCheckPreallocated(A, 1);
791: PetscCall(MatSetOption(a->A, op, flg));
792: break;
793: case MAT_SYMMETRY_ETERNAL:
794: MatCheckPreallocated(A, 1);
795: PetscCall(MatSetOption(a->A, op, flg));
796: break;
797: case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
798: MatCheckPreallocated(A, 1);
799: PetscCall(MatSetOption(a->A, op, flg));
800: break;
801: default:
802: break;
803: }
804: PetscFunctionReturn(PETSC_SUCCESS);
805: }
807: static PetscErrorCode MatDiagonalScale_MPISELL(Mat mat, Vec ll, Vec rr)
808: {
809: Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
810: Mat a = sell->A, b = sell->B;
811: PetscInt s1, s2, s3;
813: PetscFunctionBegin;
814: PetscCall(MatGetLocalSize(mat, &s2, &s3));
815: if (rr) {
816: PetscCall(VecGetLocalSize(rr, &s1));
817: PetscCheck(s1 == s3, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "right vector non-conforming local size");
818: /* Overlap communication with computation. */
819: PetscCall(VecScatterBegin(sell->Mvctx, rr, sell->lvec, INSERT_VALUES, SCATTER_FORWARD));
820: }
821: if (ll) {
822: PetscCall(VecGetLocalSize(ll, &s1));
823: PetscCheck(s1 == s2, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "left vector non-conforming local size");
824: PetscUseTypeMethod(b, diagonalscale, ll, NULL);
825: }
826: /* scale the diagonal block */
827: PetscUseTypeMethod(a, diagonalscale, ll, rr);
829: if (rr) {
830: /* Do a scatter end and then right scale the off-diagonal block */
831: PetscCall(VecScatterEnd(sell->Mvctx, rr, sell->lvec, INSERT_VALUES, SCATTER_FORWARD));
832: PetscUseTypeMethod(b, diagonalscale, NULL, sell->lvec);
833: }
834: PetscFunctionReturn(PETSC_SUCCESS);
835: }
837: static PetscErrorCode MatSetUnfactored_MPISELL(Mat A)
838: {
839: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
841: PetscFunctionBegin;
842: PetscCall(MatSetUnfactored(a->A));
843: PetscFunctionReturn(PETSC_SUCCESS);
844: }
846: static PetscErrorCode MatEqual_MPISELL(Mat A, Mat B, PetscBool *flag)
847: {
848: Mat_MPISELL *matB = (Mat_MPISELL *)B->data, *matA = (Mat_MPISELL *)A->data;
849: Mat a, b, c, d;
850: PetscBool flg;
852: PetscFunctionBegin;
853: a = matA->A;
854: b = matA->B;
855: c = matB->A;
856: d = matB->B;
858: PetscCall(MatEqual(a, c, &flg));
859: if (flg) PetscCall(MatEqual(b, d, &flg));
860: PetscCallMPI(MPIU_Allreduce(&flg, flag, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
861: PetscFunctionReturn(PETSC_SUCCESS);
862: }
864: static PetscErrorCode MatCopy_MPISELL(Mat A, Mat B, MatStructure str)
865: {
866: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
867: Mat_MPISELL *b = (Mat_MPISELL *)B->data;
869: PetscFunctionBegin;
870: /* If the two matrices don't have the same copy implementation, they aren't compatible for fast copy. */
871: if ((str != SAME_NONZERO_PATTERN) || (A->ops->copy != B->ops->copy)) {
872: /* because of the column compression in the off-processor part of the matrix a->B,
873: the number of columns in a->B and b->B may be different, hence we cannot call
874: the MatCopy() directly on the two parts. If need be, we can provide a more
875: efficient copy than the MatCopy_Basic() by first uncompressing the a->B matrices
876: then copying the submatrices */
877: PetscCall(MatCopy_Basic(A, B, str));
878: } else {
879: PetscCall(MatCopy(a->A, b->A, str));
880: PetscCall(MatCopy(a->B, b->B, str));
881: }
882: PetscFunctionReturn(PETSC_SUCCESS);
883: }
885: static PetscErrorCode MatSetUp_MPISELL(Mat A)
886: {
887: PetscFunctionBegin;
888: PetscCall(MatMPISELLSetPreallocation(A, PETSC_DEFAULT, NULL, PETSC_DEFAULT, NULL));
889: PetscFunctionReturn(PETSC_SUCCESS);
890: }
892: static PetscErrorCode MatConjugate_MPISELL(Mat mat)
893: {
894: Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
896: PetscFunctionBegin;
897: PetscCall(MatConjugate_SeqSELL(sell->A));
898: PetscCall(MatConjugate_SeqSELL(sell->B));
899: PetscFunctionReturn(PETSC_SUCCESS);
900: }
902: static PetscErrorCode MatInvertBlockDiagonal_MPISELL(Mat A, const PetscScalar **values)
903: {
904: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
906: PetscFunctionBegin;
907: PetscCall(MatInvertBlockDiagonal(a->A, values));
908: A->factorerrortype = a->A->factorerrortype;
909: PetscFunctionReturn(PETSC_SUCCESS);
910: }
912: static PetscErrorCode MatSetRandom_MPISELL(Mat x, PetscRandom rctx)
913: {
914: Mat_MPISELL *sell = (Mat_MPISELL *)x->data;
916: PetscFunctionBegin;
917: PetscCall(MatSetRandom(sell->A, rctx));
918: PetscCall(MatSetRandom(sell->B, rctx));
919: PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
920: PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
921: PetscFunctionReturn(PETSC_SUCCESS);
922: }
924: static PetscErrorCode MatSetFromOptions_MPISELL(Mat A, PetscOptionItems PetscOptionsObject)
925: {
926: PetscFunctionBegin;
927: PetscOptionsHeadBegin(PetscOptionsObject, "MPISELL options");
928: PetscOptionsHeadEnd();
929: PetscFunctionReturn(PETSC_SUCCESS);
930: }
932: static PetscErrorCode MatShift_MPISELL(Mat Y, PetscScalar a)
933: {
934: Mat_MPISELL *msell = (Mat_MPISELL *)Y->data;
935: Mat_SeqSELL *sell = (Mat_SeqSELL *)msell->A->data;
937: PetscFunctionBegin;
938: if (!Y->preallocated) {
939: PetscCall(MatMPISELLSetPreallocation(Y, 1, NULL, 0, NULL));
940: } else if (!sell->nz) {
941: PetscInt nonew = sell->nonew;
942: PetscCall(MatSeqSELLSetPreallocation(msell->A, 1, NULL));
943: sell->nonew = nonew;
944: }
945: PetscCall(MatShift_Basic(Y, a));
946: PetscFunctionReturn(PETSC_SUCCESS);
947: }
949: static PetscErrorCode MatGetDiagonalBlock_MPISELL(Mat A, Mat *a)
950: {
951: PetscFunctionBegin;
952: *a = ((Mat_MPISELL *)A->data)->A;
953: PetscFunctionReturn(PETSC_SUCCESS);
954: }
956: static PetscErrorCode MatStoreValues_MPISELL(Mat mat)
957: {
958: Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
960: PetscFunctionBegin;
961: PetscCall(MatStoreValues(sell->A));
962: PetscCall(MatStoreValues(sell->B));
963: PetscFunctionReturn(PETSC_SUCCESS);
964: }
966: static PetscErrorCode MatRetrieveValues_MPISELL(Mat mat)
967: {
968: Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
970: PetscFunctionBegin;
971: PetscCall(MatRetrieveValues(sell->A));
972: PetscCall(MatRetrieveValues(sell->B));
973: PetscFunctionReturn(PETSC_SUCCESS);
974: }
976: static PetscErrorCode MatMPISELLSetPreallocation_MPISELL(Mat B, PetscInt d_rlenmax, const PetscInt d_rlen[], PetscInt o_rlenmax, const PetscInt o_rlen[])
977: {
978: Mat_MPISELL *b;
980: PetscFunctionBegin;
981: PetscCall(PetscLayoutSetUp(B->rmap));
982: PetscCall(PetscLayoutSetUp(B->cmap));
983: b = (Mat_MPISELL *)B->data;
985: if (!B->preallocated) {
986: /* Explicitly create 2 MATSEQSELL matrices. */
987: PetscCall(MatCreate(PETSC_COMM_SELF, &b->A));
988: PetscCall(MatSetSizes(b->A, B->rmap->n, B->cmap->n, B->rmap->n, B->cmap->n));
989: PetscCall(MatSetBlockSizesFromMats(b->A, B, B));
990: PetscCall(MatSetType(b->A, MATSEQSELL));
991: PetscCall(MatCreate(PETSC_COMM_SELF, &b->B));
992: PetscCall(MatSetSizes(b->B, B->rmap->n, B->cmap->N, B->rmap->n, B->cmap->N));
993: PetscCall(MatSetBlockSizesFromMats(b->B, B, B));
994: PetscCall(MatSetType(b->B, MATSEQSELL));
995: }
997: PetscCall(MatSeqSELLSetPreallocation(b->A, d_rlenmax, d_rlen));
998: PetscCall(MatSeqSELLSetPreallocation(b->B, o_rlenmax, o_rlen));
999: B->preallocated = PETSC_TRUE;
1000: B->was_assembled = PETSC_FALSE;
1001: /*
1002: critical for MatAssemblyEnd to work.
1003: MatAssemblyBegin checks it to set up was_assembled
1004: and MatAssemblyEnd checks was_assembled to determine whether to build garray
1005: */
1006: B->assembled = PETSC_FALSE;
1007: PetscFunctionReturn(PETSC_SUCCESS);
1008: }
1010: static PetscErrorCode MatDuplicate_MPISELL(Mat matin, MatDuplicateOption cpvalues, Mat *newmat)
1011: {
1012: Mat mat;
1013: Mat_MPISELL *a, *oldmat = (Mat_MPISELL *)matin->data;
1015: PetscFunctionBegin;
1016: *newmat = NULL;
1017: PetscCall(MatCreate(PetscObjectComm((PetscObject)matin), &mat));
1018: PetscCall(MatSetSizes(mat, matin->rmap->n, matin->cmap->n, matin->rmap->N, matin->cmap->N));
1019: PetscCall(MatSetBlockSizesFromMats(mat, matin, matin));
1020: PetscCall(MatSetType(mat, ((PetscObject)matin)->type_name));
1021: a = (Mat_MPISELL *)mat->data;
1023: mat->factortype = matin->factortype;
1024: mat->assembled = PETSC_TRUE;
1025: mat->insertmode = NOT_SET_VALUES;
1026: mat->preallocated = PETSC_TRUE;
1028: a->size = oldmat->size;
1029: a->rank = oldmat->rank;
1030: a->donotstash = oldmat->donotstash;
1031: a->roworiented = oldmat->roworiented;
1032: a->rowindices = NULL;
1033: a->rowvalues = NULL;
1034: a->getrowactive = PETSC_FALSE;
1036: PetscCall(PetscLayoutReference(matin->rmap, &mat->rmap));
1037: PetscCall(PetscLayoutReference(matin->cmap, &mat->cmap));
1039: if (oldmat->colmap) {
1040: #if defined(PETSC_USE_CTABLE)
1041: PetscCall(PetscHMapIDuplicate(oldmat->colmap, &a->colmap));
1042: #else
1043: PetscCall(PetscMalloc1(mat->cmap->N, &a->colmap));
1044: PetscCall(PetscArraycpy(a->colmap, oldmat->colmap, mat->cmap->N));
1045: #endif
1046: } else a->colmap = NULL;
1047: if (oldmat->garray) {
1048: PetscInt len;
1049: len = oldmat->B->cmap->n;
1050: PetscCall(PetscMalloc1(len + 1, &a->garray));
1051: if (len) PetscCall(PetscArraycpy(a->garray, oldmat->garray, len));
1052: } else a->garray = NULL;
1054: PetscCall(VecDuplicate(oldmat->lvec, &a->lvec));
1055: PetscCall(VecScatterCopy(oldmat->Mvctx, &a->Mvctx));
1056: PetscCall(MatDuplicate(oldmat->A, cpvalues, &a->A));
1057: PetscCall(MatDuplicate(oldmat->B, cpvalues, &a->B));
1058: PetscCall(PetscFunctionListDuplicate(((PetscObject)matin)->qlist, &((PetscObject)mat)->qlist));
1059: *newmat = mat;
1060: PetscFunctionReturn(PETSC_SUCCESS);
1061: }
1063: static const struct _MatOps MatOps_Values = {MatSetValues_MPISELL,
1064: NULL,
1065: NULL,
1066: MatMult_MPISELL,
1067: /* 4*/ MatMultAdd_MPISELL,
1068: MatMultTranspose_MPISELL,
1069: MatMultTransposeAdd_MPISELL,
1070: NULL,
1071: NULL,
1072: NULL,
1073: /*10*/ NULL,
1074: NULL,
1075: NULL,
1076: MatSOR_MPISELL,
1077: NULL,
1078: /*15*/ MatGetInfo_MPISELL,
1079: MatEqual_MPISELL,
1080: MatGetDiagonal_MPISELL,
1081: MatDiagonalScale_MPISELL,
1082: NULL,
1083: /*20*/ MatAssemblyBegin_MPISELL,
1084: MatAssemblyEnd_MPISELL,
1085: MatSetOption_MPISELL,
1086: MatZeroEntries_MPISELL,
1087: /*24*/ NULL,
1088: NULL,
1089: NULL,
1090: NULL,
1091: NULL,
1092: /*29*/ MatSetUp_MPISELL,
1093: NULL,
1094: NULL,
1095: MatGetDiagonalBlock_MPISELL,
1096: NULL,
1097: /*34*/ MatDuplicate_MPISELL,
1098: NULL,
1099: NULL,
1100: NULL,
1101: NULL,
1102: /*39*/ NULL,
1103: NULL,
1104: NULL,
1105: MatGetValues_MPISELL,
1106: MatCopy_MPISELL,
1107: /*44*/ NULL,
1108: MatScale_MPISELL,
1109: MatShift_MPISELL,
1110: MatDiagonalSet_MPISELL,
1111: NULL,
1112: /*49*/ MatSetRandom_MPISELL,
1113: NULL,
1114: NULL,
1115: NULL,
1116: NULL,
1117: /*54*/ MatFDColoringCreate_MPIXAIJ,
1118: NULL,
1119: MatSetUnfactored_MPISELL,
1120: NULL,
1121: NULL,
1122: /*59*/ NULL,
1123: MatDestroy_MPISELL,
1124: MatView_MPISELL,
1125: NULL,
1126: NULL,
1127: /*64*/ NULL,
1128: NULL,
1129: NULL,
1130: NULL,
1131: NULL,
1132: /*69*/ NULL,
1133: NULL,
1134: NULL,
1135: MatFDColoringApply_AIJ, /* reuse AIJ function */
1136: MatSetFromOptions_MPISELL,
1137: NULL,
1138: /*75*/ NULL,
1139: NULL,
1140: NULL,
1141: NULL,
1142: NULL,
1143: /*80*/ NULL,
1144: NULL,
1145: NULL,
1146: /*83*/ NULL,
1147: NULL,
1148: NULL,
1149: NULL,
1150: NULL,
1151: NULL,
1152: /*89*/ NULL,
1153: NULL,
1154: NULL,
1155: NULL,
1156: MatConjugate_MPISELL,
1157: /*94*/ NULL,
1158: NULL,
1159: NULL,
1160: NULL,
1161: NULL,
1162: /*99*/ NULL,
1163: NULL,
1164: NULL,
1165: NULL,
1166: NULL,
1167: /*104*/ NULL,
1168: NULL,
1169: MatGetGhosts_MPISELL,
1170: NULL,
1171: NULL,
1172: /*109*/ MatMultDiagonalBlock_MPISELL,
1173: NULL,
1174: NULL,
1175: NULL,
1176: NULL,
1177: /*114*/ NULL,
1178: NULL,
1179: MatInvertBlockDiagonal_MPISELL,
1180: NULL,
1181: /*119*/ NULL,
1182: NULL,
1183: NULL,
1184: NULL,
1185: NULL,
1186: /*124*/ NULL,
1187: NULL,
1188: NULL,
1189: NULL,
1190: MatFDColoringSetUp_MPIXAIJ,
1191: /*129*/ NULL,
1192: NULL,
1193: NULL,
1194: NULL,
1195: NULL,
1196: /*134*/ NULL,
1197: NULL,
1198: NULL,
1199: NULL,
1200: NULL,
1201: /*139*/ NULL,
1202: NULL,
1203: NULL,
1204: NULL,
1205: NULL,
1206: MatADot_Default,
1207: /*144*/ MatANorm_Default,
1208: NULL,
1209: NULL,
1210: NULL};
1212: /*@C
1213: MatMPISELLSetPreallocation - Preallocates memory for a `MATMPISELL` sparse parallel matrix in sell format.
1214: For good matrix assembly performance the user should preallocate the matrix storage by
1215: setting the parameters `d_nz` (or `d_nnz`) and `o_nz` (or `o_nnz`).
1217: Collective
1219: Input Parameters:
1220: + B - the matrix
1221: . d_nz - number of nonzeros per row in DIAGONAL portion of local submatrix
1222: (same value is used for all local rows)
1223: . d_nnz - array containing the number of nonzeros in the various rows of the
1224: DIAGONAL portion of the local submatrix (possibly different for each row)
1225: or NULL (`PETSC_NULL_INTEGER` in Fortran), if `d_nz` is used to specify the nonzero structure.
1226: The size of this array is equal to the number of local rows, i.e 'm'.
1227: For matrices that will be factored, you must leave room for (and set)
1228: the diagonal entry even if it is zero.
1229: . o_nz - number of nonzeros per row in the OFF-DIAGONAL portion of local
1230: submatrix (same value is used for all local rows).
1231: - o_nnz - array containing the number of nonzeros in the various rows of the
1232: OFF-DIAGONAL portion of the local submatrix (possibly different for
1233: each row) or NULL (`PETSC_NULL_INTEGER` in Fortran), if `o_nz` is used to specify the nonzero
1234: structure. The size of this array is equal to the number
1235: of local rows, i.e 'm'.
1237: Example usage:
1238: Consider the following 8x8 matrix with 34 non-zero values, that is
1239: assembled across 3 processors. Lets assume that proc0 owns 3 rows,
1240: proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
1241: as follows
1243: .vb
1244: 1 2 0 | 0 3 0 | 0 4
1245: Proc0 0 5 6 | 7 0 0 | 8 0
1246: 9 0 10 | 11 0 0 | 12 0
1247: -------------------------------------
1248: 13 0 14 | 15 16 17 | 0 0
1249: Proc1 0 18 0 | 19 20 21 | 0 0
1250: 0 0 0 | 22 23 0 | 24 0
1251: -------------------------------------
1252: Proc2 25 26 27 | 0 0 28 | 29 0
1253: 30 0 0 | 31 32 33 | 0 34
1254: .ve
1256: This can be represented as a collection of submatrices as
1258: .vb
1259: A B C
1260: D E F
1261: G H I
1262: .ve
1264: Where the submatrices A,B,C are owned by proc0, D,E,F are
1265: owned by proc1, G,H,I are owned by proc2.
1267: The 'm' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
1268: The 'n' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
1269: The 'M','N' parameters are 8,8, and have the same values on all procs.
1271: The DIAGONAL submatrices corresponding to proc0,proc1,proc2 are
1272: submatrices [A], [E], [I] respectively. The OFF-DIAGONAL submatrices
1273: corresponding to proc0,proc1,proc2 are [BC], [DF], [GH] respectively.
1274: Internally, each processor stores the DIAGONAL part, and the OFF-DIAGONAL
1275: part as `MATSEQSELL` matrices. For example, proc1 will store [E] as a `MATSEQSELL`
1276: matrix, and [DF] as another SeqSELL matrix.
1278: When `d_nz`, `o_nz` parameters are specified, `d_nz` storage elements are
1279: allocated for every row of the local DIAGONAL submatrix, and o_nz
1280: storage locations are allocated for every row of the OFF-DIAGONAL submatrix.
1281: One way to choose `d_nz` and `o_nz` is to use the maximum number of nonzeros over
1282: the local rows for each of the local DIAGONAL, and the OFF-DIAGONAL submatrices.
1283: In this case, the values of d_nz,o_nz are
1284: .vb
1285: proc0 dnz = 2, o_nz = 2
1286: proc1 dnz = 3, o_nz = 2
1287: proc2 dnz = 1, o_nz = 4
1288: .ve
1289: We are allocating m*(d_nz+o_nz) storage locations for every proc. This
1290: translates to 3*(2+2)=12 for proc0, 3*(3+2)=15 for proc1, 2*(1+4)=10
1291: for proc3. i.e we are using 12+15+10=37 storage locations to store
1292: 34 values.
1294: When `d_nnz`, `o_nnz` parameters are specified, the storage is specified
1295: for every row, corresponding to both DIAGONAL and OFF-DIAGONAL submatrices.
1296: In the above case the values for d_nnz,o_nnz are
1297: .vb
1298: proc0 d_nnz = [2,2,2] and o_nnz = [2,2,2]
1299: proc1 d_nnz = [3,3,2] and o_nnz = [2,1,1]
1300: proc2 d_nnz = [1,1] and o_nnz = [4,4]
1301: .ve
1302: Here the space allocated is according to nz (or maximum values in the nnz
1303: if nnz is provided) for DIAGONAL and OFF-DIAGONAL submatrices, i.e (2+2+3+2)*3+(1+4)*2=37
1305: Level: intermediate
1307: Notes:
1308: If the *_nnz parameter is given then the *_nz parameter is ignored
1310: The stored row and column indices begin with zero.
1312: The parallel matrix is partitioned such that the first m0 rows belong to
1313: process 0, the next m1 rows belong to process 1, the next m2 rows belong
1314: to process 2 etc.. where m0,m1,m2... are the input parameter 'm'.
1316: The DIAGONAL portion of the local submatrix of a processor can be defined
1317: as the submatrix which is obtained by extraction the part corresponding to
1318: the rows r1-r2 and columns c1-c2 of the global matrix, where r1 is the
1319: first row that belongs to the processor, r2 is the last row belonging to
1320: the this processor, and c1-c2 is range of indices of the local part of a
1321: vector suitable for applying the matrix to. This is an mxn matrix. In the
1322: common case of a square matrix, the row and column ranges are the same and
1323: the DIAGONAL part is also square. The remaining portion of the local
1324: submatrix (mxN) constitute the OFF-DIAGONAL portion.
1326: If `o_nnz`, `d_nnz` are specified, then `o_nz`, and `d_nz` are ignored.
1328: You can call `MatGetInfo()` to get information on how effective the preallocation was;
1329: for example the fields mallocs,nz_allocated,nz_used,nz_unneeded;
1330: You can also run with the option -info and look for messages with the string
1331: malloc in them to see if additional memory allocation was needed.
1333: .seealso: `Mat`, `MatCreate()`, `MatCreateSeqSELL()`, `MatSetValues()`, `MatCreateSELL()`,
1334: `MATMPISELL`, `MatGetInfo()`, `PetscSplitOwnership()`, `MATSELL`
1335: @*/
1336: PetscErrorCode MatMPISELLSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1337: {
1338: PetscFunctionBegin;
1341: PetscTryMethod(B, "MatMPISELLSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
1342: PetscFunctionReturn(PETSC_SUCCESS);
1343: }
1345: /*MC
1346: MATMPISELL - MATMPISELL = "mpisell" - A matrix type to be used for MPI sparse matrices,
1347: based on the sliced Ellpack format
1349: Options Database Key:
1350: . -mat_type sell - sets the matrix type to `MATSELL` during a call to `MatSetFromOptions()`
1352: Level: beginner
1354: .seealso: `Mat`, `MatCreateSELL()`, `MATSEQSELL`, `MATSELL`, `MATSEQAIJ`, `MATAIJ`, `MATMPIAIJ`
1355: M*/
1357: /*@C
1358: MatCreateSELL - Creates a sparse parallel matrix in `MATSELL` format.
1360: Collective
1362: Input Parameters:
1363: + comm - MPI communicator
1364: . m - number of local rows (or `PETSC_DECIDE` to have calculated if M is given)
1365: This value should be the same as the local size used in creating the
1366: y vector for the matrix-vector product y = Ax.
1367: . n - This value should be the same as the local size used in creating the
1368: x vector for the matrix-vector product y = Ax. (or `PETSC_DECIDE` to have
1369: calculated if `N` is given) For square matrices n is almost always `m`.
1370: . M - number of global rows (or `PETSC_DETERMINE` to have calculated if `m` is given)
1371: . N - number of global columns (or `PETSC_DETERMINE` to have calculated if `n` is given)
1372: . d_rlenmax - max number of nonzeros per row in DIAGONAL portion of local submatrix
1373: (same value is used for all local rows)
1374: . d_rlen - array containing the number of nonzeros in the various rows of the
1375: DIAGONAL portion of the local submatrix (possibly different for each row)
1376: or `NULL`, if d_rlenmax is used to specify the nonzero structure.
1377: The size of this array is equal to the number of local rows, i.e `m`.
1378: . o_rlenmax - max number of nonzeros per row in the OFF-DIAGONAL portion of local
1379: submatrix (same value is used for all local rows).
1380: - o_rlen - array containing the number of nonzeros in the various rows of the
1381: OFF-DIAGONAL portion of the local submatrix (possibly different for
1382: each row) or `NULL`, if `o_rlenmax` is used to specify the nonzero
1383: structure. The size of this array is equal to the number
1384: of local rows, i.e `m`.
1386: Output Parameter:
1387: . A - the matrix
1389: Options Database Key:
1390: . -mat_sell_oneindex - Internally use indexing starting at 1
1391: rather than 0. When calling `MatSetValues()`,
1392: the user still MUST index entries starting at 0!
1394: Example:
1395: Consider the following 8x8 matrix with 34 non-zero values, that is
1396: assembled across 3 processors. Lets assume that proc0 owns 3 rows,
1397: proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
1398: as follows
1400: .vb
1401: 1 2 0 | 0 3 0 | 0 4
1402: Proc0 0 5 6 | 7 0 0 | 8 0
1403: 9 0 10 | 11 0 0 | 12 0
1404: -------------------------------------
1405: 13 0 14 | 15 16 17 | 0 0
1406: Proc1 0 18 0 | 19 20 21 | 0 0
1407: 0 0 0 | 22 23 0 | 24 0
1408: -------------------------------------
1409: Proc2 25 26 27 | 0 0 28 | 29 0
1410: 30 0 0 | 31 32 33 | 0 34
1411: .ve
1413: This can be represented as a collection of submatrices as
1414: .vb
1415: A B C
1416: D E F
1417: G H I
1418: .ve
1420: Where the submatrices A,B,C are owned by proc0, D,E,F are
1421: owned by proc1, G,H,I are owned by proc2.
1423: The 'm' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
1424: The 'n' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
1425: The 'M','N' parameters are 8,8, and have the same values on all procs.
1427: The DIAGONAL submatrices corresponding to proc0,proc1,proc2 are
1428: submatrices [A], [E], [I] respectively. The OFF-DIAGONAL submatrices
1429: corresponding to proc0,proc1,proc2 are [BC], [DF], [GH] respectively.
1430: Internally, each processor stores the DIAGONAL part, and the OFF-DIAGONAL
1431: part as `MATSEQSELL` matrices. For example, proc1 will store [E] as a `MATSEQSELL`
1432: matrix, and [DF] as another `MATSEQSELL` matrix.
1434: When d_rlenmax, o_rlenmax parameters are specified, d_rlenmax storage elements are
1435: allocated for every row of the local DIAGONAL submatrix, and o_rlenmax
1436: storage locations are allocated for every row of the OFF-DIAGONAL submatrix.
1437: One way to choose `d_rlenmax` and `o_rlenmax` is to use the maximum number of nonzeros over
1438: the local rows for each of the local DIAGONAL, and the OFF-DIAGONAL submatrices.
1439: In this case, the values of d_rlenmax,o_rlenmax are
1440: .vb
1441: proc0 - d_rlenmax = 2, o_rlenmax = 2
1442: proc1 - d_rlenmax = 3, o_rlenmax = 2
1443: proc2 - d_rlenmax = 1, o_rlenmax = 4
1444: .ve
1445: We are allocating m*(d_rlenmax+o_rlenmax) storage locations for every proc. This
1446: translates to 3*(2+2)=12 for proc0, 3*(3+2)=15 for proc1, 2*(1+4)=10
1447: for proc3. i.e we are using 12+15+10=37 storage locations to store
1448: 34 values.
1450: When `d_rlen`, `o_rlen` parameters are specified, the storage is specified
1451: for every row, corresponding to both DIAGONAL and OFF-DIAGONAL submatrices.
1452: In the above case the values for `d_nnz`, `o_nnz` are
1453: .vb
1454: proc0 - d_nnz = [2,2,2] and o_nnz = [2,2,2]
1455: proc1 - d_nnz = [3,3,2] and o_nnz = [2,1,1]
1456: proc2 - d_nnz = [1,1] and o_nnz = [4,4]
1457: .ve
1458: Here the space allocated is still 37 though there are 34 nonzeros because
1459: the allocation is always done according to rlenmax.
1461: Level: intermediate
1463: Notes:
1464: It is recommended that one use the `MatCreate()`, `MatSetType()` and/or `MatSetFromOptions()`,
1465: MatXXXXSetPreallocation() paradigm instead of this routine directly.
1466: [MatXXXXSetPreallocation() is, for example, `MatSeqSELLSetPreallocation()`]
1468: If the *_rlen parameter is given then the *_rlenmax parameter is ignored
1470: `m`, `n`, `M`, `N` parameters specify the size of the matrix, and its partitioning across
1471: processors, while `d_rlenmax`, `d_rlen`, `o_rlenmax` , `o_rlen` parameters specify the approximate
1472: storage requirements for this matrix.
1474: If `PETSC_DECIDE` or `PETSC_DETERMINE` is used for a particular argument on one
1475: processor than it must be used on all processors that share the object for
1476: that argument.
1478: The user MUST specify either the local or global matrix dimensions
1479: (possibly both).
1481: The parallel matrix is partitioned across processors such that the
1482: first m0 rows belong to process 0, the next m1 rows belong to
1483: process 1, the next m2 rows belong to process 2 etc.. where
1484: m0,m1,m2,.. are the input parameter 'm'. i.e each processor stores
1485: values corresponding to [`m` x `N`] submatrix.
1487: The columns are logically partitioned with the n0 columns belonging
1488: to 0th partition, the next n1 columns belonging to the next
1489: partition etc.. where n0,n1,n2... are the input parameter `n`.
1491: The DIAGONAL portion of the local submatrix on any given processor
1492: is the submatrix corresponding to the rows and columns `m`, `n`
1493: corresponding to the given processor. i.e diagonal matrix on
1494: process 0 is [m0 x n0], diagonal matrix on process 1 is [m1 x n1]
1495: etc. The remaining portion of the local submatrix [m x (N-n)]
1496: constitute the OFF-DIAGONAL portion. The example below better
1497: illustrates this concept.
1499: For a square global matrix we define each processor's diagonal portion
1500: to be its local rows and the corresponding columns (a square submatrix);
1501: each processor's off-diagonal portion encompasses the remainder of the
1502: local matrix (a rectangular submatrix).
1504: If `o_rlen`, `d_rlen` are specified, then `o_rlenmax`, and `d_rlenmax` are ignored.
1506: When calling this routine with a single process communicator, a matrix of
1507: type `MATSEQSELL` is returned. If a matrix of type `MATMPISELL` is desired for this
1508: type of communicator, use the construction mechanism
1509: .vb
1510: MatCreate(...,&A);
1511: MatSetType(A,MATMPISELL);
1512: MatSetSizes(A, m,n,M,N);
1513: MatMPISELLSetPreallocation(A,...);
1514: .ve
1516: .seealso: `Mat`, `MATSELL`, `MatCreate()`, `MatCreateSeqSELL()`, `MatSetValues()`, `MatMPISELLSetPreallocation()`, `MATMPISELL`
1517: @*/
1518: PetscErrorCode MatCreateSELL(MPI_Comm comm, PetscInt m, PetscInt n, PetscInt M, PetscInt N, PetscInt d_rlenmax, const PetscInt d_rlen[], PetscInt o_rlenmax, const PetscInt o_rlen[], Mat *A)
1519: {
1520: PetscMPIInt size;
1522: PetscFunctionBegin;
1523: PetscCall(MatCreate(comm, A));
1524: PetscCall(MatSetSizes(*A, m, n, M, N));
1525: PetscCallMPI(MPI_Comm_size(comm, &size));
1526: if (size > 1) {
1527: PetscCall(MatSetType(*A, MATMPISELL));
1528: PetscCall(MatMPISELLSetPreallocation(*A, d_rlenmax, d_rlen, o_rlenmax, o_rlen));
1529: } else {
1530: PetscCall(MatSetType(*A, MATSEQSELL));
1531: PetscCall(MatSeqSELLSetPreallocation(*A, d_rlenmax, d_rlen));
1532: }
1533: PetscFunctionReturn(PETSC_SUCCESS);
1534: }
1536: /*@C
1537: MatMPISELLGetSeqSELL - Returns the local pieces of this distributed matrix
1539: Not Collective
1541: Input Parameter:
1542: . A - the `MATMPISELL` matrix
1544: Output Parameters:
1545: + Ad - The diagonal portion of `A`
1546: . Ao - The off-diagonal portion of `A`
1547: - colmap - An array mapping local column numbers of `Ao` to global column numbers of the parallel matrix
1549: Level: advanced
1551: .seealso: `Mat`, `MATSEQSELL`, `MATMPISELL`
1552: @*/
1553: PetscErrorCode MatMPISELLGetSeqSELL(Mat A, Mat *Ad, Mat *Ao, const PetscInt *colmap[])
1554: {
1555: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
1556: PetscBool flg;
1558: PetscFunctionBegin;
1559: PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPISELL, &flg));
1560: PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "This function requires a MATMPISELL matrix as input");
1561: if (Ad) *Ad = a->A;
1562: if (Ao) *Ao = a->B;
1563: if (colmap) *colmap = a->garray;
1564: PetscFunctionReturn(PETSC_SUCCESS);
1565: }
1567: /*@C
1568: MatMPISELLGetLocalMatCondensed - Creates a `MATSEQSELL` matrix from an `MATMPISELL` matrix by
1569: taking all its local rows and NON-ZERO columns
1571: Not Collective
1573: Input Parameters:
1574: + A - the matrix
1575: . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
1576: . row - index sets of rows to extract (or `NULL`)
1577: - col - index sets of columns to extract (or `NULL`)
1579: Output Parameter:
1580: . A_loc - the local sequential matrix generated
1582: Level: advanced
1584: .seealso: `Mat`, `MATSEQSELL`, `MATMPISELL`, `MatGetOwnershipRange()`, `MatMPISELLGetLocalMat()`
1585: @*/
1586: PetscErrorCode MatMPISELLGetLocalMatCondensed(Mat A, MatReuse scall, IS *row, IS *col, Mat *A_loc)
1587: {
1588: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
1589: PetscInt i, start, end, ncols, nzA, nzB, *cmap, imark, *idx;
1590: IS isrowa, iscola;
1591: Mat *aloc;
1592: PetscBool match;
1594: PetscFunctionBegin;
1595: PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPISELL, &match));
1596: PetscCheck(match, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Requires MATMPISELL matrix as input");
1597: PetscCall(PetscLogEventBegin(MAT_Getlocalmatcondensed, A, 0, 0, 0));
1598: if (!row) {
1599: start = A->rmap->rstart;
1600: end = A->rmap->rend;
1601: PetscCall(ISCreateStride(PETSC_COMM_SELF, end - start, start, 1, &isrowa));
1602: } else {
1603: isrowa = *row;
1604: }
1605: if (!col) {
1606: start = A->cmap->rstart;
1607: cmap = a->garray;
1608: nzA = a->A->cmap->n;
1609: nzB = a->B->cmap->n;
1610: PetscCall(PetscMalloc1(nzA + nzB, &idx));
1611: ncols = 0;
1612: for (i = 0; i < nzB; i++) {
1613: if (cmap[i] < start) idx[ncols++] = cmap[i];
1614: else break;
1615: }
1616: imark = i;
1617: for (i = 0; i < nzA; i++) idx[ncols++] = start + i;
1618: for (i = imark; i < nzB; i++) idx[ncols++] = cmap[i];
1619: PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncols, idx, PETSC_OWN_POINTER, &iscola));
1620: } else {
1621: iscola = *col;
1622: }
1623: if (scall != MAT_INITIAL_MATRIX) {
1624: PetscCall(PetscMalloc1(1, &aloc));
1625: aloc[0] = *A_loc;
1626: }
1627: PetscCall(MatCreateSubMatrices(A, 1, &isrowa, &iscola, scall, &aloc));
1628: *A_loc = aloc[0];
1629: PetscCall(PetscFree(aloc));
1630: if (!row) PetscCall(ISDestroy(&isrowa));
1631: if (!col) PetscCall(ISDestroy(&iscola));
1632: PetscCall(PetscLogEventEnd(MAT_Getlocalmatcondensed, A, 0, 0, 0));
1633: PetscFunctionReturn(PETSC_SUCCESS);
1634: }
1636: #include <../src/mat/impls/aij/mpi/mpiaij.h>
1638: PetscErrorCode MatConvert_MPISELL_MPIAIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1639: {
1640: Mat_MPISELL *a = (Mat_MPISELL *)A->data;
1641: Mat B;
1642: Mat_MPIAIJ *b;
1644: PetscFunctionBegin;
1645: PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Matrix must be assembled");
1647: if (reuse == MAT_REUSE_MATRIX) {
1648: B = *newmat;
1649: } else {
1650: PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
1651: PetscCall(MatSetType(B, MATMPIAIJ));
1652: PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
1653: PetscCall(MatSetBlockSizes(B, A->rmap->bs, A->cmap->bs));
1654: PetscCall(MatSeqAIJSetPreallocation(B, 0, NULL));
1655: PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL));
1656: }
1657: b = (Mat_MPIAIJ *)B->data;
1659: if (reuse == MAT_REUSE_MATRIX) {
1660: PetscCall(MatConvert_SeqSELL_SeqAIJ(a->A, MATSEQAIJ, MAT_REUSE_MATRIX, &b->A));
1661: PetscCall(MatConvert_SeqSELL_SeqAIJ(a->B, MATSEQAIJ, MAT_REUSE_MATRIX, &b->B));
1662: } else {
1663: PetscCall(MatDestroy(&b->A));
1664: PetscCall(MatDestroy(&b->B));
1665: PetscCall(MatDisAssemble_MPISELL(A));
1666: PetscCall(MatConvert_SeqSELL_SeqAIJ(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &b->A));
1667: PetscCall(MatConvert_SeqSELL_SeqAIJ(a->B, MATSEQAIJ, MAT_INITIAL_MATRIX, &b->B));
1668: PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
1669: PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
1670: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
1671: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1672: }
1674: if (reuse == MAT_INPLACE_MATRIX) {
1675: PetscCall(MatHeaderReplace(A, &B));
1676: } else {
1677: *newmat = B;
1678: }
1679: PetscFunctionReturn(PETSC_SUCCESS);
1680: }
1682: PetscErrorCode MatConvert_MPIAIJ_MPISELL(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1683: {
1684: Mat_MPIAIJ *a = (Mat_MPIAIJ *)A->data;
1685: Mat B;
1686: Mat_MPISELL *b;
1688: PetscFunctionBegin;
1689: PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Matrix must be assembled");
1691: if (reuse == MAT_REUSE_MATRIX) {
1692: B = *newmat;
1693: } else {
1694: Mat_SeqAIJ *Aa = (Mat_SeqAIJ *)a->A->data, *Ba = (Mat_SeqAIJ *)a->B->data;
1695: PetscInt i, d_nz = 0, o_nz = 0, m = A->rmap->N, n = A->cmap->N, lm = A->rmap->n, ln = A->cmap->n;
1696: PetscInt *d_nnz, *o_nnz;
1697: PetscCall(PetscMalloc2(lm, &d_nnz, lm, &o_nnz));
1698: for (i = 0; i < lm; i++) {
1699: d_nnz[i] = Aa->i[i + 1] - Aa->i[i];
1700: o_nnz[i] = Ba->i[i + 1] - Ba->i[i];
1701: if (d_nnz[i] > d_nz) d_nz = d_nnz[i];
1702: if (o_nnz[i] > o_nz) o_nz = o_nnz[i];
1703: }
1704: PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
1705: PetscCall(MatSetType(B, MATMPISELL));
1706: PetscCall(MatSetSizes(B, lm, ln, m, n));
1707: PetscCall(MatSetBlockSizes(B, A->rmap->bs, A->cmap->bs));
1708: PetscCall(MatSeqSELLSetPreallocation(B, d_nz, d_nnz));
1709: PetscCall(MatMPISELLSetPreallocation(B, d_nz, d_nnz, o_nz, o_nnz));
1710: PetscCall(PetscFree2(d_nnz, o_nnz));
1711: }
1712: b = (Mat_MPISELL *)B->data;
1714: if (reuse == MAT_REUSE_MATRIX) {
1715: PetscCall(MatConvert_SeqAIJ_SeqSELL(a->A, MATSEQSELL, MAT_REUSE_MATRIX, &b->A));
1716: PetscCall(MatConvert_SeqAIJ_SeqSELL(a->B, MATSEQSELL, MAT_REUSE_MATRIX, &b->B));
1717: } else {
1718: PetscBool nooffprocentries_A = A->nooffprocentries, nooffprocentries_B = B->nooffprocentries;
1720: PetscCall(MatDestroy(&b->A));
1721: PetscCall(MatDestroy(&b->B));
1722: /* Expand a->B from compacted local off-diag columns back to global columns so the new MPISELL's
1723: MatAssemblyEnd() builds the correct garray/Mvctx for its off-diagonal block. */
1724: PetscCall(MatDisAssemble_MPIAIJ(A, PETSC_FALSE));
1725: PetscCall(MatConvert_SeqAIJ_SeqSELL(a->A, MATSEQSELL, MAT_INITIAL_MATRIX, &b->A));
1726: PetscCall(MatConvert_SeqAIJ_SeqSELL(a->B, MATSEQSELL, MAT_INITIAL_MATRIX, &b->B));
1727: /* The locally-populated A and B have no stashed off-processor entries, so skip the stash scatter. */
1728: A->nooffprocentries = PETSC_TRUE;
1729: B->nooffprocentries = PETSC_TRUE;
1730: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
1731: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1732: PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
1733: PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
1734: A->nooffprocentries = nooffprocentries_A;
1735: B->nooffprocentries = nooffprocentries_B;
1736: }
1738: if (reuse == MAT_INPLACE_MATRIX) {
1739: PetscCall(MatHeaderReplace(A, &B));
1740: } else {
1741: *newmat = B;
1742: }
1743: PetscFunctionReturn(PETSC_SUCCESS);
1744: }
1746: PetscErrorCode MatSOR_MPISELL(Mat matin, Vec bb, PetscReal omega, MatSORType flag, PetscReal fshift, PetscInt its, PetscInt lits, Vec xx)
1747: {
1748: Mat_MPISELL *mat = (Mat_MPISELL *)matin->data;
1749: Vec bb1 = NULL;
1751: PetscFunctionBegin;
1752: if (flag == SOR_APPLY_UPPER) {
1753: PetscUseTypeMethod(mat->A, sor, bb, omega, flag, fshift, lits, 1, xx);
1754: PetscFunctionReturn(PETSC_SUCCESS);
1755: }
1757: if (its > 1 || ~flag & SOR_ZERO_INITIAL_GUESS || flag & SOR_EISENSTAT) PetscCall(VecDuplicate(bb, &bb1));
1759: if ((flag & SOR_LOCAL_SYMMETRIC_SWEEP) == SOR_LOCAL_SYMMETRIC_SWEEP) {
1760: if (flag & SOR_ZERO_INITIAL_GUESS) {
1761: PetscUseTypeMethod(mat->A, sor, bb, omega, flag, fshift, lits, 1, xx);
1762: its--;
1763: }
1765: while (its--) {
1766: PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1767: PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1769: /* update rhs: bb1 = bb - B*x */
1770: PetscCall(VecScale(mat->lvec, -1.0));
1771: PetscUseTypeMethod(mat->B, multadd, mat->lvec, bb, bb1);
1773: /* local sweep */
1774: PetscUseTypeMethod(mat->A, sor, bb1, omega, SOR_SYMMETRIC_SWEEP, fshift, lits, 1, xx);
1775: }
1776: } else if (flag & SOR_LOCAL_FORWARD_SWEEP) {
1777: if (flag & SOR_ZERO_INITIAL_GUESS) {
1778: PetscUseTypeMethod(mat->A, sor, bb, omega, flag, fshift, lits, 1, xx);
1779: its--;
1780: }
1781: while (its--) {
1782: PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1783: PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1785: /* update rhs: bb1 = bb - B*x */
1786: PetscCall(VecScale(mat->lvec, -1.0));
1787: PetscUseTypeMethod(mat->B, multadd, mat->lvec, bb, bb1);
1789: /* local sweep */
1790: PetscUseTypeMethod(mat->A, sor, bb1, omega, SOR_FORWARD_SWEEP, fshift, lits, 1, xx);
1791: }
1792: } else if (flag & SOR_LOCAL_BACKWARD_SWEEP) {
1793: if (flag & SOR_ZERO_INITIAL_GUESS) {
1794: PetscUseTypeMethod(mat->A, sor, bb, omega, flag, fshift, lits, 1, xx);
1795: its--;
1796: }
1797: while (its--) {
1798: PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1799: PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1801: /* update rhs: bb1 = bb - B*x */
1802: PetscCall(VecScale(mat->lvec, -1.0));
1803: PetscUseTypeMethod(mat->B, multadd, mat->lvec, bb, bb1);
1805: /* local sweep */
1806: PetscUseTypeMethod(mat->A, sor, bb1, omega, SOR_BACKWARD_SWEEP, fshift, lits, 1, xx);
1807: }
1808: } else SETERRQ(PetscObjectComm((PetscObject)matin), PETSC_ERR_SUP, "Parallel SOR not supported");
1810: PetscCall(VecDestroy(&bb1));
1812: matin->factorerrortype = mat->A->factorerrortype;
1813: PetscFunctionReturn(PETSC_SUCCESS);
1814: }
1816: #if defined(PETSC_HAVE_CUDA)
1817: PETSC_INTERN PetscErrorCode MatConvert_MPISELL_MPISELLCUDA(Mat, MatType, MatReuse, Mat *);
1818: #endif
1820: /*MC
1821: MATMPISELL - MATMPISELL = "MPISELL" - A matrix type to be used for parallel sparse matrices.
1823: Options Database Keys:
1824: . -mat_type mpisell - sets the matrix type to `MATMPISELL` during a call to `MatSetFromOptions()`
1826: Level: beginner
1828: .seealso: `Mat`, `MATSELL`, `MATSEQSELL`, `MatCreateSELL()`
1829: M*/
1830: PETSC_EXTERN PetscErrorCode MatCreate_MPISELL(Mat B)
1831: {
1832: Mat_MPISELL *b;
1833: PetscMPIInt size;
1835: PetscFunctionBegin;
1836: PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size));
1837: PetscCall(PetscNew(&b));
1838: B->data = (void *)b;
1839: B->ops[0] = MatOps_Values;
1840: B->assembled = PETSC_FALSE;
1841: B->insertmode = NOT_SET_VALUES;
1842: b->size = size;
1843: PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)B), &b->rank));
1844: /* build cache for off array entries formed */
1845: PetscCall(MatStashCreate_Private(PetscObjectComm((PetscObject)B), 1, &B->stash));
1847: b->donotstash = PETSC_FALSE;
1848: b->colmap = NULL;
1849: b->garray = NULL;
1850: b->roworiented = PETSC_TRUE;
1852: /* stuff used for matrix vector multiply */
1853: b->lvec = NULL;
1854: b->Mvctx = NULL;
1856: /* stuff for MatGetRow() */
1857: b->rowindices = NULL;
1858: b->rowvalues = NULL;
1859: b->getrowactive = PETSC_FALSE;
1861: PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_MPISELL));
1862: PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_MPISELL));
1863: PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_MPISELL));
1864: PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatMPISELLSetPreallocation_C", MatMPISELLSetPreallocation_MPISELL));
1865: PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_mpisell_mpiaij_C", MatConvert_MPISELL_MPIAIJ));
1866: #if defined(PETSC_HAVE_CUDA)
1867: PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_mpisell_mpisellcuda_C", MatConvert_MPISELL_MPISELLCUDA));
1868: #endif
1869: PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatDiagonalScaleLocal_C", MatDiagonalScaleLocal_MPISELL));
1870: PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatGetMultPetscSF_C", MatGetMultPetscSF_MPISELL));
1871: PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATMPISELL));
1872: PetscFunctionReturn(PETSC_SUCCESS);
1873: }