xref: /petsc/src/mat/impls/sell/mpi/mpisell.c (revision 27430b45d0a5eedd7547ed99d6048b6750b3fa8a)
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:
18d4002b98SHong Zhang . -mat_type sell - sets the matrix type to "sell" 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 
25d71ae5a4SJacob Faibussowitsch 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; \
69d4002b98SHong Zhang       if (*(cp1 + 8 * t) > col) high1 = t; \
70d4002b98SHong Zhang       else low1 = t; \
71d4002b98SHong Zhang     } \
72d4002b98SHong Zhang     for (_i = low1; _i < high1; _i++) { \
73d4002b98SHong Zhang       if (*(cp1 + 8 * _i) > col) break; \
74d4002b98SHong Zhang       if (*(cp1 + 8 * _i) == col) { \
75d4002b98SHong Zhang         if (addv == ADD_VALUES) *(vp1 + 8 * _i) += value; \
76d4002b98SHong Zhang         else *(vp1 + 8 * _i) = value; \
77d4002b98SHong Zhang         goto a_noinsert; \
78d4002b98SHong Zhang       } \
79d4002b98SHong Zhang     } \
809371c9d4SSatish Balay     if (value == 0.0 && ignorezeroentries) { \
819371c9d4SSatish Balay       low1  = 0; \
829371c9d4SSatish Balay       high1 = nrow1; \
839371c9d4SSatish Balay       goto a_noinsert; \
849371c9d4SSatish Balay     } \
859371c9d4SSatish Balay     if (nonew == 1) { \
869371c9d4SSatish Balay       low1  = 0; \
879371c9d4SSatish Balay       high1 = nrow1; \
889371c9d4SSatish Balay       goto a_noinsert; \
899371c9d4SSatish Balay     } \
9008401ef6SPierre 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); \
91d4002b98SHong Zhang     MatSeqXSELLReallocateSELL(A, am, 1, nrow1, a->sliidx, row / 8, row, col, a->colidx, a->val, cp1, vp1, nonew, MatScalar); \
92d4002b98SHong Zhang     /* shift up all the later entries in this row */ \
93d4002b98SHong Zhang     for (ii = nrow1 - 1; ii >= _i; ii--) { \
94d4002b98SHong Zhang       *(cp1 + 8 * (ii + 1)) = *(cp1 + 8 * ii); \
95d4002b98SHong Zhang       *(vp1 + 8 * (ii + 1)) = *(vp1 + 8 * ii); \
96d4002b98SHong Zhang     } \
97d4002b98SHong Zhang     *(cp1 + 8 * _i) = col; \
98d4002b98SHong Zhang     *(vp1 + 8 * _i) = value; \
999371c9d4SSatish Balay     a->nz++; \
1009371c9d4SSatish Balay     nrow1++; \
1019371c9d4SSatish Balay     A->nonzerostate++; \
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; \
113d4002b98SHong Zhang       if (*(cp2 + 8 * t) > col) high2 = t; \
114d4002b98SHong Zhang       else low2 = t; \
115d4002b98SHong Zhang     } \
116d4002b98SHong Zhang     for (_i = low2; _i < high2; _i++) { \
117d4002b98SHong Zhang       if (*(cp2 + 8 * _i) > col) break; \
118d4002b98SHong Zhang       if (*(cp2 + 8 * _i) == col) { \
119d4002b98SHong Zhang         if (addv == ADD_VALUES) *(vp2 + 8 * _i) += value; \
120d4002b98SHong Zhang         else *(vp2 + 8 * _i) = value; \
121d4002b98SHong Zhang         goto b_noinsert; \
122d4002b98SHong Zhang       } \
123d4002b98SHong Zhang     } \
1249371c9d4SSatish Balay     if (value == 0.0 && ignorezeroentries) { \
1259371c9d4SSatish Balay       low2  = 0; \
1269371c9d4SSatish Balay       high2 = nrow2; \
1279371c9d4SSatish Balay       goto b_noinsert; \
1289371c9d4SSatish Balay     } \
1299371c9d4SSatish Balay     if (nonew == 1) { \
1309371c9d4SSatish Balay       low2  = 0; \
1319371c9d4SSatish Balay       high2 = nrow2; \
1329371c9d4SSatish Balay       goto b_noinsert; \
1339371c9d4SSatish Balay     } \
13408401ef6SPierre 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); \
135d4002b98SHong Zhang     MatSeqXSELLReallocateSELL(B, bm, 1, nrow2, b->sliidx, row / 8, row, col, b->colidx, b->val, cp2, vp2, nonew, MatScalar); \
136d4002b98SHong Zhang     /* shift up all the later entries in this row */ \
137d4002b98SHong Zhang     for (ii = nrow2 - 1; ii >= _i; ii--) { \
138d4002b98SHong Zhang       *(cp2 + 8 * (ii + 1)) = *(cp2 + 8 * ii); \
139d4002b98SHong Zhang       *(vp2 + 8 * (ii + 1)) = *(vp2 + 8 * ii); \
140d4002b98SHong Zhang     } \
141d4002b98SHong Zhang     *(cp2 + 8 * _i) = col; \
142d4002b98SHong Zhang     *(vp2 + 8 * _i) = value; \
1439371c9d4SSatish Balay     b->nz++; \
1449371c9d4SSatish Balay     nrow2++; \
1459371c9d4SSatish Balay     B->nonzerostate++; \
146d4002b98SHong Zhang   b_noinsert:; \
147d4002b98SHong Zhang     b->rlen[row] = nrow2; \
148d4002b98SHong Zhang   }
149d4002b98SHong Zhang 
150d71ae5a4SJacob Faibussowitsch 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;
164d4002b98SHong Zhang   PetscInt    *cp1, *cp2, ii, _i, nrow1, nrow2, low1, high1, low2, high2, t, lastcol1, lastcol2;
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;
174d4002b98SHong Zhang       shift1   = a->sliidx[row >> 3] + (row & 0x07); /* starting index of the row */
175d4002b98SHong Zhang       cp1      = a->colidx + shift1;
176d4002b98SHong Zhang       vp1      = a->val + shift1;
177d4002b98SHong Zhang       nrow1    = a->rlen[row];
178d4002b98SHong Zhang       low1     = 0;
179d4002b98SHong Zhang       high1    = nrow1;
180d4002b98SHong Zhang       lastcol2 = -1;
181d4002b98SHong Zhang       shift2   = b->sliidx[row >> 3] + (row & 0x07); /* starting index of the row */
182d4002b98SHong Zhang       cp2      = b->colidx + shift2;
183d4002b98SHong Zhang       vp2      = 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 */
195f7d195e4SLawrence Mitchell         } else if (in[j] < 0) {
196f7d195e4SLawrence Mitchell           continue;
197f7d195e4SLawrence Mitchell         } else {
198f7d195e4SLawrence 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);
199d4002b98SHong Zhang           if (mat->was_assembled) {
20048a46eb9SPierre Jolivet             if (!sell->colmap) PetscCall(MatCreateColmap_MPISELL_Private(mat));
201d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE)
202eec179cfSJacob Faibussowitsch             PetscCall(PetscHMapIGetWithDefault(sell->colmap, in[j] + 1, 0, &col));
203d4002b98SHong Zhang             col--;
204d4002b98SHong Zhang #else
205d4002b98SHong Zhang             col = sell->colmap[in[j]] - 1;
206d4002b98SHong Zhang #endif
207d4002b98SHong Zhang             if (col < 0 && !((Mat_SeqSELL *)(sell->B->data))->nonew) {
2089566063dSJacob Faibussowitsch               PetscCall(MatDisAssemble_MPISELL(mat));
209d4002b98SHong Zhang               col = in[j];
210d4002b98SHong Zhang               /* Reinitialize the variables required by MatSetValues_SeqSELL_B_Private() */
211d4002b98SHong Zhang               B      = sell->B;
212d4002b98SHong Zhang               b      = (Mat_SeqSELL *)B->data;
213d4002b98SHong Zhang               shift2 = b->sliidx[row >> 3] + (row & 0x07); /* starting index of the row */
214d4002b98SHong Zhang               cp2    = b->colidx + shift2;
215d4002b98SHong Zhang               vp2    = b->val + shift2;
216d4002b98SHong Zhang               nrow2  = b->rlen[row];
217d4002b98SHong Zhang               low2   = 0;
218d4002b98SHong Zhang               high2  = nrow2;
219f7d195e4SLawrence Mitchell             } else {
220f7d195e4SLawrence 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]);
221f7d195e4SLawrence Mitchell             }
222d4002b98SHong Zhang           } else col = in[j];
223d4002b98SHong Zhang           MatSetValue_SeqSELL_Private(B, row, col, value, addv, im[i], in[j], cp2, vp2, lastcol2, low2, high2); /* set one value */
224d4002b98SHong Zhang         }
225d4002b98SHong Zhang       }
226d4002b98SHong Zhang     } else {
22728b400f6SJacob 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]);
228d4002b98SHong Zhang       if (!sell->donotstash) {
229d4002b98SHong Zhang         mat->assembled = PETSC_FALSE;
230d4002b98SHong Zhang         if (roworiented) {
2319566063dSJacob Faibussowitsch           PetscCall(MatStashValuesRow_Private(&mat->stash, im[i], n, in, v + i * n, (PetscBool)(ignorezeroentries && (addv == ADD_VALUES))));
232d4002b98SHong Zhang         } else {
2339566063dSJacob Faibussowitsch           PetscCall(MatStashValuesCol_Private(&mat->stash, im[i], n, in, v + i, m, (PetscBool)(ignorezeroentries && (addv == ADD_VALUES))));
234d4002b98SHong Zhang         }
235d4002b98SHong Zhang       }
236d4002b98SHong Zhang     }
237d4002b98SHong Zhang   }
2383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
239d4002b98SHong Zhang }
240d4002b98SHong Zhang 
241d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetValues_MPISELL(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], PetscScalar v[])
242d71ae5a4SJacob Faibussowitsch {
243d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
244d4002b98SHong Zhang   PetscInt     i, j, rstart = mat->rmap->rstart, rend = mat->rmap->rend;
245d4002b98SHong Zhang   PetscInt     cstart = mat->cmap->rstart, cend = mat->cmap->rend, row, col;
246d4002b98SHong Zhang 
247d4002b98SHong Zhang   PetscFunctionBegin;
248d4002b98SHong Zhang   for (i = 0; i < m; i++) {
24954c59aa7SJacob Faibussowitsch     if (idxm[i] < 0) continue; /* negative row */
25054c59aa7SJacob 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);
251d4002b98SHong Zhang     if (idxm[i] >= rstart && idxm[i] < rend) {
252d4002b98SHong Zhang       row = idxm[i] - rstart;
253d4002b98SHong Zhang       for (j = 0; j < n; j++) {
25454c59aa7SJacob Faibussowitsch         if (idxn[j] < 0) continue; /* negative column */
25554c59aa7SJacob 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);
256d4002b98SHong Zhang         if (idxn[j] >= cstart && idxn[j] < cend) {
257d4002b98SHong Zhang           col = idxn[j] - cstart;
2589566063dSJacob Faibussowitsch           PetscCall(MatGetValues(sell->A, 1, &row, 1, &col, v + i * n + j));
259d4002b98SHong Zhang         } else {
26048a46eb9SPierre Jolivet           if (!sell->colmap) PetscCall(MatCreateColmap_MPISELL_Private(mat));
261d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE)
262eec179cfSJacob Faibussowitsch           PetscCall(PetscHMapIGetWithDefault(sell->colmap, idxn[j] + 1, 0, &col));
263d4002b98SHong Zhang           col--;
264d4002b98SHong Zhang #else
265d4002b98SHong Zhang           col = sell->colmap[idxn[j]] - 1;
266d4002b98SHong Zhang #endif
267d4002b98SHong Zhang           if ((col < 0) || (sell->garray[col] != idxn[j])) *(v + i * n + j) = 0.0;
26848a46eb9SPierre Jolivet           else PetscCall(MatGetValues(sell->B, 1, &row, 1, &col, v + i * n + j));
269d4002b98SHong Zhang         }
270d4002b98SHong Zhang       }
271d4002b98SHong Zhang     } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only local values currently supported");
272d4002b98SHong Zhang   }
2733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
274d4002b98SHong Zhang }
275d4002b98SHong Zhang 
276d4002b98SHong Zhang extern PetscErrorCode MatMultDiagonalBlock_MPISELL(Mat, Vec, Vec);
277d4002b98SHong Zhang 
278d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAssemblyBegin_MPISELL(Mat mat, MatAssemblyType mode)
279d71ae5a4SJacob Faibussowitsch {
280d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
281d4002b98SHong Zhang   PetscInt     nstash, reallocs;
282d4002b98SHong Zhang 
283d4002b98SHong Zhang   PetscFunctionBegin;
2843ba16761SJacob Faibussowitsch   if (sell->donotstash || mat->nooffprocentries) PetscFunctionReturn(PETSC_SUCCESS);
285d4002b98SHong Zhang 
2869566063dSJacob Faibussowitsch   PetscCall(MatStashScatterBegin_Private(mat, &mat->stash, mat->rmap->range));
2879566063dSJacob Faibussowitsch   PetscCall(MatStashGetInfo_Private(&mat->stash, &nstash, &reallocs));
2889566063dSJacob Faibussowitsch   PetscCall(PetscInfo(sell->A, "Stash has %" PetscInt_FMT " entries, uses %" PetscInt_FMT " mallocs.\n", nstash, reallocs));
2893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
290d4002b98SHong Zhang }
291d4002b98SHong Zhang 
292d71ae5a4SJacob Faibussowitsch PetscErrorCode MatAssemblyEnd_MPISELL(Mat mat, MatAssemblyType mode)
293d71ae5a4SJacob Faibussowitsch {
294d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
295d4002b98SHong Zhang   PetscMPIInt  n;
296d4002b98SHong Zhang   PetscInt     i, flg;
297d4002b98SHong Zhang   PetscInt    *row, *col;
298d4002b98SHong Zhang   PetscScalar *val;
299d4002b98SHong Zhang   PetscBool    other_disassembled;
300d4002b98SHong Zhang   /* do not use 'b = (Mat_SeqSELL*)sell->B->data' as B can be reset in disassembly */
301d4002b98SHong Zhang   PetscFunctionBegin;
302d4002b98SHong Zhang   if (!sell->donotstash && !mat->nooffprocentries) {
303d4002b98SHong Zhang     while (1) {
3049566063dSJacob Faibussowitsch       PetscCall(MatStashScatterGetMesg_Private(&mat->stash, &n, &row, &col, &val, &flg));
305d4002b98SHong Zhang       if (!flg) break;
306d4002b98SHong Zhang 
307d4002b98SHong Zhang       for (i = 0; i < n; i++) { /* assemble one by one */
3089566063dSJacob Faibussowitsch         PetscCall(MatSetValues_MPISELL(mat, 1, row + i, 1, col + i, val + i, mat->insertmode));
309d4002b98SHong Zhang       }
310d4002b98SHong Zhang     }
3119566063dSJacob Faibussowitsch     PetscCall(MatStashScatterEnd_Private(&mat->stash));
312d4002b98SHong Zhang   }
3139566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(sell->A, mode));
3149566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(sell->A, mode));
315d4002b98SHong Zhang 
316d4002b98SHong Zhang   /*
317d4002b98SHong Zhang      determine if any processor has disassembled, if so we must
3186aad120cSJose E. Roman      also disassemble ourselves, in order that we may reassemble.
319d4002b98SHong Zhang   */
320d4002b98SHong Zhang   /*
321d4002b98SHong Zhang      if nonzero structure of submatrix B cannot change then we know that
322d4002b98SHong Zhang      no processor disassembled thus we can skip this stuff
323d4002b98SHong Zhang   */
324d4002b98SHong Zhang   if (!((Mat_SeqSELL *)sell->B->data)->nonew) {
3255f9db2b2SJunchao Zhang     PetscCall(MPIU_Allreduce(&mat->was_assembled, &other_disassembled, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat)));
32608401ef6SPierre Jolivet     PetscCheck(!mat->was_assembled || other_disassembled, PETSC_COMM_SELF, PETSC_ERR_SUP, "MatDisAssemble not implemented yet");
327d4002b98SHong Zhang   }
32848a46eb9SPierre Jolivet   if (!mat->was_assembled && mode == MAT_FINAL_ASSEMBLY) PetscCall(MatSetUpMultiply_MPISELL(mat));
329d4002b98SHong Zhang   /*
3309566063dSJacob Faibussowitsch   PetscCall(MatSetOption(sell->B,MAT_USE_INODES,PETSC_FALSE));
331d4002b98SHong Zhang   */
3329566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(sell->B, mode));
3339566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(sell->B, mode));
3349566063dSJacob Faibussowitsch   PetscCall(PetscFree2(sell->rowvalues, sell->rowindices));
335f4259b30SLisandro Dalcin   sell->rowvalues = NULL;
3369566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sell->diag));
337d4002b98SHong Zhang 
338d4002b98SHong Zhang   /* if no new nonzero locations are allowed in matrix then only set the matrix state the first time through */
339d4002b98SHong Zhang   if ((!mat->was_assembled && mode == MAT_FINAL_ASSEMBLY) || !((Mat_SeqSELL *)(sell->A->data))->nonew) {
340d4002b98SHong Zhang     PetscObjectState state = sell->A->nonzerostate + sell->B->nonzerostate;
3411c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&state, &mat->nonzerostate, 1, MPIU_INT64, MPI_SUM, PetscObjectComm((PetscObject)mat)));
342d4002b98SHong Zhang   }
3433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
344d4002b98SHong Zhang }
345d4002b98SHong Zhang 
346d71ae5a4SJacob Faibussowitsch PetscErrorCode MatZeroEntries_MPISELL(Mat A)
347d71ae5a4SJacob Faibussowitsch {
348d4002b98SHong Zhang   Mat_MPISELL *l = (Mat_MPISELL *)A->data;
349d4002b98SHong Zhang 
350d4002b98SHong Zhang   PetscFunctionBegin;
3519566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(l->A));
3529566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(l->B));
3533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
354d4002b98SHong Zhang }
355d4002b98SHong Zhang 
356d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMult_MPISELL(Mat A, Vec xx, Vec yy)
357d71ae5a4SJacob Faibussowitsch {
358d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
359d4002b98SHong Zhang   PetscInt     nt;
360d4002b98SHong Zhang 
361d4002b98SHong Zhang   PetscFunctionBegin;
3629566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(xx, &nt));
36308401ef6SPierre 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);
3649566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
3659566063dSJacob Faibussowitsch   PetscCall((*a->A->ops->mult)(a->A, xx, yy));
3669566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
3679566063dSJacob Faibussowitsch   PetscCall((*a->B->ops->multadd)(a->B, a->lvec, yy, yy));
3683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
369d4002b98SHong Zhang }
370d4002b98SHong Zhang 
371d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMultDiagonalBlock_MPISELL(Mat A, Vec bb, Vec xx)
372d71ae5a4SJacob Faibussowitsch {
373d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
374d4002b98SHong Zhang 
375d4002b98SHong Zhang   PetscFunctionBegin;
3769566063dSJacob Faibussowitsch   PetscCall(MatMultDiagonalBlock(a->A, bb, xx));
3773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
378d4002b98SHong Zhang }
379d4002b98SHong Zhang 
380d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMultAdd_MPISELL(Mat A, Vec xx, Vec yy, Vec zz)
381d71ae5a4SJacob Faibussowitsch {
382d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
383d4002b98SHong Zhang 
384d4002b98SHong Zhang   PetscFunctionBegin;
3859566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
3869566063dSJacob Faibussowitsch   PetscCall((*a->A->ops->multadd)(a->A, xx, yy, zz));
3879566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(a->Mvctx, xx, a->lvec, INSERT_VALUES, SCATTER_FORWARD));
3889566063dSJacob Faibussowitsch   PetscCall((*a->B->ops->multadd)(a->B, a->lvec, zz, zz));
3893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
390d4002b98SHong Zhang }
391d4002b98SHong Zhang 
392d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMultTranspose_MPISELL(Mat A, Vec xx, Vec yy)
393d71ae5a4SJacob Faibussowitsch {
394d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
395d4002b98SHong Zhang 
396d4002b98SHong Zhang   PetscFunctionBegin;
397d4002b98SHong Zhang   /* do nondiagonal part */
3989566063dSJacob Faibussowitsch   PetscCall((*a->B->ops->multtranspose)(a->B, xx, a->lvec));
399d4002b98SHong Zhang   /* do local part */
4009566063dSJacob Faibussowitsch   PetscCall((*a->A->ops->multtranspose)(a->A, xx, yy));
401a29b4eb7SJunchao Zhang   /* add partial results together */
4029566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(a->Mvctx, a->lvec, yy, ADD_VALUES, SCATTER_REVERSE));
4039566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(a->Mvctx, a->lvec, yy, ADD_VALUES, SCATTER_REVERSE));
4043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
405d4002b98SHong Zhang }
406d4002b98SHong Zhang 
407d71ae5a4SJacob Faibussowitsch PetscErrorCode MatIsTranspose_MPISELL(Mat Amat, Mat Bmat, PetscReal tol, PetscBool *f)
408d71ae5a4SJacob Faibussowitsch {
409d4002b98SHong Zhang   MPI_Comm     comm;
410d4002b98SHong Zhang   Mat_MPISELL *Asell = (Mat_MPISELL *)Amat->data, *Bsell;
411d4002b98SHong Zhang   Mat          Adia  = Asell->A, Bdia, Aoff, Boff, *Aoffs, *Boffs;
412d4002b98SHong Zhang   IS           Me, Notme;
413d4002b98SHong Zhang   PetscInt     M, N, first, last, *notme, i;
414d4002b98SHong Zhang   PetscMPIInt  size;
415d4002b98SHong Zhang 
416d4002b98SHong Zhang   PetscFunctionBegin;
417d4002b98SHong Zhang   /* Easy test: symmetric diagonal block */
4189371c9d4SSatish Balay   Bsell = (Mat_MPISELL *)Bmat->data;
4199371c9d4SSatish Balay   Bdia  = Bsell->A;
4209566063dSJacob Faibussowitsch   PetscCall(MatIsTranspose(Adia, Bdia, tol, f));
4213ba16761SJacob Faibussowitsch   if (!*f) PetscFunctionReturn(PETSC_SUCCESS);
4229566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)Amat, &comm));
4239566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
4243ba16761SJacob Faibussowitsch   if (size == 1) PetscFunctionReturn(PETSC_SUCCESS);
425d4002b98SHong Zhang 
426d4002b98SHong Zhang   /* Hard test: off-diagonal block. This takes a MatCreateSubMatrix. */
4279566063dSJacob Faibussowitsch   PetscCall(MatGetSize(Amat, &M, &N));
4289566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRange(Amat, &first, &last));
4299566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(N - last + first, &notme));
430d4002b98SHong Zhang   for (i = 0; i < first; i++) notme[i] = i;
431d4002b98SHong Zhang   for (i = last; i < M; i++) notme[i - last + first] = i;
4329566063dSJacob Faibussowitsch   PetscCall(ISCreateGeneral(MPI_COMM_SELF, N - last + first, notme, PETSC_COPY_VALUES, &Notme));
4339566063dSJacob Faibussowitsch   PetscCall(ISCreateStride(MPI_COMM_SELF, last - first, first, 1, &Me));
4349566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(Amat, 1, &Me, &Notme, MAT_INITIAL_MATRIX, &Aoffs));
435d4002b98SHong Zhang   Aoff = Aoffs[0];
4369566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(Bmat, 1, &Notme, &Me, MAT_INITIAL_MATRIX, &Boffs));
437d4002b98SHong Zhang   Boff = Boffs[0];
4389566063dSJacob Faibussowitsch   PetscCall(MatIsTranspose(Aoff, Boff, tol, f));
4399566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1, &Aoffs));
4409566063dSJacob Faibussowitsch   PetscCall(MatDestroyMatrices(1, &Boffs));
4419566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&Me));
4429566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&Notme));
4439566063dSJacob Faibussowitsch   PetscCall(PetscFree(notme));
4443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
445d4002b98SHong Zhang }
446d4002b98SHong Zhang 
447d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMultTransposeAdd_MPISELL(Mat A, Vec xx, Vec yy, Vec zz)
448d71ae5a4SJacob Faibussowitsch {
449d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
450d4002b98SHong Zhang 
451d4002b98SHong Zhang   PetscFunctionBegin;
452d4002b98SHong Zhang   /* do nondiagonal part */
4539566063dSJacob Faibussowitsch   PetscCall((*a->B->ops->multtranspose)(a->B, xx, a->lvec));
454d4002b98SHong Zhang   /* do local part */
4559566063dSJacob Faibussowitsch   PetscCall((*a->A->ops->multtransposeadd)(a->A, xx, yy, zz));
456e4a140f6SJunchao Zhang   /* add partial results together */
4579566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(a->Mvctx, a->lvec, zz, ADD_VALUES, SCATTER_REVERSE));
4589566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(a->Mvctx, a->lvec, zz, ADD_VALUES, SCATTER_REVERSE));
4593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
460d4002b98SHong Zhang }
461d4002b98SHong Zhang 
462d4002b98SHong Zhang /*
463d4002b98SHong Zhang   This only works correctly for square matrices where the subblock A->A is the
464d4002b98SHong Zhang    diagonal block
465d4002b98SHong Zhang */
466d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetDiagonal_MPISELL(Mat A, Vec v)
467d71ae5a4SJacob Faibussowitsch {
468d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
469d4002b98SHong Zhang 
470d4002b98SHong Zhang   PetscFunctionBegin;
47108401ef6SPierre Jolivet   PetscCheck(A->rmap->N == A->cmap->N, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Supports only square matrix where A->A is diag block");
472aed4548fSBarry 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");
4739566063dSJacob Faibussowitsch   PetscCall(MatGetDiagonal(a->A, v));
4743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
475d4002b98SHong Zhang }
476d4002b98SHong Zhang 
477d71ae5a4SJacob Faibussowitsch PetscErrorCode MatScale_MPISELL(Mat A, PetscScalar aa)
478d71ae5a4SJacob Faibussowitsch {
479d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
480d4002b98SHong Zhang 
481d4002b98SHong Zhang   PetscFunctionBegin;
4829566063dSJacob Faibussowitsch   PetscCall(MatScale(a->A, aa));
4839566063dSJacob Faibussowitsch   PetscCall(MatScale(a->B, aa));
4843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
485d4002b98SHong Zhang }
486d4002b98SHong Zhang 
487d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDestroy_MPISELL(Mat mat)
488d71ae5a4SJacob Faibussowitsch {
489d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
490d4002b98SHong Zhang 
491d4002b98SHong Zhang   PetscFunctionBegin;
492d4002b98SHong Zhang #if defined(PETSC_USE_LOG)
4933ba16761SJacob Faibussowitsch   PetscCall(PetscLogObjectState((PetscObject)mat, "Rows=%" PetscInt_FMT ", Cols=%" PetscInt_FMT, mat->rmap->N, mat->cmap->N));
494d4002b98SHong Zhang #endif
4959566063dSJacob Faibussowitsch   PetscCall(MatStashDestroy_Private(&mat->stash));
4969566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sell->diag));
4979566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sell->A));
4989566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&sell->B));
499d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE)
500eec179cfSJacob Faibussowitsch   PetscCall(PetscHMapIDestroy(&sell->colmap));
501d4002b98SHong Zhang #else
5029566063dSJacob Faibussowitsch   PetscCall(PetscFree(sell->colmap));
503d4002b98SHong Zhang #endif
5049566063dSJacob Faibussowitsch   PetscCall(PetscFree(sell->garray));
5059566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&sell->lvec));
5069566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&sell->Mvctx));
5079566063dSJacob Faibussowitsch   PetscCall(PetscFree2(sell->rowvalues, sell->rowindices));
5089566063dSJacob Faibussowitsch   PetscCall(PetscFree(sell->ld));
5099566063dSJacob Faibussowitsch   PetscCall(PetscFree(mat->data));
510d4002b98SHong Zhang 
5119566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)mat, NULL));
5129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatStoreValues_C", NULL));
5139566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatRetrieveValues_C", NULL));
5149566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatIsTranspose_C", NULL));
5159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatMPISELLSetPreallocation_C", NULL));
5169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatConvert_mpisell_mpiaij_C", NULL));
5179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)mat, "MatDiagonalScaleLocal_C", NULL));
5183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
519d4002b98SHong Zhang }
520d4002b98SHong Zhang 
521d4002b98SHong Zhang #include <petscdraw.h>
522d71ae5a4SJacob Faibussowitsch PetscErrorCode MatView_MPISELL_ASCIIorDraworSocket(Mat mat, PetscViewer viewer)
523d71ae5a4SJacob Faibussowitsch {
524d4002b98SHong Zhang   Mat_MPISELL      *sell = (Mat_MPISELL *)mat->data;
525d4002b98SHong Zhang   PetscMPIInt       rank = sell->rank, size = sell->size;
526d4002b98SHong Zhang   PetscBool         isdraw, iascii, isbinary;
527d4002b98SHong Zhang   PetscViewer       sviewer;
528d4002b98SHong Zhang   PetscViewerFormat format;
529d4002b98SHong Zhang 
530d4002b98SHong Zhang   PetscFunctionBegin;
5319566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
5329566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
5339566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
534d4002b98SHong Zhang   if (iascii) {
5359566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetFormat(viewer, &format));
536d4002b98SHong Zhang     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
537d4002b98SHong Zhang       MatInfo   info;
5386335e310SSatish Balay       PetscInt *inodes;
539d4002b98SHong Zhang 
5409566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)mat), &rank));
5419566063dSJacob Faibussowitsch       PetscCall(MatGetInfo(mat, MAT_LOCAL, &info));
5429566063dSJacob Faibussowitsch       PetscCall(MatInodeGetInodeSizes(sell->A, NULL, &inodes, NULL));
5439566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
544d4002b98SHong Zhang       if (!inodes) {
5459371c9d4SSatish 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,
5469371c9d4SSatish Balay                                                      (PetscInt)info.nz_allocated, (PetscInt)info.memory));
547d4002b98SHong Zhang       } else {
5489371c9d4SSatish 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,
5499371c9d4SSatish Balay                                                      (PetscInt)info.nz_allocated, (PetscInt)info.memory));
550d4002b98SHong Zhang       }
5519566063dSJacob Faibussowitsch       PetscCall(MatGetInfo(sell->A, MAT_LOCAL, &info));
5529566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] on-diagonal part: nz %" PetscInt_FMT " \n", rank, (PetscInt)info.nz_used));
5539566063dSJacob Faibussowitsch       PetscCall(MatGetInfo(sell->B, MAT_LOCAL, &info));
5549566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] off-diagonal part: nz %" PetscInt_FMT " \n", rank, (PetscInt)info.nz_used));
5559566063dSJacob Faibussowitsch       PetscCall(PetscViewerFlush(viewer));
5569566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
5579566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Information on VecScatter used in matrix-vector product: \n"));
5589566063dSJacob Faibussowitsch       PetscCall(VecScatterView(sell->Mvctx, viewer));
5593ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
560d4002b98SHong Zhang     } else if (format == PETSC_VIEWER_ASCII_INFO) {
561d4002b98SHong Zhang       PetscInt inodecount, inodelimit, *inodes;
5629566063dSJacob Faibussowitsch       PetscCall(MatInodeGetInodeSizes(sell->A, &inodecount, &inodes, &inodelimit));
563d4002b98SHong Zhang       if (inodes) {
5649566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "using I-node (on process 0) routines: found %" PetscInt_FMT " nodes, limit used is %" PetscInt_FMT "\n", inodecount, inodelimit));
565d4002b98SHong Zhang       } else {
5669566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "not using I-node (on process 0) routines\n"));
567d4002b98SHong Zhang       }
5683ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
569d4002b98SHong Zhang     } else if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
5703ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
571d4002b98SHong Zhang     }
572d4002b98SHong Zhang   } else if (isbinary) {
573d4002b98SHong Zhang     if (size == 1) {
5749566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)sell->A, ((PetscObject)mat)->name));
5759566063dSJacob Faibussowitsch       PetscCall(MatView(sell->A, viewer));
576d4002b98SHong Zhang     } else {
5779566063dSJacob Faibussowitsch       /* PetscCall(MatView_MPISELL_Binary(mat,viewer)); */
578d4002b98SHong Zhang     }
5793ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
580d4002b98SHong Zhang   } else if (isdraw) {
581d4002b98SHong Zhang     PetscDraw draw;
582d4002b98SHong Zhang     PetscBool isnull;
5839566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
5849566063dSJacob Faibussowitsch     PetscCall(PetscDrawIsNull(draw, &isnull));
5853ba16761SJacob Faibussowitsch     if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
586d4002b98SHong Zhang   }
587d4002b98SHong Zhang 
588d4002b98SHong Zhang   {
589d4002b98SHong Zhang     /* assemble the entire matrix onto first processor. */
590d4002b98SHong Zhang     Mat          A;
591d4002b98SHong Zhang     Mat_SeqSELL *Aloc;
592d4002b98SHong Zhang     PetscInt     M = mat->rmap->N, N = mat->cmap->N, *acolidx, row, col, i, j;
593d4002b98SHong Zhang     MatScalar   *aval;
594d4002b98SHong Zhang     PetscBool    isnonzero;
595d4002b98SHong Zhang 
5969566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &A));
597dd400576SPatrick Sanan     if (rank == 0) {
5989566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(A, M, N, M, N));
599d4002b98SHong Zhang     } else {
6009566063dSJacob Faibussowitsch       PetscCall(MatSetSizes(A, 0, 0, M, N));
601d4002b98SHong Zhang     }
602d4002b98SHong Zhang     /* This is just a temporary matrix, so explicitly using MATMPISELL is probably best */
6039566063dSJacob Faibussowitsch     PetscCall(MatSetType(A, MATMPISELL));
6049566063dSJacob Faibussowitsch     PetscCall(MatMPISELLSetPreallocation(A, 0, NULL, 0, NULL));
6059566063dSJacob Faibussowitsch     PetscCall(MatSetOption(A, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_FALSE));
606d4002b98SHong Zhang 
607d4002b98SHong Zhang     /* copy over the A part */
608d4002b98SHong Zhang     Aloc    = (Mat_SeqSELL *)sell->A->data;
6099371c9d4SSatish Balay     acolidx = Aloc->colidx;
6109371c9d4SSatish Balay     aval    = Aloc->val;
611d4002b98SHong Zhang     for (i = 0; i < Aloc->totalslices; i++) { /* loop over slices */
612d4002b98SHong Zhang       for (j = Aloc->sliidx[i]; j < Aloc->sliidx[i + 1]; j++) {
613d4002b98SHong Zhang         isnonzero = (PetscBool)((j - Aloc->sliidx[i]) / 8 < Aloc->rlen[(i << 3) + (j & 0x07)]);
614d4002b98SHong Zhang         if (isnonzero) {                                   /* check the mask bit */
615d4002b98SHong Zhang           row = (i << 3) + (j & 0x07) + mat->rmap->rstart; /* i<<3 is the starting row of this slice */
616d4002b98SHong Zhang           col = *acolidx + mat->rmap->rstart;
6179566063dSJacob Faibussowitsch           PetscCall(MatSetValues(A, 1, &row, 1, &col, aval, INSERT_VALUES));
618d4002b98SHong Zhang         }
6199371c9d4SSatish Balay         aval++;
6209371c9d4SSatish Balay         acolidx++;
621d4002b98SHong Zhang       }
622d4002b98SHong Zhang     }
623d4002b98SHong Zhang 
624d4002b98SHong Zhang     /* copy over the B part */
625d4002b98SHong Zhang     Aloc    = (Mat_SeqSELL *)sell->B->data;
6269371c9d4SSatish Balay     acolidx = Aloc->colidx;
6279371c9d4SSatish Balay     aval    = Aloc->val;
628d4002b98SHong Zhang     for (i = 0; i < Aloc->totalslices; i++) {
629d4002b98SHong Zhang       for (j = Aloc->sliidx[i]; j < Aloc->sliidx[i + 1]; j++) {
630d4002b98SHong Zhang         isnonzero = (PetscBool)((j - Aloc->sliidx[i]) / 8 < Aloc->rlen[(i << 3) + (j & 0x07)]);
631d4002b98SHong Zhang         if (isnonzero) {
632d4002b98SHong Zhang           row = (i << 3) + (j & 0x07) + mat->rmap->rstart;
633d4002b98SHong Zhang           col = sell->garray[*acolidx];
6349566063dSJacob Faibussowitsch           PetscCall(MatSetValues(A, 1, &row, 1, &col, aval, INSERT_VALUES));
635d4002b98SHong Zhang         }
6369371c9d4SSatish Balay         aval++;
6379371c9d4SSatish Balay         acolidx++;
638d4002b98SHong Zhang       }
639d4002b98SHong Zhang     }
640d4002b98SHong Zhang 
6419566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
6429566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
643d4002b98SHong Zhang     /*
644d4002b98SHong Zhang        Everyone has to call to draw the matrix since the graphics waits are
645d4002b98SHong Zhang        synchronized across all processors that share the PetscDraw object
646d4002b98SHong Zhang     */
6479566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
648dd400576SPatrick Sanan     if (rank == 0) {
6499566063dSJacob Faibussowitsch       PetscCall(PetscObjectSetName((PetscObject)((Mat_MPISELL *)(A->data))->A, ((PetscObject)mat)->name));
6509566063dSJacob Faibussowitsch       PetscCall(MatView_SeqSELL(((Mat_MPISELL *)(A->data))->A, sviewer));
651d4002b98SHong Zhang     }
6529566063dSJacob Faibussowitsch     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
6539566063dSJacob Faibussowitsch     PetscCall(PetscViewerFlush(viewer));
6549566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&A));
655d4002b98SHong Zhang   }
6563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
657d4002b98SHong Zhang }
658d4002b98SHong Zhang 
659d71ae5a4SJacob Faibussowitsch PetscErrorCode MatView_MPISELL(Mat mat, PetscViewer viewer)
660d71ae5a4SJacob Faibussowitsch {
661d4002b98SHong Zhang   PetscBool iascii, isdraw, issocket, isbinary;
662d4002b98SHong Zhang 
663d4002b98SHong Zhang   PetscFunctionBegin;
6649566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
6659566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
6669566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
6679566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSOCKET, &issocket));
66848a46eb9SPierre Jolivet   if (iascii || isdraw || isbinary || issocket) PetscCall(MatView_MPISELL_ASCIIorDraworSocket(mat, viewer));
6693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
670d4002b98SHong Zhang }
671d4002b98SHong Zhang 
672d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetGhosts_MPISELL(Mat mat, PetscInt *nghosts, const PetscInt *ghosts[])
673d71ae5a4SJacob Faibussowitsch {
674d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
675d4002b98SHong Zhang 
676d4002b98SHong Zhang   PetscFunctionBegin;
6779566063dSJacob Faibussowitsch   PetscCall(MatGetSize(sell->B, NULL, nghosts));
678d4002b98SHong Zhang   if (ghosts) *ghosts = sell->garray;
6793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
680d4002b98SHong Zhang }
681d4002b98SHong Zhang 
682d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetInfo_MPISELL(Mat matin, MatInfoType flag, MatInfo *info)
683d71ae5a4SJacob Faibussowitsch {
684d4002b98SHong Zhang   Mat_MPISELL   *mat = (Mat_MPISELL *)matin->data;
685d4002b98SHong Zhang   Mat            A = mat->A, B = mat->B;
6863966268fSBarry Smith   PetscLogDouble isend[5], irecv[5];
687d4002b98SHong Zhang 
688d4002b98SHong Zhang   PetscFunctionBegin;
689d4002b98SHong Zhang   info->block_size = 1.0;
6909566063dSJacob Faibussowitsch   PetscCall(MatGetInfo(A, MAT_LOCAL, info));
691d4002b98SHong Zhang 
6929371c9d4SSatish Balay   isend[0] = info->nz_used;
6939371c9d4SSatish Balay   isend[1] = info->nz_allocated;
6949371c9d4SSatish Balay   isend[2] = info->nz_unneeded;
6959371c9d4SSatish Balay   isend[3] = info->memory;
6969371c9d4SSatish Balay   isend[4] = info->mallocs;
697d4002b98SHong Zhang 
6989566063dSJacob Faibussowitsch   PetscCall(MatGetInfo(B, MAT_LOCAL, info));
699d4002b98SHong Zhang 
7009371c9d4SSatish Balay   isend[0] += info->nz_used;
7019371c9d4SSatish Balay   isend[1] += info->nz_allocated;
7029371c9d4SSatish Balay   isend[2] += info->nz_unneeded;
7039371c9d4SSatish Balay   isend[3] += info->memory;
7049371c9d4SSatish Balay   isend[4] += info->mallocs;
705d4002b98SHong Zhang   if (flag == MAT_LOCAL) {
706d4002b98SHong Zhang     info->nz_used      = isend[0];
707d4002b98SHong Zhang     info->nz_allocated = isend[1];
708d4002b98SHong Zhang     info->nz_unneeded  = isend[2];
709d4002b98SHong Zhang     info->memory       = isend[3];
710d4002b98SHong Zhang     info->mallocs      = isend[4];
711d4002b98SHong Zhang   } else if (flag == MAT_GLOBAL_MAX) {
7121c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)matin)));
713d4002b98SHong Zhang 
714d4002b98SHong Zhang     info->nz_used      = irecv[0];
715d4002b98SHong Zhang     info->nz_allocated = irecv[1];
716d4002b98SHong Zhang     info->nz_unneeded  = irecv[2];
717d4002b98SHong Zhang     info->memory       = irecv[3];
718d4002b98SHong Zhang     info->mallocs      = irecv[4];
719d4002b98SHong Zhang   } else if (flag == MAT_GLOBAL_SUM) {
7201c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)matin)));
721d4002b98SHong Zhang 
722d4002b98SHong Zhang     info->nz_used      = irecv[0];
723d4002b98SHong Zhang     info->nz_allocated = irecv[1];
724d4002b98SHong Zhang     info->nz_unneeded  = irecv[2];
725d4002b98SHong Zhang     info->memory       = irecv[3];
726d4002b98SHong Zhang     info->mallocs      = irecv[4];
727d4002b98SHong Zhang   }
728d4002b98SHong Zhang   info->fill_ratio_given  = 0; /* no parallel LU/ILU/Cholesky */
729d4002b98SHong Zhang   info->fill_ratio_needed = 0;
730d4002b98SHong Zhang   info->factor_mallocs    = 0;
7313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
732d4002b98SHong Zhang }
733d4002b98SHong Zhang 
734d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetOption_MPISELL(Mat A, MatOption op, PetscBool flg)
735d71ae5a4SJacob Faibussowitsch {
736d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
737d4002b98SHong Zhang 
738d4002b98SHong Zhang   PetscFunctionBegin;
739d4002b98SHong Zhang   switch (op) {
740d4002b98SHong Zhang   case MAT_NEW_NONZERO_LOCATIONS:
741d4002b98SHong Zhang   case MAT_NEW_NONZERO_ALLOCATION_ERR:
742d4002b98SHong Zhang   case MAT_UNUSED_NONZERO_LOCATION_ERR:
743d4002b98SHong Zhang   case MAT_KEEP_NONZERO_PATTERN:
744d4002b98SHong Zhang   case MAT_NEW_NONZERO_LOCATION_ERR:
745d4002b98SHong Zhang   case MAT_USE_INODES:
746d4002b98SHong Zhang   case MAT_IGNORE_ZERO_ENTRIES:
747d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7489566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
7499566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->B, op, flg));
750d4002b98SHong Zhang     break;
751d4002b98SHong Zhang   case MAT_ROW_ORIENTED:
752d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
753d4002b98SHong Zhang     a->roworiented = flg;
754d4002b98SHong Zhang 
7559566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
7569566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->B, op, flg));
757d4002b98SHong Zhang     break;
7588c78258cSHong Zhang   case MAT_FORCE_DIAGONAL_ENTRIES:
759d71ae5a4SJacob Faibussowitsch   case MAT_SORTED_FULL:
760d71ae5a4SJacob Faibussowitsch     PetscCall(PetscInfo(A, "Option %s ignored\n", MatOptions[op]));
761d71ae5a4SJacob Faibussowitsch     break;
762d71ae5a4SJacob Faibussowitsch   case MAT_IGNORE_OFF_PROC_ENTRIES:
763d71ae5a4SJacob Faibussowitsch     a->donotstash = flg;
764d71ae5a4SJacob Faibussowitsch     break;
765d4002b98SHong Zhang   case MAT_SPD:
766d71ae5a4SJacob Faibussowitsch   case MAT_SPD_ETERNAL:
767d71ae5a4SJacob Faibussowitsch     break;
768d4002b98SHong Zhang   case MAT_SYMMETRIC:
769d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7709566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
771d4002b98SHong Zhang     break;
772d4002b98SHong Zhang   case MAT_STRUCTURALLY_SYMMETRIC:
773d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7749566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
775d4002b98SHong Zhang     break;
776d4002b98SHong Zhang   case MAT_HERMITIAN:
777d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7789566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
779d4002b98SHong Zhang     break;
780d4002b98SHong Zhang   case MAT_SYMMETRY_ETERNAL:
781d4002b98SHong Zhang     MatCheckPreallocated(A, 1);
7829566063dSJacob Faibussowitsch     PetscCall(MatSetOption(a->A, op, flg));
783d4002b98SHong Zhang     break;
784b94d7dedSBarry Smith   case MAT_STRUCTURAL_SYMMETRY_ETERNAL:
785b94d7dedSBarry Smith     MatCheckPreallocated(A, 1);
786b94d7dedSBarry Smith     PetscCall(MatSetOption(a->A, op, flg));
787b94d7dedSBarry Smith     break;
788d71ae5a4SJacob Faibussowitsch   default:
789d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "unknown option %d", op);
790d4002b98SHong Zhang   }
7913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
792d4002b98SHong Zhang }
793d4002b98SHong Zhang 
794d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDiagonalScale_MPISELL(Mat mat, Vec ll, Vec rr)
795d71ae5a4SJacob Faibussowitsch {
796d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
797d4002b98SHong Zhang   Mat          a = sell->A, b = sell->B;
798d4002b98SHong Zhang   PetscInt     s1, s2, s3;
799d4002b98SHong Zhang 
800d4002b98SHong Zhang   PetscFunctionBegin;
8019566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat, &s2, &s3));
802d4002b98SHong Zhang   if (rr) {
8039566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(rr, &s1));
80408401ef6SPierre Jolivet     PetscCheck(s1 == s3, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "right vector non-conforming local size");
805d4002b98SHong Zhang     /* Overlap communication with computation. */
8069566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(sell->Mvctx, rr, sell->lvec, INSERT_VALUES, SCATTER_FORWARD));
807d4002b98SHong Zhang   }
808d4002b98SHong Zhang   if (ll) {
8099566063dSJacob Faibussowitsch     PetscCall(VecGetLocalSize(ll, &s1));
81008401ef6SPierre Jolivet     PetscCheck(s1 == s2, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "left vector non-conforming local size");
811dbbe0bcdSBarry Smith     PetscUseTypeMethod(b, diagonalscale, ll, NULL);
812d4002b98SHong Zhang   }
813d4002b98SHong Zhang   /* scale  the diagonal block */
814dbbe0bcdSBarry Smith   PetscUseTypeMethod(a, diagonalscale, ll, rr);
815d4002b98SHong Zhang 
816d4002b98SHong Zhang   if (rr) {
817d4002b98SHong Zhang     /* Do a scatter end and then right scale the off-diagonal block */
8189566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(sell->Mvctx, rr, sell->lvec, INSERT_VALUES, SCATTER_FORWARD));
819dbbe0bcdSBarry Smith     PetscUseTypeMethod(b, diagonalscale, NULL, sell->lvec);
820d4002b98SHong Zhang   }
8213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
822d4002b98SHong Zhang }
823d4002b98SHong Zhang 
824d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetUnfactored_MPISELL(Mat A)
825d71ae5a4SJacob Faibussowitsch {
826d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
827d4002b98SHong Zhang 
828d4002b98SHong Zhang   PetscFunctionBegin;
8299566063dSJacob Faibussowitsch   PetscCall(MatSetUnfactored(a->A));
8303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
831d4002b98SHong Zhang }
832d4002b98SHong Zhang 
833d71ae5a4SJacob Faibussowitsch PetscErrorCode MatEqual_MPISELL(Mat A, Mat B, PetscBool *flag)
834d71ae5a4SJacob Faibussowitsch {
835d4002b98SHong Zhang   Mat_MPISELL *matB = (Mat_MPISELL *)B->data, *matA = (Mat_MPISELL *)A->data;
836d4002b98SHong Zhang   Mat          a, b, c, d;
837d4002b98SHong Zhang   PetscBool    flg;
838d4002b98SHong Zhang 
839d4002b98SHong Zhang   PetscFunctionBegin;
8409371c9d4SSatish Balay   a = matA->A;
8419371c9d4SSatish Balay   b = matA->B;
8429371c9d4SSatish Balay   c = matB->A;
8439371c9d4SSatish Balay   d = matB->B;
844d4002b98SHong Zhang 
8459566063dSJacob Faibussowitsch   PetscCall(MatEqual(a, c, &flg));
84648a46eb9SPierre Jolivet   if (flg) PetscCall(MatEqual(b, d, &flg));
8471c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&flg, flag, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A)));
8483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
849d4002b98SHong Zhang }
850d4002b98SHong Zhang 
851d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCopy_MPISELL(Mat A, Mat B, MatStructure str)
852d71ae5a4SJacob Faibussowitsch {
853d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
854d4002b98SHong Zhang   Mat_MPISELL *b = (Mat_MPISELL *)B->data;
855d4002b98SHong Zhang 
856d4002b98SHong Zhang   PetscFunctionBegin;
857d4002b98SHong Zhang   /* If the two matrices don't have the same copy implementation, they aren't compatible for fast copy. */
858d4002b98SHong Zhang   if ((str != SAME_NONZERO_PATTERN) || (A->ops->copy != B->ops->copy)) {
859d4002b98SHong Zhang     /* because of the column compression in the off-processor part of the matrix a->B,
860d4002b98SHong Zhang        the number of columns in a->B and b->B may be different, hence we cannot call
861d4002b98SHong Zhang        the MatCopy() directly on the two parts. If need be, we can provide a more
862d4002b98SHong Zhang        efficient copy than the MatCopy_Basic() by first uncompressing the a->B matrices
863d4002b98SHong Zhang        then copying the submatrices */
8649566063dSJacob Faibussowitsch     PetscCall(MatCopy_Basic(A, B, str));
865d4002b98SHong Zhang   } else {
8669566063dSJacob Faibussowitsch     PetscCall(MatCopy(a->A, b->A, str));
8679566063dSJacob Faibussowitsch     PetscCall(MatCopy(a->B, b->B, str));
868d4002b98SHong Zhang   }
8693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
870d4002b98SHong Zhang }
871d4002b98SHong Zhang 
872d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetUp_MPISELL(Mat A)
873d71ae5a4SJacob Faibussowitsch {
874d4002b98SHong Zhang   PetscFunctionBegin;
8759566063dSJacob Faibussowitsch   PetscCall(MatMPISELLSetPreallocation(A, PETSC_DEFAULT, NULL, PETSC_DEFAULT, NULL));
8763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
877d4002b98SHong Zhang }
878d4002b98SHong Zhang 
879d4002b98SHong Zhang extern PetscErrorCode MatConjugate_SeqSELL(Mat);
880d4002b98SHong Zhang 
881d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConjugate_MPISELL(Mat mat)
882d71ae5a4SJacob Faibussowitsch {
8835f80ce2aSJacob Faibussowitsch   PetscFunctionBegin;
8845f80ce2aSJacob Faibussowitsch   if (PetscDefined(USE_COMPLEX)) {
885d4002b98SHong Zhang     Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
886d4002b98SHong Zhang 
8879566063dSJacob Faibussowitsch     PetscCall(MatConjugate_SeqSELL(sell->A));
8889566063dSJacob Faibussowitsch     PetscCall(MatConjugate_SeqSELL(sell->B));
8895f80ce2aSJacob Faibussowitsch   }
8903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
891d4002b98SHong Zhang }
892d4002b98SHong Zhang 
893d71ae5a4SJacob Faibussowitsch PetscErrorCode MatRealPart_MPISELL(Mat A)
894d71ae5a4SJacob Faibussowitsch {
895d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
896d4002b98SHong Zhang 
897d4002b98SHong Zhang   PetscFunctionBegin;
8989566063dSJacob Faibussowitsch   PetscCall(MatRealPart(a->A));
8999566063dSJacob Faibussowitsch   PetscCall(MatRealPart(a->B));
9003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
901d4002b98SHong Zhang }
902d4002b98SHong Zhang 
903d71ae5a4SJacob Faibussowitsch PetscErrorCode MatImaginaryPart_MPISELL(Mat A)
904d71ae5a4SJacob Faibussowitsch {
905d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
906d4002b98SHong Zhang 
907d4002b98SHong Zhang   PetscFunctionBegin;
9089566063dSJacob Faibussowitsch   PetscCall(MatImaginaryPart(a->A));
9099566063dSJacob Faibussowitsch   PetscCall(MatImaginaryPart(a->B));
9103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
911d4002b98SHong Zhang }
912d4002b98SHong Zhang 
913d71ae5a4SJacob Faibussowitsch PetscErrorCode MatInvertBlockDiagonal_MPISELL(Mat A, const PetscScalar **values)
914d71ae5a4SJacob Faibussowitsch {
915d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
916d4002b98SHong Zhang 
917d4002b98SHong Zhang   PetscFunctionBegin;
9189566063dSJacob Faibussowitsch   PetscCall(MatInvertBlockDiagonal(a->A, values));
919d4002b98SHong Zhang   A->factorerrortype = a->A->factorerrortype;
9203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
921d4002b98SHong Zhang }
922d4002b98SHong Zhang 
923d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_MPISELL(Mat x, PetscRandom rctx)
924d71ae5a4SJacob Faibussowitsch {
925d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)x->data;
926d4002b98SHong Zhang 
927d4002b98SHong Zhang   PetscFunctionBegin;
9289566063dSJacob Faibussowitsch   PetscCall(MatSetRandom(sell->A, rctx));
9299566063dSJacob Faibussowitsch   PetscCall(MatSetRandom(sell->B, rctx));
9309566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(x, MAT_FINAL_ASSEMBLY));
9319566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(x, MAT_FINAL_ASSEMBLY));
9323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
933d4002b98SHong Zhang }
934d4002b98SHong Zhang 
935d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSetFromOptions_MPISELL(Mat A, PetscOptionItems *PetscOptionsObject)
936d71ae5a4SJacob Faibussowitsch {
937d4002b98SHong Zhang   PetscFunctionBegin;
938d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "MPISELL options");
939d0609cedSBarry Smith   PetscOptionsHeadEnd();
9403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
941d4002b98SHong Zhang }
942d4002b98SHong Zhang 
943d71ae5a4SJacob Faibussowitsch PetscErrorCode MatShift_MPISELL(Mat Y, PetscScalar a)
944d71ae5a4SJacob Faibussowitsch {
945d4002b98SHong Zhang   Mat_MPISELL *msell = (Mat_MPISELL *)Y->data;
946d4002b98SHong Zhang   Mat_SeqSELL *sell  = (Mat_SeqSELL *)msell->A->data;
947d4002b98SHong Zhang 
948d4002b98SHong Zhang   PetscFunctionBegin;
949d4002b98SHong Zhang   if (!Y->preallocated) {
9509566063dSJacob Faibussowitsch     PetscCall(MatMPISELLSetPreallocation(Y, 1, NULL, 0, NULL));
951d4002b98SHong Zhang   } else if (!sell->nz) {
952d4002b98SHong Zhang     PetscInt nonew = sell->nonew;
9539566063dSJacob Faibussowitsch     PetscCall(MatSeqSELLSetPreallocation(msell->A, 1, NULL));
954d4002b98SHong Zhang     sell->nonew = nonew;
955d4002b98SHong Zhang   }
9569566063dSJacob Faibussowitsch   PetscCall(MatShift_Basic(Y, a));
9573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
958d4002b98SHong Zhang }
959d4002b98SHong Zhang 
960d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMissingDiagonal_MPISELL(Mat A, PetscBool *missing, PetscInt *d)
961d71ae5a4SJacob Faibussowitsch {
962d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
963d4002b98SHong Zhang 
964d4002b98SHong Zhang   PetscFunctionBegin;
96508401ef6SPierre Jolivet   PetscCheck(A->rmap->n == A->cmap->n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only works for square matrices");
9669566063dSJacob Faibussowitsch   PetscCall(MatMissingDiagonal(a->A, missing, d));
967d4002b98SHong Zhang   if (d) {
968d4002b98SHong Zhang     PetscInt rstart;
9699566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(A, &rstart, NULL));
970d4002b98SHong Zhang     *d += rstart;
971d4002b98SHong Zhang   }
9723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
973d4002b98SHong Zhang }
974d4002b98SHong Zhang 
975d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetDiagonalBlock_MPISELL(Mat A, Mat *a)
976d71ae5a4SJacob Faibussowitsch {
977d4002b98SHong Zhang   PetscFunctionBegin;
978d4002b98SHong Zhang   *a = ((Mat_MPISELL *)A->data)->A;
9793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
980d4002b98SHong Zhang }
981d4002b98SHong Zhang 
982d4002b98SHong Zhang /* -------------------------------------------------------------------*/
983d4002b98SHong Zhang static struct _MatOps MatOps_Values = {MatSetValues_MPISELL,
984f4259b30SLisandro Dalcin                                        NULL,
985f4259b30SLisandro Dalcin                                        NULL,
986d4002b98SHong Zhang                                        MatMult_MPISELL,
987d4002b98SHong Zhang                                        /* 4*/ MatMultAdd_MPISELL,
988d4002b98SHong Zhang                                        MatMultTranspose_MPISELL,
989d4002b98SHong Zhang                                        MatMultTransposeAdd_MPISELL,
990f4259b30SLisandro Dalcin                                        NULL,
991f4259b30SLisandro Dalcin                                        NULL,
992f4259b30SLisandro Dalcin                                        NULL,
993f4259b30SLisandro Dalcin                                        /*10*/ NULL,
994f4259b30SLisandro Dalcin                                        NULL,
995f4259b30SLisandro Dalcin                                        NULL,
996d4002b98SHong Zhang                                        MatSOR_MPISELL,
997f4259b30SLisandro Dalcin                                        NULL,
998d4002b98SHong Zhang                                        /*15*/ MatGetInfo_MPISELL,
999d4002b98SHong Zhang                                        MatEqual_MPISELL,
1000d4002b98SHong Zhang                                        MatGetDiagonal_MPISELL,
1001d4002b98SHong Zhang                                        MatDiagonalScale_MPISELL,
1002f4259b30SLisandro Dalcin                                        NULL,
1003d4002b98SHong Zhang                                        /*20*/ MatAssemblyBegin_MPISELL,
1004d4002b98SHong Zhang                                        MatAssemblyEnd_MPISELL,
1005d4002b98SHong Zhang                                        MatSetOption_MPISELL,
1006d4002b98SHong Zhang                                        MatZeroEntries_MPISELL,
1007f4259b30SLisandro Dalcin                                        /*24*/ NULL,
1008f4259b30SLisandro Dalcin                                        NULL,
1009f4259b30SLisandro Dalcin                                        NULL,
1010f4259b30SLisandro Dalcin                                        NULL,
1011f4259b30SLisandro Dalcin                                        NULL,
1012d4002b98SHong Zhang                                        /*29*/ MatSetUp_MPISELL,
1013f4259b30SLisandro Dalcin                                        NULL,
1014f4259b30SLisandro Dalcin                                        NULL,
1015d4002b98SHong Zhang                                        MatGetDiagonalBlock_MPISELL,
1016f4259b30SLisandro Dalcin                                        NULL,
1017d4002b98SHong Zhang                                        /*34*/ MatDuplicate_MPISELL,
1018f4259b30SLisandro Dalcin                                        NULL,
1019f4259b30SLisandro Dalcin                                        NULL,
1020f4259b30SLisandro Dalcin                                        NULL,
1021f4259b30SLisandro Dalcin                                        NULL,
1022f4259b30SLisandro Dalcin                                        /*39*/ NULL,
1023f4259b30SLisandro Dalcin                                        NULL,
1024f4259b30SLisandro Dalcin                                        NULL,
1025d4002b98SHong Zhang                                        MatGetValues_MPISELL,
1026d4002b98SHong Zhang                                        MatCopy_MPISELL,
1027f4259b30SLisandro Dalcin                                        /*44*/ NULL,
1028d4002b98SHong Zhang                                        MatScale_MPISELL,
1029d4002b98SHong Zhang                                        MatShift_MPISELL,
1030d4002b98SHong Zhang                                        MatDiagonalSet_MPISELL,
1031f4259b30SLisandro Dalcin                                        NULL,
1032d4002b98SHong Zhang                                        /*49*/ MatSetRandom_MPISELL,
1033f4259b30SLisandro Dalcin                                        NULL,
1034f4259b30SLisandro Dalcin                                        NULL,
1035f4259b30SLisandro Dalcin                                        NULL,
1036f4259b30SLisandro Dalcin                                        NULL,
1037d4002b98SHong Zhang                                        /*54*/ MatFDColoringCreate_MPIXAIJ,
1038f4259b30SLisandro Dalcin                                        NULL,
1039d4002b98SHong Zhang                                        MatSetUnfactored_MPISELL,
1040f4259b30SLisandro Dalcin                                        NULL,
1041f4259b30SLisandro Dalcin                                        NULL,
1042f4259b30SLisandro Dalcin                                        /*59*/ NULL,
1043d4002b98SHong Zhang                                        MatDestroy_MPISELL,
1044d4002b98SHong Zhang                                        MatView_MPISELL,
1045f4259b30SLisandro Dalcin                                        NULL,
1046f4259b30SLisandro Dalcin                                        NULL,
1047f4259b30SLisandro Dalcin                                        /*64*/ NULL,
1048f4259b30SLisandro Dalcin                                        NULL,
1049f4259b30SLisandro Dalcin                                        NULL,
1050f4259b30SLisandro Dalcin                                        NULL,
1051f4259b30SLisandro Dalcin                                        NULL,
1052f4259b30SLisandro Dalcin                                        /*69*/ NULL,
1053f4259b30SLisandro Dalcin                                        NULL,
1054f4259b30SLisandro Dalcin                                        NULL,
1055f4259b30SLisandro Dalcin                                        NULL,
1056f4259b30SLisandro Dalcin                                        NULL,
1057f4259b30SLisandro Dalcin                                        NULL,
1058d4002b98SHong Zhang                                        /*75*/ MatFDColoringApply_AIJ, /* reuse AIJ function */
1059d4002b98SHong Zhang                                        MatSetFromOptions_MPISELL,
1060f4259b30SLisandro Dalcin                                        NULL,
1061f4259b30SLisandro Dalcin                                        NULL,
1062f4259b30SLisandro Dalcin                                        NULL,
1063f4259b30SLisandro Dalcin                                        /*80*/ NULL,
1064f4259b30SLisandro Dalcin                                        NULL,
1065f4259b30SLisandro Dalcin                                        NULL,
1066f4259b30SLisandro Dalcin                                        /*83*/ NULL,
1067f4259b30SLisandro Dalcin                                        NULL,
1068f4259b30SLisandro Dalcin                                        NULL,
1069f4259b30SLisandro Dalcin                                        NULL,
1070f4259b30SLisandro Dalcin                                        NULL,
1071f4259b30SLisandro Dalcin                                        NULL,
1072f4259b30SLisandro Dalcin                                        /*89*/ NULL,
1073f4259b30SLisandro Dalcin                                        NULL,
1074f4259b30SLisandro Dalcin                                        NULL,
1075f4259b30SLisandro Dalcin                                        NULL,
1076f4259b30SLisandro Dalcin                                        NULL,
1077f4259b30SLisandro Dalcin                                        /*94*/ NULL,
1078f4259b30SLisandro Dalcin                                        NULL,
1079f4259b30SLisandro Dalcin                                        NULL,
1080f4259b30SLisandro Dalcin                                        NULL,
1081f4259b30SLisandro Dalcin                                        NULL,
1082f4259b30SLisandro Dalcin                                        /*99*/ NULL,
1083f4259b30SLisandro Dalcin                                        NULL,
1084f4259b30SLisandro Dalcin                                        NULL,
1085d4002b98SHong Zhang                                        MatConjugate_MPISELL,
1086f4259b30SLisandro Dalcin                                        NULL,
1087f4259b30SLisandro Dalcin                                        /*104*/ NULL,
1088d4002b98SHong Zhang                                        MatRealPart_MPISELL,
1089d4002b98SHong Zhang                                        MatImaginaryPart_MPISELL,
1090f4259b30SLisandro Dalcin                                        NULL,
1091f4259b30SLisandro Dalcin                                        NULL,
1092f4259b30SLisandro Dalcin                                        /*109*/ NULL,
1093f4259b30SLisandro Dalcin                                        NULL,
1094f4259b30SLisandro Dalcin                                        NULL,
1095f4259b30SLisandro Dalcin                                        NULL,
1096d4002b98SHong Zhang                                        MatMissingDiagonal_MPISELL,
1097f4259b30SLisandro Dalcin                                        /*114*/ NULL,
1098f4259b30SLisandro Dalcin                                        NULL,
1099d4002b98SHong Zhang                                        MatGetGhosts_MPISELL,
1100f4259b30SLisandro Dalcin                                        NULL,
1101f4259b30SLisandro Dalcin                                        NULL,
1102f4259b30SLisandro Dalcin                                        /*119*/ NULL,
1103f4259b30SLisandro Dalcin                                        NULL,
1104f4259b30SLisandro Dalcin                                        NULL,
1105f4259b30SLisandro Dalcin                                        NULL,
1106f4259b30SLisandro Dalcin                                        NULL,
1107f4259b30SLisandro Dalcin                                        /*124*/ NULL,
1108f4259b30SLisandro Dalcin                                        NULL,
1109d4002b98SHong Zhang                                        MatInvertBlockDiagonal_MPISELL,
1110f4259b30SLisandro Dalcin                                        NULL,
1111f4259b30SLisandro Dalcin                                        NULL,
1112f4259b30SLisandro Dalcin                                        /*129*/ NULL,
1113f4259b30SLisandro Dalcin                                        NULL,
1114f4259b30SLisandro Dalcin                                        NULL,
1115f4259b30SLisandro Dalcin                                        NULL,
1116f4259b30SLisandro Dalcin                                        NULL,
1117f4259b30SLisandro Dalcin                                        /*134*/ NULL,
1118f4259b30SLisandro Dalcin                                        NULL,
1119f4259b30SLisandro Dalcin                                        NULL,
1120f4259b30SLisandro Dalcin                                        NULL,
1121f4259b30SLisandro Dalcin                                        NULL,
1122f4259b30SLisandro Dalcin                                        /*139*/ NULL,
1123f4259b30SLisandro Dalcin                                        NULL,
1124f4259b30SLisandro Dalcin                                        NULL,
1125d4002b98SHong Zhang                                        MatFDColoringSetUp_MPIXAIJ,
1126f4259b30SLisandro Dalcin                                        NULL,
1127d70f29a3SPierre Jolivet                                        /*144*/ NULL,
1128d70f29a3SPierre Jolivet                                        NULL,
1129d70f29a3SPierre Jolivet                                        NULL,
113099a7f59eSMark Adams                                        NULL,
113199a7f59eSMark Adams                                        NULL,
11327fb60732SBarry Smith                                        NULL,
1133dec0b466SHong Zhang                                        /*150*/ NULL,
1134dec0b466SHong Zhang                                        NULL};
1135d4002b98SHong Zhang 
1136d4002b98SHong Zhang /* ----------------------------------------------------------------------------------------*/
1137d4002b98SHong Zhang 
1138d71ae5a4SJacob Faibussowitsch PetscErrorCode MatStoreValues_MPISELL(Mat mat)
1139d71ae5a4SJacob Faibussowitsch {
1140d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
1141d4002b98SHong Zhang 
1142d4002b98SHong Zhang   PetscFunctionBegin;
11439566063dSJacob Faibussowitsch   PetscCall(MatStoreValues(sell->A));
11449566063dSJacob Faibussowitsch   PetscCall(MatStoreValues(sell->B));
11453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1146d4002b98SHong Zhang }
1147d4002b98SHong Zhang 
1148d71ae5a4SJacob Faibussowitsch PetscErrorCode MatRetrieveValues_MPISELL(Mat mat)
1149d71ae5a4SJacob Faibussowitsch {
1150d4002b98SHong Zhang   Mat_MPISELL *sell = (Mat_MPISELL *)mat->data;
1151d4002b98SHong Zhang 
1152d4002b98SHong Zhang   PetscFunctionBegin;
11539566063dSJacob Faibussowitsch   PetscCall(MatRetrieveValues(sell->A));
11549566063dSJacob Faibussowitsch   PetscCall(MatRetrieveValues(sell->B));
11553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1156d4002b98SHong Zhang }
1157d4002b98SHong Zhang 
1158d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMPISELLSetPreallocation_MPISELL(Mat B, PetscInt d_rlenmax, const PetscInt d_rlen[], PetscInt o_rlenmax, const PetscInt o_rlen[])
1159d71ae5a4SJacob Faibussowitsch {
1160d4002b98SHong Zhang   Mat_MPISELL *b;
1161d4002b98SHong Zhang 
1162d4002b98SHong Zhang   PetscFunctionBegin;
11639566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(B->rmap));
11649566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(B->cmap));
1165d4002b98SHong Zhang   b = (Mat_MPISELL *)B->data;
1166d4002b98SHong Zhang 
1167d4002b98SHong Zhang   if (!B->preallocated) {
1168d4002b98SHong Zhang     /* Explicitly create 2 MATSEQSELL matrices. */
11699566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &b->A));
11709566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(b->A, B->rmap->n, B->cmap->n, B->rmap->n, B->cmap->n));
11719566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizesFromMats(b->A, B, B));
11729566063dSJacob Faibussowitsch     PetscCall(MatSetType(b->A, MATSEQSELL));
11739566063dSJacob Faibussowitsch     PetscCall(MatCreate(PETSC_COMM_SELF, &b->B));
11749566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(b->B, B->rmap->n, B->cmap->N, B->rmap->n, B->cmap->N));
11759566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizesFromMats(b->B, B, B));
11769566063dSJacob Faibussowitsch     PetscCall(MatSetType(b->B, MATSEQSELL));
1177d4002b98SHong Zhang   }
1178d4002b98SHong Zhang 
11799566063dSJacob Faibussowitsch   PetscCall(MatSeqSELLSetPreallocation(b->A, d_rlenmax, d_rlen));
11809566063dSJacob Faibussowitsch   PetscCall(MatSeqSELLSetPreallocation(b->B, o_rlenmax, o_rlen));
1181d4002b98SHong Zhang   B->preallocated  = PETSC_TRUE;
1182d4002b98SHong Zhang   B->was_assembled = PETSC_FALSE;
1183d4002b98SHong Zhang   /*
1184d4002b98SHong Zhang     critical for MatAssemblyEnd to work.
1185d4002b98SHong Zhang     MatAssemblyBegin checks it to set up was_assembled
1186d4002b98SHong Zhang     and MatAssemblyEnd checks was_assembled to determine whether to build garray
1187d4002b98SHong Zhang   */
1188d4002b98SHong Zhang   B->assembled = PETSC_FALSE;
11893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1190d4002b98SHong Zhang }
1191d4002b98SHong Zhang 
1192d71ae5a4SJacob Faibussowitsch PetscErrorCode MatDuplicate_MPISELL(Mat matin, MatDuplicateOption cpvalues, Mat *newmat)
1193d71ae5a4SJacob Faibussowitsch {
1194d4002b98SHong Zhang   Mat          mat;
1195d4002b98SHong Zhang   Mat_MPISELL *a, *oldmat = (Mat_MPISELL *)matin->data;
1196d4002b98SHong Zhang 
1197d4002b98SHong Zhang   PetscFunctionBegin;
1198f4259b30SLisandro Dalcin   *newmat = NULL;
11999566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)matin), &mat));
12009566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(mat, matin->rmap->n, matin->cmap->n, matin->rmap->N, matin->cmap->N));
12019566063dSJacob Faibussowitsch   PetscCall(MatSetBlockSizesFromMats(mat, matin, matin));
12029566063dSJacob Faibussowitsch   PetscCall(MatSetType(mat, ((PetscObject)matin)->type_name));
1203d4002b98SHong Zhang   a = (Mat_MPISELL *)mat->data;
1204d4002b98SHong Zhang 
1205d4002b98SHong Zhang   mat->factortype   = matin->factortype;
1206d4002b98SHong Zhang   mat->assembled    = PETSC_TRUE;
1207d4002b98SHong Zhang   mat->insertmode   = NOT_SET_VALUES;
1208d4002b98SHong Zhang   mat->preallocated = PETSC_TRUE;
1209d4002b98SHong Zhang 
1210d4002b98SHong Zhang   a->size         = oldmat->size;
1211d4002b98SHong Zhang   a->rank         = oldmat->rank;
1212d4002b98SHong Zhang   a->donotstash   = oldmat->donotstash;
1213d4002b98SHong Zhang   a->roworiented  = oldmat->roworiented;
1214f4259b30SLisandro Dalcin   a->rowindices   = NULL;
1215f4259b30SLisandro Dalcin   a->rowvalues    = NULL;
1216d4002b98SHong Zhang   a->getrowactive = PETSC_FALSE;
1217d4002b98SHong Zhang 
12189566063dSJacob Faibussowitsch   PetscCall(PetscLayoutReference(matin->rmap, &mat->rmap));
12199566063dSJacob Faibussowitsch   PetscCall(PetscLayoutReference(matin->cmap, &mat->cmap));
1220d4002b98SHong Zhang 
1221d4002b98SHong Zhang   if (oldmat->colmap) {
1222d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE)
1223eec179cfSJacob Faibussowitsch     PetscCall(PetscHMapIDuplicate(oldmat->colmap, &a->colmap));
1224d4002b98SHong Zhang #else
12259566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(mat->cmap->N, &a->colmap));
12269566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(a->colmap, oldmat->colmap, mat->cmap->N));
1227d4002b98SHong Zhang #endif
1228f4259b30SLisandro Dalcin   } else a->colmap = NULL;
1229d4002b98SHong Zhang   if (oldmat->garray) {
1230d4002b98SHong Zhang     PetscInt len;
1231d4002b98SHong Zhang     len = oldmat->B->cmap->n;
12329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(len + 1, &a->garray));
12339566063dSJacob Faibussowitsch     if (len) PetscCall(PetscArraycpy(a->garray, oldmat->garray, len));
1234f4259b30SLisandro Dalcin   } else a->garray = NULL;
1235d4002b98SHong Zhang 
12369566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(oldmat->lvec, &a->lvec));
12379566063dSJacob Faibussowitsch   PetscCall(VecScatterCopy(oldmat->Mvctx, &a->Mvctx));
12389566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(oldmat->A, cpvalues, &a->A));
12399566063dSJacob Faibussowitsch   PetscCall(MatDuplicate(oldmat->B, cpvalues, &a->B));
12409566063dSJacob Faibussowitsch   PetscCall(PetscFunctionListDuplicate(((PetscObject)matin)->qlist, &((PetscObject)mat)->qlist));
1241d4002b98SHong Zhang   *newmat = mat;
12423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1243d4002b98SHong Zhang }
1244d4002b98SHong Zhang 
1245d4002b98SHong Zhang /*@C
124611a5261eSBarry Smith    MatMPISELLSetPreallocation - Preallocates memory for a `MATMPISELL` sparse parallel matrix in sell format.
1247d4002b98SHong Zhang    For good matrix assembly performance the user should preallocate the matrix storage by
124867be906fSBarry Smith    setting the parameters `d_nz` (or `d_nnz`) and `o_nz` (or `o_nnz`).
1249d4002b98SHong Zhang 
1250d083f849SBarry Smith    Collective
1251d4002b98SHong Zhang 
1252d4002b98SHong Zhang    Input Parameters:
1253d4002b98SHong Zhang +  B - the matrix
1254d4002b98SHong Zhang .  d_nz  - number of nonzeros per row in DIAGONAL portion of local submatrix
1255d4002b98SHong Zhang            (same value is used for all local rows)
1256d4002b98SHong Zhang .  d_nnz - array containing the number of nonzeros in the various rows of the
1257d4002b98SHong Zhang            DIAGONAL portion of the local submatrix (possibly different for each row)
125867be906fSBarry Smith            or NULL (`PETSC_NULL_INTEGER` in Fortran), if `d_nz` is used to specify the nonzero structure.
1259d4002b98SHong Zhang            The size of this array is equal to the number of local rows, i.e 'm'.
1260d4002b98SHong Zhang            For matrices that will be factored, you must leave room for (and set)
1261d4002b98SHong Zhang            the diagonal entry even if it is zero.
1262d4002b98SHong Zhang .  o_nz  - number of nonzeros per row in the OFF-DIAGONAL portion of local
1263d4002b98SHong Zhang            submatrix (same value is used for all local rows).
1264d4002b98SHong Zhang -  o_nnz - array containing the number of nonzeros in the various rows of the
1265d4002b98SHong Zhang            OFF-DIAGONAL portion of the local submatrix (possibly different for
126667be906fSBarry Smith            each row) or NULL (`PETSC_NULL_INTEGER` in Fortran), if `o_nz` is used to specify the nonzero
1267d4002b98SHong Zhang            structure. The size of this array is equal to the number
1268d4002b98SHong Zhang            of local rows, i.e 'm'.
1269d4002b98SHong Zhang 
1270d4002b98SHong Zhang    Example usage:
1271d4002b98SHong Zhang    Consider the following 8x8 matrix with 34 non-zero values, that is
1272d4002b98SHong Zhang    assembled across 3 processors. Lets assume that proc0 owns 3 rows,
1273d4002b98SHong Zhang    proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
127467be906fSBarry Smith    as follows
1275d4002b98SHong Zhang 
1276d4002b98SHong Zhang .vb
1277d4002b98SHong Zhang             1  2  0  |  0  3  0  |  0  4
1278d4002b98SHong Zhang     Proc0   0  5  6  |  7  0  0  |  8  0
1279d4002b98SHong Zhang             9  0 10  | 11  0  0  | 12  0
1280d4002b98SHong Zhang     -------------------------------------
1281d4002b98SHong Zhang            13  0 14  | 15 16 17  |  0  0
1282d4002b98SHong Zhang     Proc1   0 18  0  | 19 20 21  |  0  0
1283d4002b98SHong Zhang             0  0  0  | 22 23  0  | 24  0
1284d4002b98SHong Zhang     -------------------------------------
1285d4002b98SHong Zhang     Proc2  25 26 27  |  0  0 28  | 29  0
1286d4002b98SHong Zhang            30  0  0  | 31 32 33  |  0 34
1287d4002b98SHong Zhang .ve
1288d4002b98SHong Zhang 
1289*27430b45SBarry Smith    This can be represented as a collection of submatrices as
1290d4002b98SHong Zhang 
1291d4002b98SHong Zhang .vb
1292d4002b98SHong Zhang       A B C
1293d4002b98SHong Zhang       D E F
1294d4002b98SHong Zhang       G H I
1295d4002b98SHong Zhang .ve
1296d4002b98SHong Zhang 
1297d4002b98SHong Zhang    Where the submatrices A,B,C are owned by proc0, D,E,F are
1298d4002b98SHong Zhang    owned by proc1, G,H,I are owned by proc2.
1299d4002b98SHong Zhang 
1300d4002b98SHong Zhang    The 'm' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
1301d4002b98SHong Zhang    The 'n' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
1302d4002b98SHong Zhang    The 'M','N' parameters are 8,8, and have the same values on all procs.
1303d4002b98SHong Zhang 
1304d4002b98SHong Zhang    The DIAGONAL submatrices corresponding to proc0,proc1,proc2 are
1305d4002b98SHong Zhang    submatrices [A], [E], [I] respectively. The OFF-DIAGONAL submatrices
1306d4002b98SHong Zhang    corresponding to proc0,proc1,proc2 are [BC], [DF], [GH] respectively.
1307d4002b98SHong Zhang    Internally, each processor stores the DIAGONAL part, and the OFF-DIAGONAL
1308*27430b45SBarry Smith    part as `MATSEQSELL` matrices. For example, proc1 will store [E] as a `MATSEQSELL`
1309d4002b98SHong Zhang    matrix, ans [DF] as another SeqSELL matrix.
1310d4002b98SHong Zhang 
131167be906fSBarry Smith    When `d_nz`, `o_nz` parameters are specified, `d_nz` storage elements are
1312d4002b98SHong Zhang    allocated for every row of the local diagonal submatrix, and o_nz
1313d4002b98SHong Zhang    storage locations are allocated for every row of the OFF-DIAGONAL submat.
131467be906fSBarry Smith    One way to choose `d_nz` and `o_nz` is to use the max nonzerors per local
1315d4002b98SHong Zhang    rows for each of the local DIAGONAL, and the OFF-DIAGONAL submatrices.
1316*27430b45SBarry Smith    In this case, the values of d_nz,o_nz are
1317d4002b98SHong Zhang .vb
1318*27430b45SBarry Smith      proc0  dnz = 2, o_nz = 2
1319*27430b45SBarry Smith      proc1  dnz = 3, o_nz = 2
1320*27430b45SBarry Smith      proc2  dnz = 1, o_nz = 4
1321d4002b98SHong Zhang .ve
1322d4002b98SHong Zhang    We are allocating m*(d_nz+o_nz) storage locations for every proc. This
1323d4002b98SHong Zhang    translates to 3*(2+2)=12 for proc0, 3*(3+2)=15 for proc1, 2*(1+4)=10
1324d4002b98SHong Zhang    for proc3. i.e we are using 12+15+10=37 storage locations to store
1325d4002b98SHong Zhang    34 values.
1326d4002b98SHong Zhang 
132767be906fSBarry Smith    When `d_nnz`, `o_nnz` parameters are specified, the storage is specified
1328a5b23f4aSJose E. Roman    for every row, corresponding to both DIAGONAL and OFF-DIAGONAL submatrices.
1329*27430b45SBarry Smith    In the above case the values for d_nnz,o_nnz are
1330d4002b98SHong Zhang .vb
1331*27430b45SBarry Smith      proc0 d_nnz = [2,2,2] and o_nnz = [2,2,2]
1332*27430b45SBarry Smith      proc1 d_nnz = [3,3,2] and o_nnz = [2,1,1]
1333*27430b45SBarry Smith      proc2 d_nnz = [1,1]   and o_nnz = [4,4]
1334d4002b98SHong Zhang .ve
1335d4002b98SHong Zhang    Here the space allocated is according to nz (or maximum values in the nnz
1336d4002b98SHong Zhang    if nnz is provided) for DIAGONAL and OFF-DIAGONAL submatrices, i.e (2+2+3+2)*3+(1+4)*2=37
1337d4002b98SHong Zhang 
1338d4002b98SHong Zhang    Level: intermediate
1339d4002b98SHong Zhang 
134067be906fSBarry Smith    Notes:
134167be906fSBarry Smith    If the *_nnz parameter is given then the *_nz parameter is ignored
134267be906fSBarry Smith 
134367be906fSBarry Smith    The stored row and column indices begin with zero.
134467be906fSBarry Smith 
134567be906fSBarry Smith    The parallel matrix is partitioned such that the first m0 rows belong to
134667be906fSBarry Smith    process 0, the next m1 rows belong to process 1, the next m2 rows belong
134767be906fSBarry Smith    to process 2 etc.. where m0,m1,m2... are the input parameter 'm'.
134867be906fSBarry Smith 
134967be906fSBarry Smith    The DIAGONAL portion of the local submatrix of a processor can be defined
135067be906fSBarry Smith    as the submatrix which is obtained by extraction the part corresponding to
135167be906fSBarry Smith    the rows r1-r2 and columns c1-c2 of the global matrix, where r1 is the
135267be906fSBarry Smith    first row that belongs to the processor, r2 is the last row belonging to
135367be906fSBarry Smith    the this processor, and c1-c2 is range of indices of the local part of a
135467be906fSBarry Smith    vector suitable for applying the matrix to.  This is an mxn matrix.  In the
135567be906fSBarry Smith    common case of a square matrix, the row and column ranges are the same and
135667be906fSBarry Smith    the DIAGONAL part is also square. The remaining portion of the local
135767be906fSBarry Smith    submatrix (mxN) constitute the OFF-DIAGONAL portion.
135867be906fSBarry Smith 
135967be906fSBarry Smith    If `o_nnz`, `d_nnz` are specified, then `o_nz`, and `d_nz` are ignored.
136067be906fSBarry Smith 
136167be906fSBarry Smith    You can call `MatGetInfo()` to get information on how effective the preallocation was;
136267be906fSBarry Smith    for example the fields mallocs,nz_allocated,nz_used,nz_unneeded;
136367be906fSBarry Smith    You can also run with the option -info and look for messages with the string
136467be906fSBarry Smith    malloc in them to see if additional memory allocation was needed.
136567be906fSBarry Smith 
136667be906fSBarry Smith .seealso: `Mat`, `MatCreate()`, `MatCreateSeqSELL()`, `MatSetValues()`, `MatCreatesell()`,
136711a5261eSBarry Smith           `MATMPISELL`, `MatGetInfo()`, `PetscSplitOwnership()`, `MATSELL`
1368d4002b98SHong Zhang @*/
1369d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMPISELLSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[])
1370d71ae5a4SJacob Faibussowitsch {
1371d4002b98SHong Zhang   PetscFunctionBegin;
1372d4002b98SHong Zhang   PetscValidHeaderSpecific(B, MAT_CLASSID, 1);
1373d4002b98SHong Zhang   PetscValidType(B, 1);
1374cac4c232SBarry Smith   PetscTryMethod(B, "MatMPISELLSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz));
13753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1376d4002b98SHong Zhang }
1377d4002b98SHong Zhang 
1378ed73aabaSBarry Smith /*MC
1379ed73aabaSBarry Smith    MATMPISELL - MATMPISELL = "mpisell" - A matrix type to be used for MPI sparse matrices,
1380ed73aabaSBarry Smith    based on the sliced Ellpack format
1381ed73aabaSBarry Smith 
1382*27430b45SBarry Smith    Options Database Key:
1383ed73aabaSBarry Smith . -mat_type sell - sets the matrix type to "seqsell" during a call to MatSetFromOptions()
1384ed73aabaSBarry Smith 
1385ed73aabaSBarry Smith    Level: beginner
1386ed73aabaSBarry Smith 
138767be906fSBarry Smith .seealso: `Mat`, `MatCreateSell()`, `MATSEQSELL`, `MATSELL`, `MATSEQAIJ`, `MATAIJ`, `MATMPIAIJ`
1388ed73aabaSBarry Smith M*/
1389ed73aabaSBarry Smith 
1390d4002b98SHong Zhang /*@C
139111a5261eSBarry Smith    MatCreateSELL - Creates a sparse parallel matrix in `MATSELL` format.
1392d4002b98SHong Zhang 
1393d083f849SBarry Smith    Collective
1394d4002b98SHong Zhang 
1395d4002b98SHong Zhang    Input Parameters:
1396d4002b98SHong Zhang +  comm - MPI communicator
139711a5261eSBarry Smith .  m - number of local rows (or `PETSC_DECIDE` to have calculated if M is given)
1398d4002b98SHong Zhang            This value should be the same as the local size used in creating the
1399d4002b98SHong Zhang            y vector for the matrix-vector product y = Ax.
1400d4002b98SHong Zhang .  n - This value should be the same as the local size used in creating the
1401d4002b98SHong Zhang        x vector for the matrix-vector product y = Ax. (or PETSC_DECIDE to have
1402d4002b98SHong Zhang        calculated if N is given) For square matrices n is almost always m.
140311a5261eSBarry Smith .  M - number of global rows (or `PETSC_DETERMINE` to have calculated if m is given)
140411a5261eSBarry Smith .  N - number of global columns (or `PETSC_DETERMINE` to have calculated if n is given)
1405d4002b98SHong Zhang .  d_rlenmax - max number of nonzeros per row in DIAGONAL portion of local submatrix
1406d4002b98SHong Zhang                (same value is used for all local rows)
1407d4002b98SHong Zhang .  d_rlen - array containing the number of nonzeros in the various rows of the
1408d4002b98SHong Zhang             DIAGONAL portion of the local submatrix (possibly different for each row)
1409d4002b98SHong Zhang             or NULL, if d_rlenmax is used to specify the nonzero structure.
1410d4002b98SHong Zhang             The size of this array is equal to the number of local rows, i.e 'm'.
1411d4002b98SHong Zhang .  o_rlenmax - max number of nonzeros per row in the OFF-DIAGONAL portion of local
1412d4002b98SHong Zhang                submatrix (same value is used for all local rows).
1413d4002b98SHong Zhang -  o_rlen - array containing the number of nonzeros in the various rows of the
1414d4002b98SHong Zhang             OFF-DIAGONAL portion of the local submatrix (possibly different for
1415d4002b98SHong Zhang             each row) or NULL, if o_rlenmax is used to specify the nonzero
1416d4002b98SHong Zhang             structure. The size of this array is equal to the number
1417d4002b98SHong Zhang             of local rows, i.e 'm'.
1418d4002b98SHong Zhang 
1419d4002b98SHong Zhang    Output Parameter:
1420d4002b98SHong Zhang .  A - the matrix
1421d4002b98SHong Zhang 
1422*27430b45SBarry Smith    Options Database Key:
1423*27430b45SBarry Smith -  -mat_sell_oneindex - Internally use indexing starting at 1
1424*27430b45SBarry Smith         rather than 0.  When calling `MatSetValues()`,
1425*27430b45SBarry Smith         the user still MUST index entries starting at 0!
1426*27430b45SBarry Smith 
1427*27430b45SBarry Smith    Example:
1428*27430b45SBarry Smith    Consider the following 8x8 matrix with 34 non-zero values, that is
1429*27430b45SBarry Smith    assembled across 3 processors. Lets assume that proc0 owns 3 rows,
1430*27430b45SBarry Smith    proc1 owns 3 rows, proc2 owns 2 rows. This division can be shown
1431*27430b45SBarry Smith    as follows
1432*27430b45SBarry Smith 
1433*27430b45SBarry Smith .vb
1434*27430b45SBarry Smith             1  2  0  |  0  3  0  |  0  4
1435*27430b45SBarry Smith     Proc0   0  5  6  |  7  0  0  |  8  0
1436*27430b45SBarry Smith             9  0 10  | 11  0  0  | 12  0
1437*27430b45SBarry Smith     -------------------------------------
1438*27430b45SBarry Smith            13  0 14  | 15 16 17  |  0  0
1439*27430b45SBarry Smith     Proc1   0 18  0  | 19 20 21  |  0  0
1440*27430b45SBarry Smith             0  0  0  | 22 23  0  | 24  0
1441*27430b45SBarry Smith     -------------------------------------
1442*27430b45SBarry Smith     Proc2  25 26 27  |  0  0 28  | 29  0
1443*27430b45SBarry Smith            30  0  0  | 31 32 33  |  0 34
1444*27430b45SBarry Smith .ve
1445*27430b45SBarry Smith 
1446*27430b45SBarry Smith    This can be represented as a collection of submatrices as:
1447*27430b45SBarry Smith 
1448*27430b45SBarry Smith .vb
1449*27430b45SBarry Smith       A B C
1450*27430b45SBarry Smith       D E F
1451*27430b45SBarry Smith       G H I
1452*27430b45SBarry Smith .ve
1453*27430b45SBarry Smith 
1454*27430b45SBarry Smith    Where the submatrices A,B,C are owned by proc0, D,E,F are
1455*27430b45SBarry Smith    owned by proc1, G,H,I are owned by proc2.
1456*27430b45SBarry Smith 
1457*27430b45SBarry Smith    The 'm' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
1458*27430b45SBarry Smith    The 'n' parameters for proc0,proc1,proc2 are 3,3,2 respectively.
1459*27430b45SBarry Smith    The 'M','N' parameters are 8,8, and have the same values on all procs.
1460*27430b45SBarry Smith 
1461*27430b45SBarry Smith    The DIAGONAL submatrices corresponding to proc0,proc1,proc2 are
1462*27430b45SBarry Smith    submatrices [A], [E], [I] respectively. The OFF-DIAGONAL submatrices
1463*27430b45SBarry Smith    corresponding to proc0,proc1,proc2 are [BC], [DF], [GH] respectively.
1464*27430b45SBarry Smith    Internally, each processor stores the DIAGONAL part, and the OFF-DIAGONAL
1465*27430b45SBarry Smith    part as `MATSEQSELL` matrices. For example, proc1 will store [E] as a `MATSEQSELL`
1466*27430b45SBarry Smith    matrix, ans [DF] as another `MATSEQSELL` matrix.
1467*27430b45SBarry Smith 
1468*27430b45SBarry Smith    When d_rlenmax, o_rlenmax parameters are specified, d_rlenmax storage elements are
1469*27430b45SBarry Smith    allocated for every row of the local diagonal submatrix, and o_rlenmax
1470*27430b45SBarry Smith    storage locations are allocated for every row of the OFF-DIAGONAL submat.
1471*27430b45SBarry Smith    One way to choose d_rlenmax and o_rlenmax is to use the max nonzerors per local
1472*27430b45SBarry Smith    rows for each of the local DIAGONAL, and the OFF-DIAGONAL submatrices.
1473*27430b45SBarry Smith    In this case, the values of d_rlenmax,o_rlenmax are:
1474*27430b45SBarry Smith .vb
1475*27430b45SBarry Smith      proc0 : d_rlenmax = 2, o_rlenmax = 2
1476*27430b45SBarry Smith      proc1 : d_rlenmax = 3, o_rlenmax = 2
1477*27430b45SBarry Smith      proc2 : d_rlenmax = 1, o_rlenmax = 4
1478*27430b45SBarry Smith .ve
1479*27430b45SBarry Smith    We are allocating m*(d_rlenmax+o_rlenmax) storage locations for every proc. This
1480*27430b45SBarry Smith    translates to 3*(2+2)=12 for proc0, 3*(3+2)=15 for proc1, 2*(1+4)=10
1481*27430b45SBarry Smith    for proc3. i.e we are using 12+15+10=37 storage locations to store
1482*27430b45SBarry Smith    34 values.
1483*27430b45SBarry Smith 
1484*27430b45SBarry Smith    When d_rlen, o_rlen parameters are specified, the storage is specified
1485*27430b45SBarry Smith    for every row, corresponding to both DIAGONAL and OFF-DIAGONAL submatrices.
1486*27430b45SBarry Smith    In the above case the values for d_nnz,o_nnz are:
1487*27430b45SBarry Smith .vb
1488*27430b45SBarry Smith      proc0: d_nnz = [2,2,2] and o_nnz = [2,2,2]
1489*27430b45SBarry Smith      proc1: d_nnz = [3,3,2] and o_nnz = [2,1,1]
1490*27430b45SBarry Smith      proc2: d_nnz = [1,1]   and o_nnz = [4,4]
1491*27430b45SBarry Smith .ve
1492*27430b45SBarry Smith    Here the space allocated is still 37 though there are 34 nonzeros because
1493*27430b45SBarry Smith    the allocation is always done according to rlenmax.
1494*27430b45SBarry Smith 
1495*27430b45SBarry Smith    Level: intermediate
1496*27430b45SBarry Smith 
1497*27430b45SBarry Smith    Notes:
149811a5261eSBarry Smith    It is recommended that one use the `MatCreate()`, `MatSetType()` and/or `MatSetFromOptions()`,
1499f6f02116SRichard Tran Mills    MatXXXXSetPreallocation() paradigm instead of this routine directly.
150011a5261eSBarry Smith    [MatXXXXSetPreallocation() is, for example, `MatSeqSELLSetPreallocation()`]
1501d4002b98SHong Zhang 
1502d4002b98SHong Zhang    If the *_rlen parameter is given then the *_rlenmax parameter is ignored
1503d4002b98SHong Zhang 
1504d4002b98SHong Zhang    m,n,M,N parameters specify the size of the matrix, and its partitioning across
1505d4002b98SHong Zhang    processors, while d_rlenmax,d_rlen,o_rlenmax,o_rlen parameters specify the approximate
1506d4002b98SHong Zhang    storage requirements for this matrix.
1507d4002b98SHong Zhang 
150811a5261eSBarry Smith    If `PETSC_DECIDE` or  `PETSC_DETERMINE` is used for a particular argument on one
1509d4002b98SHong Zhang    processor than it must be used on all processors that share the object for
1510d4002b98SHong Zhang    that argument.
1511d4002b98SHong Zhang 
1512d4002b98SHong Zhang    The user MUST specify either the local or global matrix dimensions
1513d4002b98SHong Zhang    (possibly both).
1514d4002b98SHong Zhang 
1515d4002b98SHong Zhang    The parallel matrix is partitioned across processors such that the
1516d4002b98SHong Zhang    first m0 rows belong to process 0, the next m1 rows belong to
1517d4002b98SHong Zhang    process 1, the next m2 rows belong to process 2 etc.. where
1518d4002b98SHong Zhang    m0,m1,m2,.. are the input parameter 'm'. i.e each processor stores
1519d4002b98SHong Zhang    values corresponding to [m x N] submatrix.
1520d4002b98SHong Zhang 
1521d4002b98SHong Zhang    The columns are logically partitioned with the n0 columns belonging
1522d4002b98SHong Zhang    to 0th partition, the next n1 columns belonging to the next
1523d4002b98SHong Zhang    partition etc.. where n0,n1,n2... are the input parameter 'n'.
1524d4002b98SHong Zhang 
1525d4002b98SHong Zhang    The DIAGONAL portion of the local submatrix on any given processor
1526d4002b98SHong Zhang    is the submatrix corresponding to the rows and columns m,n
1527d4002b98SHong Zhang    corresponding to the given processor. i.e diagonal matrix on
1528d4002b98SHong Zhang    process 0 is [m0 x n0], diagonal matrix on process 1 is [m1 x n1]
1529d4002b98SHong Zhang    etc. The remaining portion of the local submatrix [m x (N-n)]
1530d4002b98SHong Zhang    constitute the OFF-DIAGONAL portion. The example below better
1531d4002b98SHong Zhang    illustrates this concept.
1532d4002b98SHong Zhang 
1533d4002b98SHong Zhang    For a square global matrix we define each processor's diagonal portion
1534d4002b98SHong Zhang    to be its local rows and the corresponding columns (a square submatrix);
1535d4002b98SHong Zhang    each processor's off-diagonal portion encompasses the remainder of the
1536d4002b98SHong Zhang    local matrix (a rectangular submatrix).
1537d4002b98SHong Zhang 
1538d4002b98SHong Zhang    If o_rlen, d_rlen are specified, then o_rlenmax, and d_rlenmax are ignored.
1539d4002b98SHong Zhang 
1540d4002b98SHong Zhang    When calling this routine with a single process communicator, a matrix of
154111a5261eSBarry Smith    type `MATSEQSELL` is returned.  If a matrix of type `MATMPISELL` is desired for this
1542*27430b45SBarry Smith    type of communicator, use the construction mechanism
1543d4002b98SHong Zhang .vb
1544*27430b45SBarry Smith    MatCreate(...,&A);
1545*27430b45SBarry Smith    MatSetType(A,MATMPISELL);
1546*27430b45SBarry Smith    MatSetSizes(A, m,n,M,N);
1547*27430b45SBarry Smith    MatMPISELLSetPreallocation(A,...);
1548d4002b98SHong Zhang .ve
1549d4002b98SHong Zhang 
155067be906fSBarry Smith .seealso: `Mat`, `MATSELL`, `MatCreate()`, `MatCreateSeqSELL()`, `MatSetValues()`, `MatMPISELLSetPreallocation()`, `MatMPISELLSetPreallocationSELL()`,
1551db781477SPatrick Sanan           `MATMPISELL`, `MatCreateMPISELLWithArrays()`
1552d4002b98SHong Zhang @*/
1553d71ae5a4SJacob 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)
1554d71ae5a4SJacob Faibussowitsch {
1555d4002b98SHong Zhang   PetscMPIInt size;
1556d4002b98SHong Zhang 
1557d4002b98SHong Zhang   PetscFunctionBegin;
15589566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm, A));
15599566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*A, m, n, M, N));
15609566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
1561d4002b98SHong Zhang   if (size > 1) {
15629566063dSJacob Faibussowitsch     PetscCall(MatSetType(*A, MATMPISELL));
15639566063dSJacob Faibussowitsch     PetscCall(MatMPISELLSetPreallocation(*A, d_rlenmax, d_rlen, o_rlenmax, o_rlen));
1564d4002b98SHong Zhang   } else {
15659566063dSJacob Faibussowitsch     PetscCall(MatSetType(*A, MATSEQSELL));
15669566063dSJacob Faibussowitsch     PetscCall(MatSeqSELLSetPreallocation(*A, d_rlenmax, d_rlen));
1567d4002b98SHong Zhang   }
15683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1569d4002b98SHong Zhang }
1570d4002b98SHong Zhang 
1571d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMPISELLGetSeqSELL(Mat A, Mat *Ad, Mat *Ao, const PetscInt *colmap[])
1572d71ae5a4SJacob Faibussowitsch {
1573d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
1574d4002b98SHong Zhang   PetscBool    flg;
1575d4002b98SHong Zhang 
1576d4002b98SHong Zhang   PetscFunctionBegin;
15779566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPISELL, &flg));
157828b400f6SJacob Faibussowitsch   PetscCheck(flg, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "This function requires a MATMPISELL matrix as input");
1579d4002b98SHong Zhang   if (Ad) *Ad = a->A;
1580d4002b98SHong Zhang   if (Ao) *Ao = a->B;
1581d4002b98SHong Zhang   if (colmap) *colmap = a->garray;
15823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1583d4002b98SHong Zhang }
1584d4002b98SHong Zhang 
1585d4002b98SHong Zhang /*@C
158611a5261eSBarry Smith      MatMPISELLGetLocalMatCondensed - Creates a `MATSEQSELL` matrix from an `MATMPISELL` matrix by taking all its local rows and NON-ZERO columns
1587d4002b98SHong Zhang 
1588d4002b98SHong Zhang     Not Collective
1589d4002b98SHong Zhang 
1590d4002b98SHong Zhang    Input Parameters:
1591d4002b98SHong Zhang +    A - the matrix
159211a5261eSBarry Smith .    scall - either `MAT_INITIAL_MATRIX` or `MAT_REUSE_MATRIX`
159367be906fSBarry Smith .    row - index sets of rows to extract (or `NULL`)
159467be906fSBarry Smith -    col - index sets of columns to extract (or `NULL`)
1595d4002b98SHong Zhang 
1596d4002b98SHong Zhang    Output Parameter:
1597d4002b98SHong Zhang .    A_loc - the local sequential matrix generated
1598d4002b98SHong Zhang 
1599d4002b98SHong Zhang     Level: developer
1600d4002b98SHong Zhang 
160167be906fSBarry Smith .seealso: `Mat`, `MATSEQSELL`, `MATMPISELL`, `MatGetOwnershipRange()`, `MatMPISELLGetLocalMat()`
1602d4002b98SHong Zhang @*/
1603d71ae5a4SJacob Faibussowitsch PetscErrorCode MatMPISELLGetLocalMatCondensed(Mat A, MatReuse scall, IS *row, IS *col, Mat *A_loc)
1604d71ae5a4SJacob Faibussowitsch {
1605d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
1606d4002b98SHong Zhang   PetscInt     i, start, end, ncols, nzA, nzB, *cmap, imark, *idx;
1607d4002b98SHong Zhang   IS           isrowa, iscola;
1608d4002b98SHong Zhang   Mat         *aloc;
1609d4002b98SHong Zhang   PetscBool    match;
1610d4002b98SHong Zhang 
1611d4002b98SHong Zhang   PetscFunctionBegin;
16129566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)A, MATMPISELL, &match));
161328b400f6SJacob Faibussowitsch   PetscCheck(match, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Requires MATMPISELL matrix as input");
16149566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(MAT_Getlocalmatcondensed, A, 0, 0, 0));
1615d4002b98SHong Zhang   if (!row) {
16169371c9d4SSatish Balay     start = A->rmap->rstart;
16179371c9d4SSatish Balay     end   = A->rmap->rend;
16189566063dSJacob Faibussowitsch     PetscCall(ISCreateStride(PETSC_COMM_SELF, end - start, start, 1, &isrowa));
1619d4002b98SHong Zhang   } else {
1620d4002b98SHong Zhang     isrowa = *row;
1621d4002b98SHong Zhang   }
1622d4002b98SHong Zhang   if (!col) {
1623d4002b98SHong Zhang     start = A->cmap->rstart;
1624d4002b98SHong Zhang     cmap  = a->garray;
1625d4002b98SHong Zhang     nzA   = a->A->cmap->n;
1626d4002b98SHong Zhang     nzB   = a->B->cmap->n;
16279566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nzA + nzB, &idx));
1628d4002b98SHong Zhang     ncols = 0;
1629d4002b98SHong Zhang     for (i = 0; i < nzB; i++) {
1630d4002b98SHong Zhang       if (cmap[i] < start) idx[ncols++] = cmap[i];
1631d4002b98SHong Zhang       else break;
1632d4002b98SHong Zhang     }
1633d4002b98SHong Zhang     imark = i;
1634d4002b98SHong Zhang     for (i = 0; i < nzA; i++) idx[ncols++] = start + i;
1635d4002b98SHong Zhang     for (i = imark; i < nzB; i++) idx[ncols++] = cmap[i];
16369566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncols, idx, PETSC_OWN_POINTER, &iscola));
1637d4002b98SHong Zhang   } else {
1638d4002b98SHong Zhang     iscola = *col;
1639d4002b98SHong Zhang   }
1640d4002b98SHong Zhang   if (scall != MAT_INITIAL_MATRIX) {
16419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(1, &aloc));
1642d4002b98SHong Zhang     aloc[0] = *A_loc;
1643d4002b98SHong Zhang   }
16449566063dSJacob Faibussowitsch   PetscCall(MatCreateSubMatrices(A, 1, &isrowa, &iscola, scall, &aloc));
1645d4002b98SHong Zhang   *A_loc = aloc[0];
16469566063dSJacob Faibussowitsch   PetscCall(PetscFree(aloc));
164748a46eb9SPierre Jolivet   if (!row) PetscCall(ISDestroy(&isrowa));
164848a46eb9SPierre Jolivet   if (!col) PetscCall(ISDestroy(&iscola));
16499566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(MAT_Getlocalmatcondensed, A, 0, 0, 0));
16503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1651d4002b98SHong Zhang }
1652d4002b98SHong Zhang 
1653d4002b98SHong Zhang #include <../src/mat/impls/aij/mpi/mpiaij.h>
1654d4002b98SHong Zhang 
1655d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_MPISELL_MPIAIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1656d71ae5a4SJacob Faibussowitsch {
1657d4002b98SHong Zhang   Mat_MPISELL *a = (Mat_MPISELL *)A->data;
1658d4002b98SHong Zhang   Mat          B;
1659d4002b98SHong Zhang   Mat_MPIAIJ  *b;
1660d4002b98SHong Zhang 
1661d4002b98SHong Zhang   PetscFunctionBegin;
166228b400f6SJacob Faibussowitsch   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Matrix must be assembled");
1663d4002b98SHong Zhang 
166494a8b381SRichard Tran Mills   if (reuse == MAT_REUSE_MATRIX) {
166594a8b381SRichard Tran Mills     B = *newmat;
166694a8b381SRichard Tran Mills   } else {
16679566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
16689566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATMPIAIJ));
16699566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
16709566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, A->rmap->bs, A->cmap->bs));
16719566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(B, 0, NULL));
16729566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL));
167394a8b381SRichard Tran Mills   }
1674d4002b98SHong Zhang   b = (Mat_MPIAIJ *)B->data;
167594a8b381SRichard Tran Mills 
167694a8b381SRichard Tran Mills   if (reuse == MAT_REUSE_MATRIX) {
16779566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqSELL_SeqAIJ(a->A, MATSEQAIJ, MAT_REUSE_MATRIX, &b->A));
16789566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqSELL_SeqAIJ(a->B, MATSEQAIJ, MAT_REUSE_MATRIX, &b->B));
167994a8b381SRichard Tran Mills   } else {
16809566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b->A));
16819566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b->B));
16829566063dSJacob Faibussowitsch     PetscCall(MatDisAssemble_MPISELL(A));
16839566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqSELL_SeqAIJ(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &b->A));
16849566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqSELL_SeqAIJ(a->B, MATSEQAIJ, MAT_INITIAL_MATRIX, &b->B));
16859566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
16869566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
16879566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
16889566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
168994a8b381SRichard Tran Mills   }
1690d4002b98SHong Zhang 
1691d4002b98SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
16929566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1693d4002b98SHong Zhang   } else {
1694d4002b98SHong Zhang     *newmat = B;
1695d4002b98SHong Zhang   }
16963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1697d4002b98SHong Zhang }
1698d4002b98SHong Zhang 
1699d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_MPIAIJ_MPISELL(Mat A, MatType newtype, MatReuse reuse, Mat *newmat)
1700d71ae5a4SJacob Faibussowitsch {
1701d4002b98SHong Zhang   Mat_MPIAIJ  *a = (Mat_MPIAIJ *)A->data;
1702d4002b98SHong Zhang   Mat          B;
1703d4002b98SHong Zhang   Mat_MPISELL *b;
1704d4002b98SHong Zhang 
1705d4002b98SHong Zhang   PetscFunctionBegin;
170628b400f6SJacob Faibussowitsch   PetscCheck(A->assembled, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Matrix must be assembled");
1707d4002b98SHong Zhang 
170894a8b381SRichard Tran Mills   if (reuse == MAT_REUSE_MATRIX) {
170994a8b381SRichard Tran Mills     B = *newmat;
171094a8b381SRichard Tran Mills   } else {
17119566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &B));
17129566063dSJacob Faibussowitsch     PetscCall(MatSetType(B, MATMPISELL));
17139566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
17149566063dSJacob Faibussowitsch     PetscCall(MatSetBlockSizes(B, A->rmap->bs, A->cmap->bs));
17159566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJSetPreallocation(B, 0, NULL));
17169566063dSJacob Faibussowitsch     PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL));
171794a8b381SRichard Tran Mills   }
1718d4002b98SHong Zhang   b = (Mat_MPISELL *)B->data;
171994a8b381SRichard Tran Mills 
172094a8b381SRichard Tran Mills   if (reuse == MAT_REUSE_MATRIX) {
17219566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqAIJ_SeqSELL(a->A, MATSEQSELL, MAT_REUSE_MATRIX, &b->A));
17229566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqAIJ_SeqSELL(a->B, MATSEQSELL, MAT_REUSE_MATRIX, &b->B));
172394a8b381SRichard Tran Mills   } else {
17249566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b->A));
17259566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b->B));
17269566063dSJacob Faibussowitsch     PetscCall(MatDisAssemble_MPIAIJ(A));
17279566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqAIJ_SeqSELL(a->A, MATSEQSELL, MAT_INITIAL_MATRIX, &b->A));
17289566063dSJacob Faibussowitsch     PetscCall(MatConvert_SeqAIJ_SeqSELL(a->B, MATSEQSELL, MAT_INITIAL_MATRIX, &b->B));
17299566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
17309566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
17319566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
17329566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
173394a8b381SRichard Tran Mills   }
1734d4002b98SHong Zhang 
1735d4002b98SHong Zhang   if (reuse == MAT_INPLACE_MATRIX) {
17369566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A, &B));
1737d4002b98SHong Zhang   } else {
1738d4002b98SHong Zhang     *newmat = B;
1739d4002b98SHong Zhang   }
17403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1741d4002b98SHong Zhang }
1742d4002b98SHong Zhang 
1743d71ae5a4SJacob Faibussowitsch PetscErrorCode MatSOR_MPISELL(Mat matin, Vec bb, PetscReal omega, MatSORType flag, PetscReal fshift, PetscInt its, PetscInt lits, Vec xx)
1744d71ae5a4SJacob Faibussowitsch {
1745d4002b98SHong Zhang   Mat_MPISELL *mat = (Mat_MPISELL *)matin->data;
1746f4259b30SLisandro Dalcin   Vec          bb1 = NULL;
1747d4002b98SHong Zhang 
1748d4002b98SHong Zhang   PetscFunctionBegin;
1749d4002b98SHong Zhang   if (flag == SOR_APPLY_UPPER) {
17509566063dSJacob Faibussowitsch     PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx));
17513ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1752d4002b98SHong Zhang   }
1753d4002b98SHong Zhang 
175448a46eb9SPierre Jolivet   if (its > 1 || ~flag & SOR_ZERO_INITIAL_GUESS || flag & SOR_EISENSTAT) PetscCall(VecDuplicate(bb, &bb1));
1755d4002b98SHong Zhang 
1756d4002b98SHong Zhang   if ((flag & SOR_LOCAL_SYMMETRIC_SWEEP) == SOR_LOCAL_SYMMETRIC_SWEEP) {
1757d4002b98SHong Zhang     if (flag & SOR_ZERO_INITIAL_GUESS) {
17589566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx));
1759d4002b98SHong Zhang       its--;
1760d4002b98SHong Zhang     }
1761d4002b98SHong Zhang 
1762d4002b98SHong Zhang     while (its--) {
17639566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
17649566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1765d4002b98SHong Zhang 
1766d4002b98SHong Zhang       /* update rhs: bb1 = bb - B*x */
17679566063dSJacob Faibussowitsch       PetscCall(VecScale(mat->lvec, -1.0));
17689566063dSJacob Faibussowitsch       PetscCall((*mat->B->ops->multadd)(mat->B, mat->lvec, bb, bb1));
1769d4002b98SHong Zhang 
1770d4002b98SHong Zhang       /* local sweep */
17719566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb1, omega, SOR_SYMMETRIC_SWEEP, fshift, lits, 1, xx));
1772d4002b98SHong Zhang     }
1773d4002b98SHong Zhang   } else if (flag & SOR_LOCAL_FORWARD_SWEEP) {
1774d4002b98SHong Zhang     if (flag & SOR_ZERO_INITIAL_GUESS) {
17759566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx));
1776d4002b98SHong Zhang       its--;
1777d4002b98SHong Zhang     }
1778d4002b98SHong Zhang     while (its--) {
17799566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
17809566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1781d4002b98SHong Zhang 
1782d4002b98SHong Zhang       /* update rhs: bb1 = bb - B*x */
17839566063dSJacob Faibussowitsch       PetscCall(VecScale(mat->lvec, -1.0));
17849566063dSJacob Faibussowitsch       PetscCall((*mat->B->ops->multadd)(mat->B, mat->lvec, bb, bb1));
1785d4002b98SHong Zhang 
1786d4002b98SHong Zhang       /* local sweep */
17879566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb1, omega, SOR_FORWARD_SWEEP, fshift, lits, 1, xx));
1788d4002b98SHong Zhang     }
1789d4002b98SHong Zhang   } else if (flag & SOR_LOCAL_BACKWARD_SWEEP) {
1790d4002b98SHong Zhang     if (flag & SOR_ZERO_INITIAL_GUESS) {
17919566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb, omega, flag, fshift, lits, 1, xx));
1792d4002b98SHong Zhang       its--;
1793d4002b98SHong Zhang     }
1794d4002b98SHong Zhang     while (its--) {
17959566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
17969566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(mat->Mvctx, xx, mat->lvec, INSERT_VALUES, SCATTER_FORWARD));
1797d4002b98SHong Zhang 
1798d4002b98SHong Zhang       /* update rhs: bb1 = bb - B*x */
17999566063dSJacob Faibussowitsch       PetscCall(VecScale(mat->lvec, -1.0));
18009566063dSJacob Faibussowitsch       PetscCall((*mat->B->ops->multadd)(mat->B, mat->lvec, bb, bb1));
1801d4002b98SHong Zhang 
1802d4002b98SHong Zhang       /* local sweep */
18039566063dSJacob Faibussowitsch       PetscCall((*mat->A->ops->sor)(mat->A, bb1, omega, SOR_BACKWARD_SWEEP, fshift, lits, 1, xx));
1804d4002b98SHong Zhang     }
1805d4002b98SHong Zhang   } else SETERRQ(PetscObjectComm((PetscObject)matin), PETSC_ERR_SUP, "Parallel SOR not supported");
1806d4002b98SHong Zhang 
18079566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bb1));
1808d4002b98SHong Zhang 
1809d4002b98SHong Zhang   matin->factorerrortype = mat->A->factorerrortype;
18103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1811d4002b98SHong Zhang }
1812d4002b98SHong Zhang 
1813d4002b98SHong Zhang /*MC
1814d4002b98SHong Zhang    MATMPISELL - MATMPISELL = "MPISELL" - A matrix type to be used for parallel sparse matrices.
1815d4002b98SHong Zhang 
1816d4002b98SHong Zhang    Options Database Keys:
181711a5261eSBarry Smith . -mat_type mpisell - sets the matrix type to `MATMPISELL` during a call to `MatSetFromOptions()`
1818d4002b98SHong Zhang 
1819d4002b98SHong Zhang   Level: beginner
1820d4002b98SHong Zhang 
182167be906fSBarry Smith .seealso: `Mat`, `MATSELL`, `MATSEQSELL` `MatCreateSELL()`
1822d4002b98SHong Zhang M*/
1823d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_MPISELL(Mat B)
1824d71ae5a4SJacob Faibussowitsch {
1825d4002b98SHong Zhang   Mat_MPISELL *b;
1826d4002b98SHong Zhang   PetscMPIInt  size;
1827d4002b98SHong Zhang 
1828d4002b98SHong Zhang   PetscFunctionBegin;
18299566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)B), &size));
18304dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
1831d4002b98SHong Zhang   B->data = (void *)b;
18329566063dSJacob Faibussowitsch   PetscCall(PetscMemcpy(B->ops, &MatOps_Values, sizeof(struct _MatOps)));
1833d4002b98SHong Zhang   B->assembled  = PETSC_FALSE;
1834d4002b98SHong Zhang   B->insertmode = NOT_SET_VALUES;
1835d4002b98SHong Zhang   b->size       = size;
18369566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)B), &b->rank));
1837d4002b98SHong Zhang   /* build cache for off array entries formed */
18389566063dSJacob Faibussowitsch   PetscCall(MatStashCreate_Private(PetscObjectComm((PetscObject)B), 1, &B->stash));
1839d4002b98SHong Zhang 
1840d4002b98SHong Zhang   b->donotstash  = PETSC_FALSE;
1841f4259b30SLisandro Dalcin   b->colmap      = NULL;
1842f4259b30SLisandro Dalcin   b->garray      = NULL;
1843d4002b98SHong Zhang   b->roworiented = PETSC_TRUE;
1844d4002b98SHong Zhang 
1845d4002b98SHong Zhang   /* stuff used for matrix vector multiply */
1846d4002b98SHong Zhang   b->lvec  = NULL;
1847d4002b98SHong Zhang   b->Mvctx = NULL;
1848d4002b98SHong Zhang 
1849d4002b98SHong Zhang   /* stuff for MatGetRow() */
1850f4259b30SLisandro Dalcin   b->rowindices   = NULL;
1851f4259b30SLisandro Dalcin   b->rowvalues    = NULL;
1852d4002b98SHong Zhang   b->getrowactive = PETSC_FALSE;
1853d4002b98SHong Zhang 
18549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatStoreValues_C", MatStoreValues_MPISELL));
18559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatRetrieveValues_C", MatRetrieveValues_MPISELL));
18569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatIsTranspose_C", MatIsTranspose_MPISELL));
18579566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatMPISELLSetPreallocation_C", MatMPISELLSetPreallocation_MPISELL));
18589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatConvert_mpisell_mpiaij_C", MatConvert_MPISELL_MPIAIJ));
18599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)B, "MatDiagonalScaleLocal_C", MatDiagonalScaleLocal_MPISELL));
18609566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)B, MATMPISELL));
18613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1862d4002b98SHong Zhang }
1863