xref: /petsc/src/mat/impls/sell/mpi/mpisell.c (revision fa078d78a6dfdf5056b639be8e29801e504ec191)
1d4002b98SHong Zhang #include <../src/mat/impls/aij/mpi/mpiaij.h>   /*I "petscmat.h" I*/
2d4002b98SHong Zhang #include <../src/mat/impls/sell/mpi/mpisell.h> /*I "petscmat.h" I*/
3d4002b98SHong Zhang #include <petsc/private/vecimpl.h>
4d4002b98SHong Zhang #include <petsc/private/isimpl.h>
5d4002b98SHong Zhang #include <petscblaslapack.h>
6d4002b98SHong Zhang #include <petscsf.h>
7d4002b98SHong Zhang 
8d4002b98SHong Zhang /*MC
9d4002b98SHong Zhang    MATSELL - MATSELL = "sell" - A matrix type to be used for sparse matrices.
10d4002b98SHong Zhang 
1111a5261eSBarry Smith    This matrix type is identical to `MATSEQSELL` when constructed with a single process communicator,
1211a5261eSBarry Smith    and `MATMPISELL` otherwise.  As a result, for single process communicators,
1311a5261eSBarry Smith   `MatSeqSELLSetPreallocation()` is supported, and similarly `MatMPISELLSetPreallocation()` is supported
14d4002b98SHong Zhang   for communicators controlling multiple processes.  It is recommended that you call both of
15d4002b98SHong Zhang   the above preallocation routines for simplicity.
16d4002b98SHong Zhang 
17d4002b98SHong Zhang    Options Database Keys:
1820f4b53cSBarry Smith . -mat_type sell - sets the matrix type to `MATSELL` during a call to `MatSetFromOptions()`
19d4002b98SHong Zhang 
20d4002b98SHong Zhang   Level: beginner
21d4002b98SHong Zhang 
2267be906fSBarry Smith .seealso: `Mat`, `MATAIJ`, `MATBAIJ`, `MATSBAIJ`, `MatCreateSELL()`, `MatCreateSeqSELL()`, `MATSEQSELL`, `MATMPISELL`
23d4002b98SHong Zhang M*/
24d4002b98SHong Zhang 
25ba38deedSJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_MPISELL(Mat Y, Vec D, InsertMode is)
26d71ae5a4SJacob Faibussowitsch {
27d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)Y->data;
28d4002b98SHong Zhang 
29d4002b98SHong Zhang   PetscFunctionBegin;
30d4002b98SHong Zhang   if (Y->assembled && Y->rmap->rstart == Y->cmap->rstart && Y->rmap->rend == Y->cmap->rend) {
319566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(sell->A, D, is));
32d4002b98SHong Zhang   } else {
339566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet_Default(Y, D, is));
34d4002b98SHong Zhang   }
353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36d4002b98SHong Zhang }
37d4002b98SHong Zhang 
38d4002b98SHong Zhang /*
39d4002b98SHong Zhang   Local utility routine that creates a mapping from the global column
40d4002b98SHong Zhang number to the local number in the off-diagonal part of the local
41d4002b98SHong Zhang storage of the matrix.  When PETSC_USE_CTABLE is used this is scalable at
42d4002b98SHong Zhang a slightly higher hash table cost; without it it is not scalable (each processor
43da81f932SPierre Jolivet has an order N integer array but is fast to access.
44d4002b98SHong Zhang */
45d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateColmap_MPISELL_Private(Mat mat)
46d71ae5a4SJacob Faibussowitsch {
47d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
48d4002b98SHong Zhang   PetscInt     n    = sell->B->cmap->n, i;
49d4002b98SHong Zhang 
50d4002b98SHong Zhang   PetscFunctionBegin;
5128b400f6SJacob Faibussowitsch   PetscCheck(sell->garray, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MPISELL Matrix was assembled but is missing garray");
52d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE)
53eec179cfSJacob Faibussowitsch   PetscCall(PetscHMapICreateWithSize(n, &sell->colmap));
54c76ffc5fSJacob Faibussowitsch   for (i = 0; i < n; i++) PetscCall(PetscHMapISet(sell->colmap, sell->garray[i] + 1, i + 1));
55d4002b98SHong Zhang #else
569566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(mat->cmap->N + 1, &sell->colmap));
57d4002b98SHong Zhang   for (i = 0; i < n; i++) sell->colmap[sell->garray[i]] = i + 1;
58d4002b98SHong Zhang #endif
593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
60d4002b98SHong Zhang }
61d4002b98SHong Zhang 
62d4002b98SHong Zhang #define MatSetValues_SeqSELL_A_Private(row, col, value, addv, orow, ocol) \
63d4002b98SHong Zhang   { \
64d4002b98SHong Zhang     if (col <= lastcol1) low1 = 0; \
65d4002b98SHong Zhang     else high1 = nrow1; \
66d4002b98SHong Zhang     lastcol1 = col; \
67d4002b98SHong Zhang     while (high1 - low1 > 5) { \
68d4002b98SHong Zhang       t = (low1 + high1) / 2; \
694f8ff0b3SHong Zhang       if (cp1[sliceheight * t] > col) high1 = t; \
70d4002b98SHong Zhang       else low1 = t; \
71d4002b98SHong Zhang     } \
72d4002b98SHong Zhang     for (_i = low1; _i < high1; _i++) { \
734f8ff0b3SHong Zhang       if (cp1[sliceheight * _i] > col) break; \
744f8ff0b3SHong Zhang       if (cp1[sliceheight * _i] == col) { \
754f8ff0b3SHong Zhang         if (addv == ADD_VALUES) vp1[sliceheight * _i] += value; \
764f8ff0b3SHong Zhang         else vp1[sliceheight * _i] = value; \
772d1451d4SHong Zhang         inserted = PETSC_TRUE; \
78d4002b98SHong Zhang         goto a_noinsert; \
79d4002b98SHong Zhang       } \
80d4002b98SHong Zhang     } \
819371c9d4SSatish Balay     if (value == 0.0 && ignorezeroentries) { \
829371c9d4SSatish Balay       low1  = 0; \
839371c9d4SSatish Balay       high1 = nrow1; \
849371c9d4SSatish Balay       goto a_noinsert; \
859371c9d4SSatish Balay     } \
869371c9d4SSatish Balay     if (nonew == 1) { \
879371c9d4SSatish Balay       low1  = 0; \
889371c9d4SSatish Balay       high1 = nrow1; \
899371c9d4SSatish Balay       goto a_noinsert; \
909371c9d4SSatish Balay     } \
9108401ef6SPierre Jolivet     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); \
9207e43b41SHong Zhang     MatSeqXSELLReallocateSELL(A, am, 1, nrow1, a->sliidx, a->sliceheight, row / sliceheight, row, col, a->colidx, a->val, cp1, vp1, nonew, MatScalar); \
93d4002b98SHong Zhang     /* shift up all the later entries in this row */ \
94d4002b98SHong Zhang     for (ii = nrow1 - 1; ii >= _i; ii--) { \
954f8ff0b3SHong Zhang       cp1[sliceheight * (ii + 1)] = cp1[sliceheight * ii]; \
964f8ff0b3SHong Zhang       vp1[sliceheight * (ii + 1)] = vp1[sliceheight * ii]; \
97d4002b98SHong Zhang     } \
984f8ff0b3SHong Zhang     cp1[sliceheight * _i] = col; \
994f8ff0b3SHong Zhang     vp1[sliceheight * _i] = value; \
1009371c9d4SSatish Balay     a->nz++; \
1019371c9d4SSatish Balay     nrow1++; \
1029371c9d4SSatish Balay     A->nonzerostate++; \
103d4002b98SHong Zhang   a_noinsert:; \
104d4002b98SHong Zhang     a->rlen[row] = nrow1; \
105d4002b98SHong Zhang   }
106d4002b98SHong Zhang 
107d4002b98SHong Zhang #define MatSetValues_SeqSELL_B_Private(row, col, value, addv, orow, ocol) \
108d4002b98SHong Zhang   { \
109d4002b98SHong Zhang     if (col <= lastcol2) low2 = 0; \
110d4002b98SHong Zhang     else high2 = nrow2; \
111d4002b98SHong Zhang     lastcol2 = col; \
112d4002b98SHong Zhang     while (high2 - low2 > 5) { \
113d4002b98SHong Zhang       t = (low2 + high2) / 2; \
1144f8ff0b3SHong Zhang       if (cp2[sliceheight * t] > col) high2 = t; \
115d4002b98SHong Zhang       else low2 = t; \
116d4002b98SHong Zhang     } \
117d4002b98SHong Zhang     for (_i = low2; _i < high2; _i++) { \
1184f8ff0b3SHong Zhang       if (cp2[sliceheight * _i] > col) break; \
1194f8ff0b3SHong Zhang       if (cp2[sliceheight * _i] == col) { \
1204f8ff0b3SHong Zhang         if (addv == ADD_VALUES) vp2[sliceheight * _i] += value; \
1214f8ff0b3SHong Zhang         else vp2[sliceheight * _i] = value; \
1222d1451d4SHong Zhang         inserted = PETSC_TRUE; \
123d4002b98SHong Zhang         goto b_noinsert; \
124d4002b98SHong Zhang       } \
125d4002b98SHong Zhang     } \
1269371c9d4SSatish Balay     if (value == 0.0 && ignorezeroentries) { \
1279371c9d4SSatish Balay       low2  = 0; \
1289371c9d4SSatish Balay       high2 = nrow2; \
1299371c9d4SSatish Balay       goto b_noinsert; \
1309371c9d4SSatish Balay     } \
1319371c9d4SSatish Balay     if (nonew == 1) { \
1329371c9d4SSatish Balay       low2  = 0; \
1339371c9d4SSatish Balay       high2 = nrow2; \
1349371c9d4SSatish Balay       goto b_noinsert; \
1359371c9d4SSatish Balay     } \
13608401ef6SPierre Jolivet     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); \
13707e43b41SHong Zhang     MatSeqXSELLReallocateSELL(B, bm, 1, nrow2, b->sliidx, b->sliceheight, row / sliceheight, row, col, b->colidx, b->val, cp2, vp2, nonew, MatScalar); \
138d4002b98SHong Zhang     /* shift up all the later entries in this row */ \
139d4002b98SHong Zhang     for (ii = nrow2 - 1; ii >= _i; ii--) { \
1404f8ff0b3SHong Zhang       cp2[sliceheight * (ii + 1)] = cp2[sliceheight * ii]; \
1414f8ff0b3SHong Zhang       vp2[sliceheight * (ii + 1)] = vp2[sliceheight * ii]; \
142d4002b98SHong Zhang     } \
1434f8ff0b3SHong Zhang     cp2[sliceheight * _i] = col; \
1444f8ff0b3SHong Zhang     vp2[sliceheight * _i] = value; \
1459371c9d4SSatish Balay     b->nz++; \
1469371c9d4SSatish Balay     nrow2++; \
1479371c9d4SSatish Balay     B->nonzerostate++; \
148d4002b98SHong Zhang   b_noinsert:; \
149d4002b98SHong Zhang     b->rlen[row] = nrow2; \
150d4002b98SHong Zhang   }
151d4002b98SHong Zhang 
152d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetValues_MPISELL(Mat mat, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode addv)
153d71ae5a4SJacob Faibussowitsch {
154d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
155d4002b98SHong Zhang   PetscScalar  value;
156d4002b98SHong Zhang   PetscInt     i, j, rstart = mat->rmap->rstart, rend = mat->rmap->rend, shift1, shift2;
157d4002b98SHong Zhang   PetscInt     cstart = mat->cmap->rstart, cend = mat->cmap->rend, row, col;
158d4002b98SHong Zhang   PetscBool    roworiented = sell->roworiented;
159d4002b98SHong Zhang 
160d4002b98SHong Zhang   /* Some Variables required in the macro */
161d4002b98SHong Zhang   Mat          A                 = sell->A;
162d4002b98SHong Zhang   Mat_SeqSELL *a                 = (Mat_SeqSELL *)A->data;
163d4002b98SHong Zhang   PetscBool    ignorezeroentries = a->ignorezeroentries, found;
164d4002b98SHong Zhang   Mat          B                 = sell->B;
165d4002b98SHong Zhang   Mat_SeqSELL *b                 = (Mat_SeqSELL *)B->data;
16607e43b41SHong Zhang   PetscInt    *cp1, *cp2, ii, _i, nrow1, nrow2, low1, high1, low2, high2, t, lastcol1, lastcol2, sliceheight = a->sliceheight;
167d4002b98SHong Zhang   MatScalar   *vp1, *vp2;
168d4002b98SHong Zhang 
169d4002b98SHong Zhang   PetscFunctionBegin;
170d4002b98SHong Zhang   for (i = 0; i < m; i++) {
171d4002b98SHong Zhang     if (im[i] < 0) continue;
1726bdcaf15SBarry Smith     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);
173d4002b98SHong Zhang     if (im[i] >= rstart && im[i] < rend) {
174d4002b98SHong Zhang       row      = im[i] - rstart;
175d4002b98SHong Zhang       lastcol1 = -1;
17607e43b41SHong Zhang       shift1   = a->sliidx[row / sliceheight] + (row % sliceheight); /* starting index of the row */
177d4002b98SHong Zhang       cp1      = a->colidx + shift1;
178d4002b98SHong Zhang       vp1      = a->val + shift1;
179d4002b98SHong Zhang       nrow1    = a->rlen[row];
180d4002b98SHong Zhang       low1     = 0;
181d4002b98SHong Zhang       high1    = nrow1;
182d4002b98SHong Zhang       lastcol2 = -1;
18307e43b41SHong Zhang       shift2   = b->sliidx[row / sliceheight] + (row % sliceheight); /* starting index of the row */
184d4002b98SHong Zhang       cp2      = b->colidx + shift2;
185d4002b98SHong Zhang       vp2      = b->val + shift2;
186d4002b98SHong Zhang       nrow2    = b->rlen[row];
187d4002b98SHong Zhang       low2     = 0;
188d4002b98SHong Zhang       high2    = nrow2;
189d4002b98SHong Zhang 
190d4002b98SHong Zhang       for (j = 0; j < n; j++) {
191d4002b98SHong Zhang         if (roworiented) value = v[i * n + j];
192d4002b98SHong Zhang         else value = v[i + j * m];
193d4002b98SHong Zhang         if (ignorezeroentries && value == 0.0 && (addv == ADD_VALUES)) continue;
194d4002b98SHong Zhang         if (in[j] >= cstart && in[j] < cend) {
195d4002b98SHong Zhang           col = in[j] - cstart;
196d4002b98SHong Zhang           MatSetValue_SeqSELL_Private(A, row, col, value, addv, im[i], in[j], cp1, vp1, lastcol1, low1, high1); /* set one value */
1972d1451d4SHong Zhang #if defined(PETSC_HAVE_CUDA)
1982d1451d4SHong Zhang           if (A->offloadmask != PETSC_OFFLOAD_UNALLOCATED && found) A->offloadmask = PETSC_OFFLOAD_CPU;
1992d1451d4SHong Zhang #endif
200f7d195e4SLawrence Mitchell         } else if (in[j] < 0) {
201f7d195e4SLawrence Mitchell           continue;
202f7d195e4SLawrence Mitchell         } else {
203f7d195e4SLawrence Mitchell           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);
204d4002b98SHong Zhang           if (mat->was_assembled) {
20548a46eb9SPierre Jolivet             if (!sell->colmap) PetscCall(MatCreateColmap_MPISELL_Private(mat));
206d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE)
207eec179cfSJacob Faibussowitsch             PetscCall(PetscHMapIGetWithDefault(sell->colmap, in[j] + 1, 0, &col));
208d4002b98SHong Zhang             col--;
209d4002b98SHong Zhang #else
210d4002b98SHong Zhang             col = sell->colmap[in[j]] - 1;
211d4002b98SHong Zhang #endif
212d4002b98SHong Zhang             if (col < 0 && !((Mat_SeqSELL *)(sell->B->data))->nonew) {
2139566063dSJacob Faibussowitsch               PetscCall(MatDisAssemble_MPISELL(mat));
214d4002b98SHong Zhang               col = in[j];
215d4002b98SHong Zhang               /* Reinitialize the variables required by MatSetValues_SeqSELL_B_Private() */
216d4002b98SHong Zhang               B      = sell->B;
217d4002b98SHong Zhang               b      = (Mat_SeqSELL *)B->data;
21807e43b41SHong Zhang               shift2 = b->sliidx[row / sliceheight] + (row % sliceheight); /* starting index of the row */
219d4002b98SHong Zhang               cp2    = b->colidx + shift2;
220d4002b98SHong Zhang               vp2    = b->val + shift2;
221d4002b98SHong Zhang               nrow2  = b->rlen[row];
222d4002b98SHong Zhang               low2   = 0;
223d4002b98SHong Zhang               high2  = nrow2;
2242d1451d4SHong Zhang               found  = PETSC_FALSE;
225f7d195e4SLawrence Mitchell             } else {
226f7d195e4SLawrence Mitchell               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]);
227f7d195e4SLawrence Mitchell             }
228d4002b98SHong Zhang           } else col = in[j];
229d4002b98SHong Zhang           MatSetValue_SeqSELL_Private(B, row, col, value, addv, im[i], in[j], cp2, vp2, lastcol2, low2, high2); /* set one value */
2302d1451d4SHong Zhang #if defined(PETSC_HAVE_CUDA)
2312d1451d4SHong Zhang           if (B->offloadmask != PETSC_OFFLOAD_UNALLOCATED && found) B->offloadmask = PETSC_OFFLOAD_CPU;
2322d1451d4SHong Zhang #endif
233d4002b98SHong Zhang         }
234d4002b98SHong Zhang       }
235d4002b98SHong Zhang     } else {
23628b400f6SJacob Faibussowitsch       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]);
237d4002b98SHong Zhang       if (!sell->donotstash) {
238d4002b98SHong Zhang         mat->assembled = PETSC_FALSE;
239d4002b98SHong Zhang         if (roworiented) {
2409566063dSJacob Faibussowitsch           PetscCall(MatStashValuesRow_Private(&mat->stash, im[i], n, in, v + i * n, (PetscBool)(ignorezeroentries && (addv == ADD_VALUES))));
241d4002b98SHong Zhang         } else {
2429566063dSJacob Faibussowitsch           PetscCall(MatStashValuesCol_Private(&mat->stash, im[i], n, in, v + i, m, (PetscBool)(ignorezeroentries && (addv == ADD_VALUES))));
243d4002b98SHong Zhang         }
244d4002b98SHong Zhang       }
245d4002b98SHong Zhang     }
246d4002b98SHong Zhang   }
2473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
248d4002b98SHong Zhang }
249d4002b98SHong Zhang 
250ba38deedSJacob Faibussowitsch static PetscErrorCode MatGetValues_MPISELL(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], PetscScalar v[])
251d71ae5a4SJacob Faibussowitsch {
252d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
253d4002b98SHong Zhang   PetscInt     i, j, rstart = mat->rmap->rstart, rend = mat->rmap->rend;
254d4002b98SHong Zhang   PetscInt     cstart = mat->cmap->rstart, cend = mat->cmap->rend, row, col;
255d4002b98SHong Zhang 
256d4002b98SHong Zhang   PetscFunctionBegin;
257d4002b98SHong Zhang   for (i = 0; i < m; i++) {
25854c59aa7SJacob Faibussowitsch     if (idxm[i] < 0) continue; /* negative row */
25954c59aa7SJacob Faibussowitsch     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);
260d4002b98SHong Zhang     if (idxm[i] >= rstart && idxm[i] < rend) {
261d4002b98SHong Zhang       row = idxm[i] - rstart;
262d4002b98SHong Zhang       for (j = 0; j < n; j++) {
26354c59aa7SJacob Faibussowitsch         if (idxn[j] < 0) continue; /* negative column */
26454c59aa7SJacob Faibussowitsch         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);
265d4002b98SHong Zhang         if (idxn[j] >= cstart && idxn[j] < cend) {
266d4002b98SHong Zhang           col = idxn[j] - cstart;
2679566063dSJacob Faibussowitsch           PetscCall(MatGetValues(sell->A, 1, &row, 1, &col, v + i * n + j));
268d4002b98SHong Zhang         } else {
26948a46eb9SPierre Jolivet           if (!sell->colmap) PetscCall(MatCreateColmap_MPISELL_Private(mat));
270d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE)
271eec179cfSJacob Faibussowitsch           PetscCall(PetscHMapIGetWithDefault(sell->colmap, idxn[j] + 1, 0, &col));
272d4002b98SHong Zhang           col--;
273d4002b98SHong Zhang #else
274d4002b98SHong Zhang           col = sell->colmap[idxn[j]] - 1;
275d4002b98SHong Zhang #endif
276d4002b98SHong Zhang           if ((col < 0) || (sell->garray[col] != idxn[j])) *(v + i * n + j) = 0.0;
27748a46eb9SPierre Jolivet           else PetscCall(MatGetValues(sell->B, 1, &row, 1, &col, v + i * n + j));
278d4002b98SHong Zhang         }
279d4002b98SHong Zhang       }
280d4002b98SHong Zhang     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only local values currently supported");
281d4002b98SHong Zhang   }
2823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
283d4002b98SHong Zhang }
284d4002b98SHong Zhang 
285ba38deedSJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_MPISELL(Mat mat, MatAssemblyType mode)
286d71ae5a4SJacob Faibussowitsch {
287d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
288d4002b98SHong Zhang   PetscInt     nstash, reallocs;
289d4002b98SHong Zhang 
290d4002b98SHong Zhang   PetscFunctionBegin;
2913ba16761SJacob Faibussowitsch   if (sell->donotstash || mat->nooffprocentries) PetscFunctionReturn(PETSC_SUCCESS);
292d4002b98SHong Zhang 
2939566063dSJacob Faibussowitsch   PetscCall(MatStashScatterBegin_Private(mat, &mat->stash, mat->rmap->range));
2949566063dSJacob Faibussowitsch   PetscCall(MatStashGetInfo_Private(&mat->stash, &nstash, &reallocs));
2959566063dSJacob Faibussowitsch   PetscCall(PetscInfo(sell->A, "Stash has %" PetscInt_FMT " entries, uses %" PetscInt_FMT " mallocs.\n", nstash, reallocs));
2963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
297d4002b98SHong Zhang }
298d4002b98SHong Zhang 
299d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAssemblyEnd_MPISELL(Mat mat, MatAssemblyType mode)
300d71ae5a4SJacob Faibussowitsch {
301d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
302d4002b98SHong Zhang   PetscMPIInt  n;
303d4002b98SHong Zhang   PetscInt     i, flg;
304d4002b98SHong Zhang   PetscInt    *row, *col;
305d4002b98SHong Zhang   PetscScalar *val;
306d4002b98SHong Zhang   PetscBool    other_disassembled;
307d4002b98SHong Zhang   /* do not use 'b = (Mat_SeqSELL*)sell->B->data' as B can be reset in disassembly */
308d4002b98SHong Zhang   PetscFunctionBegin;
309d4002b98SHong Zhang   if (!sell->donotstash && !mat->nooffprocentries) {
310d4002b98SHong Zhang     while (1) {
3119566063dSJacob Faibussowitsch       PetscCall(MatStashScatterGetMesg_Private(&mat->stash, &n, &row, &col, &val, &flg));
312d4002b98SHong Zhang       if (!flg) break;
313d4002b98SHong Zhang 
314d4002b98SHong Zhang       for (i = 0; i < n; i++) { /* assemble one by one */
3159566063dSJacob Faibussowitsch         PetscCall(MatSetValues_MPISELL(mat, 1, row + i, 1, col + i, val + i, mat->insertmode));
316d4002b98SHong Zhang       }
317d4002b98SHong Zhang     }
3189566063dSJacob Faibussowitsch     PetscCall(MatStashScatterEnd_Private(&mat->stash));
319d4002b98SHong Zhang   }
3202d1451d4SHong Zhang #if defined(PETSC_HAVE_CUDA)
3212d1451d4SHong Zhang   if (mat->offloadmask == PETSC_OFFLOAD_CPU) sell->A->offloadmask = PETSC_OFFLOAD_CPU;
3222d1451d4SHong Zhang #endif
3239566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(sell->A, mode));
3249566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(sell->A, mode));
325d4002b98SHong Zhang 
326d4002b98SHong Zhang   /*
327d4002b98SHong Zhang      determine if any processor has disassembled, if so we must
3286aad120cSJose E. Roman      also disassemble ourselves, in order that we may reassemble.
329d4002b98SHong Zhang   */
330d4002b98SHong Zhang   /*
331d4002b98SHong Zhang      if nonzero structure of submatrix B cannot change then we know that
332d4002b98SHong Zhang      no processor disassembled thus we can skip this stuff
333d4002b98SHong Zhang   */
334d4002b98SHong Zhang   if (!((Mat_SeqSELL *)sell->B->data)->nonew) {
3355f9db2b2SJunchao Zhang     PetscCall(MPIU_Allreduce(&mat->was_assembled, &other_disassembled, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
3362d1451d4SHong Zhang     if (mat->was_assembled && !other_disassembled) PetscCall(MatDisAssemble_MPISELL(mat));
337d4002b98SHong Zhang   }
33848a46eb9SPierre Jolivet   if (!mat->was_assembled && mode == MAT_FINAL_ASSEMBLY) PetscCall(MatSetUpMultiply_MPISELL(mat));
3392d1451d4SHong Zhang #if defined(PETSC_HAVE_CUDA)
3402d1451d4SHong Zhang   if (mat->offloadmask == PETSC_OFFLOAD_CPU && sell->B->offloadmask != PETSC_OFFLOAD_UNALLOCATED) sell->B->offloadmask = PETSC_OFFLOAD_CPU;
3412d1451d4SHong Zhang #endif
3429566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(sell->B, mode));
3439566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(sell->B, mode));
3449566063dSJacob Faibussowitsch   PetscCall(PetscFree2(sell->rowvalues, sell->rowindices));
345f4259b30SLisandro Dalcin   sell->rowvalues = NULL;
3469566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sell->diag));
347d4002b98SHong Zhang 
348d4002b98SHong Zhang   /* if no new nonzero locations are allowed in matrix then only set the matrix state the first time through */
349d4002b98SHong Zhang   if ((!mat->was_assembled && mode == MAT_FINAL_ASSEMBLY) || !((Mat_SeqSELL *)(sell->A->data))->nonew) {
350d4002b98SHong Zhang     PetscObjectState state = sell->A->nonzerostate + sell->B->nonzerostate;
3511c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&state, &mat->nonzerostate, 1, MPIU_INT64, MPI_SUM, PetscObjectComm((PetscObject)mat)));
352d4002b98SHong Zhang   }
3532d1451d4SHong Zhang #if defined(PETSC_HAVE_CUDA)
3542d1451d4SHong Zhang   mat->offloadmask = PETSC_OFFLOAD_BOTH;
3552d1451d4SHong Zhang #endif
3563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
357d4002b98SHong Zhang }
358d4002b98SHong Zhang 
359ba38deedSJacob Faibussowitsch static PetscErrorCode MatZeroEntries_MPISELL(Mat A)
360d71ae5a4SJacob Faibussowitsch {
361d4002b98SHong Zhang   Mat_MPISELL *l = (Mat_MPISELL *)A->data;
362d4002b98SHong Zhang 
363d4002b98SHong Zhang   PetscFunctionBegin;
3649566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(l->A));
3659566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(l->B));
3663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
367d4002b98SHong Zhang }
368d4002b98SHong Zhang 
369ba38deedSJacob Faibussowitsch static PetscErrorCode MatMult_MPISELL(Mat A, Vec xx, Vec yy)
370d71ae5a4SJacob Faibussowitsch {
371d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
372d4002b98SHong Zhang   PetscInt     nt;
373d4002b98SHong Zhang 
374d4002b98SHong Zhang   PetscFunctionBegin;
3759566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(xx, &nt));
37608401ef6SPierre Jolivet   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);
3779566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
3789566063dSJacob Faibussowitsch   PetscCall((*a->A->ops->mult)(a->A, xx, yy));
3799566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
3809566063dSJacob Faibussowitsch   PetscCall((*a->B->ops->multadd)(a->B, a->lvec, yy, yy));
3813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
382d4002b98SHong Zhang }
383d4002b98SHong Zhang 
384*fa078d78SJacob Faibussowitsch static PetscErrorCode MatMultDiagonalBlock_MPISELL(Mat A, Vec bb, Vec xx)
385d71ae5a4SJacob Faibussowitsch {
386d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
387d4002b98SHong Zhang 
388d4002b98SHong Zhang   PetscFunctionBegin;
3899566063dSJacob Faibussowitsch   PetscCall(MatMultDiagonalBlock(a->A, bb, xx));
3903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
391d4002b98SHong Zhang }
392d4002b98SHong Zhang 
393ba38deedSJacob Faibussowitsch static PetscErrorCode MatMultAdd_MPISELL(Mat A, Vec xx, Vec yy, Vec zz)
394d71ae5a4SJacob Faibussowitsch {
395d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
396d4002b98SHong Zhang 
397d4002b98SHong Zhang   PetscFunctionBegin;
3989566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
3999566063dSJacob Faibussowitsch   PetscCall((*a->A->ops->multadd)(a->A, xx, yy, zz));
4009566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
4019566063dSJacob Faibussowitsch   PetscCall((*a->B->ops->multadd)(a->B, a->lvec, zz, zz));
4023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
403d4002b98SHong Zhang }
404d4002b98SHong Zhang 
405ba38deedSJacob Faibussowitsch static PetscErrorCode MatMultTranspose_MPISELL(Mat A, Vec xx, Vec yy)
406d71ae5a4SJacob Faibussowitsch {
407d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
408d4002b98SHong Zhang 
409d4002b98SHong Zhang   PetscFunctionBegin;
410d4002b98SHong Zhang   /* do nondiagonal part */
4119566063dSJacob Faibussowitsch   PetscCall((*a->B->ops->multtranspose)(a->B, xx, a->lvec));
412d4002b98SHong Zhang   /* do local part */
4139566063dSJacob Faibussowitsch   PetscCall((*a->A->ops->multtranspose)(a->A, xx, yy));
414a29b4eb7SJunchao Zhang   /* add partial results together */
4159566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(a->Mvctx, a->lvec, yy, ADD_VALUES, SCATTER_REVERSE));
4169566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(a->Mvctx, a->lvec, yy, ADD_VALUES, SCATTER_REVERSE));
4173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
418d4002b98SHong Zhang }
419d4002b98SHong Zhang 
420ba38deedSJacob Faibussowitsch static PetscErrorCode MatIsTranspose_MPISELL(Mat Amat, Mat Bmat, PetscReal tol, PetscBool *f)
421d71ae5a4SJacob Faibussowitsch {
422d4002b98SHong Zhang   MPI_Comm     comm;
423d4002b98SHong Zhang   Mat_MPISELL *Asell = (Mat_MPISELL *)Amat->data, *Bsell;
424d4002b98SHong Zhang   Mat          Adia  = Asell->A, Bdia, Aoff, Boff, *Aoffs, *Boffs;
425d4002b98SHong Zhang   IS           Me, Notme;
426d4002b98SHong Zhang   PetscInt     M, N, first, last, *notme, i;
427d4002b98SHong Zhang   PetscMPIInt  size;
428d4002b98SHong Zhang 
429d4002b98SHong Zhang   PetscFunctionBegin;
430d4002b98SHong Zhang   /* Easy test: symmetric diagonal block */
4319371c9d4SSatish Balay   Bsell = (Mat_MPISELL *)Bmat->data;
4329371c9d4SSatish Balay   Bdia  = Bsell->A;
4339566063dSJacob Faibussowitsch   PetscCall(MatIsTranspose(Adia, Bdia, tol, f));
4343ba16761SJacob Faibussowitsch   if (!*f) PetscFunctionReturn(PETSC_SUCCESS);
4359566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)Amat, &comm));
4369566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
4373ba16761SJacob Faibussowitsch   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
438d4002b98SHong Zhang 
439d4002b98SHong Zhang   /* Hard test: off-diagonal block. This takes a MatCreateSubMatrix. */
4409566063dSJacob Faibussowitsch   PetscCall(MatGetSize(Amat, &M, &N));
4419566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(Amat, &first, &last));
4429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(N - last + first, &notme));
443d4002b98SHong Zhang   for (i = 0; i < first; i++) notme[i] = i;
444d4002b98SHong Zhang   for (i = last; i < M; i++) notme[i - last + first] = i;
4459566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(MPI_COMM_SELF, N - last + first, notme, PETSC_COPY_VALUES, &Notme));
4469566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(MPI_COMM_SELF, last - first, first, 1, &Me));
4479566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(Amat, 1, &Me, &Notme, MAT_INITIAL_MATRIX, &Aoffs));
448d4002b98SHong Zhang   Aoff = Aoffs[0];
4499566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(Bmat, 1, &Notme, &Me, MAT_INITIAL_MATRIX, &Boffs));
450d4002b98SHong Zhang   Boff = Boffs[0];
4519566063dSJacob Faibussowitsch   PetscCall(MatIsTranspose(Aoff, Boff, tol, f));
4529566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1, &Aoffs));
4539566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1, &Boffs));
4549566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&Me));
4559566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&Notme));
4569566063dSJacob Faibussowitsch   PetscCall(PetscFree(notme));
4573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
458d4002b98SHong Zhang }
459d4002b98SHong Zhang 
460ba38deedSJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_MPISELL(Mat A, Vec xx, Vec yy, Vec zz)
461d71ae5a4SJacob Faibussowitsch {
462d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
463d4002b98SHong Zhang 
464d4002b98SHong Zhang   PetscFunctionBegin;
465d4002b98SHong Zhang   /* do nondiagonal part */
4669566063dSJacob Faibussowitsch   PetscCall((*a->B->ops->multtranspose)(a->B, xx, a->lvec));
467d4002b98SHong Zhang   /* do local part */
4689566063dSJacob Faibussowitsch   PetscCall((*a->A->ops->multtransposeadd)(a->A, xx, yy, zz));
469e4a140f6SJunchao Zhang   /* add partial results together */
4709566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(a->Mvctx, a->lvec, zz, ADD_VALUES, SCATTER_REVERSE));
4719566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(a->Mvctx, a->lvec, zz, ADD_VALUES, SCATTER_REVERSE));
4723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
473d4002b98SHong Zhang }
474d4002b98SHong Zhang 
475d4002b98SHong Zhang /*
476d4002b98SHong Zhang   This only works correctly for square matrices where the subblock A->A is the
477d4002b98SHong Zhang    diagonal block
478d4002b98SHong Zhang */
479ba38deedSJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_MPISELL(Mat A, Vec v)
480d71ae5a4SJacob Faibussowitsch {
481d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
482d4002b98SHong Zhang 
483d4002b98SHong Zhang   PetscFunctionBegin;
48408401ef6SPierre Jolivet   PetscCheck(A->rmap->N == A->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Supports only square matrix where A->A is diag block");
485aed4548fSBarry Smith   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");
4869566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(a->A, v));
4873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
488d4002b98SHong Zhang }
489d4002b98SHong Zhang 
490ba38deedSJacob Faibussowitsch static PetscErrorCode MatScale_MPISELL(Mat A, PetscScalar aa)
491d71ae5a4SJacob Faibussowitsch {
492d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
493d4002b98SHong Zhang 
494d4002b98SHong Zhang   PetscFunctionBegin;
4959566063dSJacob Faibussowitsch   PetscCall(MatScale(a->A, aa));
4969566063dSJacob Faibussowitsch   PetscCall(MatScale(a->B, aa));
4973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
498d4002b98SHong Zhang }
499d4002b98SHong Zhang 
500d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDestroy_MPISELL(Mat mat)
501d71ae5a4SJacob Faibussowitsch {
502d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
503d4002b98SHong Zhang 
504d4002b98SHong Zhang   PetscFunctionBegin;
5053ba16761SJacob Faibussowitsch   PetscCall(PetscLogObjectState((PetscObject)mat, "Rows=%" PetscInt_FMT ", Cols=%" PetscInt_FMT, mat->rmap->N, mat->cmap->N));
5069566063dSJacob Faibussowitsch   PetscCall(MatStashDestroy_Private(&mat->stash));
5079566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sell->diag));
5089566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sell->A));
5099566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sell->B));
510d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE)
511eec179cfSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&sell->colmap));
512d4002b98SHong Zhang #else
5139566063dSJacob Faibussowitsch   PetscCall(PetscFree(sell->colmap));
514d4002b98SHong Zhang #endif
5159566063dSJacob Faibussowitsch   PetscCall(PetscFree(sell->garray));
5169566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sell->lvec));
5179566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&sell->Mvctx));
5189566063dSJacob Faibussowitsch   PetscCall(PetscFree2(sell->rowvalues, sell->rowindices));
5199566063dSJacob Faibussowitsch   PetscCall(PetscFree(sell->ld));
5209566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
521d4002b98SHong Zhang 
5229566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)mat, NULL));
5239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatStoreValues_C", NULL));
5249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatRetrieveValues_C", NULL));
5259566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatIsTranspose_C", NULL));
5269566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMPISELLSetPreallocation_C", NULL));
5279566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpisell_mpiaij_C", NULL));
528b5917f1bSHong Zhang #if defined(PETSC_HAVE_CUDA)
529b5917f1bSHong Zhang   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpisell_mpisellcuda_C", NULL));
530b5917f1bSHong Zhang #endif
5319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalScaleLocal_C", NULL));
5323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
533d4002b98SHong Zhang }
534d4002b98SHong Zhang 
535d4002b98SHong Zhang #include <petscdraw.h>
536ba38deedSJacob Faibussowitsch static PetscErrorCode MatView_MPISELL_ASCIIorDraworSocket(Mat mat, PetscViewer viewer)
537d71ae5a4SJacob Faibussowitsch {
538d4002b98SHong Zhang   Mat_MPISELL      *sell = (Mat_MPISELL *)mat->data;
539d4002b98SHong Zhang   PetscMPIInt       rank = sell->rank, size = sell->size;
540d4002b98SHong Zhang   PetscBool         isdraw, iascii, isbinary;
541d4002b98SHong Zhang   PetscViewer       sviewer;
542d4002b98SHong Zhang   PetscViewerFormat format;
543d4002b98SHong Zhang 
544d4002b98SHong Zhang   PetscFunctionBegin;
5459566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
5469566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
5479566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
548d4002b98SHong Zhang   if (iascii) {
5499566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
550d4002b98SHong Zhang     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
551d4002b98SHong Zhang       MatInfo   info;
5526335e310SSatish Balay       PetscInt *inodes;
553d4002b98SHong Zhang 
5549566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank));
5559566063dSJacob Faibussowitsch       PetscCall(MatGetInfo(mat, MAT_LOCAL, &info));
5569566063dSJacob Faibussowitsch       PetscCall(MatInodeGetInodeSizes(sell->A, NULL, &inodes, NULL));
5579566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
558d4002b98SHong Zhang       if (!inodes) {
5599371c9d4SSatish Balay         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,
5609371c9d4SSatish Balay                                                      (PetscInt)info.nz_allocated, (PetscInt)info.memory));
561d4002b98SHong Zhang       } else {
5629371c9d4SSatish Balay         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,
5639371c9d4SSatish Balay                                                      (PetscInt)info.nz_allocated, (PetscInt)info.memory));
564d4002b98SHong Zhang       }
5659566063dSJacob Faibussowitsch       PetscCall(MatGetInfo(sell->A, MAT_LOCAL, &info));
5669566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] on-diagonal part: nz %" PetscInt_FMT " \n", rank, (PetscInt)info.nz_used));
5679566063dSJacob Faibussowitsch       PetscCall(MatGetInfo(sell->B, MAT_LOCAL, &info));
5689566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] off-diagonal part: nz %" PetscInt_FMT " \n", rank, (PetscInt)info.nz_used));
5699566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
5709566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
5719566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Information on VecScatter used in matrix-vector product: \n"));
5729566063dSJacob Faibussowitsch       PetscCall(VecScatterView(sell->Mvctx, viewer));
5733ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
574d4002b98SHong Zhang     } else if (format == PETSC_VIEWER_ASCII_INFO) {
575d4002b98SHong Zhang       PetscInt inodecount, inodelimit, *inodes;
5769566063dSJacob Faibussowitsch       PetscCall(MatInodeGetInodeSizes(sell->A, &inodecount, &inodes, &inodelimit));
577d4002b98SHong Zhang       if (inodes) {
5789566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "using I-node (on process 0) routines: found %" PetscInt_FMT " nodes, limit used is %" PetscInt_FMT "\n", inodecount, inodelimit));
579d4002b98SHong Zhang       } else {
5809566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "not using I-node (on process 0) routines\n"));
581d4002b98SHong Zhang       }
5823ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
583d4002b98SHong Zhang     } else if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
5843ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
585d4002b98SHong Zhang     }
586d4002b98SHong Zhang   } else if (isbinary) {
587d4002b98SHong Zhang     if (size == 1) {
5889566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)sell->A, ((PetscObject)mat)->name));
5899566063dSJacob Faibussowitsch       PetscCall(MatView(sell->A, viewer));
590d4002b98SHong Zhang     } else {
5919566063dSJacob Faibussowitsch       /* PetscCall(MatView_MPISELL_Binary(mat,viewer)); */
592d4002b98SHong Zhang     }
5933ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
594d4002b98SHong Zhang   } else if (isdraw) {
595d4002b98SHong Zhang     PetscDraw draw;
596d4002b98SHong Zhang     PetscBool isnull;
5979566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
5989566063dSJacob Faibussowitsch     PetscCall(PetscDrawIsNull(draw, &isnull));
5993ba16761SJacob Faibussowitsch     if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
600d4002b98SHong Zhang   }
601d4002b98SHong Zhang 
602d4002b98SHong Zhang   {
603d4002b98SHong Zhang     /* assemble the entire matrix onto first processor. */
604d4002b98SHong Zhang     Mat          A;
605d4002b98SHong Zhang     Mat_SeqSELL *Aloc;
606d4002b98SHong Zhang     PetscInt     M = mat->rmap->N, N = mat->cmap->N, *acolidx, row, col, i, j;
607d4002b98SHong Zhang     MatScalar   *aval;
608d4002b98SHong Zhang     PetscBool    isnonzero;
609d4002b98SHong Zhang 
6109566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &A));
611dd400576SPatrick Sanan     if (rank == 0) {
6129566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(A, M, N, M, N));
613d4002b98SHong Zhang     } else {
6149566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(A, 0, 0, M, N));
615d4002b98SHong Zhang     }
616d4002b98SHong Zhang     /* This is just a temporary matrix, so explicitly using MATMPISELL is probably best */
6179566063dSJacob Faibussowitsch     PetscCall(MatSetType(A, MATMPISELL));
6189566063dSJacob Faibussowitsch     PetscCall(MatMPISELLSetPreallocation(A, 0, NULL, 0, NULL));
6199566063dSJacob Faibussowitsch     PetscCall(MatSetOption(A, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
620d4002b98SHong Zhang 
621d4002b98SHong Zhang     /* copy over the A part */
622d4002b98SHong Zhang     Aloc    = (Mat_SeqSELL *)sell->A->data;
6239371c9d4SSatish Balay     acolidx = Aloc->colidx;
6249371c9d4SSatish Balay     aval    = Aloc->val;
625d4002b98SHong Zhang     for (i = 0; i < Aloc->totalslices; i++) { /* loop over slices */
626d4002b98SHong Zhang       for (j = Aloc->sliidx[i]; j < Aloc->sliidx[i + 1]; j++) {
62707e43b41SHong Zhang         isnonzero = (PetscBool)((j - Aloc->sliidx[i]) / Aloc->sliceheight < Aloc->rlen[i * Aloc->sliceheight + j % Aloc->sliceheight]);
628d4002b98SHong Zhang         if (isnonzero) { /* check the mask bit */
62907e43b41SHong Zhang           row = i * Aloc->sliceheight + j % Aloc->sliceheight + mat->rmap->rstart;
630d4002b98SHong Zhang           col = *acolidx + mat->rmap->rstart;
6319566063dSJacob Faibussowitsch           PetscCall(MatSetValues(A, 1, &row, 1, &col, aval, INSERT_VALUES));
632d4002b98SHong Zhang         }
6339371c9d4SSatish Balay         aval++;
6349371c9d4SSatish Balay         acolidx++;
635d4002b98SHong Zhang       }
636d4002b98SHong Zhang     }
637d4002b98SHong Zhang 
638d4002b98SHong Zhang     /* copy over the B part */
639d4002b98SHong Zhang     Aloc    = (Mat_SeqSELL *)sell->B->data;
6409371c9d4SSatish Balay     acolidx = Aloc->colidx;
6419371c9d4SSatish Balay     aval    = Aloc->val;
642d4002b98SHong Zhang     for (i = 0; i < Aloc->totalslices; i++) {
643d4002b98SHong Zhang       for (j = Aloc->sliidx[i]; j < Aloc->sliidx[i + 1]; j++) {
64407e43b41SHong Zhang         isnonzero = (PetscBool)((j - Aloc->sliidx[i]) / Aloc->sliceheight < Aloc->rlen[i * Aloc->sliceheight + j % Aloc->sliceheight]);
645d4002b98SHong Zhang         if (isnonzero) {
64607e43b41SHong Zhang           row = i * Aloc->sliceheight + j % Aloc->sliceheight + mat->rmap->rstart;
647d4002b98SHong Zhang           col = sell->garray[*acolidx];
6489566063dSJacob Faibussowitsch           PetscCall(MatSetValues(A, 1, &row, 1, &col, aval, INSERT_VALUES));
649d4002b98SHong Zhang         }
6509371c9d4SSatish Balay         aval++;
6519371c9d4SSatish Balay         acolidx++;
652d4002b98SHong Zhang       }
653d4002b98SHong Zhang     }
654d4002b98SHong Zhang 
6559566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
6569566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
657d4002b98SHong Zhang     /*
658d4002b98SHong Zhang        Everyone has to call to draw the matrix since the graphics waits are
659d4002b98SHong Zhang        synchronized across all processors that share the PetscDraw object
660d4002b98SHong Zhang     */
6619566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
662dd400576SPatrick Sanan     if (rank == 0) {
6639566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)((Mat_MPISELL *)(A->data))->A, ((PetscObject)mat)->name));
6649566063dSJacob Faibussowitsch       PetscCall(MatView_SeqSELL(((Mat_MPISELL *)(A->data))->A, sviewer));
665d4002b98SHong Zhang     }
6669566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
6679566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
6689566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A));
669d4002b98SHong Zhang   }
6703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
671d4002b98SHong Zhang }
672d4002b98SHong Zhang 
673ba38deedSJacob Faibussowitsch static PetscErrorCode MatView_MPISELL(Mat mat, PetscViewer viewer)
674d71ae5a4SJacob Faibussowitsch {
675d4002b98SHong Zhang   PetscBool iascii, isdraw, issocket, isbinary;
676d4002b98SHong Zhang 
677d4002b98SHong Zhang   PetscFunctionBegin;
6789566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
6799566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
6809566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
6819566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSOCKET, &issocket));
68248a46eb9SPierre Jolivet   if (iascii || isdraw || isbinary || issocket) PetscCall(MatView_MPISELL_ASCIIorDraworSocket(mat, viewer));
6833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
684d4002b98SHong Zhang }
685d4002b98SHong Zhang 
686ba38deedSJacob Faibussowitsch static PetscErrorCode MatGetGhosts_MPISELL(Mat mat, PetscInt *nghosts, const PetscInt *ghosts[])
687d71ae5a4SJacob Faibussowitsch {
688d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
689d4002b98SHong Zhang 
690d4002b98SHong Zhang   PetscFunctionBegin;
6919566063dSJacob Faibussowitsch   PetscCall(MatGetSize(sell->B, NULL, nghosts));
692d4002b98SHong Zhang   if (ghosts) *ghosts = sell->garray;
6933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
694d4002b98SHong Zhang }
695d4002b98SHong Zhang 
696ba38deedSJacob Faibussowitsch static PetscErrorCode MatGetInfo_MPISELL(Mat matin, MatInfoType flag, MatInfo *info)
697d71ae5a4SJacob Faibussowitsch {
698d4002b98SHong Zhang   Mat_MPISELL   *mat = (Mat_MPISELL *)matin->data;
699d4002b98SHong Zhang   Mat            A = mat->A, B = mat->B;
7003966268fSBarry Smith   PetscLogDouble isend[5], irecv[5];
701d4002b98SHong Zhang 
702d4002b98SHong Zhang   PetscFunctionBegin;
703d4002b98SHong Zhang   info->block_size = 1.0;
7049566063dSJacob Faibussowitsch   PetscCall(MatGetInfo(A, MAT_LOCAL, info));
705d4002b98SHong Zhang 
7069371c9d4SSatish Balay   isend[0] = info->nz_used;
7079371c9d4SSatish Balay   isend[1] = info->nz_allocated;
7089371c9d4SSatish Balay   isend[2] = info->nz_unneeded;
7099371c9d4SSatish Balay   isend[3] = info->memory;
7109371c9d4SSatish Balay   isend[4] = info->mallocs;
711d4002b98SHong Zhang 
7129566063dSJacob Faibussowitsch   PetscCall(MatGetInfo(B, MAT_LOCAL, info));
713d4002b98SHong Zhang 
7149371c9d4SSatish Balay   isend[0] += info->nz_used;
7159371c9d4SSatish Balay   isend[1] += info->nz_allocated;
7169371c9d4SSatish Balay   isend[2] += info->nz_unneeded;
7179371c9d4SSatish Balay   isend[3] += info->memory;
7189371c9d4SSatish Balay   isend[4] += info->mallocs;
719d4002b98SHong Zhang   if (flag == MAT_LOCAL) {
720d4002b98SHong Zhang     info->nz_used      = isend[0];
721d4002b98SHong Zhang     info->nz_allocated = isend[1];
722d4002b98SHong Zhang     info->nz_unneeded  = isend[2];
723d4002b98SHong Zhang     info->memory       = isend[3];
724d4002b98SHong Zhang     info->mallocs      = isend[4];
725d4002b98SHong Zhang   } else if (flag == MAT_GLOBAL_MAX) {
7261c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)matin)));
727d4002b98SHong Zhang 
728d4002b98SHong Zhang     info->nz_used      = irecv[0];
729d4002b98SHong Zhang     info->nz_allocated = irecv[1];
730d4002b98SHong Zhang     info->nz_unneeded  = irecv[2];
731d4002b98SHong Zhang     info->memory       = irecv[3];
732d4002b98SHong Zhang     info->mallocs      = irecv[4];
733d4002b98SHong Zhang   } else if (flag == MAT_GLOBAL_SUM) {
7341c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)matin)));
735d4002b98SHong Zhang 
736d4002b98SHong Zhang     info->nz_used      = irecv[0];
737d4002b98SHong Zhang     info->nz_allocated = irecv[1];
738d4002b98SHong Zhang     info->nz_unneeded  = irecv[2];
739d4002b98SHong Zhang     info->memory       = irecv[3];
740d4002b98SHong Zhang     info->mallocs      = irecv[4];
741d4002b98SHong Zhang   }
742d4002b98SHong Zhang   info->fill_ratio_given  = 0; /* no parallel LU/ILU/Cholesky */
743d4002b98SHong Zhang   info->fill_ratio_needed = 0;
744d4002b98SHong Zhang   info->factor_mallocs    = 0;
7453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
746d4002b98SHong Zhang }
747d4002b98SHong Zhang 
748d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetOption_MPISELL(Mat A, MatOption op, PetscBool flg)
749d71ae5a4SJacob Faibussowitsch {
750d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
751d4002b98SHong Zhang 
752d4002b98SHong Zhang   PetscFunctionBegin;
753d4002b98SHong Zhang   switch (op) {
754d4002b98SHong Zhang   case MAT_NEW_NONZERO_LOCATIONS:
755d4002b98SHong Zhang   case MAT_NEW_NONZERO_ALLOCATION_ERR:
756d4002b98SHong Zhang   case MAT_UNUSED_NONZERO_LOCATION_ERR:
757d4002b98SHong Zhang   case MAT_KEEP_NONZERO_PATTERN:
758d4002b98SHong Zhang   case MAT_NEW_NONZERO_LOCATION_ERR:
759d4002b98SHong Zhang   case MAT_USE_INODES:
760d4002b98SHong Zhang   case MAT_IGNORE_ZERO_ENTRIES:
761d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7629566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
7639566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->B, op, flg));
764d4002b98SHong Zhang     break;
765d4002b98SHong Zhang   case MAT_ROW_ORIENTED:
766d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
767d4002b98SHong Zhang     a->roworiented = flg;
768d4002b98SHong Zhang 
7699566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
7709566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->B, op, flg));
771d4002b98SHong Zhang     break;
7728c78258cSHong Zhang   case MAT_FORCE_DIAGONAL_ENTRIES:
773d71ae5a4SJacob Faibussowitsch   case MAT_SORTED_FULL:
774d71ae5a4SJacob Faibussowitsch     PetscCall(PetscInfo(A, "Option %s ignored\n", MatOptions[op]));
775d71ae5a4SJacob Faibussowitsch     break;
776d71ae5a4SJacob Faibussowitsch   case MAT_IGNORE_OFF_PROC_ENTRIES:
777d71ae5a4SJacob Faibussowitsch     a->donotstash = flg;
778d71ae5a4SJacob Faibussowitsch     break;
779d4002b98SHong Zhang   case MAT_SPD:
780d71ae5a4SJacob Faibussowitsch   case MAT_SPD_ETERNAL:
781d71ae5a4SJacob Faibussowitsch     break;
782d4002b98SHong Zhang   case MAT_SYMMETRIC:
783d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7849566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
785d4002b98SHong Zhang     break;
786d4002b98SHong Zhang   case MAT_STRUCTURALLY_SYMMETRIC:
787d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7889566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
789d4002b98SHong Zhang     break;
790d4002b98SHong Zhang   case MAT_HERMITIAN:
791d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7929566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
793d4002b98SHong Zhang     break;
794d4002b98SHong Zhang   case MAT_SYMMETRY_ETERNAL:
795d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7969566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
797d4002b98SHong Zhang     break;
798b94d7dedSBarry Smith   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
799b94d7dedSBarry Smith     MatCheckPreallocated(A, 1);
800b94d7dedSBarry Smith     PetscCall(MatSetOption(a->A, op, flg));
801b94d7dedSBarry Smith     break;
802d71ae5a4SJacob Faibussowitsch   default:
803d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "unknown option %d", op);
804d4002b98SHong Zhang   }
8053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
806d4002b98SHong Zhang }
807d4002b98SHong Zhang 
808ba38deedSJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_MPISELL(Mat mat, Vec ll, Vec rr)
809d71ae5a4SJacob Faibussowitsch {
810d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
811d4002b98SHong Zhang   Mat          a = sell->A, b = sell->B;
812d4002b98SHong Zhang   PetscInt     s1, s2, s3;
813d4002b98SHong Zhang 
814d4002b98SHong Zhang   PetscFunctionBegin;
8159566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &s2, &s3));
816d4002b98SHong Zhang   if (rr) {
8179566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(rr, &s1));
81808401ef6SPierre Jolivet     PetscCheck(s1 == s3, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "right vector non-conforming local size");
819d4002b98SHong Zhang     /* Overlap communication with computation. */
8209566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sell->Mvctx, rr, sell->lvec, INSERT_VALUES, SCATTER_FORWARD));
821d4002b98SHong Zhang   }
822d4002b98SHong Zhang   if (ll) {
8239566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(ll, &s1));
82408401ef6SPierre Jolivet     PetscCheck(s1 == s2, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "left vector non-conforming local size");
825dbbe0bcdSBarry Smith     PetscUseTypeMethod(b, diagonalscale, ll, NULL);
826d4002b98SHong Zhang   }
827d4002b98SHong Zhang   /* scale  the diagonal block */
828dbbe0bcdSBarry Smith   PetscUseTypeMethod(a, diagonalscale, ll, rr);
829d4002b98SHong Zhang 
830d4002b98SHong Zhang   if (rr) {
831d4002b98SHong Zhang     /* Do a scatter end and then right scale the off-diagonal block */
8329566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sell->Mvctx, rr, sell->lvec, INSERT_VALUES, SCATTER_FORWARD));
833dbbe0bcdSBarry Smith     PetscUseTypeMethod(b, diagonalscale, NULL, sell->lvec);
834d4002b98SHong Zhang   }
8353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
836d4002b98SHong Zhang }
837d4002b98SHong Zhang 
838ba38deedSJacob Faibussowitsch static PetscErrorCode MatSetUnfactored_MPISELL(Mat A)
839d71ae5a4SJacob Faibussowitsch {
840d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
841d4002b98SHong Zhang 
842d4002b98SHong Zhang   PetscFunctionBegin;
8439566063dSJacob Faibussowitsch   PetscCall(MatSetUnfactored(a->A));
8443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
845d4002b98SHong Zhang }
846d4002b98SHong Zhang 
847ba38deedSJacob Faibussowitsch static PetscErrorCode MatEqual_MPISELL(Mat A, Mat B, PetscBool *flag)
848d71ae5a4SJacob Faibussowitsch {
849d4002b98SHong Zhang   Mat_MPISELL *matB = (Mat_MPISELL *)B->data, *matA = (Mat_MPISELL *)A->data;
850d4002b98SHong Zhang   Mat          a, b, c, d;
851d4002b98SHong Zhang   PetscBool    flg;
852d4002b98SHong Zhang 
853d4002b98SHong Zhang   PetscFunctionBegin;
8549371c9d4SSatish Balay   a = matA->A;
8559371c9d4SSatish Balay   b = matA->B;
8569371c9d4SSatish Balay   c = matB->A;
8579371c9d4SSatish Balay   d = matB->B;
858d4002b98SHong Zhang 
8599566063dSJacob Faibussowitsch   PetscCall(MatEqual(a, c, &flg));
86048a46eb9SPierre Jolivet   if (flg) PetscCall(MatEqual(b, d, &flg));
8611c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&flg, flag, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
8623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
863d4002b98SHong Zhang }
864d4002b98SHong Zhang 
865ba38deedSJacob Faibussowitsch static PetscErrorCode MatCopy_MPISELL(Mat A, Mat B, MatStructure str)
866d71ae5a4SJacob Faibussowitsch {
867d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
868d4002b98SHong Zhang   Mat_MPISELL *b = (Mat_MPISELL *)B->data;
869d4002b98SHong Zhang 
870d4002b98SHong Zhang   PetscFunctionBegin;
871d4002b98SHong Zhang   /* If the two matrices don't have the same copy implementation, they aren't compatible for fast copy. */
872d4002b98SHong Zhang   if ((str != SAME_NONZERO_PATTERN) || (A->ops->copy != B->ops->copy)) {
873d4002b98SHong Zhang     /* because of the column compression in the off-processor part of the matrix a->B,
874d4002b98SHong Zhang        the number of columns in a->B and b->B may be different, hence we cannot call
875d4002b98SHong Zhang        the MatCopy() directly on the two parts. If need be, we can provide a more
876d4002b98SHong Zhang        efficient copy than the MatCopy_Basic() by first uncompressing the a->B matrices
877d4002b98SHong Zhang        then copying the submatrices */
8789566063dSJacob Faibussowitsch     PetscCall(MatCopy_Basic(A, B, str));
879d4002b98SHong Zhang   } else {
8809566063dSJacob Faibussowitsch     PetscCall(MatCopy(a->A, b->A, str));
8819566063dSJacob Faibussowitsch     PetscCall(MatCopy(a->B, b->B, str));
882d4002b98SHong Zhang   }
8833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
884d4002b98SHong Zhang }
885d4002b98SHong Zhang 
886ba38deedSJacob Faibussowitsch static PetscErrorCode MatSetUp_MPISELL(Mat A)
887d71ae5a4SJacob Faibussowitsch {
888d4002b98SHong Zhang   PetscFunctionBegin;
8899566063dSJacob Faibussowitsch   PetscCall(MatMPISELLSetPreallocation(A, PETSC_DEFAULT, NULL, PETSC_DEFAULT, NULL));
8903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
891d4002b98SHong Zhang }
892d4002b98SHong Zhang 
893ba38deedSJacob Faibussowitsch static PetscErrorCode MatConjugate_MPISELL(Mat mat)
894d71ae5a4SJacob Faibussowitsch {
8955f80ce2aSJacob Faibussowitsch   PetscFunctionBegin;
8965f80ce2aSJacob Faibussowitsch   if (PetscDefined(USE_COMPLEX)) {
897d4002b98SHong Zhang     Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
898d4002b98SHong Zhang 
8999566063dSJacob Faibussowitsch     PetscCall(MatConjugate_SeqSELL(sell->A));
9009566063dSJacob Faibussowitsch     PetscCall(MatConjugate_SeqSELL(sell->B));
9015f80ce2aSJacob Faibussowitsch   }
9023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
903d4002b98SHong Zhang }
904d4002b98SHong Zhang 
905ba38deedSJacob Faibussowitsch static PetscErrorCode MatRealPart_MPISELL(Mat A)
906d71ae5a4SJacob Faibussowitsch {
907d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
908d4002b98SHong Zhang 
909d4002b98SHong Zhang   PetscFunctionBegin;
9109566063dSJacob Faibussowitsch   PetscCall(MatRealPart(a->A));
9119566063dSJacob Faibussowitsch   PetscCall(MatRealPart(a->B));
9123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
913d4002b98SHong Zhang }
914d4002b98SHong Zhang 
915ba38deedSJacob Faibussowitsch static PetscErrorCode MatImaginaryPart_MPISELL(Mat A)
916d71ae5a4SJacob Faibussowitsch {
917d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
918d4002b98SHong Zhang 
919d4002b98SHong Zhang   PetscFunctionBegin;
9209566063dSJacob Faibussowitsch   PetscCall(MatImaginaryPart(a->A));
9219566063dSJacob Faibussowitsch   PetscCall(MatImaginaryPart(a->B));
9223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
923d4002b98SHong Zhang }
924d4002b98SHong Zhang 
925ba38deedSJacob Faibussowitsch static PetscErrorCode MatInvertBlockDiagonal_MPISELL(Mat A, const PetscScalar **values)
926d71ae5a4SJacob Faibussowitsch {
927d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
928d4002b98SHong Zhang 
929d4002b98SHong Zhang   PetscFunctionBegin;
9309566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(a->A, values));
931d4002b98SHong Zhang   A->factorerrortype = a->A->factorerrortype;
9323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
933d4002b98SHong Zhang }
934d4002b98SHong Zhang 
935d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_MPISELL(Mat x, PetscRandom rctx)
936d71ae5a4SJacob Faibussowitsch {
937d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)x->data;
938d4002b98SHong Zhang 
939d4002b98SHong Zhang   PetscFunctionBegin;
9409566063dSJacob Faibussowitsch   PetscCall(MatSetRandom(sell->A, rctx));
9419566063dSJacob Faibussowitsch   PetscCall(MatSetRandom(sell->B, rctx));
9429566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
9439566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
9443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
945d4002b98SHong Zhang }
946d4002b98SHong Zhang 
947d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetFromOptions_MPISELL(Mat A, PetscOptionItems *PetscOptionsObject)
948d71ae5a4SJacob Faibussowitsch {
949d4002b98SHong Zhang   PetscFunctionBegin;
950d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MPISELL options");
951d0609cedSBarry Smith   PetscOptionsHeadEnd();
9523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
953d4002b98SHong Zhang }
954d4002b98SHong Zhang 
955ba38deedSJacob Faibussowitsch static PetscErrorCode MatShift_MPISELL(Mat Y, PetscScalar a)
956d71ae5a4SJacob Faibussowitsch {
957d4002b98SHong Zhang   Mat_MPISELL *msell = (Mat_MPISELL *)Y->data;
958d4002b98SHong Zhang   Mat_SeqSELL *sell  = (Mat_SeqSELL *)msell->A->data;
959d4002b98SHong Zhang 
960d4002b98SHong Zhang   PetscFunctionBegin;
961d4002b98SHong Zhang   if (!Y->preallocated) {
9629566063dSJacob Faibussowitsch     PetscCall(MatMPISELLSetPreallocation(Y, 1, NULL, 0, NULL));
963d4002b98SHong Zhang   } else if (!sell->nz) {
964d4002b98SHong Zhang     PetscInt nonew = sell->nonew;
9659566063dSJacob Faibussowitsch     PetscCall(MatSeqSELLSetPreallocation(msell->A, 1, NULL));
966d4002b98SHong Zhang     sell->nonew = nonew;
967d4002b98SHong Zhang   }
9689566063dSJacob Faibussowitsch   PetscCall(MatShift_Basic(Y, a));
9693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
970d4002b98SHong Zhang }
971d4002b98SHong Zhang 
972ba38deedSJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_MPISELL(Mat A, PetscBool *missing, PetscInt *d)
973d71ae5a4SJacob Faibussowitsch {
974d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
975d4002b98SHong Zhang 
976d4002b98SHong Zhang   PetscFunctionBegin;
97708401ef6SPierre Jolivet   PetscCheck(A->rmap->n == A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only works for square matrices");
9789566063dSJacob Faibussowitsch   PetscCall(MatMissingDiagonal(a->A, missing, d));
979d4002b98SHong Zhang   if (d) {
980d4002b98SHong Zhang     PetscInt rstart;
9819566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
982d4002b98SHong Zhang     *d += rstart;
983d4002b98SHong Zhang   }
9843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
985d4002b98SHong Zhang }
986d4002b98SHong Zhang 
987ba38deedSJacob Faibussowitsch static PetscErrorCode MatGetDiagonalBlock_MPISELL(Mat A, Mat *a)
988d71ae5a4SJacob Faibussowitsch {
989d4002b98SHong Zhang   PetscFunctionBegin;
990d4002b98SHong Zhang   *a = ((Mat_MPISELL *)A->data)->A;
9913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
992d4002b98SHong Zhang }
993d4002b98SHong Zhang 
994d4002b98SHong Zhang static struct _MatOps MatOps_Values = {MatSetValues_MPISELL,
995f4259b30SLisandro Dalcin                                        NULL,
996f4259b30SLisandro Dalcin                                        NULL,
997d4002b98SHong Zhang                                        MatMult_MPISELL,
998d4002b98SHong Zhang                                        /* 4*/ MatMultAdd_MPISELL,
999d4002b98SHong Zhang                                        MatMultTranspose_MPISELL,
1000d4002b98SHong Zhang                                        MatMultTransposeAdd_MPISELL,
1001f4259b30SLisandro Dalcin                                        NULL,
1002f4259b30SLisandro Dalcin                                        NULL,
1003f4259b30SLisandro Dalcin                                        NULL,
1004f4259b30SLisandro Dalcin                                        /*10*/ NULL,
1005f4259b30SLisandro Dalcin                                        NULL,
1006f4259b30SLisandro Dalcin                                        NULL,
1007d4002b98SHong Zhang                                        MatSOR_MPISELL,
1008f4259b30SLisandro Dalcin                                        NULL,
1009d4002b98SHong Zhang                                        /*15*/ MatGetInfo_MPISELL,
1010d4002b98SHong Zhang                                        MatEqual_MPISELL,
1011d4002b98SHong Zhang                                        MatGetDiagonal_MPISELL,
1012d4002b98SHong Zhang                                        MatDiagonalScale_MPISELL,
1013f4259b30SLisandro Dalcin                                        NULL,
1014d4002b98SHong Zhang                                        /*20*/ MatAssemblyBegin_MPISELL,
1015d4002b98SHong Zhang                                        MatAssemblyEnd_MPISELL,
1016d4002b98SHong Zhang                                        MatSetOption_MPISELL,
1017d4002b98SHong Zhang                                        MatZeroEntries_MPISELL,
1018f4259b30SLisandro Dalcin                                        /*24*/ NULL,
1019f4259b30SLisandro Dalcin                                        NULL,
1020f4259b30SLisandro Dalcin                                        NULL,
1021f4259b30SLisandro Dalcin                                        NULL,
1022f4259b30SLisandro Dalcin                                        NULL,
1023d4002b98SHong Zhang                                        /*29*/ MatSetUp_MPISELL,
1024f4259b30SLisandro Dalcin                                        NULL,
1025f4259b30SLisandro Dalcin                                        NULL,
1026d4002b98SHong Zhang                                        MatGetDiagonalBlock_MPISELL,
1027f4259b30SLisandro Dalcin                                        NULL,
1028d4002b98SHong Zhang                                        /*34*/ MatDuplicate_MPISELL,
1029f4259b30SLisandro Dalcin                                        NULL,
1030f4259b30SLisandro Dalcin                                        NULL,
1031f4259b30SLisandro Dalcin                                        NULL,
1032f4259b30SLisandro Dalcin                                        NULL,
1033f4259b30SLisandro Dalcin                                        /*39*/ NULL,
1034f4259b30SLisandro Dalcin                                        NULL,
1035f4259b30SLisandro Dalcin                                        NULL,
1036d4002b98SHong Zhang                                        MatGetValues_MPISELL,
1037d4002b98SHong Zhang                                        MatCopy_MPISELL,
1038f4259b30SLisandro Dalcin                                        /*44*/ NULL,
1039d4002b98SHong Zhang                                        MatScale_MPISELL,
1040d4002b98SHong Zhang                                        MatShift_MPISELL,
1041d4002b98SHong Zhang                                        MatDiagonalSet_MPISELL,
1042f4259b30SLisandro Dalcin                                        NULL,
1043d4002b98SHong Zhang                                        /*49*/ MatSetRandom_MPISELL,
1044f4259b30SLisandro Dalcin                                        NULL,
1045f4259b30SLisandro Dalcin                                        NULL,
1046f4259b30SLisandro Dalcin                                        NULL,
1047f4259b30SLisandro Dalcin                                        NULL,
1048d4002b98SHong Zhang                                        /*54*/ MatFDColoringCreate_MPIXAIJ,
1049f4259b30SLisandro Dalcin                                        NULL,
1050d4002b98SHong Zhang                                        MatSetUnfactored_MPISELL,
1051f4259b30SLisandro Dalcin                                        NULL,
1052f4259b30SLisandro Dalcin                                        NULL,
1053f4259b30SLisandro Dalcin                                        /*59*/ NULL,
1054d4002b98SHong Zhang                                        MatDestroy_MPISELL,
1055d4002b98SHong Zhang                                        MatView_MPISELL,
1056f4259b30SLisandro Dalcin                                        NULL,
1057f4259b30SLisandro Dalcin                                        NULL,
1058f4259b30SLisandro Dalcin                                        /*64*/ NULL,
1059f4259b30SLisandro Dalcin                                        NULL,
1060f4259b30SLisandro Dalcin                                        NULL,
1061f4259b30SLisandro Dalcin                                        NULL,
1062f4259b30SLisandro Dalcin                                        NULL,
1063f4259b30SLisandro Dalcin                                        /*69*/ NULL,
1064f4259b30SLisandro Dalcin                                        NULL,
1065f4259b30SLisandro Dalcin                                        NULL,
1066f4259b30SLisandro Dalcin                                        NULL,
1067f4259b30SLisandro Dalcin                                        NULL,
1068f4259b30SLisandro Dalcin                                        NULL,
1069d4002b98SHong Zhang                                        /*75*/ MatFDColoringApply_AIJ, /* reuse AIJ function */
1070d4002b98SHong Zhang                                        MatSetFromOptions_MPISELL,
1071f4259b30SLisandro Dalcin                                        NULL,
1072f4259b30SLisandro Dalcin                                        NULL,
1073f4259b30SLisandro Dalcin                                        NULL,
1074f4259b30SLisandro Dalcin                                        /*80*/ NULL,
1075f4259b30SLisandro Dalcin                                        NULL,
1076f4259b30SLisandro Dalcin                                        NULL,
1077f4259b30SLisandro Dalcin                                        /*83*/ NULL,
1078f4259b30SLisandro Dalcin                                        NULL,
1079f4259b30SLisandro Dalcin                                        NULL,
1080f4259b30SLisandro Dalcin                                        NULL,
1081f4259b30SLisandro Dalcin                                        NULL,
1082f4259b30SLisandro Dalcin                                        NULL,
1083f4259b30SLisandro Dalcin                                        /*89*/ NULL,
1084f4259b30SLisandro Dalcin                                        NULL,
1085f4259b30SLisandro Dalcin                                        NULL,
1086f4259b30SLisandro Dalcin                                        NULL,
1087f4259b30SLisandro Dalcin                                        NULL,
1088f4259b30SLisandro Dalcin                                        /*94*/ NULL,
1089f4259b30SLisandro Dalcin                                        NULL,
1090f4259b30SLisandro Dalcin                                        NULL,
1091f4259b30SLisandro Dalcin                                        NULL,
1092f4259b30SLisandro Dalcin                                        NULL,
1093f4259b30SLisandro Dalcin                                        /*99*/ NULL,
1094f4259b30SLisandro Dalcin                                        NULL,
1095f4259b30SLisandro Dalcin                                        NULL,
1096d4002b98SHong Zhang                                        MatConjugate_MPISELL,
1097f4259b30SLisandro Dalcin                                        NULL,
1098f4259b30SLisandro Dalcin                                        /*104*/ NULL,
1099d4002b98SHong Zhang                                        MatRealPart_MPISELL,
1100d4002b98SHong Zhang                                        MatImaginaryPart_MPISELL,
1101f4259b30SLisandro Dalcin                                        NULL,
1102f4259b30SLisandro Dalcin                                        NULL,
1103f4259b30SLisandro Dalcin                                        /*109*/ NULL,
1104f4259b30SLisandro Dalcin                                        NULL,
1105f4259b30SLisandro Dalcin                                        NULL,
1106f4259b30SLisandro Dalcin                                        NULL,
1107d4002b98SHong Zhang                                        MatMissingDiagonal_MPISELL,
1108f4259b30SLisandro Dalcin                                        /*114*/ NULL,
1109f4259b30SLisandro Dalcin                                        NULL,
1110d4002b98SHong Zhang                                        MatGetGhosts_MPISELL,
1111f4259b30SLisandro Dalcin                                        NULL,
1112f4259b30SLisandro Dalcin                                        NULL,
1113f4259b30SLisandro Dalcin                                        /*119*/ NULL,
1114f4259b30SLisandro Dalcin                                        NULL,
1115f4259b30SLisandro Dalcin                                        NULL,
1116f4259b30SLisandro Dalcin                                        NULL,
1117f4259b30SLisandro Dalcin                                        NULL,
1118f4259b30SLisandro Dalcin                                        /*124*/ NULL,
1119f4259b30SLisandro Dalcin                                        NULL,
1120d4002b98SHong Zhang                                        MatInvertBlockDiagonal_MPISELL,
1121f4259b30SLisandro Dalcin                                        NULL,
1122f4259b30SLisandro Dalcin                                        NULL,
1123f4259b30SLisandro Dalcin                                        /*129*/ NULL,
1124f4259b30SLisandro Dalcin                                        NULL,
1125f4259b30SLisandro Dalcin                                        NULL,
1126f4259b30SLisandro Dalcin                                        NULL,
1127f4259b30SLisandro Dalcin                                        NULL,
1128f4259b30SLisandro Dalcin                                        /*134*/ NULL,
1129f4259b30SLisandro Dalcin                                        NULL,
1130f4259b30SLisandro Dalcin                                        NULL,
1131f4259b30SLisandro Dalcin                                        NULL,
1132f4259b30SLisandro Dalcin                                        NULL,
1133f4259b30SLisandro Dalcin                                        /*139*/ NULL,
1134f4259b30SLisandro Dalcin                                        NULL,
1135f4259b30SLisandro Dalcin                                        NULL,
1136d4002b98SHong Zhang                                        MatFDColoringSetUp_MPIXAIJ,
1137f4259b30SLisandro Dalcin                                        NULL,
1138d70f29a3SPierre Jolivet                                        /*144*/ NULL,
1139d70f29a3SPierre Jolivet                                        NULL,
1140d70f29a3SPierre Jolivet                                        NULL,
114199a7f59eSMark Adams                                        NULL,
114299a7f59eSMark Adams                                        NULL,
11437fb60732SBarry Smith                                        NULL,
1144dec0b466SHong Zhang                                        /*150*/ NULL,
1145dec0b466SHong Zhang                                        NULL};
1146d4002b98SHong Zhang 
1147ba38deedSJacob Faibussowitsch static PetscErrorCode MatStoreValues_MPISELL(Mat mat)
1148d71ae5a4SJacob Faibussowitsch {
1149d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
1150d4002b98SHong Zhang 
1151d4002b98SHong Zhang   PetscFunctionBegin;
11529566063dSJacob Faibussowitsch   PetscCall(MatStoreValues(sell->A));
11539566063dSJacob Faibussowitsch   PetscCall(MatStoreValues(sell->B));
11543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1155d4002b98SHong Zhang }
1156d4002b98SHong Zhang 
1157ba38deedSJacob Faibussowitsch static PetscErrorCode MatRetrieveValues_MPISELL(Mat mat)
1158d71ae5a4SJacob Faibussowitsch {
1159d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
1160d4002b98SHong Zhang 
1161d4002b98SHong Zhang   PetscFunctionBegin;
11629566063dSJacob Faibussowitsch   PetscCall(MatRetrieveValues(sell->A));
11639566063dSJacob Faibussowitsch   PetscCall(MatRetrieveValues(sell->B));
11643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1165d4002b98SHong Zhang }
1166d4002b98SHong Zhang 
1167d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMPISELLSetPreallocation_MPISELL(Mat B, PetscInt d_rlenmax, const PetscInt d_rlen[], PetscInt o_rlenmax, const PetscInt o_rlen[])
1168d71ae5a4SJacob Faibussowitsch {
1169d4002b98SHong Zhang   Mat_MPISELL *b;
1170d4002b98SHong Zhang 
1171d4002b98SHong Zhang   PetscFunctionBegin;
11729566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(B->rmap));
11739566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(B->cmap));
1174d4002b98SHong Zhang   b = (Mat_MPISELL *)B->data;
1175d4002b98SHong Zhang 
1176d4002b98SHong Zhang   if (!B->preallocated) {
1177d4002b98SHong Zhang     /* Explicitly create 2 MATSEQSELL matrices. */
11789566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &b->A));
11799566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(b->A, B->rmap->n, B->cmap->n, B->rmap->n, B->cmap->n));
11809566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizesFromMats(b->A, B, B));
11819566063dSJacob Faibussowitsch     PetscCall(MatSetType(b->A, MATSEQSELL));
11829566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &b->B));
11839566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(b->B, B->rmap->n, B->cmap->N, B->rmap->n, B->cmap->N));
11849566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizesFromMats(b->B, B, B));
11859566063dSJacob Faibussowitsch     PetscCall(MatSetType(b->B, MATSEQSELL));
1186d4002b98SHong Zhang   }
1187d4002b98SHong Zhang 
11889566063dSJacob Faibussowitsch   PetscCall(MatSeqSELLSetPreallocation(b->A, d_rlenmax, d_rlen));
11899566063dSJacob Faibussowitsch   PetscCall(MatSeqSELLSetPreallocation(b->B, o_rlenmax, o_rlen));
1190d4002b98SHong Zhang   B->preallocated  = PETSC_TRUE;
1191d4002b98SHong Zhang   B->was_assembled = PETSC_FALSE;
1192d4002b98SHong Zhang   /*
1193d4002b98SHong Zhang     critical for MatAssemblyEnd to work.
1194d4002b98SHong Zhang     MatAssemblyBegin checks it to set up was_assembled
1195d4002b98SHong Zhang     and MatAssemblyEnd checks was_assembled to determine whether to build garray
1196d4002b98SHong Zhang   */
1197d4002b98SHong Zhang   B->assembled = PETSC_FALSE;
11983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1199d4002b98SHong Zhang }
1200d4002b98SHong Zhang 
1201d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDuplicate_MPISELL(Mat matin, MatDuplicateOption cpvalues, Mat *newmat)
1202d71ae5a4SJacob Faibussowitsch {
1203d4002b98SHong Zhang   Mat          mat;
1204d4002b98SHong Zhang   Mat_MPISELL *a, *oldmat = (Mat_MPISELL *)matin->data;
1205d4002b98SHong Zhang 
1206d4002b98SHong Zhang   PetscFunctionBegin;
1207f4259b30SLisandro Dalcin   *newmat = NULL;
12089566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)matin), &mat));
12099566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat, matin->rmap->n, matin->cmap->n, matin->rmap->N, matin->cmap->N));
12109566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizesFromMats(mat, matin, matin));
12119566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat, ((PetscObject)matin)->type_name));
1212d4002b98SHong Zhang   a = (Mat_MPISELL *)mat->data;
1213d4002b98SHong Zhang 
1214d4002b98SHong Zhang   mat->factortype   = matin->factortype;
1215d4002b98SHong Zhang   mat->assembled    = PETSC_TRUE;
1216d4002b98SHong Zhang   mat->insertmode   = NOT_SET_VALUES;
1217d4002b98SHong Zhang   mat->preallocated = PETSC_TRUE;
1218d4002b98SHong Zhang 
1219d4002b98SHong Zhang   a->size         = oldmat->size;
1220d4002b98SHong Zhang   a->rank         = oldmat->rank;
1221d4002b98SHong Zhang   a->donotstash   = oldmat->donotstash;
1222d4002b98SHong Zhang   a->roworiented  = oldmat->roworiented;
1223f4259b30SLisandro Dalcin   a->rowindices   = NULL;
1224f4259b30SLisandro Dalcin   a->rowvalues    = NULL;
1225d4002b98SHong Zhang   a->getrowactive = PETSC_FALSE;
1226d4002b98SHong Zhang 
12279566063dSJacob Faibussowitsch   PetscCall(PetscLayoutReference(matin->rmap, &mat->rmap));
12289566063dSJacob Faibussowitsch   PetscCall(PetscLayoutReference(matin->cmap, &mat->cmap));
1229d4002b98SHong Zhang 
1230d4002b98SHong Zhang   if (oldmat->colmap) {
1231d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE)
1232eec179cfSJacob Faibussowitsch     PetscCall(PetscHMapIDuplicate(oldmat->colmap, &a->colmap));
1233d4002b98SHong Zhang #else
12349566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(mat->cmap->N, &a->colmap));
12359566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(a->colmap, oldmat->colmap, mat->cmap->N));
1236d4002b98SHong Zhang #endif
1237f4259b30SLisandro Dalcin   } else a->colmap = NULL;
1238d4002b98SHong Zhang   if (oldmat->garray) {
1239d4002b98SHong Zhang     PetscInt len;
1240d4002b98SHong Zhang     len = oldmat->B->cmap->n;
12419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(len + 1, &a->garray));
12429566063dSJacob Faibussowitsch     if (len) PetscCall(PetscArraycpy(a->garray, oldmat->garray, len));
1243f4259b30SLisandro Dalcin   } else a->garray = NULL;
1244d4002b98SHong Zhang 
12459566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(oldmat->lvec, &a->lvec));
12469566063dSJacob Faibussowitsch   PetscCall(VecScatterCopy(oldmat->Mvctx, &a->Mvctx));
12479566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(oldmat->A, cpvalues, &a->A));
12489566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(oldmat->B, cpvalues, &a->B));
12499566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDuplicate(((PetscObject)matin)->qlist, &((PetscObject)mat)->qlist));
1250d4002b98SHong Zhang   *newmat = mat;
12513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1252d4002b98SHong Zhang }
1253d4002b98SHong Zhang 
1254d4002b98SHong Zhang /*@C
125511a5261eSBarry Smith   MatMPISELLSetPreallocation - Preallocates memory for a `MATMPISELL` sparse parallel matrix in sell format.
1256d4002b98SHong Zhang   For good matrix assembly performance the user should preallocate the matrix storage by
125767be906fSBarry Smith   setting the parameters `d_nz` (or `d_nnz`) and `o_nz` (or `o_nnz`).
1258d4002b98SHong Zhang 
1259d083f849SBarry Smith   Collective
1260d4002b98SHong Zhang 
1261d4002b98SHong Zhang   Input Parameters:
1262d4002b98SHong Zhang + B     - the matrix
1263d4002b98SHong Zhang . d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1264d4002b98SHong Zhang            (same value is used for all local rows)
1265d4002b98SHong Zhang . d_nnz - array containing the number of nonzeros in the various rows of the
1266d4002b98SHong Zhang            DIAGONAL portion of the local submatrix (possibly different for each row)
126767be906fSBarry Smith            or NULL (`PETSC_NULL_INTEGER` in Fortran), if `d_nz` is used to specify the nonzero structure.
1268d4002b98SHong Zhang            The size of this array is equal to the number of local rows, i.e 'm'.
1269d4002b98SHong Zhang            For matrices that will be factored, you must leave room for (and set)
1270d4002b98SHong Zhang            the diagonal entry even if it is zero.
1271d4002b98SHong Zhang . o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1272d4002b98SHong Zhang            submatrix (same value is used for all local rows).
1273d4002b98SHong Zhang - o_nnz - array containing the number of nonzeros in the various rows of the
1274d4002b98SHong Zhang            OFF-DIAGONAL portion of the local submatrix (possibly different for
127567be906fSBarry Smith            each row) or NULL (`PETSC_NULL_INTEGER` in Fortran), if `o_nz` is used to specify the nonzero
1276d4002b98SHong Zhang            structure. The size of this array is equal to the number
1277d4002b98SHong Zhang            of local rows, i.e 'm'.
1278d4002b98SHong Zhang 
1279d4002b98SHong Zhang   Example usage:
1280d4002b98SHong Zhang   Consider the following 8x8 matrix with 34 non-zero values, that is
1281d4002b98SHong Zhang   assembled across 3 processors. Lets assume that proc0 owns 3 rows,
1282d4002b98SHong Zhang   proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
128367be906fSBarry Smith   as follows
1284d4002b98SHong Zhang 
1285d4002b98SHong Zhang .vb
1286d4002b98SHong Zhang             1  2  0  |  0  3  0  |  0  4
1287d4002b98SHong Zhang     Proc0   0  5  6  |  7  0  0  |  8  0
1288d4002b98SHong Zhang             9  0 10  | 11  0  0  | 12  0
1289d4002b98SHong Zhang     -------------------------------------
1290d4002b98SHong Zhang            13  0 14  | 15 16 17  |  0  0
1291d4002b98SHong Zhang     Proc1   0 18  0  | 19 20 21  |  0  0
1292d4002b98SHong Zhang             0  0  0  | 22 23  0  | 24  0
1293d4002b98SHong Zhang     -------------------------------------
1294d4002b98SHong Zhang     Proc2  25 26 27  |  0  0 28  | 29  0
1295d4002b98SHong Zhang            30  0  0  | 31 32 33  |  0 34
1296d4002b98SHong Zhang .ve
1297d4002b98SHong Zhang 
129827430b45SBarry Smith   This can be represented as a collection of submatrices as
1299d4002b98SHong Zhang 
1300d4002b98SHong Zhang .vb
1301d4002b98SHong Zhang       A B C
1302d4002b98SHong Zhang       D E F
1303d4002b98SHong Zhang       G H I
1304d4002b98SHong Zhang .ve
1305d4002b98SHong Zhang 
1306d4002b98SHong Zhang   Where the submatrices A,B,C are owned by proc0, D,E,F are
1307d4002b98SHong Zhang   owned by proc1, G,H,I are owned by proc2.
1308d4002b98SHong Zhang 
1309d4002b98SHong Zhang   The 'm' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
1310d4002b98SHong Zhang   The 'n' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
1311d4002b98SHong Zhang   The 'M','N' parameters are 8,8, and have the same values on all procs.
1312d4002b98SHong Zhang 
1313d4002b98SHong Zhang   The DIAGONAL submatrices corresponding to proc0,proc1,proc2 are
1314d4002b98SHong Zhang   submatrices [A], [E], [I] respectively. The OFF-DIAGONAL submatrices
1315d4002b98SHong Zhang   corresponding to proc0,proc1,proc2 are [BC], [DF], [GH] respectively.
1316d4002b98SHong Zhang   Internally, each processor stores the DIAGONAL part, and the OFF-DIAGONAL
131727430b45SBarry Smith   part as `MATSEQSELL` matrices. For example, proc1 will store [E] as a `MATSEQSELL`
1318d4002b98SHong Zhang   matrix, ans [DF] as another SeqSELL matrix.
1319d4002b98SHong Zhang 
132067be906fSBarry Smith   When `d_nz`, `o_nz` parameters are specified, `d_nz` storage elements are
1321d4002b98SHong Zhang   allocated for every row of the local diagonal submatrix, and o_nz
1322d4002b98SHong Zhang   storage locations are allocated for every row of the OFF-DIAGONAL submat.
132367be906fSBarry Smith   One way to choose `d_nz` and `o_nz` is to use the max nonzerors per local
1324d4002b98SHong Zhang   rows for each of the local DIAGONAL, and the OFF-DIAGONAL submatrices.
132527430b45SBarry Smith   In this case, the values of d_nz,o_nz are
1326d4002b98SHong Zhang .vb
132727430b45SBarry Smith      proc0  dnz = 2, o_nz = 2
132827430b45SBarry Smith      proc1  dnz = 3, o_nz = 2
132927430b45SBarry Smith      proc2  dnz = 1, o_nz = 4
1330d4002b98SHong Zhang .ve
1331d4002b98SHong Zhang   We are allocating m*(d_nz+o_nz) storage locations for every proc. This
1332d4002b98SHong Zhang   translates to 3*(2+2)=12 for proc0, 3*(3+2)=15 for proc1, 2*(1+4)=10
1333d4002b98SHong Zhang   for proc3. i.e we are using 12+15+10=37 storage locations to store
1334d4002b98SHong Zhang   34 values.
1335d4002b98SHong Zhang 
133667be906fSBarry Smith   When `d_nnz`, `o_nnz` parameters are specified, the storage is specified
1337a5b23f4aSJose E. Roman   for every row, corresponding to both DIAGONAL and OFF-DIAGONAL submatrices.
133827430b45SBarry Smith   In the above case the values for d_nnz,o_nnz are
1339d4002b98SHong Zhang .vb
134027430b45SBarry Smith      proc0 d_nnz = [2,2,2] and o_nnz = [2,2,2]
134127430b45SBarry Smith      proc1 d_nnz = [3,3,2] and o_nnz = [2,1,1]
134227430b45SBarry Smith      proc2 d_nnz = [1,1]   and o_nnz = [4,4]
1343d4002b98SHong Zhang .ve
1344d4002b98SHong Zhang   Here the space allocated is according to nz (or maximum values in the nnz
1345d4002b98SHong Zhang   if nnz is provided) for DIAGONAL and OFF-DIAGONAL submatrices, i.e (2+2+3+2)*3+(1+4)*2=37
1346d4002b98SHong Zhang 
1347d4002b98SHong Zhang   Level: intermediate
1348d4002b98SHong Zhang 
134967be906fSBarry Smith   Notes:
135067be906fSBarry Smith   If the *_nnz parameter is given then the *_nz parameter is ignored
135167be906fSBarry Smith 
135267be906fSBarry Smith   The stored row and column indices begin with zero.
135367be906fSBarry Smith 
135467be906fSBarry Smith   The parallel matrix is partitioned such that the first m0 rows belong to
135567be906fSBarry Smith   process 0, the next m1 rows belong to process 1, the next m2 rows belong
135667be906fSBarry Smith   to process 2 etc.. where m0,m1,m2... are the input parameter 'm'.
135767be906fSBarry Smith 
135867be906fSBarry Smith   The DIAGONAL portion of the local submatrix of a processor can be defined
135967be906fSBarry Smith   as the submatrix which is obtained by extraction the part corresponding to
136067be906fSBarry Smith   the rows r1-r2 and columns c1-c2 of the global matrix, where r1 is the
136167be906fSBarry Smith   first row that belongs to the processor, r2 is the last row belonging to
136267be906fSBarry Smith   the this processor, and c1-c2 is range of indices of the local part of a
136367be906fSBarry Smith   vector suitable for applying the matrix to.  This is an mxn matrix.  In the
136467be906fSBarry Smith   common case of a square matrix, the row and column ranges are the same and
136567be906fSBarry Smith   the DIAGONAL part is also square. The remaining portion of the local
136667be906fSBarry Smith   submatrix (mxN) constitute the OFF-DIAGONAL portion.
136767be906fSBarry Smith 
136867be906fSBarry Smith   If `o_nnz`, `d_nnz` are specified, then `o_nz`, and `d_nz` are ignored.
136967be906fSBarry Smith 
137067be906fSBarry Smith   You can call `MatGetInfo()` to get information on how effective the preallocation was;
137167be906fSBarry Smith   for example the fields mallocs,nz_allocated,nz_used,nz_unneeded;
137267be906fSBarry Smith   You can also run with the option -info and look for messages with the string
137367be906fSBarry Smith   malloc in them to see if additional memory allocation was needed.
137467be906fSBarry Smith 
137567be906fSBarry Smith .seealso: `Mat`, `MatCreate()`, `MatCreateSeqSELL()`, `MatSetValues()`, `MatCreatesell()`,
137611a5261eSBarry Smith           `MATMPISELL`, `MatGetInfo()`, `PetscSplitOwnership()`, `MATSELL`
1377d4002b98SHong Zhang @*/
1378d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMPISELLSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1379d71ae5a4SJacob Faibussowitsch {
1380d4002b98SHong Zhang   PetscFunctionBegin;
1381d4002b98SHong Zhang   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
1382d4002b98SHong Zhang   PetscValidType(B, 1);
1383cac4c232SBarry Smith   PetscTryMethod(B, "MatMPISELLSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
13843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1385d4002b98SHong Zhang }
1386d4002b98SHong Zhang 
1387ed73aabaSBarry Smith /*MC
1388ed73aabaSBarry Smith    MATMPISELL - MATMPISELL = "mpisell" - A matrix type to be used for MPI sparse matrices,
1389ed73aabaSBarry Smith    based on the sliced Ellpack format
1390ed73aabaSBarry Smith 
139127430b45SBarry Smith    Options Database Key:
139220f4b53cSBarry Smith . -mat_type sell - sets the matrix type to `MATSELL` during a call to `MatSetFromOptions()`
1393ed73aabaSBarry Smith 
1394ed73aabaSBarry Smith    Level: beginner
1395ed73aabaSBarry Smith 
139667be906fSBarry Smith .seealso: `Mat`, `MatCreateSell()`, `MATSEQSELL`, `MATSELL`, `MATSEQAIJ`, `MATAIJ`, `MATMPIAIJ`
1397ed73aabaSBarry Smith M*/
1398ed73aabaSBarry Smith 
1399d4002b98SHong Zhang /*@C
140011a5261eSBarry Smith   MatCreateSELL - Creates a sparse parallel matrix in `MATSELL` format.
1401d4002b98SHong Zhang 
1402d083f849SBarry Smith   Collective
1403d4002b98SHong Zhang 
1404d4002b98SHong Zhang   Input Parameters:
1405d4002b98SHong Zhang + comm      - MPI communicator
140611a5261eSBarry Smith . m         - number of local rows (or `PETSC_DECIDE` to have calculated if M is given)
1407d4002b98SHong Zhang            This value should be the same as the local size used in creating the
1408d4002b98SHong Zhang            y vector for the matrix-vector product y = Ax.
1409d4002b98SHong Zhang . n         - This value should be the same as the local size used in creating the
141020f4b53cSBarry Smith        x vector for the matrix-vector product y = Ax. (or `PETSC_DECIDE` to have
141120f4b53cSBarry Smith        calculated if `N` is given) For square matrices n is almost always `m`.
141220f4b53cSBarry Smith . M         - number of global rows (or `PETSC_DETERMINE` to have calculated if `m` is given)
141320f4b53cSBarry Smith . N         - number of global columns (or `PETSC_DETERMINE` to have calculated if `n` is given)
1414d4002b98SHong Zhang . d_rlenmax - max number of nonzeros per row in DIAGONAL portion of local submatrix
1415d4002b98SHong Zhang                (same value is used for all local rows)
1416d4002b98SHong Zhang . d_rlen    - array containing the number of nonzeros in the various rows of the
1417d4002b98SHong Zhang             DIAGONAL portion of the local submatrix (possibly different for each row)
141820f4b53cSBarry Smith             or `NULL`, if d_rlenmax is used to specify the nonzero structure.
141920f4b53cSBarry Smith             The size of this array is equal to the number of local rows, i.e `m`.
1420d4002b98SHong Zhang . o_rlenmax - max number of nonzeros per row in the OFF-DIAGONAL portion of local
1421d4002b98SHong Zhang                submatrix (same value is used for all local rows).
1422d4002b98SHong Zhang - o_rlen    - array containing the number of nonzeros in the various rows of the
1423d4002b98SHong Zhang             OFF-DIAGONAL portion of the local submatrix (possibly different for
142420f4b53cSBarry Smith             each row) or `NULL`, if `o_rlenmax` is used to specify the nonzero
1425d4002b98SHong Zhang             structure. The size of this array is equal to the number
142620f4b53cSBarry Smith             of local rows, i.e `m`.
1427d4002b98SHong Zhang 
1428d4002b98SHong Zhang   Output Parameter:
1429d4002b98SHong Zhang . A - the matrix
1430d4002b98SHong Zhang 
143127430b45SBarry Smith   Options Database Key:
1432fe59aa6dSJacob Faibussowitsch . -mat_sell_oneindex - Internally use indexing starting at 1
143327430b45SBarry Smith         rather than 0.  When calling `MatSetValues()`,
143427430b45SBarry Smith         the user still MUST index entries starting at 0!
143527430b45SBarry Smith 
143627430b45SBarry Smith   Example:
143727430b45SBarry Smith   Consider the following 8x8 matrix with 34 non-zero values, that is
143827430b45SBarry Smith   assembled across 3 processors. Lets assume that proc0 owns 3 rows,
143927430b45SBarry Smith   proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
144027430b45SBarry Smith   as follows
144127430b45SBarry Smith 
144227430b45SBarry Smith .vb
144327430b45SBarry Smith             1  2  0  |  0  3  0  |  0  4
144427430b45SBarry Smith     Proc0   0  5  6  |  7  0  0  |  8  0
144527430b45SBarry Smith             9  0 10  | 11  0  0  | 12  0
144627430b45SBarry Smith     -------------------------------------
144727430b45SBarry Smith            13  0 14  | 15 16 17  |  0  0
144827430b45SBarry Smith     Proc1   0 18  0  | 19 20 21  |  0  0
144927430b45SBarry Smith             0  0  0  | 22 23  0  | 24  0
145027430b45SBarry Smith     -------------------------------------
145127430b45SBarry Smith     Proc2  25 26 27  |  0  0 28  | 29  0
145227430b45SBarry Smith            30  0  0  | 31 32 33  |  0 34
145327430b45SBarry Smith .ve
145427430b45SBarry Smith 
145520f4b53cSBarry Smith   This can be represented as a collection of submatrices as
145627430b45SBarry Smith .vb
145727430b45SBarry Smith       A B C
145827430b45SBarry Smith       D E F
145927430b45SBarry Smith       G H I
146027430b45SBarry Smith .ve
146127430b45SBarry Smith 
146227430b45SBarry Smith   Where the submatrices A,B,C are owned by proc0, D,E,F are
146327430b45SBarry Smith   owned by proc1, G,H,I are owned by proc2.
146427430b45SBarry Smith 
146527430b45SBarry Smith   The 'm' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
146627430b45SBarry Smith   The 'n' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
146727430b45SBarry Smith   The 'M','N' parameters are 8,8, and have the same values on all procs.
146827430b45SBarry Smith 
146927430b45SBarry Smith   The DIAGONAL submatrices corresponding to proc0,proc1,proc2 are
147027430b45SBarry Smith   submatrices [A], [E], [I] respectively. The OFF-DIAGONAL submatrices
147127430b45SBarry Smith   corresponding to proc0,proc1,proc2 are [BC], [DF], [GH] respectively.
147227430b45SBarry Smith   Internally, each processor stores the DIAGONAL part, and the OFF-DIAGONAL
147327430b45SBarry Smith   part as `MATSEQSELL` matrices. For example, proc1 will store [E] as a `MATSEQSELL`
147427430b45SBarry Smith   matrix, ans [DF] as another `MATSEQSELL` matrix.
147527430b45SBarry Smith 
147627430b45SBarry Smith   When d_rlenmax, o_rlenmax parameters are specified, d_rlenmax storage elements are
147727430b45SBarry Smith   allocated for every row of the local diagonal submatrix, and o_rlenmax
147827430b45SBarry Smith   storage locations are allocated for every row of the OFF-DIAGONAL submat.
147927430b45SBarry Smith   One way to choose d_rlenmax and o_rlenmax is to use the max nonzerors per local
148027430b45SBarry Smith   rows for each of the local DIAGONAL, and the OFF-DIAGONAL submatrices.
148120f4b53cSBarry Smith   In this case, the values of d_rlenmax,o_rlenmax are
148227430b45SBarry Smith .vb
148320f4b53cSBarry Smith      proc0 - d_rlenmax = 2, o_rlenmax = 2
148420f4b53cSBarry Smith      proc1 - d_rlenmax = 3, o_rlenmax = 2
148520f4b53cSBarry Smith      proc2 - d_rlenmax = 1, o_rlenmax = 4
148627430b45SBarry Smith .ve
148727430b45SBarry Smith   We are allocating m*(d_rlenmax+o_rlenmax) storage locations for every proc. This
148827430b45SBarry Smith   translates to 3*(2+2)=12 for proc0, 3*(3+2)=15 for proc1, 2*(1+4)=10
148927430b45SBarry Smith   for proc3. i.e we are using 12+15+10=37 storage locations to store
149027430b45SBarry Smith   34 values.
149127430b45SBarry Smith 
149220f4b53cSBarry Smith   When `d_rlen`, `o_rlen` parameters are specified, the storage is specified
149327430b45SBarry Smith   for every row, corresponding to both DIAGONAL and OFF-DIAGONAL submatrices.
149420f4b53cSBarry Smith   In the above case the values for `d_nnz`, `o_nnz` are
149527430b45SBarry Smith .vb
149620f4b53cSBarry Smith      proc0 - d_nnz = [2,2,2] and o_nnz = [2,2,2]
149720f4b53cSBarry Smith      proc1 - d_nnz = [3,3,2] and o_nnz = [2,1,1]
149820f4b53cSBarry Smith      proc2 - d_nnz = [1,1]   and o_nnz = [4,4]
149927430b45SBarry Smith .ve
150027430b45SBarry Smith   Here the space allocated is still 37 though there are 34 nonzeros because
150127430b45SBarry Smith   the allocation is always done according to rlenmax.
150227430b45SBarry Smith 
150327430b45SBarry Smith   Level: intermediate
150427430b45SBarry Smith 
150527430b45SBarry Smith   Notes:
150611a5261eSBarry Smith   It is recommended that one use the `MatCreate()`, `MatSetType()` and/or `MatSetFromOptions()`,
1507f6f02116SRichard Tran Mills   MatXXXXSetPreallocation() paradigm instead of this routine directly.
150811a5261eSBarry Smith   [MatXXXXSetPreallocation() is, for example, `MatSeqSELLSetPreallocation()`]
1509d4002b98SHong Zhang 
1510d4002b98SHong Zhang   If the *_rlen parameter is given then the *_rlenmax parameter is ignored
1511d4002b98SHong Zhang 
151220f4b53cSBarry Smith   `m`, `n`, `M`, `N` parameters specify the size of the matrix, and its partitioning across
151320f4b53cSBarry Smith   processors, while `d_rlenmax`, `d_rlen`, `o_rlenmax` , `o_rlen` parameters specify the approximate
1514d4002b98SHong Zhang   storage requirements for this matrix.
1515d4002b98SHong Zhang 
151611a5261eSBarry Smith   If `PETSC_DECIDE` or  `PETSC_DETERMINE` is used for a particular argument on one
1517d4002b98SHong Zhang   processor than it must be used on all processors that share the object for
1518d4002b98SHong Zhang   that argument.
1519d4002b98SHong Zhang 
1520d4002b98SHong Zhang   The user MUST specify either the local or global matrix dimensions
1521d4002b98SHong Zhang   (possibly both).
1522d4002b98SHong Zhang 
1523d4002b98SHong Zhang   The parallel matrix is partitioned across processors such that the
1524d4002b98SHong Zhang   first m0 rows belong to process 0, the next m1 rows belong to
1525d4002b98SHong Zhang   process 1, the next m2 rows belong to process 2 etc.. where
1526d4002b98SHong Zhang   m0,m1,m2,.. are the input parameter 'm'. i.e each processor stores
152720f4b53cSBarry Smith   values corresponding to [`m` x `N`] submatrix.
1528d4002b98SHong Zhang 
1529d4002b98SHong Zhang   The columns are logically partitioned with the n0 columns belonging
1530d4002b98SHong Zhang   to 0th partition, the next n1 columns belonging to the next
153120f4b53cSBarry Smith   partition etc.. where n0,n1,n2... are the input parameter `n`.
1532d4002b98SHong Zhang 
1533d4002b98SHong Zhang   The DIAGONAL portion of the local submatrix on any given processor
153420f4b53cSBarry Smith   is the submatrix corresponding to the rows and columns `m`, `n`
1535d4002b98SHong Zhang   corresponding to the given processor. i.e diagonal matrix on
1536d4002b98SHong Zhang   process 0 is [m0 x n0], diagonal matrix on process 1 is [m1 x n1]
1537d4002b98SHong Zhang   etc. The remaining portion of the local submatrix [m x (N-n)]
1538d4002b98SHong Zhang   constitute the OFF-DIAGONAL portion. The example below better
1539d4002b98SHong Zhang   illustrates this concept.
1540d4002b98SHong Zhang 
1541d4002b98SHong Zhang   For a square global matrix we define each processor's diagonal portion
1542d4002b98SHong Zhang   to be its local rows and the corresponding columns (a square submatrix);
1543d4002b98SHong Zhang   each processor's off-diagonal portion encompasses the remainder of the
1544d4002b98SHong Zhang   local matrix (a rectangular submatrix).
1545d4002b98SHong Zhang 
154620f4b53cSBarry Smith   If `o_rlen`, `d_rlen` are specified, then `o_rlenmax`, and `d_rlenmax` are ignored.
1547d4002b98SHong Zhang 
1548d4002b98SHong Zhang   When calling this routine with a single process communicator, a matrix of
154911a5261eSBarry Smith   type `MATSEQSELL` is returned.  If a matrix of type `MATMPISELL` is desired for this
155027430b45SBarry Smith   type of communicator, use the construction mechanism
1551d4002b98SHong Zhang .vb
155227430b45SBarry Smith    MatCreate(...,&A);
155327430b45SBarry Smith    MatSetType(A,MATMPISELL);
155427430b45SBarry Smith    MatSetSizes(A, m,n,M,N);
155527430b45SBarry Smith    MatMPISELLSetPreallocation(A,...);
1556d4002b98SHong Zhang .ve
1557d4002b98SHong Zhang 
155867be906fSBarry Smith .seealso: `Mat`, `MATSELL`, `MatCreate()`, `MatCreateSeqSELL()`, `MatSetValues()`, `MatMPISELLSetPreallocation()`, `MatMPISELLSetPreallocationSELL()`,
1559db781477SPatrick Sanan           `MATMPISELL`, `MatCreateMPISELLWithArrays()`
1560d4002b98SHong Zhang @*/
1561d71ae5a4SJacob Faibussowitsch 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)
1562d71ae5a4SJacob Faibussowitsch {
1563d4002b98SHong Zhang   PetscMPIInt size;
1564d4002b98SHong Zhang 
1565d4002b98SHong Zhang   PetscFunctionBegin;
15669566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
15679566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
15689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
1569d4002b98SHong Zhang   if (size > 1) {
15709566063dSJacob Faibussowitsch     PetscCall(MatSetType(*A, MATMPISELL));
15719566063dSJacob Faibussowitsch     PetscCall(MatMPISELLSetPreallocation(*A, d_rlenmax, d_rlen, o_rlenmax, o_rlen));
1572d4002b98SHong Zhang   } else {
15739566063dSJacob Faibussowitsch     PetscCall(MatSetType(*A, MATSEQSELL));
15749566063dSJacob Faibussowitsch     PetscCall(MatSeqSELLSetPreallocation(*A, d_rlenmax, d_rlen));
1575d4002b98SHong Zhang   }
15763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1577d4002b98SHong Zhang }
1578d4002b98SHong Zhang 
1579*fa078d78SJacob Faibussowitsch /*@C
1580*fa078d78SJacob Faibussowitsch   MatMPISELLGetSeqSELL - Returns the local pieces of this distributed matrix
1581*fa078d78SJacob Faibussowitsch 
1582*fa078d78SJacob Faibussowitsch   Not Collective
1583*fa078d78SJacob Faibussowitsch 
1584*fa078d78SJacob Faibussowitsch   Input Parameter:
1585*fa078d78SJacob Faibussowitsch . A - the `MATMPISELL` matrix
1586*fa078d78SJacob Faibussowitsch 
1587*fa078d78SJacob Faibussowitsch   Output Parameters:
1588*fa078d78SJacob Faibussowitsch + Ad     - The diagonal portion of `A`
1589*fa078d78SJacob Faibussowitsch . Ao     - The off diagonal portion of `A`
1590*fa078d78SJacob Faibussowitsch - colmap - An array mapping local column numbers of `Ao` to global column numbers of the parallel matrix
1591*fa078d78SJacob Faibussowitsch 
1592*fa078d78SJacob Faibussowitsch   Level: advanced
1593*fa078d78SJacob Faibussowitsch 
1594*fa078d78SJacob Faibussowitsch .seealso: `Mat`, `MATSEQSELL`, `MATMPISELL`
1595*fa078d78SJacob Faibussowitsch @*/
1596*fa078d78SJacob Faibussowitsch PetscErrorCode MatMPISELLGetSeqSELL(Mat A, Mat *Ad, Mat *Ao, const PetscInt *colmap[])
1597*fa078d78SJacob Faibussowitsch {
1598*fa078d78SJacob Faibussowitsch   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
1599*fa078d78SJacob Faibussowitsch   PetscBool    flg;
1600*fa078d78SJacob Faibussowitsch 
1601*fa078d78SJacob Faibussowitsch   PetscFunctionBegin;
1602*fa078d78SJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPISELL, &flg));
1603*fa078d78SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "This function requires a MATMPISELL matrix as input");
1604*fa078d78SJacob Faibussowitsch   if (Ad) *Ad = a->A;
1605*fa078d78SJacob Faibussowitsch   if (Ao) *Ao = a->B;
1606*fa078d78SJacob Faibussowitsch   if (colmap) *colmap = a->garray;
1607*fa078d78SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1608*fa078d78SJacob Faibussowitsch }
1609*fa078d78SJacob Faibussowitsch 
1610*fa078d78SJacob Faibussowitsch /*@C
1611*fa078d78SJacob Faibussowitsch   MatMPISELLGetLocalMatCondensed - Creates a `MATSEQSELL` matrix from an `MATMPISELL` matrix by
1612*fa078d78SJacob Faibussowitsch   taking all its local rows and NON-ZERO columns
1613*fa078d78SJacob Faibussowitsch 
1614*fa078d78SJacob Faibussowitsch   Not Collective
1615*fa078d78SJacob Faibussowitsch 
1616*fa078d78SJacob Faibussowitsch   Input Parameters:
1617*fa078d78SJacob Faibussowitsch + A     - the matrix
1618*fa078d78SJacob Faibussowitsch . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
1619*fa078d78SJacob Faibussowitsch . row   - index sets of rows to extract (or `NULL`)
1620*fa078d78SJacob Faibussowitsch - col   - index sets of columns to extract (or `NULL`)
1621*fa078d78SJacob Faibussowitsch 
1622*fa078d78SJacob Faibussowitsch   Output Parameter:
1623*fa078d78SJacob Faibussowitsch . A_loc - the local sequential matrix generated
1624*fa078d78SJacob Faibussowitsch 
1625*fa078d78SJacob Faibussowitsch   Level: advanced
1626*fa078d78SJacob Faibussowitsch 
1627*fa078d78SJacob Faibussowitsch .seealso: `Mat`, `MATSEQSELL`, `MATMPISELL`, `MatGetOwnershipRange()`, `MatMPISELLGetLocalMat()`
1628*fa078d78SJacob Faibussowitsch @*/
1629*fa078d78SJacob Faibussowitsch PetscErrorCode MatMPISELLGetLocalMatCondensed(Mat A, MatReuse scall, IS *row, IS *col, Mat *A_loc)
1630*fa078d78SJacob Faibussowitsch {
1631*fa078d78SJacob Faibussowitsch   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
1632*fa078d78SJacob Faibussowitsch   PetscInt     i, start, end, ncols, nzA, nzB, *cmap, imark, *idx;
1633*fa078d78SJacob Faibussowitsch   IS           isrowa, iscola;
1634*fa078d78SJacob Faibussowitsch   Mat         *aloc;
1635*fa078d78SJacob Faibussowitsch   PetscBool    match;
1636*fa078d78SJacob Faibussowitsch 
1637*fa078d78SJacob Faibussowitsch   PetscFunctionBegin;
1638*fa078d78SJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPISELL, &match));
1639*fa078d78SJacob Faibussowitsch   PetscCheck(match, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Requires MATMPISELL matrix as input");
1640*fa078d78SJacob Faibussowitsch   PetscCall(PetscLogEventBegin(MAT_Getlocalmatcondensed, A, 0, 0, 0));
1641*fa078d78SJacob Faibussowitsch   if (!row) {
1642*fa078d78SJacob Faibussowitsch     start = A->rmap->rstart;
1643*fa078d78SJacob Faibussowitsch     end   = A->rmap->rend;
1644*fa078d78SJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, end - start, start, 1, &isrowa));
1645*fa078d78SJacob Faibussowitsch   } else {
1646*fa078d78SJacob Faibussowitsch     isrowa = *row;
1647*fa078d78SJacob Faibussowitsch   }
1648*fa078d78SJacob Faibussowitsch   if (!col) {
1649*fa078d78SJacob Faibussowitsch     start = A->cmap->rstart;
1650*fa078d78SJacob Faibussowitsch     cmap  = a->garray;
1651*fa078d78SJacob Faibussowitsch     nzA   = a->A->cmap->n;
1652*fa078d78SJacob Faibussowitsch     nzB   = a->B->cmap->n;
1653*fa078d78SJacob Faibussowitsch     PetscCall(PetscMalloc1(nzA + nzB, &idx));
1654*fa078d78SJacob Faibussowitsch     ncols = 0;
1655*fa078d78SJacob Faibussowitsch     for (i = 0; i < nzB; i++) {
1656*fa078d78SJacob Faibussowitsch       if (cmap[i] < start) idx[ncols++] = cmap[i];
1657*fa078d78SJacob Faibussowitsch       else break;
1658*fa078d78SJacob Faibussowitsch     }
1659*fa078d78SJacob Faibussowitsch     imark = i;
1660*fa078d78SJacob Faibussowitsch     for (i = 0; i < nzA; i++) idx[ncols++] = start + i;
1661*fa078d78SJacob Faibussowitsch     for (i = imark; i < nzB; i++) idx[ncols++] = cmap[i];
1662*fa078d78SJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncols, idx, PETSC_OWN_POINTER, &iscola));
1663*fa078d78SJacob Faibussowitsch   } else {
1664*fa078d78SJacob Faibussowitsch     iscola = *col;
1665*fa078d78SJacob Faibussowitsch   }
1666*fa078d78SJacob Faibussowitsch   if (scall != MAT_INITIAL_MATRIX) {
1667*fa078d78SJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &aloc));
1668*fa078d78SJacob Faibussowitsch     aloc[0] = *A_loc;
1669*fa078d78SJacob Faibussowitsch   }
1670*fa078d78SJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(A, 1, &isrowa, &iscola, scall, &aloc));
1671*fa078d78SJacob Faibussowitsch   *A_loc = aloc[0];
1672*fa078d78SJacob Faibussowitsch   PetscCall(PetscFree(aloc));
1673*fa078d78SJacob Faibussowitsch   if (!row) PetscCall(ISDestroy(&isrowa));
1674*fa078d78SJacob Faibussowitsch   if (!col) PetscCall(ISDestroy(&iscola));
1675*fa078d78SJacob Faibussowitsch   PetscCall(PetscLogEventEnd(MAT_Getlocalmatcondensed, A, 0, 0, 0));
1676*fa078d78SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1677*fa078d78SJacob Faibussowitsch }
1678*fa078d78SJacob Faibussowitsch 
1679d4002b98SHong Zhang #include <../src/mat/impls/aij/mpi/mpiaij.h>
1680d4002b98SHong Zhang 
1681d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_MPISELL_MPIAIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1682d71ae5a4SJacob Faibussowitsch {
1683d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
1684d4002b98SHong Zhang   Mat          B;
1685d4002b98SHong Zhang   Mat_MPIAIJ  *b;
1686d4002b98SHong Zhang 
1687d4002b98SHong Zhang   PetscFunctionBegin;
168828b400f6SJacob Faibussowitsch   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Matrix must be assembled");
1689d4002b98SHong Zhang 
169094a8b381SRichard Tran Mills   if (reuse == MAT_REUSE_MATRIX) {
169194a8b381SRichard Tran Mills     B = *newmat;
169294a8b381SRichard Tran Mills   } else {
16939566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
16949566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATMPIAIJ));
16959566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
16969566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, A->rmap->bs, A->cmap->bs));
16979566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(B, 0, NULL));
16989566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL));
169994a8b381SRichard Tran Mills   }
1700d4002b98SHong Zhang   b = (Mat_MPIAIJ *)B->data;
170194a8b381SRichard Tran Mills 
170294a8b381SRichard Tran Mills   if (reuse == MAT_REUSE_MATRIX) {
17039566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqSELL_SeqAIJ(a->A, MATSEQAIJ, MAT_REUSE_MATRIX, &b->A));
17049566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqSELL_SeqAIJ(a->B, MATSEQAIJ, MAT_REUSE_MATRIX, &b->B));
170594a8b381SRichard Tran Mills   } else {
17069566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b->A));
17079566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b->B));
17089566063dSJacob Faibussowitsch     PetscCall(MatDisAssemble_MPISELL(A));
17099566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqSELL_SeqAIJ(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &b->A));
17109566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqSELL_SeqAIJ(a->B, MATSEQAIJ, MAT_INITIAL_MATRIX, &b->B));
17119566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
17129566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
17139566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
17149566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
171594a8b381SRichard Tran Mills   }
1716d4002b98SHong Zhang 
1717d4002b98SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
17189566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1719d4002b98SHong Zhang   } else {
1720d4002b98SHong Zhang     *newmat = B;
1721d4002b98SHong Zhang   }
17223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1723d4002b98SHong Zhang }
1724d4002b98SHong Zhang 
1725d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_MPIAIJ_MPISELL(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1726d71ae5a4SJacob Faibussowitsch {
1727d4002b98SHong Zhang   Mat_MPIAIJ  *a = (Mat_MPIAIJ *)A->data;
1728d4002b98SHong Zhang   Mat          B;
1729d4002b98SHong Zhang   Mat_MPISELL *b;
1730d4002b98SHong Zhang 
1731d4002b98SHong Zhang   PetscFunctionBegin;
173228b400f6SJacob Faibussowitsch   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Matrix must be assembled");
1733d4002b98SHong Zhang 
173494a8b381SRichard Tran Mills   if (reuse == MAT_REUSE_MATRIX) {
173594a8b381SRichard Tran Mills     B = *newmat;
173694a8b381SRichard Tran Mills   } else {
17372d1451d4SHong Zhang     Mat_SeqAIJ *Aa = (Mat_SeqAIJ *)a->A->data, *Ba = (Mat_SeqAIJ *)a->B->data;
17382d1451d4SHong Zhang     PetscInt    i, d_nz = 0, o_nz = 0, m = A->rmap->N, n = A->cmap->N, lm = A->rmap->n, ln = A->cmap->n;
17392d1451d4SHong Zhang     PetscInt   *d_nnz, *o_nnz;
17402d1451d4SHong Zhang     PetscCall(PetscMalloc2(lm, &d_nnz, lm, &o_nnz));
17412d1451d4SHong Zhang     for (i = 0; i < lm; i++) {
17422d1451d4SHong Zhang       d_nnz[i] = Aa->i[i + 1] - Aa->i[i];
17432d1451d4SHong Zhang       o_nnz[i] = Ba->i[i + 1] - Ba->i[i];
17442d1451d4SHong Zhang       if (d_nnz[i] > d_nz) d_nz = d_nnz[i];
17452d1451d4SHong Zhang       if (o_nnz[i] > o_nz) o_nz = o_nnz[i];
17462d1451d4SHong Zhang     }
17479566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
17489566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATMPISELL));
17492d1451d4SHong Zhang     PetscCall(MatSetSizes(B, lm, ln, m, n));
17509566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, A->rmap->bs, A->cmap->bs));
17512d1451d4SHong Zhang     PetscCall(MatSeqSELLSetPreallocation(B, d_nz, d_nnz));
17522d1451d4SHong Zhang     PetscCall(MatMPISELLSetPreallocation(B, d_nz, d_nnz, o_nz, o_nnz));
17532d1451d4SHong Zhang     PetscCall(PetscFree2(d_nnz, o_nnz));
175494a8b381SRichard Tran Mills   }
1755d4002b98SHong Zhang   b = (Mat_MPISELL *)B->data;
175694a8b381SRichard Tran Mills 
175794a8b381SRichard Tran Mills   if (reuse == MAT_REUSE_MATRIX) {
17589566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqAIJ_SeqSELL(a->A, MATSEQSELL, MAT_REUSE_MATRIX, &b->A));
17599566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqAIJ_SeqSELL(a->B, MATSEQSELL, MAT_REUSE_MATRIX, &b->B));
176094a8b381SRichard Tran Mills   } else {
17619566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b->A));
17629566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b->B));
17639566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqAIJ_SeqSELL(a->A, MATSEQSELL, MAT_INITIAL_MATRIX, &b->A));
17649566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqAIJ_SeqSELL(a->B, MATSEQSELL, MAT_INITIAL_MATRIX, &b->B));
17659566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
17669566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
17672d1451d4SHong Zhang     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
17682d1451d4SHong Zhang     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
176994a8b381SRichard Tran Mills   }
1770d4002b98SHong Zhang 
1771d4002b98SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
17729566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1773d4002b98SHong Zhang   } else {
1774d4002b98SHong Zhang     *newmat = B;
1775d4002b98SHong Zhang   }
17763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1777d4002b98SHong Zhang }
1778d4002b98SHong Zhang 
1779d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSOR_MPISELL(Mat matin, Vec bb, PetscReal omega, MatSORType flag, PetscReal fshift, PetscInt its, PetscInt lits, Vec xx)
1780d71ae5a4SJacob Faibussowitsch {
1781d4002b98SHong Zhang   Mat_MPISELL *mat = (Mat_MPISELL *)matin->data;
1782f4259b30SLisandro Dalcin   Vec          bb1 = NULL;
1783d4002b98SHong Zhang 
1784d4002b98SHong Zhang   PetscFunctionBegin;
1785d4002b98SHong Zhang   if (flag == SOR_APPLY_UPPER) {
17869566063dSJacob Faibussowitsch     PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx));
17873ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1788d4002b98SHong Zhang   }
1789d4002b98SHong Zhang 
179048a46eb9SPierre Jolivet   if (its > 1 || ~flag & SOR_ZERO_INITIAL_GUESS || flag & SOR_EISENSTAT) PetscCall(VecDuplicate(bb, &bb1));
1791d4002b98SHong Zhang 
1792d4002b98SHong Zhang   if ((flag & SOR_LOCAL_SYMMETRIC_SWEEP) == SOR_LOCAL_SYMMETRIC_SWEEP) {
1793d4002b98SHong Zhang     if (flag & SOR_ZERO_INITIAL_GUESS) {
17949566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx));
1795d4002b98SHong Zhang       its--;
1796d4002b98SHong Zhang     }
1797d4002b98SHong Zhang 
1798d4002b98SHong Zhang     while (its--) {
17999566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
18009566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1801d4002b98SHong Zhang 
1802d4002b98SHong Zhang       /* update rhs: bb1 = bb - B*x */
18039566063dSJacob Faibussowitsch       PetscCall(VecScale(mat->lvec, -1.0));
18049566063dSJacob Faibussowitsch       PetscCall((*mat->B->ops->multadd)(mat->B, mat->lvec, bb, bb1));
1805d4002b98SHong Zhang 
1806d4002b98SHong Zhang       /* local sweep */
18079566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb1, omega, SOR_SYMMETRIC_SWEEP, fshift, lits, 1, xx));
1808d4002b98SHong Zhang     }
1809d4002b98SHong Zhang   } else if (flag & SOR_LOCAL_FORWARD_SWEEP) {
1810d4002b98SHong Zhang     if (flag & SOR_ZERO_INITIAL_GUESS) {
18119566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx));
1812d4002b98SHong Zhang       its--;
1813d4002b98SHong Zhang     }
1814d4002b98SHong Zhang     while (its--) {
18159566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
18169566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1817d4002b98SHong Zhang 
1818d4002b98SHong Zhang       /* update rhs: bb1 = bb - B*x */
18199566063dSJacob Faibussowitsch       PetscCall(VecScale(mat->lvec, -1.0));
18209566063dSJacob Faibussowitsch       PetscCall((*mat->B->ops->multadd)(mat->B, mat->lvec, bb, bb1));
1821d4002b98SHong Zhang 
1822d4002b98SHong Zhang       /* local sweep */
18239566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb1, omega, SOR_FORWARD_SWEEP, fshift, lits, 1, xx));
1824d4002b98SHong Zhang     }
1825d4002b98SHong Zhang   } else if (flag & SOR_LOCAL_BACKWARD_SWEEP) {
1826d4002b98SHong Zhang     if (flag & SOR_ZERO_INITIAL_GUESS) {
18279566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx));
1828d4002b98SHong Zhang       its--;
1829d4002b98SHong Zhang     }
1830d4002b98SHong Zhang     while (its--) {
18319566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
18329566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1833d4002b98SHong Zhang 
1834d4002b98SHong Zhang       /* update rhs: bb1 = bb - B*x */
18359566063dSJacob Faibussowitsch       PetscCall(VecScale(mat->lvec, -1.0));
18369566063dSJacob Faibussowitsch       PetscCall((*mat->B->ops->multadd)(mat->B, mat->lvec, bb, bb1));
1837d4002b98SHong Zhang 
1838d4002b98SHong Zhang       /* local sweep */
18399566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb1, omega, SOR_BACKWARD_SWEEP, fshift, lits, 1, xx));
1840d4002b98SHong Zhang     }
1841d4002b98SHong Zhang   } else SETERRQ(PetscObjectComm((PetscObject)matin), PETSC_ERR_SUP, "Parallel SOR not supported");
1842d4002b98SHong Zhang 
18439566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bb1));
1844d4002b98SHong Zhang 
1845d4002b98SHong Zhang   matin->factorerrortype = mat->A->factorerrortype;
18463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1847d4002b98SHong Zhang }
1848d4002b98SHong Zhang 
1849b5917f1bSHong Zhang #if defined(PETSC_HAVE_CUDA)
1850b5917f1bSHong Zhang PETSC_INTERN PetscErrorCode MatConvert_MPISELL_MPISELLCUDA(Mat, MatType, MatReuse, Mat *);
1851b5917f1bSHong Zhang #endif
1852b5917f1bSHong Zhang 
1853d4002b98SHong Zhang /*MC
1854d4002b98SHong Zhang    MATMPISELL - MATMPISELL = "MPISELL" - A matrix type to be used for parallel sparse matrices.
1855d4002b98SHong Zhang 
1856d4002b98SHong Zhang    Options Database Keys:
185711a5261eSBarry Smith . -mat_type mpisell - sets the matrix type to `MATMPISELL` during a call to `MatSetFromOptions()`
1858d4002b98SHong Zhang 
1859d4002b98SHong Zhang   Level: beginner
1860d4002b98SHong Zhang 
186167be906fSBarry Smith .seealso: `Mat`, `MATSELL`, `MATSEQSELL` `MatCreateSELL()`
1862d4002b98SHong Zhang M*/
1863d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_MPISELL(Mat B)
1864d71ae5a4SJacob Faibussowitsch {
1865d4002b98SHong Zhang   Mat_MPISELL *b;
1866d4002b98SHong Zhang   PetscMPIInt  size;
1867d4002b98SHong Zhang 
1868d4002b98SHong Zhang   PetscFunctionBegin;
18699566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size));
18704dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
1871d4002b98SHong Zhang   B->data       = (void *)b;
1872aea10558SJacob Faibussowitsch   B->ops[0]     = MatOps_Values;
1873d4002b98SHong Zhang   B->assembled  = PETSC_FALSE;
1874d4002b98SHong Zhang   B->insertmode = NOT_SET_VALUES;
1875d4002b98SHong Zhang   b->size       = size;
18769566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)B), &b->rank));
1877d4002b98SHong Zhang   /* build cache for off array entries formed */
18789566063dSJacob Faibussowitsch   PetscCall(MatStashCreate_Private(PetscObjectComm((PetscObject)B), 1, &B->stash));
1879d4002b98SHong Zhang 
1880d4002b98SHong Zhang   b->donotstash  = PETSC_FALSE;
1881f4259b30SLisandro Dalcin   b->colmap      = NULL;
1882f4259b30SLisandro Dalcin   b->garray      = NULL;
1883d4002b98SHong Zhang   b->roworiented = PETSC_TRUE;
1884d4002b98SHong Zhang 
1885d4002b98SHong Zhang   /* stuff used for matrix vector multiply */
1886d4002b98SHong Zhang   b->lvec  = NULL;
1887d4002b98SHong Zhang   b->Mvctx = NULL;
1888d4002b98SHong Zhang 
1889d4002b98SHong Zhang   /* stuff for MatGetRow() */
1890f4259b30SLisandro Dalcin   b->rowindices   = NULL;
1891f4259b30SLisandro Dalcin   b->rowvalues    = NULL;
1892d4002b98SHong Zhang   b->getrowactive = PETSC_FALSE;
1893d4002b98SHong Zhang 
18949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_MPISELL));
18959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_MPISELL));
18969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_MPISELL));
18979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatMPISELLSetPreallocation_C", MatMPISELLSetPreallocation_MPISELL));
18989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_mpisell_mpiaij_C", MatConvert_MPISELL_MPIAIJ));
1899b5917f1bSHong Zhang #if defined(PETSC_HAVE_CUDA)
1900b5917f1bSHong Zhang   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_mpisell_mpisellcuda_C", MatConvert_MPISELL_MPISELLCUDA));
1901b5917f1bSHong Zhang #endif
19029566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatDiagonalScaleLocal_C", MatDiagonalScaleLocal_MPISELL));
19039566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATMPISELL));
19043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1905d4002b98SHong Zhang }
1906