xref: /petsc/src/mat/impls/sell/mpi/mpisell.c (revision 421480d92be24cdb9933c60510b8e175c0a8d034)
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++; \
102d4002b98SHong Zhang   a_noinsert:; \
103d4002b98SHong Zhang     a->rlen[row] = nrow1; \
104d4002b98SHong Zhang   }
105d4002b98SHong Zhang 
106d4002b98SHong Zhang #define MatSetValues_SeqSELL_B_Private(row, col, value, addv, orow, ocol) \
107d4002b98SHong Zhang   { \
108d4002b98SHong Zhang     if (col <= lastcol2) low2 = 0; \
109d4002b98SHong Zhang     else high2 = nrow2; \
110d4002b98SHong Zhang     lastcol2 = col; \
111d4002b98SHong Zhang     while (high2 - low2 > 5) { \
112d4002b98SHong Zhang       t = (low2 + high2) / 2; \
1134f8ff0b3SHong Zhang       if (cp2[sliceheight * t] > col) high2 = t; \
114d4002b98SHong Zhang       else low2 = t; \
115d4002b98SHong Zhang     } \
116d4002b98SHong Zhang     for (_i = low2; _i < high2; _i++) { \
1174f8ff0b3SHong Zhang       if (cp2[sliceheight * _i] > col) break; \
1184f8ff0b3SHong Zhang       if (cp2[sliceheight * _i] == col) { \
1194f8ff0b3SHong Zhang         if (addv == ADD_VALUES) vp2[sliceheight * _i] += value; \
1204f8ff0b3SHong Zhang         else vp2[sliceheight * _i] = value; \
1212d1451d4SHong Zhang         inserted = PETSC_TRUE; \
122d4002b98SHong Zhang         goto b_noinsert; \
123d4002b98SHong Zhang       } \
124d4002b98SHong Zhang     } \
1259371c9d4SSatish Balay     if (value == 0.0 && ignorezeroentries) { \
1269371c9d4SSatish Balay       low2  = 0; \
1279371c9d4SSatish Balay       high2 = nrow2; \
1289371c9d4SSatish Balay       goto b_noinsert; \
1299371c9d4SSatish Balay     } \
1309371c9d4SSatish Balay     if (nonew == 1) { \
1319371c9d4SSatish Balay       low2  = 0; \
1329371c9d4SSatish Balay       high2 = nrow2; \
1339371c9d4SSatish Balay       goto b_noinsert; \
1349371c9d4SSatish Balay     } \
13508401ef6SPierre 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); \
13607e43b41SHong Zhang     MatSeqXSELLReallocateSELL(B, bm, 1, nrow2, b->sliidx, b->sliceheight, row / sliceheight, row, col, b->colidx, b->val, cp2, vp2, nonew, MatScalar); \
137d4002b98SHong Zhang     /* shift up all the later entries in this row */ \
138d4002b98SHong Zhang     for (ii = nrow2 - 1; ii >= _i; ii--) { \
1394f8ff0b3SHong Zhang       cp2[sliceheight * (ii + 1)] = cp2[sliceheight * ii]; \
1404f8ff0b3SHong Zhang       vp2[sliceheight * (ii + 1)] = vp2[sliceheight * ii]; \
141d4002b98SHong Zhang     } \
1424f8ff0b3SHong Zhang     cp2[sliceheight * _i] = col; \
1434f8ff0b3SHong Zhang     vp2[sliceheight * _i] = value; \
1449371c9d4SSatish Balay     b->nz++; \
1459371c9d4SSatish Balay     nrow2++; \
146d4002b98SHong Zhang   b_noinsert:; \
147d4002b98SHong Zhang     b->rlen[row] = nrow2; \
148d4002b98SHong Zhang   }
149d4002b98SHong Zhang 
15043b34f9dSJacob Faibussowitsch static PetscErrorCode MatSetValues_MPISELL(Mat mat, PetscInt m, const PetscInt im[], PetscInt n, const PetscInt in[], const PetscScalar v[], InsertMode addv)
151d71ae5a4SJacob Faibussowitsch {
152d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
153d4002b98SHong Zhang   PetscScalar  value;
154d4002b98SHong Zhang   PetscInt     i, j, rstart = mat->rmap->rstart, rend = mat->rmap->rend, shift1, shift2;
155d4002b98SHong Zhang   PetscInt     cstart = mat->cmap->rstart, cend = mat->cmap->rend, row, col;
156d4002b98SHong Zhang   PetscBool    roworiented = sell->roworiented;
157d4002b98SHong Zhang 
158d4002b98SHong Zhang   /* Some Variables required in the macro */
159d4002b98SHong Zhang   Mat          A                 = sell->A;
160d4002b98SHong Zhang   Mat_SeqSELL *a                 = (Mat_SeqSELL *)A->data;
161d4002b98SHong Zhang   PetscBool    ignorezeroentries = a->ignorezeroentries, found;
162d4002b98SHong Zhang   Mat          B                 = sell->B;
163d4002b98SHong Zhang   Mat_SeqSELL *b                 = (Mat_SeqSELL *)B->data;
16407e43b41SHong Zhang   PetscInt    *cp1, *cp2, ii, _i, nrow1, nrow2, low1, high1, low2, high2, t, lastcol1, lastcol2, sliceheight = a->sliceheight;
165d4002b98SHong Zhang   MatScalar   *vp1, *vp2;
166d4002b98SHong Zhang 
167d4002b98SHong Zhang   PetscFunctionBegin;
168d4002b98SHong Zhang   for (i = 0; i < m; i++) {
169d4002b98SHong Zhang     if (im[i] < 0) continue;
1706bdcaf15SBarry 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);
171d4002b98SHong Zhang     if (im[i] >= rstart && im[i] < rend) {
172d4002b98SHong Zhang       row      = im[i] - rstart;
173d4002b98SHong Zhang       lastcol1 = -1;
17407e43b41SHong Zhang       shift1   = a->sliidx[row / sliceheight] + (row % sliceheight); /* starting index of the row */
1758e3a54c0SPierre Jolivet       cp1      = PetscSafePointerPlusOffset(a->colidx, shift1);
1768e3a54c0SPierre Jolivet       vp1      = PetscSafePointerPlusOffset(a->val, shift1);
177d4002b98SHong Zhang       nrow1    = a->rlen[row];
178d4002b98SHong Zhang       low1     = 0;
179d4002b98SHong Zhang       high1    = nrow1;
180d4002b98SHong Zhang       lastcol2 = -1;
18107e43b41SHong Zhang       shift2   = b->sliidx[row / sliceheight] + (row % sliceheight); /* starting index of the row */
1828e3a54c0SPierre Jolivet       cp2      = PetscSafePointerPlusOffset(b->colidx, shift2);
1838e3a54c0SPierre Jolivet       vp2      = PetscSafePointerPlusOffset(b->val, shift2);
184d4002b98SHong Zhang       nrow2    = b->rlen[row];
185d4002b98SHong Zhang       low2     = 0;
186d4002b98SHong Zhang       high2    = nrow2;
187d4002b98SHong Zhang 
188d4002b98SHong Zhang       for (j = 0; j < n; j++) {
189d4002b98SHong Zhang         if (roworiented) value = v[i * n + j];
190d4002b98SHong Zhang         else value = v[i + j * m];
191d4002b98SHong Zhang         if (ignorezeroentries && value == 0.0 && (addv == ADD_VALUES)) continue;
192d4002b98SHong Zhang         if (in[j] >= cstart && in[j] < cend) {
193d4002b98SHong Zhang           col = in[j] - cstart;
194d4002b98SHong Zhang           MatSetValue_SeqSELL_Private(A, row, col, value, addv, im[i], in[j], cp1, vp1, lastcol1, low1, high1); /* set one value */
1952d1451d4SHong Zhang #if defined(PETSC_HAVE_CUDA)
1962d1451d4SHong Zhang           if (A->offloadmask != PETSC_OFFLOAD_UNALLOCATED && found) A->offloadmask = PETSC_OFFLOAD_CPU;
1972d1451d4SHong Zhang #endif
198f7d195e4SLawrence Mitchell         } else if (in[j] < 0) {
199f7d195e4SLawrence Mitchell           continue;
200f7d195e4SLawrence Mitchell         } else {
201f7d195e4SLawrence 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);
202d4002b98SHong Zhang           if (mat->was_assembled) {
20348a46eb9SPierre Jolivet             if (!sell->colmap) PetscCall(MatCreateColmap_MPISELL_Private(mat));
204d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE)
205eec179cfSJacob Faibussowitsch             PetscCall(PetscHMapIGetWithDefault(sell->colmap, in[j] + 1, 0, &col));
206d4002b98SHong Zhang             col--;
207d4002b98SHong Zhang #else
208d4002b98SHong Zhang             col = sell->colmap[in[j]] - 1;
209d4002b98SHong Zhang #endif
210f4f49eeaSPierre Jolivet             if (col < 0 && !((Mat_SeqSELL *)sell->B->data)->nonew) {
2119566063dSJacob Faibussowitsch               PetscCall(MatDisAssemble_MPISELL(mat));
212d4002b98SHong Zhang               col = in[j];
213d4002b98SHong Zhang               /* Reinitialize the variables required by MatSetValues_SeqSELL_B_Private() */
214d4002b98SHong Zhang               B      = sell->B;
215d4002b98SHong Zhang               b      = (Mat_SeqSELL *)B->data;
21607e43b41SHong Zhang               shift2 = b->sliidx[row / sliceheight] + (row % sliceheight); /* starting index of the row */
217d4002b98SHong Zhang               cp2    = b->colidx + shift2;
218d4002b98SHong Zhang               vp2    = b->val + shift2;
219d4002b98SHong Zhang               nrow2  = b->rlen[row];
220d4002b98SHong Zhang               low2   = 0;
221d4002b98SHong Zhang               high2  = nrow2;
2222d1451d4SHong Zhang               found  = PETSC_FALSE;
223f7d195e4SLawrence Mitchell             } else {
224f7d195e4SLawrence 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]);
225f7d195e4SLawrence Mitchell             }
226d4002b98SHong Zhang           } else col = in[j];
227d4002b98SHong Zhang           MatSetValue_SeqSELL_Private(B, row, col, value, addv, im[i], in[j], cp2, vp2, lastcol2, low2, high2); /* set one value */
2282d1451d4SHong Zhang #if defined(PETSC_HAVE_CUDA)
2292d1451d4SHong Zhang           if (B->offloadmask != PETSC_OFFLOAD_UNALLOCATED && found) B->offloadmask = PETSC_OFFLOAD_CPU;
2302d1451d4SHong Zhang #endif
231d4002b98SHong Zhang         }
232d4002b98SHong Zhang       }
233d4002b98SHong Zhang     } else {
23428b400f6SJacob 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]);
235d4002b98SHong Zhang       if (!sell->donotstash) {
236d4002b98SHong Zhang         mat->assembled = PETSC_FALSE;
237d4002b98SHong Zhang         if (roworiented) {
2389566063dSJacob Faibussowitsch           PetscCall(MatStashValuesRow_Private(&mat->stash, im[i], n, in, v + i * n, (PetscBool)(ignorezeroentries && (addv == ADD_VALUES))));
239d4002b98SHong Zhang         } else {
2409566063dSJacob Faibussowitsch           PetscCall(MatStashValuesCol_Private(&mat->stash, im[i], n, in, v + i, m, (PetscBool)(ignorezeroentries && (addv == ADD_VALUES))));
241d4002b98SHong Zhang         }
242d4002b98SHong Zhang       }
243d4002b98SHong Zhang     }
244d4002b98SHong Zhang   }
2453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
246d4002b98SHong Zhang }
247d4002b98SHong Zhang 
248ba38deedSJacob Faibussowitsch static PetscErrorCode MatGetValues_MPISELL(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], PetscScalar v[])
249d71ae5a4SJacob Faibussowitsch {
250d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
251d4002b98SHong Zhang   PetscInt     i, j, rstart = mat->rmap->rstart, rend = mat->rmap->rend;
252d4002b98SHong Zhang   PetscInt     cstart = mat->cmap->rstart, cend = mat->cmap->rend, row, col;
253d4002b98SHong Zhang 
254d4002b98SHong Zhang   PetscFunctionBegin;
255d4002b98SHong Zhang   for (i = 0; i < m; i++) {
25654c59aa7SJacob Faibussowitsch     if (idxm[i] < 0) continue; /* negative row */
25754c59aa7SJacob 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);
258966bd95aSPierre Jolivet     PetscCheck(idxm[i] >= rstart && idxm[i] < rend, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only local values currently supported");
259d4002b98SHong Zhang     row = idxm[i] - rstart;
260d4002b98SHong Zhang     for (j = 0; j < n; j++) {
26154c59aa7SJacob Faibussowitsch       if (idxn[j] < 0) continue; /* negative column */
26254c59aa7SJacob 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);
263d4002b98SHong Zhang       if (idxn[j] >= cstart && idxn[j] < cend) {
264d4002b98SHong Zhang         col = idxn[j] - cstart;
2659566063dSJacob Faibussowitsch         PetscCall(MatGetValues(sell->A, 1, &row, 1, &col, v + i * n + j));
266d4002b98SHong Zhang       } else {
26748a46eb9SPierre Jolivet         if (!sell->colmap) PetscCall(MatCreateColmap_MPISELL_Private(mat));
268d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE)
269eec179cfSJacob Faibussowitsch         PetscCall(PetscHMapIGetWithDefault(sell->colmap, idxn[j] + 1, 0, &col));
270d4002b98SHong Zhang         col--;
271d4002b98SHong Zhang #else
272d4002b98SHong Zhang         col = sell->colmap[idxn[j]] - 1;
273d4002b98SHong Zhang #endif
274966bd95aSPierre Jolivet         if (col < 0 || sell->garray[col] != idxn[j]) *(v + i * n + j) = 0.0;
27548a46eb9SPierre Jolivet         else PetscCall(MatGetValues(sell->B, 1, &row, 1, &col, v + i * n + j));
276d4002b98SHong Zhang       }
277d4002b98SHong Zhang     }
278d4002b98SHong Zhang   }
2793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
280d4002b98SHong Zhang }
281d4002b98SHong Zhang 
282ba38deedSJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_MPISELL(Mat mat, MatAssemblyType mode)
283d71ae5a4SJacob Faibussowitsch {
284d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
285d4002b98SHong Zhang   PetscInt     nstash, reallocs;
286d4002b98SHong Zhang 
287d4002b98SHong Zhang   PetscFunctionBegin;
2883ba16761SJacob Faibussowitsch   if (sell->donotstash || mat->nooffprocentries) PetscFunctionReturn(PETSC_SUCCESS);
289d4002b98SHong Zhang 
2909566063dSJacob Faibussowitsch   PetscCall(MatStashScatterBegin_Private(mat, &mat->stash, mat->rmap->range));
2919566063dSJacob Faibussowitsch   PetscCall(MatStashGetInfo_Private(&mat->stash, &nstash, &reallocs));
2929566063dSJacob Faibussowitsch   PetscCall(PetscInfo(sell->A, "Stash has %" PetscInt_FMT " entries, uses %" PetscInt_FMT " mallocs.\n", nstash, reallocs));
2933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
294d4002b98SHong Zhang }
295d4002b98SHong Zhang 
296d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAssemblyEnd_MPISELL(Mat mat, MatAssemblyType mode)
297d71ae5a4SJacob Faibussowitsch {
298d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
299d4002b98SHong Zhang   PetscMPIInt  n;
300d4002b98SHong Zhang   PetscInt     i, flg;
301d4002b98SHong Zhang   PetscInt    *row, *col;
302d4002b98SHong Zhang   PetscScalar *val;
303c0edf612SJunchao Zhang   PetscBool    all_assembled;
304d4002b98SHong Zhang   /* do not use 'b = (Mat_SeqSELL*)sell->B->data' as B can be reset in disassembly */
305d4002b98SHong Zhang   PetscFunctionBegin;
306d4002b98SHong Zhang   if (!sell->donotstash && !mat->nooffprocentries) {
307d4002b98SHong Zhang     while (1) {
3089566063dSJacob Faibussowitsch       PetscCall(MatStashScatterGetMesg_Private(&mat->stash, &n, &row, &col, &val, &flg));
309d4002b98SHong Zhang       if (!flg) break;
310d4002b98SHong Zhang 
311d4002b98SHong Zhang       for (i = 0; i < n; i++) { /* assemble one by one */
3129566063dSJacob Faibussowitsch         PetscCall(MatSetValues_MPISELL(mat, 1, row + i, 1, col + i, val + i, mat->insertmode));
313d4002b98SHong Zhang       }
314d4002b98SHong Zhang     }
3159566063dSJacob Faibussowitsch     PetscCall(MatStashScatterEnd_Private(&mat->stash));
316d4002b98SHong Zhang   }
3172d1451d4SHong Zhang #if defined(PETSC_HAVE_CUDA)
3182d1451d4SHong Zhang   if (mat->offloadmask == PETSC_OFFLOAD_CPU) sell->A->offloadmask = PETSC_OFFLOAD_CPU;
3192d1451d4SHong Zhang #endif
3209566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(sell->A, mode));
3219566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(sell->A, mode));
322d4002b98SHong Zhang 
323d4002b98SHong Zhang   /*
324b638e6b4SJunchao Zhang      determine if any process has disassembled, if so we must
3256aad120cSJose E. Roman      also disassemble ourselves, in order that we may reassemble.
326d4002b98SHong Zhang   */
327d4002b98SHong Zhang   /*
328d4002b98SHong Zhang      if nonzero structure of submatrix B cannot change then we know that
329b638e6b4SJunchao Zhang      no process disassembled thus we can skip this stuff
330d4002b98SHong Zhang   */
331d4002b98SHong Zhang   if (!((Mat_SeqSELL *)sell->B->data)->nonew) {
3325440e5dcSBarry Smith     PetscCallMPI(MPIU_Allreduce(&mat->was_assembled, &all_assembled, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
333c0edf612SJunchao Zhang     if (mat->was_assembled && !all_assembled) PetscCall(MatDisAssemble_MPISELL(mat));
334d4002b98SHong Zhang   }
33548a46eb9SPierre Jolivet   if (!mat->was_assembled && mode == MAT_FINAL_ASSEMBLY) PetscCall(MatSetUpMultiply_MPISELL(mat));
3362d1451d4SHong Zhang #if defined(PETSC_HAVE_CUDA)
3372d1451d4SHong Zhang   if (mat->offloadmask == PETSC_OFFLOAD_CPU && sell->B->offloadmask != PETSC_OFFLOAD_UNALLOCATED) sell->B->offloadmask = PETSC_OFFLOAD_CPU;
3382d1451d4SHong Zhang #endif
3399566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(sell->B, mode));
3409566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(sell->B, mode));
3419566063dSJacob Faibussowitsch   PetscCall(PetscFree2(sell->rowvalues, sell->rowindices));
342f4259b30SLisandro Dalcin   sell->rowvalues = NULL;
3439566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sell->diag));
344d4002b98SHong Zhang 
345d4002b98SHong Zhang   /* if no new nonzero locations are allowed in matrix then only set the matrix state the first time through */
346f4f49eeaSPierre Jolivet   if ((!mat->was_assembled && mode == MAT_FINAL_ASSEMBLY) || !((Mat_SeqSELL *)sell->A->data)->nonew) {
347d4002b98SHong Zhang     PetscObjectState state = sell->A->nonzerostate + sell->B->nonzerostate;
348462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(&state, &mat->nonzerostate, 1, MPIU_INT64, MPI_SUM, PetscObjectComm((PetscObject)mat)));
349d4002b98SHong Zhang   }
3502d1451d4SHong Zhang #if defined(PETSC_HAVE_CUDA)
3512d1451d4SHong Zhang   mat->offloadmask = PETSC_OFFLOAD_BOTH;
3522d1451d4SHong Zhang #endif
3533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
354d4002b98SHong Zhang }
355d4002b98SHong Zhang 
356ba38deedSJacob Faibussowitsch static PetscErrorCode MatZeroEntries_MPISELL(Mat A)
357d71ae5a4SJacob Faibussowitsch {
358d4002b98SHong Zhang   Mat_MPISELL *l = (Mat_MPISELL *)A->data;
359d4002b98SHong Zhang 
360d4002b98SHong Zhang   PetscFunctionBegin;
3619566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(l->A));
3629566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(l->B));
3633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
364d4002b98SHong Zhang }
365d4002b98SHong Zhang 
366ba38deedSJacob Faibussowitsch static PetscErrorCode MatMult_MPISELL(Mat A, Vec xx, Vec yy)
367d71ae5a4SJacob Faibussowitsch {
368d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
369d4002b98SHong Zhang   PetscInt     nt;
370d4002b98SHong Zhang 
371d4002b98SHong Zhang   PetscFunctionBegin;
3729566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(xx, &nt));
37308401ef6SPierre 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);
3749566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
3759566063dSJacob Faibussowitsch   PetscCall((*a->A->ops->mult)(a->A, xx, yy));
3769566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
3779566063dSJacob Faibussowitsch   PetscCall((*a->B->ops->multadd)(a->B, a->lvec, yy, yy));
3783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
379d4002b98SHong Zhang }
380d4002b98SHong Zhang 
381fa078d78SJacob Faibussowitsch static PetscErrorCode MatMultDiagonalBlock_MPISELL(Mat A, Vec bb, Vec xx)
382d71ae5a4SJacob Faibussowitsch {
383d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
384d4002b98SHong Zhang 
385d4002b98SHong Zhang   PetscFunctionBegin;
3869566063dSJacob Faibussowitsch   PetscCall(MatMultDiagonalBlock(a->A, bb, xx));
3873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
388d4002b98SHong Zhang }
389d4002b98SHong Zhang 
390ba38deedSJacob Faibussowitsch static PetscErrorCode MatMultAdd_MPISELL(Mat A, Vec xx, Vec yy, Vec zz)
391d71ae5a4SJacob Faibussowitsch {
392d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
393d4002b98SHong Zhang 
394d4002b98SHong Zhang   PetscFunctionBegin;
3959566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
3969566063dSJacob Faibussowitsch   PetscCall((*a->A->ops->multadd)(a->A, xx, yy, zz));
3979566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
3989566063dSJacob Faibussowitsch   PetscCall((*a->B->ops->multadd)(a->B, a->lvec, zz, zz));
3993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
400d4002b98SHong Zhang }
401d4002b98SHong Zhang 
402ba38deedSJacob Faibussowitsch static PetscErrorCode MatMultTranspose_MPISELL(Mat A, Vec xx, Vec yy)
403d71ae5a4SJacob Faibussowitsch {
404d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
405d4002b98SHong Zhang 
406d4002b98SHong Zhang   PetscFunctionBegin;
407d4002b98SHong Zhang   /* do nondiagonal part */
4089566063dSJacob Faibussowitsch   PetscCall((*a->B->ops->multtranspose)(a->B, xx, a->lvec));
409d4002b98SHong Zhang   /* do local part */
4109566063dSJacob Faibussowitsch   PetscCall((*a->A->ops->multtranspose)(a->A, xx, yy));
411a29b4eb7SJunchao Zhang   /* add partial results together */
4129566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(a->Mvctx, a->lvec, yy, ADD_VALUES, SCATTER_REVERSE));
4139566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(a->Mvctx, a->lvec, yy, ADD_VALUES, SCATTER_REVERSE));
4143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
415d4002b98SHong Zhang }
416d4002b98SHong Zhang 
417ba38deedSJacob Faibussowitsch static PetscErrorCode MatIsTranspose_MPISELL(Mat Amat, Mat Bmat, PetscReal tol, PetscBool *f)
418d71ae5a4SJacob Faibussowitsch {
419d4002b98SHong Zhang   MPI_Comm     comm;
420d4002b98SHong Zhang   Mat_MPISELL *Asell = (Mat_MPISELL *)Amat->data, *Bsell;
421d4002b98SHong Zhang   Mat          Adia  = Asell->A, Bdia, Aoff, Boff, *Aoffs, *Boffs;
422d4002b98SHong Zhang   IS           Me, Notme;
423d4002b98SHong Zhang   PetscInt     M, N, first, last, *notme, i;
424d4002b98SHong Zhang   PetscMPIInt  size;
425d4002b98SHong Zhang 
426d4002b98SHong Zhang   PetscFunctionBegin;
427d4002b98SHong Zhang   /* Easy test: symmetric diagonal block */
4289371c9d4SSatish Balay   Bsell = (Mat_MPISELL *)Bmat->data;
4299371c9d4SSatish Balay   Bdia  = Bsell->A;
4309566063dSJacob Faibussowitsch   PetscCall(MatIsTranspose(Adia, Bdia, tol, f));
4313ba16761SJacob Faibussowitsch   if (!*f) PetscFunctionReturn(PETSC_SUCCESS);
4329566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)Amat, &comm));
4339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
4343ba16761SJacob Faibussowitsch   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
435d4002b98SHong Zhang 
436d4002b98SHong Zhang   /* Hard test: off-diagonal block. This takes a MatCreateSubMatrix. */
4379566063dSJacob Faibussowitsch   PetscCall(MatGetSize(Amat, &M, &N));
4389566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(Amat, &first, &last));
4399566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(N - last + first, &notme));
440d4002b98SHong Zhang   for (i = 0; i < first; i++) notme[i] = i;
441d4002b98SHong Zhang   for (i = last; i < M; i++) notme[i - last + first] = i;
4429566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(MPI_COMM_SELF, N - last + first, notme, PETSC_COPY_VALUES, &Notme));
4439566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(MPI_COMM_SELF, last - first, first, 1, &Me));
4449566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(Amat, 1, &Me, &Notme, MAT_INITIAL_MATRIX, &Aoffs));
445d4002b98SHong Zhang   Aoff = Aoffs[0];
4469566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(Bmat, 1, &Notme, &Me, MAT_INITIAL_MATRIX, &Boffs));
447d4002b98SHong Zhang   Boff = Boffs[0];
4489566063dSJacob Faibussowitsch   PetscCall(MatIsTranspose(Aoff, Boff, tol, f));
4499566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1, &Aoffs));
4509566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1, &Boffs));
4519566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&Me));
4529566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&Notme));
4539566063dSJacob Faibussowitsch   PetscCall(PetscFree(notme));
4543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
455d4002b98SHong Zhang }
456d4002b98SHong Zhang 
457ba38deedSJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_MPISELL(Mat A, Vec xx, Vec yy, Vec zz)
458d71ae5a4SJacob Faibussowitsch {
459d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
460d4002b98SHong Zhang 
461d4002b98SHong Zhang   PetscFunctionBegin;
462d4002b98SHong Zhang   /* do nondiagonal part */
4639566063dSJacob Faibussowitsch   PetscCall((*a->B->ops->multtranspose)(a->B, xx, a->lvec));
464d4002b98SHong Zhang   /* do local part */
4659566063dSJacob Faibussowitsch   PetscCall((*a->A->ops->multtransposeadd)(a->A, xx, yy, zz));
466e4a140f6SJunchao Zhang   /* add partial results together */
4679566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(a->Mvctx, a->lvec, zz, ADD_VALUES, SCATTER_REVERSE));
4689566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(a->Mvctx, a->lvec, zz, ADD_VALUES, SCATTER_REVERSE));
4693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
470d4002b98SHong Zhang }
471d4002b98SHong Zhang 
472d4002b98SHong Zhang /*
473d4002b98SHong Zhang   This only works correctly for square matrices where the subblock A->A is the
474d4002b98SHong Zhang    diagonal block
475d4002b98SHong Zhang */
476ba38deedSJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_MPISELL(Mat A, Vec v)
477d71ae5a4SJacob Faibussowitsch {
478d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
479d4002b98SHong Zhang 
480d4002b98SHong Zhang   PetscFunctionBegin;
48108401ef6SPierre Jolivet   PetscCheck(A->rmap->N == A->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Supports only square matrix where A->A is diag block");
482aed4548fSBarry 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");
4839566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(a->A, v));
4843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
485d4002b98SHong Zhang }
486d4002b98SHong Zhang 
487ba38deedSJacob Faibussowitsch static PetscErrorCode MatScale_MPISELL(Mat A, PetscScalar aa)
488d71ae5a4SJacob Faibussowitsch {
489d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
490d4002b98SHong Zhang 
491d4002b98SHong Zhang   PetscFunctionBegin;
4929566063dSJacob Faibussowitsch   PetscCall(MatScale(a->A, aa));
4939566063dSJacob Faibussowitsch   PetscCall(MatScale(a->B, aa));
4943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
495d4002b98SHong Zhang }
496d4002b98SHong Zhang 
497d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDestroy_MPISELL(Mat mat)
498d71ae5a4SJacob Faibussowitsch {
499d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
500d4002b98SHong Zhang 
501d4002b98SHong Zhang   PetscFunctionBegin;
5023ba16761SJacob Faibussowitsch   PetscCall(PetscLogObjectState((PetscObject)mat, "Rows=%" PetscInt_FMT ", Cols=%" PetscInt_FMT, mat->rmap->N, mat->cmap->N));
5039566063dSJacob Faibussowitsch   PetscCall(MatStashDestroy_Private(&mat->stash));
5049566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sell->diag));
5059566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sell->A));
5069566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sell->B));
507d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE)
508eec179cfSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&sell->colmap));
509d4002b98SHong Zhang #else
5109566063dSJacob Faibussowitsch   PetscCall(PetscFree(sell->colmap));
511d4002b98SHong Zhang #endif
5129566063dSJacob Faibussowitsch   PetscCall(PetscFree(sell->garray));
5139566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sell->lvec));
5149566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&sell->Mvctx));
5159566063dSJacob Faibussowitsch   PetscCall(PetscFree2(sell->rowvalues, sell->rowindices));
5169566063dSJacob Faibussowitsch   PetscCall(PetscFree(sell->ld));
5179566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
518d4002b98SHong Zhang 
5199566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)mat, NULL));
5209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatStoreValues_C", NULL));
5219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatRetrieveValues_C", NULL));
5229566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatIsTranspose_C", NULL));
5239566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMPISELLSetPreallocation_C", NULL));
5249566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpisell_mpiaij_C", NULL));
525b5917f1bSHong Zhang #if defined(PETSC_HAVE_CUDA)
526b5917f1bSHong Zhang   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpisell_mpisellcuda_C", NULL));
527b5917f1bSHong Zhang #endif
5289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalScaleLocal_C", NULL));
5293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
530d4002b98SHong Zhang }
531d4002b98SHong Zhang 
532d4002b98SHong Zhang #include <petscdraw.h>
533ba38deedSJacob Faibussowitsch static PetscErrorCode MatView_MPISELL_ASCIIorDraworSocket(Mat mat, PetscViewer viewer)
534d71ae5a4SJacob Faibussowitsch {
535d4002b98SHong Zhang   Mat_MPISELL      *sell = (Mat_MPISELL *)mat->data;
536d4002b98SHong Zhang   PetscMPIInt       rank = sell->rank, size = sell->size;
5379f196a02SMartin Diehl   PetscBool         isdraw, isascii, isbinary;
538d4002b98SHong Zhang   PetscViewer       sviewer;
539d4002b98SHong Zhang   PetscViewerFormat format;
540d4002b98SHong Zhang 
541d4002b98SHong Zhang   PetscFunctionBegin;
5429566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
5439f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
5449566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
5459f196a02SMartin Diehl   if (isascii) {
5469566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
547d4002b98SHong Zhang     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
548d4002b98SHong Zhang       MatInfo   info;
5496335e310SSatish Balay       PetscInt *inodes;
550d4002b98SHong Zhang 
5519566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank));
5529566063dSJacob Faibussowitsch       PetscCall(MatGetInfo(mat, MAT_LOCAL, &info));
5539566063dSJacob Faibussowitsch       PetscCall(MatInodeGetInodeSizes(sell->A, NULL, &inodes, NULL));
5549566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
555d4002b98SHong Zhang       if (!inodes) {
5569371c9d4SSatish 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,
5579371c9d4SSatish Balay                                                      (PetscInt)info.nz_allocated, (PetscInt)info.memory));
558d4002b98SHong Zhang       } else {
5599371c9d4SSatish 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,
5609371c9d4SSatish Balay                                                      (PetscInt)info.nz_allocated, (PetscInt)info.memory));
561d4002b98SHong Zhang       }
5629566063dSJacob Faibussowitsch       PetscCall(MatGetInfo(sell->A, MAT_LOCAL, &info));
5639566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] on-diagonal part: nz %" PetscInt_FMT " \n", rank, (PetscInt)info.nz_used));
5649566063dSJacob Faibussowitsch       PetscCall(MatGetInfo(sell->B, MAT_LOCAL, &info));
5659566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] off-diagonal part: nz %" PetscInt_FMT " \n", rank, (PetscInt)info.nz_used));
5669566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
5679566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
5689566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Information on VecScatter used in matrix-vector product: \n"));
5699566063dSJacob Faibussowitsch       PetscCall(VecScatterView(sell->Mvctx, viewer));
5703ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
571d4002b98SHong Zhang     } else if (format == PETSC_VIEWER_ASCII_INFO) {
572d4002b98SHong Zhang       PetscInt inodecount, inodelimit, *inodes;
5739566063dSJacob Faibussowitsch       PetscCall(MatInodeGetInodeSizes(sell->A, &inodecount, &inodes, &inodelimit));
574d4002b98SHong Zhang       if (inodes) {
5759566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "using I-node (on process 0) routines: found %" PetscInt_FMT " nodes, limit used is %" PetscInt_FMT "\n", inodecount, inodelimit));
576d4002b98SHong Zhang       } else {
5779566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "not using I-node (on process 0) routines\n"));
578d4002b98SHong Zhang       }
5793ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
580d4002b98SHong Zhang     } else if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
5813ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
582d4002b98SHong Zhang     }
583d4002b98SHong Zhang   } else if (isbinary) {
584d4002b98SHong Zhang     if (size == 1) {
5859566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)sell->A, ((PetscObject)mat)->name));
5869566063dSJacob Faibussowitsch       PetscCall(MatView(sell->A, viewer));
587d4002b98SHong Zhang     } else {
5889566063dSJacob Faibussowitsch       /* PetscCall(MatView_MPISELL_Binary(mat,viewer)); */
589d4002b98SHong Zhang     }
5903ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
591d4002b98SHong Zhang   } else if (isdraw) {
592d4002b98SHong Zhang     PetscDraw draw;
593d4002b98SHong Zhang     PetscBool isnull;
5949566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
5959566063dSJacob Faibussowitsch     PetscCall(PetscDrawIsNull(draw, &isnull));
5963ba16761SJacob Faibussowitsch     if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
597d4002b98SHong Zhang   }
598d4002b98SHong Zhang 
599d4002b98SHong Zhang   {
600d4002b98SHong Zhang     /* assemble the entire matrix onto first processor. */
601d4002b98SHong Zhang     Mat          A;
602d4002b98SHong Zhang     Mat_SeqSELL *Aloc;
603d4002b98SHong Zhang     PetscInt     M = mat->rmap->N, N = mat->cmap->N, *acolidx, row, col, i, j;
604d4002b98SHong Zhang     MatScalar   *aval;
605d4002b98SHong Zhang     PetscBool    isnonzero;
606d4002b98SHong Zhang 
6079566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &A));
608dd400576SPatrick Sanan     if (rank == 0) {
6099566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(A, M, N, M, N));
610d4002b98SHong Zhang     } else {
6119566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(A, 0, 0, M, N));
612d4002b98SHong Zhang     }
613d4002b98SHong Zhang     /* This is just a temporary matrix, so explicitly using MATMPISELL is probably best */
6149566063dSJacob Faibussowitsch     PetscCall(MatSetType(A, MATMPISELL));
6159566063dSJacob Faibussowitsch     PetscCall(MatMPISELLSetPreallocation(A, 0, NULL, 0, NULL));
6169566063dSJacob Faibussowitsch     PetscCall(MatSetOption(A, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
617d4002b98SHong Zhang 
618d4002b98SHong Zhang     /* copy over the A part */
619d4002b98SHong Zhang     Aloc    = (Mat_SeqSELL *)sell->A->data;
6209371c9d4SSatish Balay     acolidx = Aloc->colidx;
6219371c9d4SSatish Balay     aval    = Aloc->val;
622d4002b98SHong Zhang     for (i = 0; i < Aloc->totalslices; i++) { /* loop over slices */
623d4002b98SHong Zhang       for (j = Aloc->sliidx[i]; j < Aloc->sliidx[i + 1]; j++) {
62407e43b41SHong Zhang         isnonzero = (PetscBool)((j - Aloc->sliidx[i]) / Aloc->sliceheight < Aloc->rlen[i * Aloc->sliceheight + j % Aloc->sliceheight]);
625d4002b98SHong Zhang         if (isnonzero) { /* check the mask bit */
62607e43b41SHong Zhang           row = i * Aloc->sliceheight + j % Aloc->sliceheight + mat->rmap->rstart;
627d4002b98SHong Zhang           col = *acolidx + mat->rmap->rstart;
6289566063dSJacob Faibussowitsch           PetscCall(MatSetValues(A, 1, &row, 1, &col, aval, INSERT_VALUES));
629d4002b98SHong Zhang         }
6309371c9d4SSatish Balay         aval++;
6319371c9d4SSatish Balay         acolidx++;
632d4002b98SHong Zhang       }
633d4002b98SHong Zhang     }
634d4002b98SHong Zhang 
635d4002b98SHong Zhang     /* copy over the B part */
636d4002b98SHong Zhang     Aloc    = (Mat_SeqSELL *)sell->B->data;
6379371c9d4SSatish Balay     acolidx = Aloc->colidx;
6389371c9d4SSatish Balay     aval    = Aloc->val;
639d4002b98SHong Zhang     for (i = 0; i < Aloc->totalslices; i++) {
640d4002b98SHong Zhang       for (j = Aloc->sliidx[i]; j < Aloc->sliidx[i + 1]; j++) {
64107e43b41SHong Zhang         isnonzero = (PetscBool)((j - Aloc->sliidx[i]) / Aloc->sliceheight < Aloc->rlen[i * Aloc->sliceheight + j % Aloc->sliceheight]);
642d4002b98SHong Zhang         if (isnonzero) {
64307e43b41SHong Zhang           row = i * Aloc->sliceheight + j % Aloc->sliceheight + mat->rmap->rstart;
644d4002b98SHong Zhang           col = sell->garray[*acolidx];
6459566063dSJacob Faibussowitsch           PetscCall(MatSetValues(A, 1, &row, 1, &col, aval, INSERT_VALUES));
646d4002b98SHong Zhang         }
6479371c9d4SSatish Balay         aval++;
6489371c9d4SSatish Balay         acolidx++;
649d4002b98SHong Zhang       }
650d4002b98SHong Zhang     }
651d4002b98SHong Zhang 
6529566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
6539566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
654d4002b98SHong Zhang     /*
655d4002b98SHong Zhang        Everyone has to call to draw the matrix since the graphics waits are
656d4002b98SHong Zhang        synchronized across all processors that share the PetscDraw object
657d4002b98SHong Zhang     */
6589566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
659dd400576SPatrick Sanan     if (rank == 0) {
660f4f49eeaSPierre Jolivet       PetscCall(PetscObjectSetName((PetscObject)((Mat_MPISELL *)A->data)->A, ((PetscObject)mat)->name));
661f4f49eeaSPierre Jolivet       PetscCall(MatView_SeqSELL(((Mat_MPISELL *)A->data)->A, sviewer));
662d4002b98SHong Zhang     }
6639566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
6649566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A));
665d4002b98SHong Zhang   }
6663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
667d4002b98SHong Zhang }
668d4002b98SHong Zhang 
669ba38deedSJacob Faibussowitsch static PetscErrorCode MatView_MPISELL(Mat mat, PetscViewer viewer)
670d71ae5a4SJacob Faibussowitsch {
6719f196a02SMartin Diehl   PetscBool isascii, isdraw, issocket, isbinary;
672d4002b98SHong Zhang 
673d4002b98SHong Zhang   PetscFunctionBegin;
6749f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
6759566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
6769566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
6779566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSOCKET, &issocket));
6789f196a02SMartin Diehl   if (isascii || isdraw || isbinary || issocket) PetscCall(MatView_MPISELL_ASCIIorDraworSocket(mat, viewer));
6793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
680d4002b98SHong Zhang }
681d4002b98SHong Zhang 
682ba38deedSJacob Faibussowitsch static PetscErrorCode MatGetGhosts_MPISELL(Mat mat, PetscInt *nghosts, const PetscInt *ghosts[])
683d71ae5a4SJacob Faibussowitsch {
684d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
685d4002b98SHong Zhang 
686d4002b98SHong Zhang   PetscFunctionBegin;
6879566063dSJacob Faibussowitsch   PetscCall(MatGetSize(sell->B, NULL, nghosts));
688d4002b98SHong Zhang   if (ghosts) *ghosts = sell->garray;
6893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
690d4002b98SHong Zhang }
691d4002b98SHong Zhang 
692ba38deedSJacob Faibussowitsch static PetscErrorCode MatGetInfo_MPISELL(Mat matin, MatInfoType flag, MatInfo *info)
693d71ae5a4SJacob Faibussowitsch {
694d4002b98SHong Zhang   Mat_MPISELL   *mat = (Mat_MPISELL *)matin->data;
695d4002b98SHong Zhang   Mat            A = mat->A, B = mat->B;
6963966268fSBarry Smith   PetscLogDouble isend[5], irecv[5];
697d4002b98SHong Zhang 
698d4002b98SHong Zhang   PetscFunctionBegin;
699d4002b98SHong Zhang   info->block_size = 1.0;
7009566063dSJacob Faibussowitsch   PetscCall(MatGetInfo(A, MAT_LOCAL, info));
701d4002b98SHong Zhang 
7029371c9d4SSatish Balay   isend[0] = info->nz_used;
7039371c9d4SSatish Balay   isend[1] = info->nz_allocated;
7049371c9d4SSatish Balay   isend[2] = info->nz_unneeded;
7059371c9d4SSatish Balay   isend[3] = info->memory;
7069371c9d4SSatish Balay   isend[4] = info->mallocs;
707d4002b98SHong Zhang 
7089566063dSJacob Faibussowitsch   PetscCall(MatGetInfo(B, MAT_LOCAL, info));
709d4002b98SHong Zhang 
7109371c9d4SSatish Balay   isend[0] += info->nz_used;
7119371c9d4SSatish Balay   isend[1] += info->nz_allocated;
7129371c9d4SSatish Balay   isend[2] += info->nz_unneeded;
7139371c9d4SSatish Balay   isend[3] += info->memory;
7149371c9d4SSatish Balay   isend[4] += info->mallocs;
715d4002b98SHong Zhang   if (flag == MAT_LOCAL) {
716d4002b98SHong Zhang     info->nz_used      = isend[0];
717d4002b98SHong Zhang     info->nz_allocated = isend[1];
718d4002b98SHong Zhang     info->nz_unneeded  = isend[2];
719d4002b98SHong Zhang     info->memory       = isend[3];
720d4002b98SHong Zhang     info->mallocs      = isend[4];
721d4002b98SHong Zhang   } else if (flag == MAT_GLOBAL_MAX) {
722462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)matin)));
723d4002b98SHong Zhang 
724d4002b98SHong Zhang     info->nz_used      = irecv[0];
725d4002b98SHong Zhang     info->nz_allocated = irecv[1];
726d4002b98SHong Zhang     info->nz_unneeded  = irecv[2];
727d4002b98SHong Zhang     info->memory       = irecv[3];
728d4002b98SHong Zhang     info->mallocs      = irecv[4];
729d4002b98SHong Zhang   } else if (flag == MAT_GLOBAL_SUM) {
730462c564dSBarry Smith     PetscCallMPI(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)matin)));
731d4002b98SHong Zhang 
732d4002b98SHong Zhang     info->nz_used      = irecv[0];
733d4002b98SHong Zhang     info->nz_allocated = irecv[1];
734d4002b98SHong Zhang     info->nz_unneeded  = irecv[2];
735d4002b98SHong Zhang     info->memory       = irecv[3];
736d4002b98SHong Zhang     info->mallocs      = irecv[4];
737d4002b98SHong Zhang   }
738d4002b98SHong Zhang   info->fill_ratio_given  = 0; /* no parallel LU/ILU/Cholesky */
739d4002b98SHong Zhang   info->fill_ratio_needed = 0;
740d4002b98SHong Zhang   info->factor_mallocs    = 0;
7413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
742d4002b98SHong Zhang }
743d4002b98SHong Zhang 
74443b34f9dSJacob Faibussowitsch static PetscErrorCode MatSetOption_MPISELL(Mat A, MatOption op, PetscBool flg)
745d71ae5a4SJacob Faibussowitsch {
746d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
747d4002b98SHong Zhang 
748d4002b98SHong Zhang   PetscFunctionBegin;
749d4002b98SHong Zhang   switch (op) {
750d4002b98SHong Zhang   case MAT_NEW_NONZERO_LOCATIONS:
751d4002b98SHong Zhang   case MAT_NEW_NONZERO_ALLOCATION_ERR:
752d4002b98SHong Zhang   case MAT_UNUSED_NONZERO_LOCATION_ERR:
753d4002b98SHong Zhang   case MAT_KEEP_NONZERO_PATTERN:
754d4002b98SHong Zhang   case MAT_NEW_NONZERO_LOCATION_ERR:
755d4002b98SHong Zhang   case MAT_USE_INODES:
756d4002b98SHong Zhang   case MAT_IGNORE_ZERO_ENTRIES:
757d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7589566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
7599566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->B, op, flg));
760d4002b98SHong Zhang     break;
761d4002b98SHong Zhang   case MAT_ROW_ORIENTED:
762d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
763d4002b98SHong Zhang     a->roworiented = flg;
764d4002b98SHong Zhang 
7659566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
7669566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->B, op, flg));
767d4002b98SHong Zhang     break;
768d71ae5a4SJacob Faibussowitsch   case MAT_IGNORE_OFF_PROC_ENTRIES:
769d71ae5a4SJacob Faibussowitsch     a->donotstash = flg;
770d71ae5a4SJacob Faibussowitsch     break;
771d4002b98SHong Zhang   case MAT_SYMMETRIC:
772d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7739566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
774d4002b98SHong Zhang     break;
775d4002b98SHong Zhang   case MAT_STRUCTURALLY_SYMMETRIC:
776d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7779566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
778d4002b98SHong Zhang     break;
779d4002b98SHong Zhang   case MAT_HERMITIAN:
780d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7819566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
782d4002b98SHong Zhang     break;
783d4002b98SHong Zhang   case MAT_SYMMETRY_ETERNAL:
784d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7859566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
786d4002b98SHong Zhang     break;
787b94d7dedSBarry Smith   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
788b94d7dedSBarry Smith     MatCheckPreallocated(A, 1);
789b94d7dedSBarry Smith     PetscCall(MatSetOption(a->A, op, flg));
790b94d7dedSBarry Smith     break;
791d71ae5a4SJacob Faibussowitsch   default:
792888c827cSStefano Zampini     break;
793d4002b98SHong Zhang   }
7943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
795d4002b98SHong Zhang }
796d4002b98SHong Zhang 
797ba38deedSJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_MPISELL(Mat mat, Vec ll, Vec rr)
798d71ae5a4SJacob Faibussowitsch {
799d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
800d4002b98SHong Zhang   Mat          a = sell->A, b = sell->B;
801d4002b98SHong Zhang   PetscInt     s1, s2, s3;
802d4002b98SHong Zhang 
803d4002b98SHong Zhang   PetscFunctionBegin;
8049566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &s2, &s3));
805d4002b98SHong Zhang   if (rr) {
8069566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(rr, &s1));
80708401ef6SPierre Jolivet     PetscCheck(s1 == s3, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "right vector non-conforming local size");
808d4002b98SHong Zhang     /* Overlap communication with computation. */
8099566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sell->Mvctx, rr, sell->lvec, INSERT_VALUES, SCATTER_FORWARD));
810d4002b98SHong Zhang   }
811d4002b98SHong Zhang   if (ll) {
8129566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(ll, &s1));
81308401ef6SPierre Jolivet     PetscCheck(s1 == s2, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "left vector non-conforming local size");
814dbbe0bcdSBarry Smith     PetscUseTypeMethod(b, diagonalscale, ll, NULL);
815d4002b98SHong Zhang   }
816d4002b98SHong Zhang   /* scale  the diagonal block */
817dbbe0bcdSBarry Smith   PetscUseTypeMethod(a, diagonalscale, ll, rr);
818d4002b98SHong Zhang 
819d4002b98SHong Zhang   if (rr) {
820d4002b98SHong Zhang     /* Do a scatter end and then right scale the off-diagonal block */
8219566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sell->Mvctx, rr, sell->lvec, INSERT_VALUES, SCATTER_FORWARD));
822dbbe0bcdSBarry Smith     PetscUseTypeMethod(b, diagonalscale, NULL, sell->lvec);
823d4002b98SHong Zhang   }
8243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
825d4002b98SHong Zhang }
826d4002b98SHong Zhang 
827ba38deedSJacob Faibussowitsch static PetscErrorCode MatSetUnfactored_MPISELL(Mat A)
828d71ae5a4SJacob Faibussowitsch {
829d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
830d4002b98SHong Zhang 
831d4002b98SHong Zhang   PetscFunctionBegin;
8329566063dSJacob Faibussowitsch   PetscCall(MatSetUnfactored(a->A));
8333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
834d4002b98SHong Zhang }
835d4002b98SHong Zhang 
836ba38deedSJacob Faibussowitsch static PetscErrorCode MatEqual_MPISELL(Mat A, Mat B, PetscBool *flag)
837d71ae5a4SJacob Faibussowitsch {
838d4002b98SHong Zhang   Mat_MPISELL *matB = (Mat_MPISELL *)B->data, *matA = (Mat_MPISELL *)A->data;
839d4002b98SHong Zhang   Mat          a, b, c, d;
840d4002b98SHong Zhang   PetscBool    flg;
841d4002b98SHong Zhang 
842d4002b98SHong Zhang   PetscFunctionBegin;
8439371c9d4SSatish Balay   a = matA->A;
8449371c9d4SSatish Balay   b = matA->B;
8459371c9d4SSatish Balay   c = matB->A;
8469371c9d4SSatish Balay   d = matB->B;
847d4002b98SHong Zhang 
8489566063dSJacob Faibussowitsch   PetscCall(MatEqual(a, c, &flg));
84948a46eb9SPierre Jolivet   if (flg) PetscCall(MatEqual(b, d, &flg));
8505440e5dcSBarry Smith   PetscCallMPI(MPIU_Allreduce(&flg, flag, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
8513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
852d4002b98SHong Zhang }
853d4002b98SHong Zhang 
854ba38deedSJacob Faibussowitsch static PetscErrorCode MatCopy_MPISELL(Mat A, Mat B, MatStructure str)
855d71ae5a4SJacob Faibussowitsch {
856d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
857d4002b98SHong Zhang   Mat_MPISELL *b = (Mat_MPISELL *)B->data;
858d4002b98SHong Zhang 
859d4002b98SHong Zhang   PetscFunctionBegin;
860d4002b98SHong Zhang   /* If the two matrices don't have the same copy implementation, they aren't compatible for fast copy. */
861d4002b98SHong Zhang   if ((str != SAME_NONZERO_PATTERN) || (A->ops->copy != B->ops->copy)) {
862d4002b98SHong Zhang     /* because of the column compression in the off-processor part of the matrix a->B,
863d4002b98SHong Zhang        the number of columns in a->B and b->B may be different, hence we cannot call
864d4002b98SHong Zhang        the MatCopy() directly on the two parts. If need be, we can provide a more
865d4002b98SHong Zhang        efficient copy than the MatCopy_Basic() by first uncompressing the a->B matrices
866d4002b98SHong Zhang        then copying the submatrices */
8679566063dSJacob Faibussowitsch     PetscCall(MatCopy_Basic(A, B, str));
868d4002b98SHong Zhang   } else {
8699566063dSJacob Faibussowitsch     PetscCall(MatCopy(a->A, b->A, str));
8709566063dSJacob Faibussowitsch     PetscCall(MatCopy(a->B, b->B, str));
871d4002b98SHong Zhang   }
8723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
873d4002b98SHong Zhang }
874d4002b98SHong Zhang 
875ba38deedSJacob Faibussowitsch static PetscErrorCode MatSetUp_MPISELL(Mat A)
876d71ae5a4SJacob Faibussowitsch {
877d4002b98SHong Zhang   PetscFunctionBegin;
8789566063dSJacob Faibussowitsch   PetscCall(MatMPISELLSetPreallocation(A, PETSC_DEFAULT, NULL, PETSC_DEFAULT, NULL));
8793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
880d4002b98SHong Zhang }
881d4002b98SHong Zhang 
882ba38deedSJacob Faibussowitsch static PetscErrorCode MatConjugate_MPISELL(Mat mat)
883d71ae5a4SJacob Faibussowitsch {
8845f80ce2aSJacob Faibussowitsch   PetscFunctionBegin;
8855f80ce2aSJacob Faibussowitsch   if (PetscDefined(USE_COMPLEX)) {
886d4002b98SHong Zhang     Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
887d4002b98SHong Zhang 
8889566063dSJacob Faibussowitsch     PetscCall(MatConjugate_SeqSELL(sell->A));
8899566063dSJacob Faibussowitsch     PetscCall(MatConjugate_SeqSELL(sell->B));
8905f80ce2aSJacob Faibussowitsch   }
8913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
892d4002b98SHong Zhang }
893d4002b98SHong Zhang 
894ba38deedSJacob Faibussowitsch static PetscErrorCode MatRealPart_MPISELL(Mat A)
895d71ae5a4SJacob Faibussowitsch {
896d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
897d4002b98SHong Zhang 
898d4002b98SHong Zhang   PetscFunctionBegin;
8999566063dSJacob Faibussowitsch   PetscCall(MatRealPart(a->A));
9009566063dSJacob Faibussowitsch   PetscCall(MatRealPart(a->B));
9013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
902d4002b98SHong Zhang }
903d4002b98SHong Zhang 
904ba38deedSJacob Faibussowitsch static PetscErrorCode MatImaginaryPart_MPISELL(Mat A)
905d71ae5a4SJacob Faibussowitsch {
906d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
907d4002b98SHong Zhang 
908d4002b98SHong Zhang   PetscFunctionBegin;
9099566063dSJacob Faibussowitsch   PetscCall(MatImaginaryPart(a->A));
9109566063dSJacob Faibussowitsch   PetscCall(MatImaginaryPart(a->B));
9113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
912d4002b98SHong Zhang }
913d4002b98SHong Zhang 
914ba38deedSJacob Faibussowitsch static PetscErrorCode MatInvertBlockDiagonal_MPISELL(Mat A, const PetscScalar **values)
915d71ae5a4SJacob Faibussowitsch {
916d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
917d4002b98SHong Zhang 
918d4002b98SHong Zhang   PetscFunctionBegin;
9199566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(a->A, values));
920d4002b98SHong Zhang   A->factorerrortype = a->A->factorerrortype;
9213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
922d4002b98SHong Zhang }
923d4002b98SHong Zhang 
924d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_MPISELL(Mat x, PetscRandom rctx)
925d71ae5a4SJacob Faibussowitsch {
926d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)x->data;
927d4002b98SHong Zhang 
928d4002b98SHong Zhang   PetscFunctionBegin;
9299566063dSJacob Faibussowitsch   PetscCall(MatSetRandom(sell->A, rctx));
9309566063dSJacob Faibussowitsch   PetscCall(MatSetRandom(sell->B, rctx));
9319566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
9329566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
9333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
934d4002b98SHong Zhang }
935d4002b98SHong Zhang 
936ce78bad3SBarry Smith static PetscErrorCode MatSetFromOptions_MPISELL(Mat A, PetscOptionItems PetscOptionsObject)
937d71ae5a4SJacob Faibussowitsch {
938d4002b98SHong Zhang   PetscFunctionBegin;
939d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MPISELL options");
940d0609cedSBarry Smith   PetscOptionsHeadEnd();
9413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
942d4002b98SHong Zhang }
943d4002b98SHong Zhang 
944ba38deedSJacob Faibussowitsch static PetscErrorCode MatShift_MPISELL(Mat Y, PetscScalar a)
945d71ae5a4SJacob Faibussowitsch {
946d4002b98SHong Zhang   Mat_MPISELL *msell = (Mat_MPISELL *)Y->data;
947d4002b98SHong Zhang   Mat_SeqSELL *sell  = (Mat_SeqSELL *)msell->A->data;
948d4002b98SHong Zhang 
949d4002b98SHong Zhang   PetscFunctionBegin;
950d4002b98SHong Zhang   if (!Y->preallocated) {
9519566063dSJacob Faibussowitsch     PetscCall(MatMPISELLSetPreallocation(Y, 1, NULL, 0, NULL));
952d4002b98SHong Zhang   } else if (!sell->nz) {
953d4002b98SHong Zhang     PetscInt nonew = sell->nonew;
9549566063dSJacob Faibussowitsch     PetscCall(MatSeqSELLSetPreallocation(msell->A, 1, NULL));
955d4002b98SHong Zhang     sell->nonew = nonew;
956d4002b98SHong Zhang   }
9579566063dSJacob Faibussowitsch   PetscCall(MatShift_Basic(Y, a));
9583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
959d4002b98SHong Zhang }
960d4002b98SHong Zhang 
961ba38deedSJacob Faibussowitsch static PetscErrorCode MatGetDiagonalBlock_MPISELL(Mat A, Mat *a)
962d71ae5a4SJacob Faibussowitsch {
963d4002b98SHong Zhang   PetscFunctionBegin;
964d4002b98SHong Zhang   *a = ((Mat_MPISELL *)A->data)->A;
9653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
966d4002b98SHong Zhang }
967d4002b98SHong Zhang 
96843b34f9dSJacob Faibussowitsch static PetscErrorCode MatStoreValues_MPISELL(Mat mat)
96943b34f9dSJacob Faibussowitsch {
97043b34f9dSJacob Faibussowitsch   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
97143b34f9dSJacob Faibussowitsch 
97243b34f9dSJacob Faibussowitsch   PetscFunctionBegin;
97343b34f9dSJacob Faibussowitsch   PetscCall(MatStoreValues(sell->A));
97443b34f9dSJacob Faibussowitsch   PetscCall(MatStoreValues(sell->B));
97543b34f9dSJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
97643b34f9dSJacob Faibussowitsch }
97743b34f9dSJacob Faibussowitsch 
97843b34f9dSJacob Faibussowitsch static PetscErrorCode MatRetrieveValues_MPISELL(Mat mat)
97943b34f9dSJacob Faibussowitsch {
98043b34f9dSJacob Faibussowitsch   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
98143b34f9dSJacob Faibussowitsch 
98243b34f9dSJacob Faibussowitsch   PetscFunctionBegin;
98343b34f9dSJacob Faibussowitsch   PetscCall(MatRetrieveValues(sell->A));
98443b34f9dSJacob Faibussowitsch   PetscCall(MatRetrieveValues(sell->B));
98543b34f9dSJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
98643b34f9dSJacob Faibussowitsch }
98743b34f9dSJacob Faibussowitsch 
98843b34f9dSJacob Faibussowitsch static PetscErrorCode MatMPISELLSetPreallocation_MPISELL(Mat B, PetscInt d_rlenmax, const PetscInt d_rlen[], PetscInt o_rlenmax, const PetscInt o_rlen[])
98943b34f9dSJacob Faibussowitsch {
99043b34f9dSJacob Faibussowitsch   Mat_MPISELL *b;
99143b34f9dSJacob Faibussowitsch 
99243b34f9dSJacob Faibussowitsch   PetscFunctionBegin;
99343b34f9dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(B->rmap));
99443b34f9dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(B->cmap));
99543b34f9dSJacob Faibussowitsch   b = (Mat_MPISELL *)B->data;
99643b34f9dSJacob Faibussowitsch 
99743b34f9dSJacob Faibussowitsch   if (!B->preallocated) {
99843b34f9dSJacob Faibussowitsch     /* Explicitly create 2 MATSEQSELL matrices. */
99943b34f9dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &b->A));
100043b34f9dSJacob Faibussowitsch     PetscCall(MatSetSizes(b->A, B->rmap->n, B->cmap->n, B->rmap->n, B->cmap->n));
100143b34f9dSJacob Faibussowitsch     PetscCall(MatSetBlockSizesFromMats(b->A, B, B));
100243b34f9dSJacob Faibussowitsch     PetscCall(MatSetType(b->A, MATSEQSELL));
100343b34f9dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &b->B));
100443b34f9dSJacob Faibussowitsch     PetscCall(MatSetSizes(b->B, B->rmap->n, B->cmap->N, B->rmap->n, B->cmap->N));
100543b34f9dSJacob Faibussowitsch     PetscCall(MatSetBlockSizesFromMats(b->B, B, B));
100643b34f9dSJacob Faibussowitsch     PetscCall(MatSetType(b->B, MATSEQSELL));
100743b34f9dSJacob Faibussowitsch   }
100843b34f9dSJacob Faibussowitsch 
100943b34f9dSJacob Faibussowitsch   PetscCall(MatSeqSELLSetPreallocation(b->A, d_rlenmax, d_rlen));
101043b34f9dSJacob Faibussowitsch   PetscCall(MatSeqSELLSetPreallocation(b->B, o_rlenmax, o_rlen));
101143b34f9dSJacob Faibussowitsch   B->preallocated  = PETSC_TRUE;
101243b34f9dSJacob Faibussowitsch   B->was_assembled = PETSC_FALSE;
101343b34f9dSJacob Faibussowitsch   /*
101443b34f9dSJacob Faibussowitsch     critical for MatAssemblyEnd to work.
101543b34f9dSJacob Faibussowitsch     MatAssemblyBegin checks it to set up was_assembled
101643b34f9dSJacob Faibussowitsch     and MatAssemblyEnd checks was_assembled to determine whether to build garray
101743b34f9dSJacob Faibussowitsch   */
101843b34f9dSJacob Faibussowitsch   B->assembled = PETSC_FALSE;
101943b34f9dSJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
102043b34f9dSJacob Faibussowitsch }
102143b34f9dSJacob Faibussowitsch 
102243b34f9dSJacob Faibussowitsch static PetscErrorCode MatDuplicate_MPISELL(Mat matin, MatDuplicateOption cpvalues, Mat *newmat)
102343b34f9dSJacob Faibussowitsch {
102443b34f9dSJacob Faibussowitsch   Mat          mat;
102543b34f9dSJacob Faibussowitsch   Mat_MPISELL *a, *oldmat = (Mat_MPISELL *)matin->data;
102643b34f9dSJacob Faibussowitsch 
102743b34f9dSJacob Faibussowitsch   PetscFunctionBegin;
102843b34f9dSJacob Faibussowitsch   *newmat = NULL;
102943b34f9dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)matin), &mat));
103043b34f9dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat, matin->rmap->n, matin->cmap->n, matin->rmap->N, matin->cmap->N));
103143b34f9dSJacob Faibussowitsch   PetscCall(MatSetBlockSizesFromMats(mat, matin, matin));
103243b34f9dSJacob Faibussowitsch   PetscCall(MatSetType(mat, ((PetscObject)matin)->type_name));
103343b34f9dSJacob Faibussowitsch   a = (Mat_MPISELL *)mat->data;
103443b34f9dSJacob Faibussowitsch 
103543b34f9dSJacob Faibussowitsch   mat->factortype   = matin->factortype;
103643b34f9dSJacob Faibussowitsch   mat->assembled    = PETSC_TRUE;
103743b34f9dSJacob Faibussowitsch   mat->insertmode   = NOT_SET_VALUES;
103843b34f9dSJacob Faibussowitsch   mat->preallocated = PETSC_TRUE;
103943b34f9dSJacob Faibussowitsch 
104043b34f9dSJacob Faibussowitsch   a->size         = oldmat->size;
104143b34f9dSJacob Faibussowitsch   a->rank         = oldmat->rank;
104243b34f9dSJacob Faibussowitsch   a->donotstash   = oldmat->donotstash;
104343b34f9dSJacob Faibussowitsch   a->roworiented  = oldmat->roworiented;
104443b34f9dSJacob Faibussowitsch   a->rowindices   = NULL;
104543b34f9dSJacob Faibussowitsch   a->rowvalues    = NULL;
104643b34f9dSJacob Faibussowitsch   a->getrowactive = PETSC_FALSE;
104743b34f9dSJacob Faibussowitsch 
104843b34f9dSJacob Faibussowitsch   PetscCall(PetscLayoutReference(matin->rmap, &mat->rmap));
104943b34f9dSJacob Faibussowitsch   PetscCall(PetscLayoutReference(matin->cmap, &mat->cmap));
105043b34f9dSJacob Faibussowitsch 
105143b34f9dSJacob Faibussowitsch   if (oldmat->colmap) {
105243b34f9dSJacob Faibussowitsch #if defined(PETSC_USE_CTABLE)
105343b34f9dSJacob Faibussowitsch     PetscCall(PetscHMapIDuplicate(oldmat->colmap, &a->colmap));
105443b34f9dSJacob Faibussowitsch #else
105543b34f9dSJacob Faibussowitsch     PetscCall(PetscMalloc1(mat->cmap->N, &a->colmap));
105643b34f9dSJacob Faibussowitsch     PetscCall(PetscArraycpy(a->colmap, oldmat->colmap, mat->cmap->N));
105743b34f9dSJacob Faibussowitsch #endif
105843b34f9dSJacob Faibussowitsch   } else a->colmap = NULL;
105943b34f9dSJacob Faibussowitsch   if (oldmat->garray) {
106043b34f9dSJacob Faibussowitsch     PetscInt len;
106143b34f9dSJacob Faibussowitsch     len = oldmat->B->cmap->n;
106243b34f9dSJacob Faibussowitsch     PetscCall(PetscMalloc1(len + 1, &a->garray));
106343b34f9dSJacob Faibussowitsch     if (len) PetscCall(PetscArraycpy(a->garray, oldmat->garray, len));
106443b34f9dSJacob Faibussowitsch   } else a->garray = NULL;
106543b34f9dSJacob Faibussowitsch 
106643b34f9dSJacob Faibussowitsch   PetscCall(VecDuplicate(oldmat->lvec, &a->lvec));
106743b34f9dSJacob Faibussowitsch   PetscCall(VecScatterCopy(oldmat->Mvctx, &a->Mvctx));
106843b34f9dSJacob Faibussowitsch   PetscCall(MatDuplicate(oldmat->A, cpvalues, &a->A));
106943b34f9dSJacob Faibussowitsch   PetscCall(MatDuplicate(oldmat->B, cpvalues, &a->B));
107043b34f9dSJacob Faibussowitsch   PetscCall(PetscFunctionListDuplicate(((PetscObject)matin)->qlist, &((PetscObject)mat)->qlist));
107143b34f9dSJacob Faibussowitsch   *newmat = mat;
107243b34f9dSJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
107343b34f9dSJacob Faibussowitsch }
107443b34f9dSJacob Faibussowitsch 
107543b34f9dSJacob Faibussowitsch static const struct _MatOps MatOps_Values = {MatSetValues_MPISELL,
1076f4259b30SLisandro Dalcin                                              NULL,
1077f4259b30SLisandro Dalcin                                              NULL,
1078d4002b98SHong Zhang                                              MatMult_MPISELL,
1079d4002b98SHong Zhang                                              /* 4*/ MatMultAdd_MPISELL,
1080d4002b98SHong Zhang                                              MatMultTranspose_MPISELL,
1081d4002b98SHong Zhang                                              MatMultTransposeAdd_MPISELL,
1082f4259b30SLisandro Dalcin                                              NULL,
1083f4259b30SLisandro Dalcin                                              NULL,
1084f4259b30SLisandro Dalcin                                              NULL,
1085f4259b30SLisandro Dalcin                                              /*10*/ NULL,
1086f4259b30SLisandro Dalcin                                              NULL,
1087f4259b30SLisandro Dalcin                                              NULL,
1088d4002b98SHong Zhang                                              MatSOR_MPISELL,
1089f4259b30SLisandro Dalcin                                              NULL,
1090d4002b98SHong Zhang                                              /*15*/ MatGetInfo_MPISELL,
1091d4002b98SHong Zhang                                              MatEqual_MPISELL,
1092d4002b98SHong Zhang                                              MatGetDiagonal_MPISELL,
1093d4002b98SHong Zhang                                              MatDiagonalScale_MPISELL,
1094f4259b30SLisandro Dalcin                                              NULL,
1095d4002b98SHong Zhang                                              /*20*/ MatAssemblyBegin_MPISELL,
1096d4002b98SHong Zhang                                              MatAssemblyEnd_MPISELL,
1097d4002b98SHong Zhang                                              MatSetOption_MPISELL,
1098d4002b98SHong Zhang                                              MatZeroEntries_MPISELL,
1099f4259b30SLisandro Dalcin                                              /*24*/ NULL,
1100f4259b30SLisandro Dalcin                                              NULL,
1101f4259b30SLisandro Dalcin                                              NULL,
1102f4259b30SLisandro Dalcin                                              NULL,
1103f4259b30SLisandro Dalcin                                              NULL,
1104d4002b98SHong Zhang                                              /*29*/ MatSetUp_MPISELL,
1105f4259b30SLisandro Dalcin                                              NULL,
1106f4259b30SLisandro Dalcin                                              NULL,
1107d4002b98SHong Zhang                                              MatGetDiagonalBlock_MPISELL,
1108f4259b30SLisandro Dalcin                                              NULL,
1109d4002b98SHong Zhang                                              /*34*/ MatDuplicate_MPISELL,
1110f4259b30SLisandro Dalcin                                              NULL,
1111f4259b30SLisandro Dalcin                                              NULL,
1112f4259b30SLisandro Dalcin                                              NULL,
1113f4259b30SLisandro Dalcin                                              NULL,
1114f4259b30SLisandro Dalcin                                              /*39*/ NULL,
1115f4259b30SLisandro Dalcin                                              NULL,
1116f4259b30SLisandro Dalcin                                              NULL,
1117d4002b98SHong Zhang                                              MatGetValues_MPISELL,
1118d4002b98SHong Zhang                                              MatCopy_MPISELL,
1119f4259b30SLisandro Dalcin                                              /*44*/ NULL,
1120d4002b98SHong Zhang                                              MatScale_MPISELL,
1121d4002b98SHong Zhang                                              MatShift_MPISELL,
1122d4002b98SHong Zhang                                              MatDiagonalSet_MPISELL,
1123f4259b30SLisandro Dalcin                                              NULL,
1124d4002b98SHong Zhang                                              /*49*/ MatSetRandom_MPISELL,
1125f4259b30SLisandro Dalcin                                              NULL,
1126f4259b30SLisandro Dalcin                                              NULL,
1127f4259b30SLisandro Dalcin                                              NULL,
1128f4259b30SLisandro Dalcin                                              NULL,
1129d4002b98SHong Zhang                                              /*54*/ MatFDColoringCreate_MPIXAIJ,
1130f4259b30SLisandro Dalcin                                              NULL,
1131d4002b98SHong Zhang                                              MatSetUnfactored_MPISELL,
1132f4259b30SLisandro Dalcin                                              NULL,
1133f4259b30SLisandro Dalcin                                              NULL,
1134f4259b30SLisandro Dalcin                                              /*59*/ NULL,
1135d4002b98SHong Zhang                                              MatDestroy_MPISELL,
1136d4002b98SHong Zhang                                              MatView_MPISELL,
1137f4259b30SLisandro Dalcin                                              NULL,
1138f4259b30SLisandro Dalcin                                              NULL,
1139f4259b30SLisandro Dalcin                                              /*64*/ NULL,
1140f4259b30SLisandro Dalcin                                              NULL,
1141f4259b30SLisandro Dalcin                                              NULL,
1142f4259b30SLisandro Dalcin                                              NULL,
1143f4259b30SLisandro Dalcin                                              NULL,
1144f4259b30SLisandro Dalcin                                              /*69*/ NULL,
1145f4259b30SLisandro Dalcin                                              NULL,
1146f4259b30SLisandro Dalcin                                              NULL,
11478bb0f5c6SPierre Jolivet                                              MatFDColoringApply_AIJ, /* reuse AIJ function */
1148d4002b98SHong Zhang                                              MatSetFromOptions_MPISELL,
1149f4259b30SLisandro Dalcin                                              NULL,
11508bb0f5c6SPierre Jolivet                                              /*75*/ NULL,
11518bb0f5c6SPierre Jolivet                                              NULL,
11528bb0f5c6SPierre Jolivet                                              NULL,
1153f4259b30SLisandro Dalcin                                              NULL,
1154f4259b30SLisandro Dalcin                                              NULL,
1155f4259b30SLisandro Dalcin                                              /*80*/ NULL,
1156f4259b30SLisandro Dalcin                                              NULL,
1157f4259b30SLisandro Dalcin                                              NULL,
1158f4259b30SLisandro Dalcin                                              /*83*/ NULL,
1159f4259b30SLisandro Dalcin                                              NULL,
1160f4259b30SLisandro Dalcin                                              NULL,
1161f4259b30SLisandro Dalcin                                              NULL,
1162f4259b30SLisandro Dalcin                                              NULL,
1163f4259b30SLisandro Dalcin                                              NULL,
1164f4259b30SLisandro Dalcin                                              /*89*/ NULL,
1165f4259b30SLisandro Dalcin                                              NULL,
1166f4259b30SLisandro Dalcin                                              NULL,
1167f4259b30SLisandro Dalcin                                              NULL,
11688bb0f5c6SPierre Jolivet                                              MatConjugate_MPISELL,
1169f4259b30SLisandro Dalcin                                              /*94*/ NULL,
1170f4259b30SLisandro Dalcin                                              NULL,
11718bb0f5c6SPierre Jolivet                                              MatRealPart_MPISELL,
11728bb0f5c6SPierre Jolivet                                              MatImaginaryPart_MPISELL,
1173f4259b30SLisandro Dalcin                                              NULL,
1174f4259b30SLisandro Dalcin                                              /*99*/ NULL,
1175f4259b30SLisandro Dalcin                                              NULL,
1176f4259b30SLisandro Dalcin                                              NULL,
1177f4259b30SLisandro Dalcin                                              NULL,
1178f4259b30SLisandro Dalcin                                              NULL,
1179*421480d9SBarry Smith                                              /*104*/ NULL,
1180f4259b30SLisandro Dalcin                                              NULL,
1181d4002b98SHong Zhang                                              MatGetGhosts_MPISELL,
1182f4259b30SLisandro Dalcin                                              NULL,
1183*421480d9SBarry Smith                                              NULL,
1184*421480d9SBarry Smith                                              /*109*/ MatMultDiagonalBlock_MPISELL,
1185*421480d9SBarry Smith                                              NULL,
1186f4259b30SLisandro Dalcin                                              NULL,
11878bb0f5c6SPierre Jolivet                                              NULL,
11888bb0f5c6SPierre Jolivet                                              NULL,
11898bb0f5c6SPierre Jolivet                                              /*114*/ NULL,
11908bb0f5c6SPierre Jolivet                                              NULL,
11918bb0f5c6SPierre Jolivet                                              MatInvertBlockDiagonal_MPISELL,
11928bb0f5c6SPierre Jolivet                                              NULL,
11938bb0f5c6SPierre Jolivet                                              /*119*/ NULL,
1194f4259b30SLisandro Dalcin                                              NULL,
1195f4259b30SLisandro Dalcin                                              NULL,
1196f4259b30SLisandro Dalcin                                              NULL,
1197f4259b30SLisandro Dalcin                                              NULL,
1198f4259b30SLisandro Dalcin                                              /*124*/ NULL,
1199f4259b30SLisandro Dalcin                                              NULL,
1200f4259b30SLisandro Dalcin                                              NULL,
1201f4259b30SLisandro Dalcin                                              NULL,
12028bb0f5c6SPierre Jolivet                                              NULL,
12038bb0f5c6SPierre Jolivet                                              /*129*/ MatFDColoringSetUp_MPIXAIJ,
1204f4259b30SLisandro Dalcin                                              NULL,
1205f4259b30SLisandro Dalcin                                              NULL,
1206f4259b30SLisandro Dalcin                                              NULL,
1207f4259b30SLisandro Dalcin                                              NULL,
1208f4259b30SLisandro Dalcin                                              /*134*/ NULL,
1209f4259b30SLisandro Dalcin                                              NULL,
1210f4259b30SLisandro Dalcin                                              NULL,
1211f4259b30SLisandro Dalcin                                              NULL,
1212f4259b30SLisandro Dalcin                                              NULL,
1213f4259b30SLisandro Dalcin                                              /*139*/ NULL,
1214f4259b30SLisandro Dalcin                                              NULL,
1215f4259b30SLisandro Dalcin                                              NULL,
121603db1824SAlex Lindsay                                              NULL,
1217c2be7ffeSStefano Zampini                                              NULL,
1218dec0b466SHong Zhang                                              NULL};
1219d4002b98SHong Zhang 
1220d4002b98SHong Zhang /*@C
122111a5261eSBarry Smith   MatMPISELLSetPreallocation - Preallocates memory for a `MATMPISELL` sparse parallel matrix in sell format.
1222d4002b98SHong Zhang   For good matrix assembly performance the user should preallocate the matrix storage by
122367be906fSBarry Smith   setting the parameters `d_nz` (or `d_nnz`) and `o_nz` (or `o_nnz`).
1224d4002b98SHong Zhang 
1225d083f849SBarry Smith   Collective
1226d4002b98SHong Zhang 
1227d4002b98SHong Zhang   Input Parameters:
1228d4002b98SHong Zhang + B     - the matrix
1229d4002b98SHong Zhang . d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1230d4002b98SHong Zhang            (same value is used for all local rows)
1231d4002b98SHong Zhang . d_nnz - array containing the number of nonzeros in the various rows of the
1232d4002b98SHong Zhang            DIAGONAL portion of the local submatrix (possibly different for each row)
123367be906fSBarry Smith            or NULL (`PETSC_NULL_INTEGER` in Fortran), if `d_nz` is used to specify the nonzero structure.
1234d4002b98SHong Zhang            The size of this array is equal to the number of local rows, i.e 'm'.
1235d4002b98SHong Zhang            For matrices that will be factored, you must leave room for (and set)
1236d4002b98SHong Zhang            the diagonal entry even if it is zero.
1237d4002b98SHong Zhang . o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1238d4002b98SHong Zhang            submatrix (same value is used for all local rows).
1239d4002b98SHong Zhang - o_nnz - array containing the number of nonzeros in the various rows of the
1240d4002b98SHong Zhang            OFF-DIAGONAL portion of the local submatrix (possibly different for
124167be906fSBarry Smith            each row) or NULL (`PETSC_NULL_INTEGER` in Fortran), if `o_nz` is used to specify the nonzero
1242d4002b98SHong Zhang            structure. The size of this array is equal to the number
1243d4002b98SHong Zhang            of local rows, i.e 'm'.
1244d4002b98SHong Zhang 
1245d4002b98SHong Zhang   Example usage:
1246d4002b98SHong Zhang   Consider the following 8x8 matrix with 34 non-zero values, that is
1247d4002b98SHong Zhang   assembled across 3 processors. Lets assume that proc0 owns 3 rows,
1248d4002b98SHong Zhang   proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
124967be906fSBarry Smith   as follows
1250d4002b98SHong Zhang 
1251d4002b98SHong Zhang .vb
1252d4002b98SHong Zhang             1  2  0  |  0  3  0  |  0  4
1253d4002b98SHong Zhang     Proc0   0  5  6  |  7  0  0  |  8  0
1254d4002b98SHong Zhang             9  0 10  | 11  0  0  | 12  0
1255d4002b98SHong Zhang     -------------------------------------
1256d4002b98SHong Zhang            13  0 14  | 15 16 17  |  0  0
1257d4002b98SHong Zhang     Proc1   0 18  0  | 19 20 21  |  0  0
1258d4002b98SHong Zhang             0  0  0  | 22 23  0  | 24  0
1259d4002b98SHong Zhang     -------------------------------------
1260d4002b98SHong Zhang     Proc2  25 26 27  |  0  0 28  | 29  0
1261d4002b98SHong Zhang            30  0  0  | 31 32 33  |  0 34
1262d4002b98SHong Zhang .ve
1263d4002b98SHong Zhang 
126427430b45SBarry Smith   This can be represented as a collection of submatrices as
1265d4002b98SHong Zhang 
1266d4002b98SHong Zhang .vb
1267d4002b98SHong Zhang       A B C
1268d4002b98SHong Zhang       D E F
1269d4002b98SHong Zhang       G H I
1270d4002b98SHong Zhang .ve
1271d4002b98SHong Zhang 
1272d4002b98SHong Zhang   Where the submatrices A,B,C are owned by proc0, D,E,F are
1273d4002b98SHong Zhang   owned by proc1, G,H,I are owned by proc2.
1274d4002b98SHong Zhang 
1275d4002b98SHong Zhang   The 'm' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
1276d4002b98SHong Zhang   The 'n' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
1277d4002b98SHong Zhang   The 'M','N' parameters are 8,8, and have the same values on all procs.
1278d4002b98SHong Zhang 
1279d4002b98SHong Zhang   The DIAGONAL submatrices corresponding to proc0,proc1,proc2 are
1280d4002b98SHong Zhang   submatrices [A], [E], [I] respectively. The OFF-DIAGONAL submatrices
1281d4002b98SHong Zhang   corresponding to proc0,proc1,proc2 are [BC], [DF], [GH] respectively.
1282d4002b98SHong Zhang   Internally, each processor stores the DIAGONAL part, and the OFF-DIAGONAL
128327430b45SBarry Smith   part as `MATSEQSELL` matrices. For example, proc1 will store [E] as a `MATSEQSELL`
12845163b989SNuno Nobre   matrix, and [DF] as another SeqSELL matrix.
1285d4002b98SHong Zhang 
128667be906fSBarry Smith   When `d_nz`, `o_nz` parameters are specified, `d_nz` storage elements are
12875163b989SNuno Nobre   allocated for every row of the local DIAGONAL submatrix, and o_nz
12885163b989SNuno Nobre   storage locations are allocated for every row of the OFF-DIAGONAL submatrix.
12895163b989SNuno Nobre   One way to choose `d_nz` and `o_nz` is to use the maximum number of nonzeros over
12905163b989SNuno Nobre   the local rows for each of the local DIAGONAL, and the OFF-DIAGONAL submatrices.
129127430b45SBarry Smith   In this case, the values of d_nz,o_nz are
1292d4002b98SHong Zhang .vb
129327430b45SBarry Smith      proc0  dnz = 2, o_nz = 2
129427430b45SBarry Smith      proc1  dnz = 3, o_nz = 2
129527430b45SBarry Smith      proc2  dnz = 1, o_nz = 4
1296d4002b98SHong Zhang .ve
1297d4002b98SHong Zhang   We are allocating m*(d_nz+o_nz) storage locations for every proc. This
1298d4002b98SHong Zhang   translates to 3*(2+2)=12 for proc0, 3*(3+2)=15 for proc1, 2*(1+4)=10
1299d4002b98SHong Zhang   for proc3. i.e we are using 12+15+10=37 storage locations to store
1300d4002b98SHong Zhang   34 values.
1301d4002b98SHong Zhang 
130267be906fSBarry Smith   When `d_nnz`, `o_nnz` parameters are specified, the storage is specified
1303a5b23f4aSJose E. Roman   for every row, corresponding to both DIAGONAL and OFF-DIAGONAL submatrices.
130427430b45SBarry Smith   In the above case the values for d_nnz,o_nnz are
1305d4002b98SHong Zhang .vb
130627430b45SBarry Smith      proc0 d_nnz = [2,2,2] and o_nnz = [2,2,2]
130727430b45SBarry Smith      proc1 d_nnz = [3,3,2] and o_nnz = [2,1,1]
130827430b45SBarry Smith      proc2 d_nnz = [1,1]   and o_nnz = [4,4]
1309d4002b98SHong Zhang .ve
1310d4002b98SHong Zhang   Here the space allocated is according to nz (or maximum values in the nnz
1311d4002b98SHong Zhang   if nnz is provided) for DIAGONAL and OFF-DIAGONAL submatrices, i.e (2+2+3+2)*3+(1+4)*2=37
1312d4002b98SHong Zhang 
1313d4002b98SHong Zhang   Level: intermediate
1314d4002b98SHong Zhang 
131567be906fSBarry Smith   Notes:
131667be906fSBarry Smith   If the *_nnz parameter is given then the *_nz parameter is ignored
131767be906fSBarry Smith 
131867be906fSBarry Smith   The stored row and column indices begin with zero.
131967be906fSBarry Smith 
132067be906fSBarry Smith   The parallel matrix is partitioned such that the first m0 rows belong to
132167be906fSBarry Smith   process 0, the next m1 rows belong to process 1, the next m2 rows belong
132267be906fSBarry Smith   to process 2 etc.. where m0,m1,m2... are the input parameter 'm'.
132367be906fSBarry Smith 
132467be906fSBarry Smith   The DIAGONAL portion of the local submatrix of a processor can be defined
132567be906fSBarry Smith   as the submatrix which is obtained by extraction the part corresponding to
132667be906fSBarry Smith   the rows r1-r2 and columns c1-c2 of the global matrix, where r1 is the
132767be906fSBarry Smith   first row that belongs to the processor, r2 is the last row belonging to
132867be906fSBarry Smith   the this processor, and c1-c2 is range of indices of the local part of a
132967be906fSBarry Smith   vector suitable for applying the matrix to.  This is an mxn matrix.  In the
133067be906fSBarry Smith   common case of a square matrix, the row and column ranges are the same and
133167be906fSBarry Smith   the DIAGONAL part is also square. The remaining portion of the local
133267be906fSBarry Smith   submatrix (mxN) constitute the OFF-DIAGONAL portion.
133367be906fSBarry Smith 
133467be906fSBarry Smith   If `o_nnz`, `d_nnz` are specified, then `o_nz`, and `d_nz` are ignored.
133567be906fSBarry Smith 
133667be906fSBarry Smith   You can call `MatGetInfo()` to get information on how effective the preallocation was;
133767be906fSBarry Smith   for example the fields mallocs,nz_allocated,nz_used,nz_unneeded;
133867be906fSBarry Smith   You can also run with the option -info and look for messages with the string
133967be906fSBarry Smith   malloc in them to see if additional memory allocation was needed.
134067be906fSBarry Smith 
134194764886SPierre Jolivet .seealso: `Mat`, `MatCreate()`, `MatCreateSeqSELL()`, `MatSetValues()`, `MatCreateSELL()`,
134211a5261eSBarry Smith           `MATMPISELL`, `MatGetInfo()`, `PetscSplitOwnership()`, `MATSELL`
1343d4002b98SHong Zhang @*/
1344d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMPISELLSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1345d71ae5a4SJacob Faibussowitsch {
1346d4002b98SHong Zhang   PetscFunctionBegin;
1347d4002b98SHong Zhang   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
1348d4002b98SHong Zhang   PetscValidType(B, 1);
1349cac4c232SBarry Smith   PetscTryMethod(B, "MatMPISELLSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
13503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1351d4002b98SHong Zhang }
1352d4002b98SHong Zhang 
1353ed73aabaSBarry Smith /*MC
1354ed73aabaSBarry Smith    MATMPISELL - MATMPISELL = "mpisell" - A matrix type to be used for MPI sparse matrices,
1355ed73aabaSBarry Smith    based on the sliced Ellpack format
1356ed73aabaSBarry Smith 
135727430b45SBarry Smith    Options Database Key:
135820f4b53cSBarry Smith . -mat_type sell - sets the matrix type to `MATSELL` during a call to `MatSetFromOptions()`
1359ed73aabaSBarry Smith 
1360ed73aabaSBarry Smith    Level: beginner
1361ed73aabaSBarry Smith 
136294764886SPierre Jolivet .seealso: `Mat`, `MatCreateSELL()`, `MATSEQSELL`, `MATSELL`, `MATSEQAIJ`, `MATAIJ`, `MATMPIAIJ`
1363ed73aabaSBarry Smith M*/
1364ed73aabaSBarry Smith 
1365d4002b98SHong Zhang /*@C
136611a5261eSBarry Smith   MatCreateSELL - Creates a sparse parallel matrix in `MATSELL` format.
1367d4002b98SHong Zhang 
1368d083f849SBarry Smith   Collective
1369d4002b98SHong Zhang 
1370d4002b98SHong Zhang   Input Parameters:
1371d4002b98SHong Zhang + comm      - MPI communicator
137211a5261eSBarry Smith . m         - number of local rows (or `PETSC_DECIDE` to have calculated if M is given)
1373d4002b98SHong Zhang               This value should be the same as the local size used in creating the
1374d4002b98SHong Zhang               y vector for the matrix-vector product y = Ax.
1375d4002b98SHong Zhang . n         - This value should be the same as the local size used in creating the
137620f4b53cSBarry Smith               x vector for the matrix-vector product y = Ax. (or `PETSC_DECIDE` to have
137720f4b53cSBarry Smith               calculated if `N` is given) For square matrices n is almost always `m`.
137820f4b53cSBarry Smith . M         - number of global rows (or `PETSC_DETERMINE` to have calculated if `m` is given)
137920f4b53cSBarry Smith . N         - number of global columns (or `PETSC_DETERMINE` to have calculated if `n` is given)
1380d4002b98SHong Zhang . d_rlenmax - max number of nonzeros per row in DIAGONAL portion of local submatrix
1381d4002b98SHong Zhang              (same value is used for all local rows)
1382d4002b98SHong Zhang . d_rlen    - array containing the number of nonzeros in the various rows of the
1383d4002b98SHong Zhang               DIAGONAL portion of the local submatrix (possibly different for each row)
138420f4b53cSBarry Smith               or `NULL`, if d_rlenmax is used to specify the nonzero structure.
138520f4b53cSBarry Smith               The size of this array is equal to the number of local rows, i.e `m`.
1386d4002b98SHong Zhang . o_rlenmax - max number of nonzeros per row in the OFF-DIAGONAL portion of local
1387d4002b98SHong Zhang               submatrix (same value is used for all local rows).
1388d4002b98SHong Zhang - o_rlen    - array containing the number of nonzeros in the various rows of the
1389d4002b98SHong Zhang               OFF-DIAGONAL portion of the local submatrix (possibly different for
139020f4b53cSBarry Smith               each row) or `NULL`, if `o_rlenmax` is used to specify the nonzero
1391d4002b98SHong Zhang               structure. The size of this array is equal to the number
139220f4b53cSBarry Smith               of local rows, i.e `m`.
1393d4002b98SHong Zhang 
1394d4002b98SHong Zhang   Output Parameter:
1395d4002b98SHong Zhang . A - the matrix
1396d4002b98SHong Zhang 
139727430b45SBarry Smith   Options Database Key:
1398fe59aa6dSJacob Faibussowitsch . -mat_sell_oneindex - Internally use indexing starting at 1
139927430b45SBarry Smith         rather than 0.  When calling `MatSetValues()`,
140027430b45SBarry Smith         the user still MUST index entries starting at 0!
140127430b45SBarry Smith 
140227430b45SBarry Smith   Example:
140327430b45SBarry Smith   Consider the following 8x8 matrix with 34 non-zero values, that is
140427430b45SBarry Smith   assembled across 3 processors. Lets assume that proc0 owns 3 rows,
140527430b45SBarry Smith   proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
140627430b45SBarry Smith   as follows
140727430b45SBarry Smith 
140827430b45SBarry Smith .vb
140927430b45SBarry Smith             1  2  0  |  0  3  0  |  0  4
141027430b45SBarry Smith     Proc0   0  5  6  |  7  0  0  |  8  0
141127430b45SBarry Smith             9  0 10  | 11  0  0  | 12  0
141227430b45SBarry Smith     -------------------------------------
141327430b45SBarry Smith            13  0 14  | 15 16 17  |  0  0
141427430b45SBarry Smith     Proc1   0 18  0  | 19 20 21  |  0  0
141527430b45SBarry Smith             0  0  0  | 22 23  0  | 24  0
141627430b45SBarry Smith     -------------------------------------
141727430b45SBarry Smith     Proc2  25 26 27  |  0  0 28  | 29  0
141827430b45SBarry Smith            30  0  0  | 31 32 33  |  0 34
141927430b45SBarry Smith .ve
142027430b45SBarry Smith 
142120f4b53cSBarry Smith   This can be represented as a collection of submatrices as
142227430b45SBarry Smith .vb
142327430b45SBarry Smith       A B C
142427430b45SBarry Smith       D E F
142527430b45SBarry Smith       G H I
142627430b45SBarry Smith .ve
142727430b45SBarry Smith 
142827430b45SBarry Smith   Where the submatrices A,B,C are owned by proc0, D,E,F are
142927430b45SBarry Smith   owned by proc1, G,H,I are owned by proc2.
143027430b45SBarry Smith 
143127430b45SBarry Smith   The 'm' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
143227430b45SBarry Smith   The 'n' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
143327430b45SBarry Smith   The 'M','N' parameters are 8,8, and have the same values on all procs.
143427430b45SBarry Smith 
143527430b45SBarry Smith   The DIAGONAL submatrices corresponding to proc0,proc1,proc2 are
143627430b45SBarry Smith   submatrices [A], [E], [I] respectively. The OFF-DIAGONAL submatrices
143727430b45SBarry Smith   corresponding to proc0,proc1,proc2 are [BC], [DF], [GH] respectively.
143827430b45SBarry Smith   Internally, each processor stores the DIAGONAL part, and the OFF-DIAGONAL
143927430b45SBarry Smith   part as `MATSEQSELL` matrices. For example, proc1 will store [E] as a `MATSEQSELL`
14405163b989SNuno Nobre   matrix, and [DF] as another `MATSEQSELL` matrix.
144127430b45SBarry Smith 
144227430b45SBarry Smith   When d_rlenmax, o_rlenmax parameters are specified, d_rlenmax storage elements are
14435163b989SNuno Nobre   allocated for every row of the local DIAGONAL submatrix, and o_rlenmax
14445163b989SNuno Nobre   storage locations are allocated for every row of the OFF-DIAGONAL submatrix.
14455163b989SNuno Nobre   One way to choose `d_rlenmax` and `o_rlenmax` is to use the maximum number of nonzeros over
14465163b989SNuno Nobre   the local rows for each of the local DIAGONAL, and the OFF-DIAGONAL submatrices.
144720f4b53cSBarry Smith   In this case, the values of d_rlenmax,o_rlenmax are
144827430b45SBarry Smith .vb
144920f4b53cSBarry Smith      proc0 - d_rlenmax = 2, o_rlenmax = 2
145020f4b53cSBarry Smith      proc1 - d_rlenmax = 3, o_rlenmax = 2
145120f4b53cSBarry Smith      proc2 - d_rlenmax = 1, o_rlenmax = 4
145227430b45SBarry Smith .ve
145327430b45SBarry Smith   We are allocating m*(d_rlenmax+o_rlenmax) storage locations for every proc. This
145427430b45SBarry Smith   translates to 3*(2+2)=12 for proc0, 3*(3+2)=15 for proc1, 2*(1+4)=10
145527430b45SBarry Smith   for proc3. i.e we are using 12+15+10=37 storage locations to store
145627430b45SBarry Smith   34 values.
145727430b45SBarry Smith 
145820f4b53cSBarry Smith   When `d_rlen`, `o_rlen` parameters are specified, the storage is specified
145927430b45SBarry Smith   for every row, corresponding to both DIAGONAL and OFF-DIAGONAL submatrices.
146020f4b53cSBarry Smith   In the above case the values for `d_nnz`, `o_nnz` are
146127430b45SBarry Smith .vb
146220f4b53cSBarry Smith      proc0 - d_nnz = [2,2,2] and o_nnz = [2,2,2]
146320f4b53cSBarry Smith      proc1 - d_nnz = [3,3,2] and o_nnz = [2,1,1]
146420f4b53cSBarry Smith      proc2 - d_nnz = [1,1]   and o_nnz = [4,4]
146527430b45SBarry Smith .ve
146627430b45SBarry Smith   Here the space allocated is still 37 though there are 34 nonzeros because
146727430b45SBarry Smith   the allocation is always done according to rlenmax.
146827430b45SBarry Smith 
146927430b45SBarry Smith   Level: intermediate
147027430b45SBarry Smith 
147127430b45SBarry Smith   Notes:
147211a5261eSBarry Smith   It is recommended that one use the `MatCreate()`, `MatSetType()` and/or `MatSetFromOptions()`,
1473f6f02116SRichard Tran Mills   MatXXXXSetPreallocation() paradigm instead of this routine directly.
147411a5261eSBarry Smith   [MatXXXXSetPreallocation() is, for example, `MatSeqSELLSetPreallocation()`]
1475d4002b98SHong Zhang 
1476d4002b98SHong Zhang   If the *_rlen parameter is given then the *_rlenmax parameter is ignored
1477d4002b98SHong Zhang 
147820f4b53cSBarry Smith   `m`, `n`, `M`, `N` parameters specify the size of the matrix, and its partitioning across
147920f4b53cSBarry Smith   processors, while `d_rlenmax`, `d_rlen`, `o_rlenmax` , `o_rlen` parameters specify the approximate
1480d4002b98SHong Zhang   storage requirements for this matrix.
1481d4002b98SHong Zhang 
148211a5261eSBarry Smith   If `PETSC_DECIDE` or  `PETSC_DETERMINE` is used for a particular argument on one
1483d4002b98SHong Zhang   processor than it must be used on all processors that share the object for
1484d4002b98SHong Zhang   that argument.
1485d4002b98SHong Zhang 
1486d4002b98SHong Zhang   The user MUST specify either the local or global matrix dimensions
1487d4002b98SHong Zhang   (possibly both).
1488d4002b98SHong Zhang 
1489d4002b98SHong Zhang   The parallel matrix is partitioned across processors such that the
1490d4002b98SHong Zhang   first m0 rows belong to process 0, the next m1 rows belong to
1491d4002b98SHong Zhang   process 1, the next m2 rows belong to process 2 etc.. where
1492d4002b98SHong Zhang   m0,m1,m2,.. are the input parameter 'm'. i.e each processor stores
149320f4b53cSBarry Smith   values corresponding to [`m` x `N`] submatrix.
1494d4002b98SHong Zhang 
1495d4002b98SHong Zhang   The columns are logically partitioned with the n0 columns belonging
1496d4002b98SHong Zhang   to 0th partition, the next n1 columns belonging to the next
149720f4b53cSBarry Smith   partition etc.. where n0,n1,n2... are the input parameter `n`.
1498d4002b98SHong Zhang 
1499d4002b98SHong Zhang   The DIAGONAL portion of the local submatrix on any given processor
150020f4b53cSBarry Smith   is the submatrix corresponding to the rows and columns `m`, `n`
1501d4002b98SHong Zhang   corresponding to the given processor. i.e diagonal matrix on
1502d4002b98SHong Zhang   process 0 is [m0 x n0], diagonal matrix on process 1 is [m1 x n1]
1503d4002b98SHong Zhang   etc. The remaining portion of the local submatrix [m x (N-n)]
1504d4002b98SHong Zhang   constitute the OFF-DIAGONAL portion. The example below better
1505d4002b98SHong Zhang   illustrates this concept.
1506d4002b98SHong Zhang 
1507d4002b98SHong Zhang   For a square global matrix we define each processor's diagonal portion
1508d4002b98SHong Zhang   to be its local rows and the corresponding columns (a square submatrix);
1509d4002b98SHong Zhang   each processor's off-diagonal portion encompasses the remainder of the
1510d4002b98SHong Zhang   local matrix (a rectangular submatrix).
1511d4002b98SHong Zhang 
151220f4b53cSBarry Smith   If `o_rlen`, `d_rlen` are specified, then `o_rlenmax`, and `d_rlenmax` are ignored.
1513d4002b98SHong Zhang 
1514d4002b98SHong Zhang   When calling this routine with a single process communicator, a matrix of
151511a5261eSBarry Smith   type `MATSEQSELL` is returned.  If a matrix of type `MATMPISELL` is desired for this
151627430b45SBarry Smith   type of communicator, use the construction mechanism
1517d4002b98SHong Zhang .vb
151827430b45SBarry Smith    MatCreate(...,&A);
151927430b45SBarry Smith    MatSetType(A,MATMPISELL);
152027430b45SBarry Smith    MatSetSizes(A, m,n,M,N);
152127430b45SBarry Smith    MatMPISELLSetPreallocation(A,...);
1522d4002b98SHong Zhang .ve
1523d4002b98SHong Zhang 
152494764886SPierre Jolivet .seealso: `Mat`, `MATSELL`, `MatCreate()`, `MatCreateSeqSELL()`, `MatSetValues()`, `MatMPISELLSetPreallocation()`, `MATMPISELL`
1525d4002b98SHong Zhang @*/
1526d71ae5a4SJacob 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)
1527d71ae5a4SJacob Faibussowitsch {
1528d4002b98SHong Zhang   PetscMPIInt size;
1529d4002b98SHong Zhang 
1530d4002b98SHong Zhang   PetscFunctionBegin;
15319566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
15329566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
15339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
1534d4002b98SHong Zhang   if (size > 1) {
15359566063dSJacob Faibussowitsch     PetscCall(MatSetType(*A, MATMPISELL));
15369566063dSJacob Faibussowitsch     PetscCall(MatMPISELLSetPreallocation(*A, d_rlenmax, d_rlen, o_rlenmax, o_rlen));
1537d4002b98SHong Zhang   } else {
15389566063dSJacob Faibussowitsch     PetscCall(MatSetType(*A, MATSEQSELL));
15399566063dSJacob Faibussowitsch     PetscCall(MatSeqSELLSetPreallocation(*A, d_rlenmax, d_rlen));
1540d4002b98SHong Zhang   }
15413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1542d4002b98SHong Zhang }
1543d4002b98SHong Zhang 
1544fa078d78SJacob Faibussowitsch /*@C
1545fa078d78SJacob Faibussowitsch   MatMPISELLGetSeqSELL - Returns the local pieces of this distributed matrix
1546fa078d78SJacob Faibussowitsch 
1547fa078d78SJacob Faibussowitsch   Not Collective
1548fa078d78SJacob Faibussowitsch 
1549fa078d78SJacob Faibussowitsch   Input Parameter:
1550fa078d78SJacob Faibussowitsch . A - the `MATMPISELL` matrix
1551fa078d78SJacob Faibussowitsch 
1552fa078d78SJacob Faibussowitsch   Output Parameters:
1553fa078d78SJacob Faibussowitsch + Ad     - The diagonal portion of `A`
15544cf0e950SBarry Smith . Ao     - The off-diagonal portion of `A`
1555fa078d78SJacob Faibussowitsch - colmap - An array mapping local column numbers of `Ao` to global column numbers of the parallel matrix
1556fa078d78SJacob Faibussowitsch 
1557fa078d78SJacob Faibussowitsch   Level: advanced
1558fa078d78SJacob Faibussowitsch 
1559fa078d78SJacob Faibussowitsch .seealso: `Mat`, `MATSEQSELL`, `MATMPISELL`
1560fa078d78SJacob Faibussowitsch @*/
1561fa078d78SJacob Faibussowitsch PetscErrorCode MatMPISELLGetSeqSELL(Mat A, Mat *Ad, Mat *Ao, const PetscInt *colmap[])
1562fa078d78SJacob Faibussowitsch {
1563fa078d78SJacob Faibussowitsch   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
1564fa078d78SJacob Faibussowitsch   PetscBool    flg;
1565fa078d78SJacob Faibussowitsch 
1566fa078d78SJacob Faibussowitsch   PetscFunctionBegin;
1567fa078d78SJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPISELL, &flg));
1568fa078d78SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "This function requires a MATMPISELL matrix as input");
1569fa078d78SJacob Faibussowitsch   if (Ad) *Ad = a->A;
1570fa078d78SJacob Faibussowitsch   if (Ao) *Ao = a->B;
1571fa078d78SJacob Faibussowitsch   if (colmap) *colmap = a->garray;
1572fa078d78SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1573fa078d78SJacob Faibussowitsch }
1574fa078d78SJacob Faibussowitsch 
1575fa078d78SJacob Faibussowitsch /*@C
1576fa078d78SJacob Faibussowitsch   MatMPISELLGetLocalMatCondensed - Creates a `MATSEQSELL` matrix from an `MATMPISELL` matrix by
1577fa078d78SJacob Faibussowitsch   taking all its local rows and NON-ZERO columns
1578fa078d78SJacob Faibussowitsch 
1579fa078d78SJacob Faibussowitsch   Not Collective
1580fa078d78SJacob Faibussowitsch 
1581fa078d78SJacob Faibussowitsch   Input Parameters:
1582fa078d78SJacob Faibussowitsch + A     - the matrix
1583fa078d78SJacob Faibussowitsch . scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
1584fa078d78SJacob Faibussowitsch . row   - index sets of rows to extract (or `NULL`)
1585fa078d78SJacob Faibussowitsch - col   - index sets of columns to extract (or `NULL`)
1586fa078d78SJacob Faibussowitsch 
1587fa078d78SJacob Faibussowitsch   Output Parameter:
1588fa078d78SJacob Faibussowitsch . A_loc - the local sequential matrix generated
1589fa078d78SJacob Faibussowitsch 
1590fa078d78SJacob Faibussowitsch   Level: advanced
1591fa078d78SJacob Faibussowitsch 
1592fa078d78SJacob Faibussowitsch .seealso: `Mat`, `MATSEQSELL`, `MATMPISELL`, `MatGetOwnershipRange()`, `MatMPISELLGetLocalMat()`
1593fa078d78SJacob Faibussowitsch @*/
1594fa078d78SJacob Faibussowitsch PetscErrorCode MatMPISELLGetLocalMatCondensed(Mat A, MatReuse scall, IS *row, IS *col, Mat *A_loc)
1595fa078d78SJacob Faibussowitsch {
1596fa078d78SJacob Faibussowitsch   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
1597fa078d78SJacob Faibussowitsch   PetscInt     i, start, end, ncols, nzA, nzB, *cmap, imark, *idx;
1598fa078d78SJacob Faibussowitsch   IS           isrowa, iscola;
1599fa078d78SJacob Faibussowitsch   Mat         *aloc;
1600fa078d78SJacob Faibussowitsch   PetscBool    match;
1601fa078d78SJacob Faibussowitsch 
1602fa078d78SJacob Faibussowitsch   PetscFunctionBegin;
1603fa078d78SJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPISELL, &match));
1604fa078d78SJacob Faibussowitsch   PetscCheck(match, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Requires MATMPISELL matrix as input");
1605fa078d78SJacob Faibussowitsch   PetscCall(PetscLogEventBegin(MAT_Getlocalmatcondensed, A, 0, 0, 0));
1606fa078d78SJacob Faibussowitsch   if (!row) {
1607fa078d78SJacob Faibussowitsch     start = A->rmap->rstart;
1608fa078d78SJacob Faibussowitsch     end   = A->rmap->rend;
1609fa078d78SJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, end - start, start, 1, &isrowa));
1610fa078d78SJacob Faibussowitsch   } else {
1611fa078d78SJacob Faibussowitsch     isrowa = *row;
1612fa078d78SJacob Faibussowitsch   }
1613fa078d78SJacob Faibussowitsch   if (!col) {
1614fa078d78SJacob Faibussowitsch     start = A->cmap->rstart;
1615fa078d78SJacob Faibussowitsch     cmap  = a->garray;
1616fa078d78SJacob Faibussowitsch     nzA   = a->A->cmap->n;
1617fa078d78SJacob Faibussowitsch     nzB   = a->B->cmap->n;
1618fa078d78SJacob Faibussowitsch     PetscCall(PetscMalloc1(nzA + nzB, &idx));
1619fa078d78SJacob Faibussowitsch     ncols = 0;
1620fa078d78SJacob Faibussowitsch     for (i = 0; i < nzB; i++) {
1621fa078d78SJacob Faibussowitsch       if (cmap[i] < start) idx[ncols++] = cmap[i];
1622fa078d78SJacob Faibussowitsch       else break;
1623fa078d78SJacob Faibussowitsch     }
1624fa078d78SJacob Faibussowitsch     imark = i;
1625fa078d78SJacob Faibussowitsch     for (i = 0; i < nzA; i++) idx[ncols++] = start + i;
1626fa078d78SJacob Faibussowitsch     for (i = imark; i < nzB; i++) idx[ncols++] = cmap[i];
1627fa078d78SJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncols, idx, PETSC_OWN_POINTER, &iscola));
1628fa078d78SJacob Faibussowitsch   } else {
1629fa078d78SJacob Faibussowitsch     iscola = *col;
1630fa078d78SJacob Faibussowitsch   }
1631fa078d78SJacob Faibussowitsch   if (scall != MAT_INITIAL_MATRIX) {
1632fa078d78SJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &aloc));
1633fa078d78SJacob Faibussowitsch     aloc[0] = *A_loc;
1634fa078d78SJacob Faibussowitsch   }
1635fa078d78SJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(A, 1, &isrowa, &iscola, scall, &aloc));
1636fa078d78SJacob Faibussowitsch   *A_loc = aloc[0];
1637fa078d78SJacob Faibussowitsch   PetscCall(PetscFree(aloc));
1638fa078d78SJacob Faibussowitsch   if (!row) PetscCall(ISDestroy(&isrowa));
1639fa078d78SJacob Faibussowitsch   if (!col) PetscCall(ISDestroy(&iscola));
1640fa078d78SJacob Faibussowitsch   PetscCall(PetscLogEventEnd(MAT_Getlocalmatcondensed, A, 0, 0, 0));
1641fa078d78SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1642fa078d78SJacob Faibussowitsch }
1643fa078d78SJacob Faibussowitsch 
1644d4002b98SHong Zhang #include <../src/mat/impls/aij/mpi/mpiaij.h>
1645d4002b98SHong Zhang 
1646d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_MPISELL_MPIAIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1647d71ae5a4SJacob Faibussowitsch {
1648d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
1649d4002b98SHong Zhang   Mat          B;
1650d4002b98SHong Zhang   Mat_MPIAIJ  *b;
1651d4002b98SHong Zhang 
1652d4002b98SHong Zhang   PetscFunctionBegin;
165328b400f6SJacob Faibussowitsch   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Matrix must be assembled");
1654d4002b98SHong Zhang 
165594a8b381SRichard Tran Mills   if (reuse == MAT_REUSE_MATRIX) {
165694a8b381SRichard Tran Mills     B = *newmat;
165794a8b381SRichard Tran Mills   } else {
16589566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
16599566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATMPIAIJ));
16609566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
16619566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, A->rmap->bs, A->cmap->bs));
16629566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(B, 0, NULL));
16639566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL));
166494a8b381SRichard Tran Mills   }
1665d4002b98SHong Zhang   b = (Mat_MPIAIJ *)B->data;
166694a8b381SRichard Tran Mills 
166794a8b381SRichard Tran Mills   if (reuse == MAT_REUSE_MATRIX) {
16689566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqSELL_SeqAIJ(a->A, MATSEQAIJ, MAT_REUSE_MATRIX, &b->A));
16699566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqSELL_SeqAIJ(a->B, MATSEQAIJ, MAT_REUSE_MATRIX, &b->B));
167094a8b381SRichard Tran Mills   } else {
16719566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b->A));
16729566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b->B));
16739566063dSJacob Faibussowitsch     PetscCall(MatDisAssemble_MPISELL(A));
16749566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqSELL_SeqAIJ(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &b->A));
16759566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqSELL_SeqAIJ(a->B, MATSEQAIJ, MAT_INITIAL_MATRIX, &b->B));
16769566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
16779566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
16789566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
16799566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
168094a8b381SRichard Tran Mills   }
1681d4002b98SHong Zhang 
1682d4002b98SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
16839566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1684d4002b98SHong Zhang   } else {
1685d4002b98SHong Zhang     *newmat = B;
1686d4002b98SHong Zhang   }
16873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1688d4002b98SHong Zhang }
1689d4002b98SHong Zhang 
1690d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_MPIAIJ_MPISELL(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1691d71ae5a4SJacob Faibussowitsch {
1692d4002b98SHong Zhang   Mat_MPIAIJ  *a = (Mat_MPIAIJ *)A->data;
1693d4002b98SHong Zhang   Mat          B;
1694d4002b98SHong Zhang   Mat_MPISELL *b;
1695d4002b98SHong Zhang 
1696d4002b98SHong Zhang   PetscFunctionBegin;
169728b400f6SJacob Faibussowitsch   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Matrix must be assembled");
1698d4002b98SHong Zhang 
169994a8b381SRichard Tran Mills   if (reuse == MAT_REUSE_MATRIX) {
170094a8b381SRichard Tran Mills     B = *newmat;
170194a8b381SRichard Tran Mills   } else {
17022d1451d4SHong Zhang     Mat_SeqAIJ *Aa = (Mat_SeqAIJ *)a->A->data, *Ba = (Mat_SeqAIJ *)a->B->data;
17032d1451d4SHong 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;
17042d1451d4SHong Zhang     PetscInt   *d_nnz, *o_nnz;
17052d1451d4SHong Zhang     PetscCall(PetscMalloc2(lm, &d_nnz, lm, &o_nnz));
17062d1451d4SHong Zhang     for (i = 0; i < lm; i++) {
17072d1451d4SHong Zhang       d_nnz[i] = Aa->i[i + 1] - Aa->i[i];
17082d1451d4SHong Zhang       o_nnz[i] = Ba->i[i + 1] - Ba->i[i];
17092d1451d4SHong Zhang       if (d_nnz[i] > d_nz) d_nz = d_nnz[i];
17102d1451d4SHong Zhang       if (o_nnz[i] > o_nz) o_nz = o_nnz[i];
17112d1451d4SHong Zhang     }
17129566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
17139566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATMPISELL));
17142d1451d4SHong Zhang     PetscCall(MatSetSizes(B, lm, ln, m, n));
17159566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, A->rmap->bs, A->cmap->bs));
17162d1451d4SHong Zhang     PetscCall(MatSeqSELLSetPreallocation(B, d_nz, d_nnz));
17172d1451d4SHong Zhang     PetscCall(MatMPISELLSetPreallocation(B, d_nz, d_nnz, o_nz, o_nnz));
17182d1451d4SHong Zhang     PetscCall(PetscFree2(d_nnz, o_nnz));
171994a8b381SRichard Tran Mills   }
1720d4002b98SHong Zhang   b = (Mat_MPISELL *)B->data;
172194a8b381SRichard Tran Mills 
172294a8b381SRichard Tran Mills   if (reuse == MAT_REUSE_MATRIX) {
17239566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqAIJ_SeqSELL(a->A, MATSEQSELL, MAT_REUSE_MATRIX, &b->A));
17249566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqAIJ_SeqSELL(a->B, MATSEQSELL, MAT_REUSE_MATRIX, &b->B));
172594a8b381SRichard Tran Mills   } else {
17269566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b->A));
17279566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b->B));
17289566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqAIJ_SeqSELL(a->A, MATSEQSELL, MAT_INITIAL_MATRIX, &b->A));
17299566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqAIJ_SeqSELL(a->B, MATSEQSELL, MAT_INITIAL_MATRIX, &b->B));
17309566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
17319566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
17322d1451d4SHong Zhang     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
17332d1451d4SHong Zhang     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
173494a8b381SRichard Tran Mills   }
1735d4002b98SHong Zhang 
1736d4002b98SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
17379566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1738d4002b98SHong Zhang   } else {
1739d4002b98SHong Zhang     *newmat = B;
1740d4002b98SHong Zhang   }
17413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1742d4002b98SHong Zhang }
1743d4002b98SHong Zhang 
1744d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSOR_MPISELL(Mat matin, Vec bb, PetscReal omega, MatSORType flag, PetscReal fshift, PetscInt its, PetscInt lits, Vec xx)
1745d71ae5a4SJacob Faibussowitsch {
1746d4002b98SHong Zhang   Mat_MPISELL *mat = (Mat_MPISELL *)matin->data;
1747f4259b30SLisandro Dalcin   Vec          bb1 = NULL;
1748d4002b98SHong Zhang 
1749d4002b98SHong Zhang   PetscFunctionBegin;
1750d4002b98SHong Zhang   if (flag == SOR_APPLY_UPPER) {
17519566063dSJacob Faibussowitsch     PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx));
17523ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1753d4002b98SHong Zhang   }
1754d4002b98SHong Zhang 
175548a46eb9SPierre Jolivet   if (its > 1 || ~flag & SOR_ZERO_INITIAL_GUESS || flag & SOR_EISENSTAT) PetscCall(VecDuplicate(bb, &bb1));
1756d4002b98SHong Zhang 
1757d4002b98SHong Zhang   if ((flag & SOR_LOCAL_SYMMETRIC_SWEEP) == SOR_LOCAL_SYMMETRIC_SWEEP) {
1758d4002b98SHong Zhang     if (flag & SOR_ZERO_INITIAL_GUESS) {
17599566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx));
1760d4002b98SHong Zhang       its--;
1761d4002b98SHong Zhang     }
1762d4002b98SHong Zhang 
1763d4002b98SHong Zhang     while (its--) {
17649566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
17659566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1766d4002b98SHong Zhang 
1767d4002b98SHong Zhang       /* update rhs: bb1 = bb - B*x */
17689566063dSJacob Faibussowitsch       PetscCall(VecScale(mat->lvec, -1.0));
17699566063dSJacob Faibussowitsch       PetscCall((*mat->B->ops->multadd)(mat->B, mat->lvec, bb, bb1));
1770d4002b98SHong Zhang 
1771d4002b98SHong Zhang       /* local sweep */
17729566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb1, omega, SOR_SYMMETRIC_SWEEP, fshift, lits, 1, xx));
1773d4002b98SHong Zhang     }
1774d4002b98SHong Zhang   } else if (flag & SOR_LOCAL_FORWARD_SWEEP) {
1775d4002b98SHong Zhang     if (flag & SOR_ZERO_INITIAL_GUESS) {
17769566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx));
1777d4002b98SHong Zhang       its--;
1778d4002b98SHong Zhang     }
1779d4002b98SHong Zhang     while (its--) {
17809566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
17819566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1782d4002b98SHong Zhang 
1783d4002b98SHong Zhang       /* update rhs: bb1 = bb - B*x */
17849566063dSJacob Faibussowitsch       PetscCall(VecScale(mat->lvec, -1.0));
17859566063dSJacob Faibussowitsch       PetscCall((*mat->B->ops->multadd)(mat->B, mat->lvec, bb, bb1));
1786d4002b98SHong Zhang 
1787d4002b98SHong Zhang       /* local sweep */
17889566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb1, omega, SOR_FORWARD_SWEEP, fshift, lits, 1, xx));
1789d4002b98SHong Zhang     }
1790d4002b98SHong Zhang   } else if (flag & SOR_LOCAL_BACKWARD_SWEEP) {
1791d4002b98SHong Zhang     if (flag & SOR_ZERO_INITIAL_GUESS) {
17929566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx));
1793d4002b98SHong Zhang       its--;
1794d4002b98SHong Zhang     }
1795d4002b98SHong Zhang     while (its--) {
17969566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
17979566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1798d4002b98SHong Zhang 
1799d4002b98SHong Zhang       /* update rhs: bb1 = bb - B*x */
18009566063dSJacob Faibussowitsch       PetscCall(VecScale(mat->lvec, -1.0));
18019566063dSJacob Faibussowitsch       PetscCall((*mat->B->ops->multadd)(mat->B, mat->lvec, bb, bb1));
1802d4002b98SHong Zhang 
1803d4002b98SHong Zhang       /* local sweep */
18049566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb1, omega, SOR_BACKWARD_SWEEP, fshift, lits, 1, xx));
1805d4002b98SHong Zhang     }
1806d4002b98SHong Zhang   } else SETERRQ(PetscObjectComm((PetscObject)matin), PETSC_ERR_SUP, "Parallel SOR not supported");
1807d4002b98SHong Zhang 
18089566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bb1));
1809d4002b98SHong Zhang 
1810d4002b98SHong Zhang   matin->factorerrortype = mat->A->factorerrortype;
18113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1812d4002b98SHong Zhang }
1813d4002b98SHong Zhang 
1814b5917f1bSHong Zhang #if defined(PETSC_HAVE_CUDA)
1815b5917f1bSHong Zhang PETSC_INTERN PetscErrorCode MatConvert_MPISELL_MPISELLCUDA(Mat, MatType, MatReuse, Mat *);
1816b5917f1bSHong Zhang #endif
1817b5917f1bSHong Zhang 
1818d4002b98SHong Zhang /*MC
1819d4002b98SHong Zhang    MATMPISELL - MATMPISELL = "MPISELL" - A matrix type to be used for parallel sparse matrices.
1820d4002b98SHong Zhang 
1821d4002b98SHong Zhang    Options Database Keys:
182211a5261eSBarry Smith . -mat_type mpisell - sets the matrix type to `MATMPISELL` during a call to `MatSetFromOptions()`
1823d4002b98SHong Zhang 
1824d4002b98SHong Zhang   Level: beginner
1825d4002b98SHong Zhang 
182667be906fSBarry Smith .seealso: `Mat`, `MATSELL`, `MATSEQSELL` `MatCreateSELL()`
1827d4002b98SHong Zhang M*/
1828d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_MPISELL(Mat B)
1829d71ae5a4SJacob Faibussowitsch {
1830d4002b98SHong Zhang   Mat_MPISELL *b;
1831d4002b98SHong Zhang   PetscMPIInt  size;
1832d4002b98SHong Zhang 
1833d4002b98SHong Zhang   PetscFunctionBegin;
18349566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size));
18354dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
1836d4002b98SHong Zhang   B->data       = (void *)b;
1837aea10558SJacob Faibussowitsch   B->ops[0]     = MatOps_Values;
1838d4002b98SHong Zhang   B->assembled  = PETSC_FALSE;
1839d4002b98SHong Zhang   B->insertmode = NOT_SET_VALUES;
1840d4002b98SHong Zhang   b->size       = size;
18419566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)B), &b->rank));
1842d4002b98SHong Zhang   /* build cache for off array entries formed */
18439566063dSJacob Faibussowitsch   PetscCall(MatStashCreate_Private(PetscObjectComm((PetscObject)B), 1, &B->stash));
1844d4002b98SHong Zhang 
1845d4002b98SHong Zhang   b->donotstash  = PETSC_FALSE;
1846f4259b30SLisandro Dalcin   b->colmap      = NULL;
1847f4259b30SLisandro Dalcin   b->garray      = NULL;
1848d4002b98SHong Zhang   b->roworiented = PETSC_TRUE;
1849d4002b98SHong Zhang 
1850d4002b98SHong Zhang   /* stuff used for matrix vector multiply */
1851d4002b98SHong Zhang   b->lvec  = NULL;
1852d4002b98SHong Zhang   b->Mvctx = NULL;
1853d4002b98SHong Zhang 
1854d4002b98SHong Zhang   /* stuff for MatGetRow() */
1855f4259b30SLisandro Dalcin   b->rowindices   = NULL;
1856f4259b30SLisandro Dalcin   b->rowvalues    = NULL;
1857d4002b98SHong Zhang   b->getrowactive = PETSC_FALSE;
1858d4002b98SHong Zhang 
18599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_MPISELL));
18609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_MPISELL));
18619566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_MPISELL));
18629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatMPISELLSetPreallocation_C", MatMPISELLSetPreallocation_MPISELL));
18639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_mpisell_mpiaij_C", MatConvert_MPISELL_MPIAIJ));
1864b5917f1bSHong Zhang #if defined(PETSC_HAVE_CUDA)
1865b5917f1bSHong Zhang   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_mpisell_mpisellcuda_C", MatConvert_MPISELL_MPISELLCUDA));
1866b5917f1bSHong Zhang #endif
18679566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatDiagonalScaleLocal_C", MatDiagonalScaleLocal_MPISELL));
18689566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATMPISELL));
18693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1870d4002b98SHong Zhang }
1871