xref: /petsc/src/mat/impls/nest/matnest.c (revision 320466b00682f8f5c48e6d3ef9f50b2a8c6dcf69)
1d8588912SDave May 
2aaa7dc30SBarry Smith #include <../src/mat/impls/nest/matnestimpl.h> /*I   "petscmat.h"   I*/
3b68353e5Sstefano_zampini #include <../src/mat/impls/aij/seq/aij.h>
40c312b8eSJed Brown #include <petscsf.h>
5d8588912SDave May 
6c8883902SJed Brown static PetscErrorCode MatSetUp_NestIS_Private(Mat,PetscInt,const IS[],PetscInt,const IS[]);
706a1af2fSStefano Zampini static PetscErrorCode MatCreateVecs_Nest(Mat,Vec*,Vec*);
806a1af2fSStefano Zampini static PetscErrorCode MatReset_Nest(Mat);
906a1af2fSStefano Zampini 
105e3038f0Sstefano_zampini PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat,MatType,MatReuse,Mat*);
11c8883902SJed Brown 
12d8588912SDave May /* private functions */
138188e55aSJed Brown static PetscErrorCode MatNestGetSizes_Private(Mat A,PetscInt *m,PetscInt *n,PetscInt *M,PetscInt *N)
14d8588912SDave May {
15d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
168188e55aSJed Brown   PetscInt       i,j;
17d8588912SDave May   PetscErrorCode ierr;
18d8588912SDave May 
19d8588912SDave May   PetscFunctionBegin;
208188e55aSJed Brown   *m = *n = *M = *N = 0;
218188e55aSJed Brown   for (i=0; i<bA->nr; i++) {  /* rows */
228188e55aSJed Brown     PetscInt sm,sM;
238188e55aSJed Brown     ierr = ISGetLocalSize(bA->isglobal.row[i],&sm);CHKERRQ(ierr);
248188e55aSJed Brown     ierr = ISGetSize(bA->isglobal.row[i],&sM);CHKERRQ(ierr);
258188e55aSJed Brown     *m  += sm;
268188e55aSJed Brown     *M  += sM;
27d8588912SDave May   }
288188e55aSJed Brown   for (j=0; j<bA->nc; j++) {  /* cols */
298188e55aSJed Brown     PetscInt sn,sN;
308188e55aSJed Brown     ierr = ISGetLocalSize(bA->isglobal.col[j],&sn);CHKERRQ(ierr);
318188e55aSJed Brown     ierr = ISGetSize(bA->isglobal.col[j],&sN);CHKERRQ(ierr);
328188e55aSJed Brown     *n  += sn;
338188e55aSJed Brown     *N  += sN;
34d8588912SDave May   }
35d8588912SDave May   PetscFunctionReturn(0);
36d8588912SDave May }
37d8588912SDave May 
38d8588912SDave May /* operations */
39207556f9SJed Brown static PetscErrorCode MatMult_Nest(Mat A,Vec x,Vec y)
40d8588912SDave May {
41d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
42207556f9SJed Brown   Vec            *bx = bA->right,*by = bA->left;
43207556f9SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
44d8588912SDave May   PetscErrorCode ierr;
45d8588912SDave May 
46d8588912SDave May   PetscFunctionBegin;
47207556f9SJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(y,bA->isglobal.row[i],&by[i]);CHKERRQ(ierr);}
48207556f9SJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
49207556f9SJed Brown   for (i=0; i<nr; i++) {
50d8588912SDave May     ierr = VecZeroEntries(by[i]);CHKERRQ(ierr);
51207556f9SJed Brown     for (j=0; j<nc; j++) {
52207556f9SJed Brown       if (!bA->m[i][j]) continue;
53d8588912SDave May       /* y[i] <- y[i] + A[i][j] * x[j] */
54d8588912SDave May       ierr = MatMultAdd(bA->m[i][j],bx[j],by[i],by[i]);CHKERRQ(ierr);
55d8588912SDave May     }
56d8588912SDave May   }
57207556f9SJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.row[i],&by[i]);CHKERRQ(ierr);}
58207556f9SJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
59d8588912SDave May   PetscFunctionReturn(0);
60d8588912SDave May }
61d8588912SDave May 
629194d70fSJed Brown static PetscErrorCode MatMultAdd_Nest(Mat A,Vec x,Vec y,Vec z)
639194d70fSJed Brown {
649194d70fSJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
659194d70fSJed Brown   Vec            *bx = bA->right,*bz = bA->left;
669194d70fSJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
679194d70fSJed Brown   PetscErrorCode ierr;
689194d70fSJed Brown 
699194d70fSJed Brown   PetscFunctionBegin;
709194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(z,bA->isglobal.row[i],&bz[i]);CHKERRQ(ierr);}
719194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
729194d70fSJed Brown   for (i=0; i<nr; i++) {
739194d70fSJed Brown     if (y != z) {
749194d70fSJed Brown       Vec by;
759194d70fSJed Brown       ierr = VecGetSubVector(y,bA->isglobal.row[i],&by);CHKERRQ(ierr);
769194d70fSJed Brown       ierr = VecCopy(by,bz[i]);CHKERRQ(ierr);
77336d21e7SJed Brown       ierr = VecRestoreSubVector(y,bA->isglobal.row[i],&by);CHKERRQ(ierr);
789194d70fSJed Brown     }
799194d70fSJed Brown     for (j=0; j<nc; j++) {
809194d70fSJed Brown       if (!bA->m[i][j]) continue;
819194d70fSJed Brown       /* y[i] <- y[i] + A[i][j] * x[j] */
829194d70fSJed Brown       ierr = MatMultAdd(bA->m[i][j],bx[j],bz[i],bz[i]);CHKERRQ(ierr);
839194d70fSJed Brown     }
849194d70fSJed Brown   }
859194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(z,bA->isglobal.row[i],&bz[i]);CHKERRQ(ierr);}
869194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
879194d70fSJed Brown   PetscFunctionReturn(0);
889194d70fSJed Brown }
899194d70fSJed Brown 
90207556f9SJed Brown static PetscErrorCode MatMultTranspose_Nest(Mat A,Vec x,Vec y)
91d8588912SDave May {
92d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
93207556f9SJed Brown   Vec            *bx = bA->left,*by = bA->right;
94207556f9SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
95d8588912SDave May   PetscErrorCode ierr;
96d8588912SDave May 
97d8588912SDave May   PetscFunctionBegin;
98609e31cbSJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
99609e31cbSJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(y,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);}
100207556f9SJed Brown   for (j=0; j<nc; j++) {
101609e31cbSJed Brown     ierr = VecZeroEntries(by[j]);CHKERRQ(ierr);
102609e31cbSJed Brown     for (i=0; i<nr; i++) {
1036c75ac25SJed Brown       if (!bA->m[i][j]) continue;
104609e31cbSJed Brown       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
105609e31cbSJed Brown       ierr = MatMultTransposeAdd(bA->m[i][j],bx[i],by[j],by[j]);CHKERRQ(ierr);
106d8588912SDave May     }
107d8588912SDave May   }
108609e31cbSJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
109609e31cbSJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);}
110d8588912SDave May   PetscFunctionReturn(0);
111d8588912SDave May }
112d8588912SDave May 
1139194d70fSJed Brown static PetscErrorCode MatMultTransposeAdd_Nest(Mat A,Vec x,Vec y,Vec z)
1149194d70fSJed Brown {
1159194d70fSJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
1169194d70fSJed Brown   Vec            *bx = bA->left,*bz = bA->right;
1179194d70fSJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
1189194d70fSJed Brown   PetscErrorCode ierr;
1199194d70fSJed Brown 
1209194d70fSJed Brown   PetscFunctionBegin;
1219194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
1229194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(z,bA->isglobal.col[i],&bz[i]);CHKERRQ(ierr);}
1239194d70fSJed Brown   for (j=0; j<nc; j++) {
1249194d70fSJed Brown     if (y != z) {
1259194d70fSJed Brown       Vec by;
1269194d70fSJed Brown       ierr = VecGetSubVector(y,bA->isglobal.col[j],&by);CHKERRQ(ierr);
1279194d70fSJed Brown       ierr = VecCopy(by,bz[j]);CHKERRQ(ierr);
1289194d70fSJed Brown       ierr = VecRestoreSubVector(y,bA->isglobal.col[j],&by);CHKERRQ(ierr);
1299194d70fSJed Brown     }
1309194d70fSJed Brown     for (i=0; i<nr; i++) {
1316c75ac25SJed Brown       if (!bA->m[i][j]) continue;
1329194d70fSJed Brown       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
1339194d70fSJed Brown       ierr = MatMultTransposeAdd(bA->m[i][j],bx[i],bz[j],bz[j]);CHKERRQ(ierr);
1349194d70fSJed Brown     }
1359194d70fSJed Brown   }
1369194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
1379194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(z,bA->isglobal.col[i],&bz[i]);CHKERRQ(ierr);}
1389194d70fSJed Brown   PetscFunctionReturn(0);
1399194d70fSJed Brown }
1409194d70fSJed Brown 
141f8170845SAlex Fikl static PetscErrorCode MatTranspose_Nest(Mat A,MatReuse reuse,Mat *B)
142f8170845SAlex Fikl {
143f8170845SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data, *bC;
144f8170845SAlex Fikl   Mat            C;
145f8170845SAlex Fikl   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
146f8170845SAlex Fikl   PetscErrorCode ierr;
147f8170845SAlex Fikl 
148f8170845SAlex Fikl   PetscFunctionBegin;
149cf37664fSBarry Smith   if (reuse == MAT_INPLACE_MATRIX && nr != nc) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Square nested matrix only for in-place");
150f8170845SAlex Fikl 
151cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
152f8170845SAlex Fikl     Mat *subs;
153f8170845SAlex Fikl     IS  *is_row,*is_col;
154f8170845SAlex Fikl 
155f8170845SAlex Fikl     ierr = PetscCalloc1(nr * nc,&subs);CHKERRQ(ierr);
156f8170845SAlex Fikl     ierr = PetscMalloc2(nr,&is_row,nc,&is_col);CHKERRQ(ierr);
157f8170845SAlex Fikl     ierr = MatNestGetISs(A,is_row,is_col);CHKERRQ(ierr);
158cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
159ddeb9bd8SAlex Fikl       for (i=0; i<nr; i++) {
160ddeb9bd8SAlex Fikl         for (j=0; j<nc; j++) {
161ddeb9bd8SAlex Fikl           subs[i + nr * j] = bA->m[i][j];
162ddeb9bd8SAlex Fikl         }
163ddeb9bd8SAlex Fikl       }
164ddeb9bd8SAlex Fikl     }
165ddeb9bd8SAlex Fikl 
166f8170845SAlex Fikl     ierr = MatCreateNest(PetscObjectComm((PetscObject)A),nc,is_col,nr,is_row,subs,&C);CHKERRQ(ierr);
167f8170845SAlex Fikl     ierr = PetscFree(subs);CHKERRQ(ierr);
1683d994f23SBarry Smith     ierr = PetscFree2(is_row,is_col);CHKERRQ(ierr);
169f8170845SAlex Fikl   } else {
170f8170845SAlex Fikl     C = *B;
171f8170845SAlex Fikl   }
172f8170845SAlex Fikl 
173f8170845SAlex Fikl   bC = (Mat_Nest*)C->data;
174f8170845SAlex Fikl   for (i=0; i<nr; i++) {
175f8170845SAlex Fikl     for (j=0; j<nc; j++) {
176f8170845SAlex Fikl       if (bA->m[i][j]) {
177f8170845SAlex Fikl         ierr = MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i]));CHKERRQ(ierr);
178f8170845SAlex Fikl       } else {
179f8170845SAlex Fikl         bC->m[j][i] = NULL;
180f8170845SAlex Fikl       }
181f8170845SAlex Fikl     }
182f8170845SAlex Fikl   }
183f8170845SAlex Fikl 
184cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
185f8170845SAlex Fikl     *B = C;
186f8170845SAlex Fikl   } else {
187f8170845SAlex Fikl     ierr = MatHeaderMerge(A, &C);CHKERRQ(ierr);
188f8170845SAlex Fikl   }
189f8170845SAlex Fikl   PetscFunctionReturn(0);
190f8170845SAlex Fikl }
191f8170845SAlex Fikl 
192e2d7f03fSJed Brown static PetscErrorCode MatNestDestroyISList(PetscInt n,IS **list)
193e2d7f03fSJed Brown {
194e2d7f03fSJed Brown   PetscErrorCode ierr;
195e2d7f03fSJed Brown   IS             *lst = *list;
196e2d7f03fSJed Brown   PetscInt       i;
197e2d7f03fSJed Brown 
198e2d7f03fSJed Brown   PetscFunctionBegin;
199e2d7f03fSJed Brown   if (!lst) PetscFunctionReturn(0);
2006bf464f9SBarry Smith   for (i=0; i<n; i++) if (lst[i]) {ierr = ISDestroy(&lst[i]);CHKERRQ(ierr);}
201e2d7f03fSJed Brown   ierr  = PetscFree(lst);CHKERRQ(ierr);
2020298fd71SBarry Smith   *list = NULL;
203e2d7f03fSJed Brown   PetscFunctionReturn(0);
204e2d7f03fSJed Brown }
205e2d7f03fSJed Brown 
20606a1af2fSStefano Zampini static PetscErrorCode MatReset_Nest(Mat A)
207d8588912SDave May {
208d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
209d8588912SDave May   PetscInt       i,j;
210d8588912SDave May   PetscErrorCode ierr;
211d8588912SDave May 
212d8588912SDave May   PetscFunctionBegin;
213d8588912SDave May   /* release the matrices and the place holders */
214e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nr,&vs->isglobal.row);CHKERRQ(ierr);
215e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nc,&vs->isglobal.col);CHKERRQ(ierr);
216e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nr,&vs->islocal.row);CHKERRQ(ierr);
217e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nc,&vs->islocal.col);CHKERRQ(ierr);
218d8588912SDave May 
219d8588912SDave May   ierr = PetscFree(vs->row_len);CHKERRQ(ierr);
220d8588912SDave May   ierr = PetscFree(vs->col_len);CHKERRQ(ierr);
22106a1af2fSStefano Zampini   ierr = PetscFree(vs->nnzstate);CHKERRQ(ierr);
222d8588912SDave May 
223207556f9SJed Brown   ierr = PetscFree2(vs->left,vs->right);CHKERRQ(ierr);
224207556f9SJed Brown 
225d8588912SDave May   /* release the matrices and the place holders */
226d8588912SDave May   if (vs->m) {
227d8588912SDave May     for (i=0; i<vs->nr; i++) {
228d8588912SDave May       for (j=0; j<vs->nc; j++) {
2296bf464f9SBarry Smith         ierr = MatDestroy(&vs->m[i][j]);CHKERRQ(ierr);
230d8588912SDave May       }
231d8588912SDave May       ierr = PetscFree(vs->m[i]);CHKERRQ(ierr);
232d8588912SDave May     }
233d8588912SDave May     ierr = PetscFree(vs->m);CHKERRQ(ierr);
234d8588912SDave May   }
23506a1af2fSStefano Zampini 
23606a1af2fSStefano Zampini   /* restore defaults */
23706a1af2fSStefano Zampini   vs->nr = 0;
23806a1af2fSStefano Zampini   vs->nc = 0;
23906a1af2fSStefano Zampini   vs->splitassembly = PETSC_FALSE;
24006a1af2fSStefano Zampini   PetscFunctionReturn(0);
24106a1af2fSStefano Zampini }
24206a1af2fSStefano Zampini 
24306a1af2fSStefano Zampini static PetscErrorCode MatDestroy_Nest(Mat A)
24406a1af2fSStefano Zampini {
24506a1af2fSStefano Zampini   PetscErrorCode ierr;
24606a1af2fSStefano Zampini 
24706a1af2fSStefano Zampini   ierr = MatReset_Nest(A);CHKERRQ(ierr);
248bf0cc555SLisandro Dalcin   ierr = PetscFree(A->data);CHKERRQ(ierr);
249d8588912SDave May 
250bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",0);CHKERRQ(ierr);
251bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",0);CHKERRQ(ierr);
252bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",0);CHKERRQ(ierr);
253bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",0);CHKERRQ(ierr);
254bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",0);CHKERRQ(ierr);
255bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",0);CHKERRQ(ierr);
256bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",0);CHKERRQ(ierr);
257bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",0);CHKERRQ(ierr);
2580899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",0);CHKERRQ(ierr);
2590899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",0);CHKERRQ(ierr);
2605e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",0);CHKERRQ(ierr);
2615e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",0);CHKERRQ(ierr);
262d8588912SDave May   PetscFunctionReturn(0);
263d8588912SDave May }
264d8588912SDave May 
265207556f9SJed Brown static PetscErrorCode MatAssemblyBegin_Nest(Mat A,MatAssemblyType type)
266d8588912SDave May {
267d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
268d8588912SDave May   PetscInt       i,j;
269d8588912SDave May   PetscErrorCode ierr;
27006a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
271d8588912SDave May 
272d8588912SDave May   PetscFunctionBegin;
273d8588912SDave May   for (i=0; i<vs->nr; i++) {
274d8588912SDave May     for (j=0; j<vs->nc; j++) {
27506a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
276e7c19651SJed Brown       if (vs->m[i][j]) {
277e7c19651SJed Brown         ierr = MatAssemblyBegin(vs->m[i][j],type);CHKERRQ(ierr);
278e7c19651SJed Brown         if (!vs->splitassembly) {
279e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
280e7c19651SJed Brown            * sub-block). This could be fixed by adding a flag to Mat so that there was a way to check if a Mat was
281e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
282e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
283e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
284e7c19651SJed Brown            */
285e7c19651SJed Brown           ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr);
28606a1af2fSStefano Zampini           ierr = MatGetNonzeroState(vs->m[i][j],&subnnzstate);CHKERRQ(ierr);
287e7c19651SJed Brown         }
288e7c19651SJed Brown       }
28906a1af2fSStefano Zampini       nnzstate = (PetscBool)(nnzstate || vs->nnzstate[i*vs->nc+j] != subnnzstate);
29006a1af2fSStefano Zampini       vs->nnzstate[i*vs->nc+j] = subnnzstate;
291d8588912SDave May     }
292d8588912SDave May   }
29306a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
294d8588912SDave May   PetscFunctionReturn(0);
295d8588912SDave May }
296d8588912SDave May 
297207556f9SJed Brown static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
298d8588912SDave May {
299d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
300d8588912SDave May   PetscInt       i,j;
301d8588912SDave May   PetscErrorCode ierr;
302d8588912SDave May 
303d8588912SDave May   PetscFunctionBegin;
304d8588912SDave May   for (i=0; i<vs->nr; i++) {
305d8588912SDave May     for (j=0; j<vs->nc; j++) {
306e7c19651SJed Brown       if (vs->m[i][j]) {
307e7c19651SJed Brown         if (vs->splitassembly) {
308e7c19651SJed Brown           ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr);
309e7c19651SJed Brown         }
310e7c19651SJed Brown       }
311d8588912SDave May     }
312d8588912SDave May   }
313d8588912SDave May   PetscFunctionReturn(0);
314d8588912SDave May }
315d8588912SDave May 
316f349c1fdSJed Brown static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat *B)
317d8588912SDave May {
318207556f9SJed Brown   PetscErrorCode ierr;
319f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
320f349c1fdSJed Brown   PetscInt       j;
321f349c1fdSJed Brown   Mat            sub;
322d8588912SDave May 
323d8588912SDave May   PetscFunctionBegin;
3240298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
325f349c1fdSJed Brown   for (j=0; !sub && j<vs->nc; j++) sub = vs->m[row][j];
3264994cf47SJed Brown   if (sub) {ierr = MatSetUp(sub);CHKERRQ(ierr);}       /* Ensure that the sizes are available */
327f349c1fdSJed Brown   *B = sub;
328f349c1fdSJed Brown   PetscFunctionReturn(0);
329d8588912SDave May }
330d8588912SDave May 
331f349c1fdSJed Brown static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat *B)
332f349c1fdSJed Brown {
333207556f9SJed Brown   PetscErrorCode ierr;
334f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
335f349c1fdSJed Brown   PetscInt       i;
336f349c1fdSJed Brown   Mat            sub;
337f349c1fdSJed Brown 
338f349c1fdSJed Brown   PetscFunctionBegin;
3390298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
340f349c1fdSJed Brown   for (i=0; !sub && i<vs->nr; i++) sub = vs->m[i][col];
3414994cf47SJed Brown   if (sub) {ierr = MatSetUp(sub);CHKERRQ(ierr);}       /* Ensure that the sizes are available */
342f349c1fdSJed Brown   *B = sub;
343f349c1fdSJed Brown   PetscFunctionReturn(0);
344d8588912SDave May }
345d8588912SDave May 
346f349c1fdSJed Brown static PetscErrorCode MatNestFindIS(Mat A,PetscInt n,const IS list[],IS is,PetscInt *found)
347f349c1fdSJed Brown {
348f349c1fdSJed Brown   PetscErrorCode ierr;
349f349c1fdSJed Brown   PetscInt       i;
350f349c1fdSJed Brown   PetscBool      flg;
351f349c1fdSJed Brown 
352f349c1fdSJed Brown   PetscFunctionBegin;
353f349c1fdSJed Brown   PetscValidPointer(list,3);
354f349c1fdSJed Brown   PetscValidHeaderSpecific(is,IS_CLASSID,4);
355f349c1fdSJed Brown   PetscValidIntPointer(found,5);
356f349c1fdSJed Brown   *found = -1;
357f349c1fdSJed Brown   for (i=0; i<n; i++) {
358207556f9SJed Brown     if (!list[i]) continue;
359*320466b0SStefano Zampini     ierr = ISEqualUnsorted(list[i],is,&flg);CHKERRQ(ierr);
360f349c1fdSJed Brown     if (flg) {
361f349c1fdSJed Brown       *found = i;
362f349c1fdSJed Brown       PetscFunctionReturn(0);
363f349c1fdSJed Brown     }
364f349c1fdSJed Brown   }
365ce94432eSBarry Smith   SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Could not find index set");
366f349c1fdSJed Brown   PetscFunctionReturn(0);
367f349c1fdSJed Brown }
368f349c1fdSJed Brown 
3698188e55aSJed Brown /* Get a block row as a new MatNest */
3708188e55aSJed Brown static PetscErrorCode MatNestGetRow(Mat A,PetscInt row,Mat *B)
3718188e55aSJed Brown {
3728188e55aSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
3738188e55aSJed Brown   char           keyname[256];
3748188e55aSJed Brown   PetscErrorCode ierr;
3758188e55aSJed Brown 
3768188e55aSJed Brown   PetscFunctionBegin;
3770298fd71SBarry Smith   *B   = NULL;
3788caf3d72SBarry Smith   ierr = PetscSNPrintf(keyname,sizeof(keyname),"NestRow_%D",row);CHKERRQ(ierr);
3798188e55aSJed Brown   ierr = PetscObjectQuery((PetscObject)A,keyname,(PetscObject*)B);CHKERRQ(ierr);
3808188e55aSJed Brown   if (*B) PetscFunctionReturn(0);
3818188e55aSJed Brown 
382ce94432eSBarry Smith   ierr = MatCreateNest(PetscObjectComm((PetscObject)A),1,NULL,vs->nc,vs->isglobal.col,vs->m[row],B);CHKERRQ(ierr);
38326fbe8dcSKarl Rupp 
3848188e55aSJed Brown   (*B)->assembled = A->assembled;
38526fbe8dcSKarl Rupp 
3868188e55aSJed Brown   ierr = PetscObjectCompose((PetscObject)A,keyname,(PetscObject)*B);CHKERRQ(ierr);
3878188e55aSJed Brown   ierr = PetscObjectDereference((PetscObject)*B);CHKERRQ(ierr); /* Leave the only remaining reference in the composition */
3888188e55aSJed Brown   PetscFunctionReturn(0);
3898188e55aSJed Brown }
3908188e55aSJed Brown 
391f349c1fdSJed Brown static PetscErrorCode MatNestFindSubMat(Mat A,struct MatNestISPair *is,IS isrow,IS iscol,Mat *B)
392f349c1fdSJed Brown {
393f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
3948188e55aSJed Brown   PetscErrorCode ierr;
3956b3a5b13SJed Brown   PetscInt       row,col;
396e072481dSJed Brown   PetscBool      same,isFullCol,isFullColGlobal;
397f349c1fdSJed Brown 
398f349c1fdSJed Brown   PetscFunctionBegin;
3998188e55aSJed Brown   /* Check if full column space. This is a hack */
4008188e55aSJed Brown   isFullCol = PETSC_FALSE;
401251f4c67SDmitry Karpeev   ierr      = PetscObjectTypeCompare((PetscObject)iscol,ISSTRIDE,&same);CHKERRQ(ierr);
4028188e55aSJed Brown   if (same) {
40377019fcaSJed Brown     PetscInt n,first,step,i,an,am,afirst,astep;
4048188e55aSJed Brown     ierr      = ISStrideGetInfo(iscol,&first,&step);CHKERRQ(ierr);
4058188e55aSJed Brown     ierr      = ISGetLocalSize(iscol,&n);CHKERRQ(ierr);
40677019fcaSJed Brown     isFullCol = PETSC_TRUE;
40705ce4453SJed Brown     for (i=0,an=A->cmap->rstart; i<vs->nc; i++) {
40806a1af2fSStefano Zampini       ierr = PetscObjectTypeCompare((PetscObject)is->col[i],ISSTRIDE,&same);CHKERRQ(ierr);
40977019fcaSJed Brown       ierr = ISGetLocalSize(is->col[i],&am);CHKERRQ(ierr);
41006a1af2fSStefano Zampini       if (same) {
41106a1af2fSStefano Zampini         ierr = ISStrideGetInfo(is->col[i],&afirst,&astep);CHKERRQ(ierr);
41277019fcaSJed Brown         if (afirst != an || astep != step) isFullCol = PETSC_FALSE;
41306a1af2fSStefano Zampini       } else isFullCol = PETSC_FALSE;
41477019fcaSJed Brown       an += am;
41577019fcaSJed Brown     }
41605ce4453SJed Brown     if (an != A->cmap->rstart+n) isFullCol = PETSC_FALSE;
4178188e55aSJed Brown   }
418b2566f29SBarry Smith   ierr = MPIU_Allreduce(&isFullCol,&isFullColGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)iscol));CHKERRQ(ierr);
4198188e55aSJed Brown 
420427230ceSLisandro Dalcin   if (isFullColGlobal && vs->nc > 1) {
4218188e55aSJed Brown     PetscInt row;
4228188e55aSJed Brown     ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr);
4238188e55aSJed Brown     ierr = MatNestGetRow(A,row,B);CHKERRQ(ierr);
4248188e55aSJed Brown   } else {
425f349c1fdSJed Brown     ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr);
426f349c1fdSJed Brown     ierr = MatNestFindIS(A,vs->nc,is->col,iscol,&col);CHKERRQ(ierr);
427b6480e04SStefano Zampini     if (!vs->m[row][col]) {
428b6480e04SStefano Zampini       PetscInt lr,lc;
429b6480e04SStefano Zampini 
430b6480e04SStefano Zampini       ierr = MatCreate(PetscObjectComm((PetscObject)A),&vs->m[row][col]);CHKERRQ(ierr);
431b6480e04SStefano Zampini       ierr = ISGetLocalSize(vs->isglobal.row[row],&lr);CHKERRQ(ierr);
432b6480e04SStefano Zampini       ierr = ISGetLocalSize(vs->isglobal.col[col],&lc);CHKERRQ(ierr);
433b6480e04SStefano Zampini       ierr = MatSetSizes(vs->m[row][col],lr,lc,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
434fa9f0909SStefano Zampini       ierr = MatSetType(vs->m[row][col],MATAIJ);CHKERRQ(ierr);
435fa9f0909SStefano Zampini       ierr = MatSeqAIJSetPreallocation(vs->m[row][col],0,NULL);CHKERRQ(ierr);
436fa9f0909SStefano Zampini       ierr = MatMPIAIJSetPreallocation(vs->m[row][col],0,NULL,0,NULL);CHKERRQ(ierr);
437b6480e04SStefano Zampini       ierr = MatSetUp(vs->m[row][col]);CHKERRQ(ierr);
438b6480e04SStefano Zampini       ierr = MatAssemblyBegin(vs->m[row][col],MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
439b6480e04SStefano Zampini       ierr = MatAssemblyEnd(vs->m[row][col],MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
440b6480e04SStefano Zampini     }
441f349c1fdSJed Brown     *B = vs->m[row][col];
4428188e55aSJed Brown   }
443f349c1fdSJed Brown   PetscFunctionReturn(0);
444f349c1fdSJed Brown }
445f349c1fdSJed Brown 
44606a1af2fSStefano Zampini /*
44706a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
44806a1af2fSStefano Zampini */
4497dae84e0SHong Zhang static PetscErrorCode MatCreateSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat *B)
450f349c1fdSJed Brown {
451f349c1fdSJed Brown   PetscErrorCode ierr;
452f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
453f349c1fdSJed Brown   Mat            sub;
454f349c1fdSJed Brown 
455f349c1fdSJed Brown   PetscFunctionBegin;
456f349c1fdSJed Brown   ierr = MatNestFindSubMat(A,&vs->isglobal,isrow,iscol,&sub);CHKERRQ(ierr);
457f349c1fdSJed Brown   switch (reuse) {
458f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
4597874fa86SDave May     if (sub) { ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr); }
460f349c1fdSJed Brown     *B = sub;
461f349c1fdSJed Brown     break;
462f349c1fdSJed Brown   case MAT_REUSE_MATRIX:
463ce94432eSBarry Smith     if (sub != *B) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Submatrix was not used before in this call");
464f349c1fdSJed Brown     break;
465f349c1fdSJed Brown   case MAT_IGNORE_MATRIX:       /* Nothing to do */
466f349c1fdSJed Brown     break;
467511c6705SHong Zhang   case MAT_INPLACE_MATRIX:       /* Nothing to do */
468511c6705SHong Zhang     SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MAT_INPLACE_MATRIX is not supported yet");
469511c6705SHong Zhang     break;
470f349c1fdSJed Brown   }
471f349c1fdSJed Brown   PetscFunctionReturn(0);
472f349c1fdSJed Brown }
473f349c1fdSJed Brown 
474f349c1fdSJed Brown PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
475f349c1fdSJed Brown {
476f349c1fdSJed Brown   PetscErrorCode ierr;
477f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
478f349c1fdSJed Brown   Mat            sub;
479f349c1fdSJed Brown 
480f349c1fdSJed Brown   PetscFunctionBegin;
481f349c1fdSJed Brown   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
482f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
483f349c1fdSJed Brown   if (sub) {ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr);}
484f349c1fdSJed Brown   *B = sub;
485d8588912SDave May   PetscFunctionReturn(0);
486d8588912SDave May }
487d8588912SDave May 
488207556f9SJed Brown static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
489d8588912SDave May {
490d8588912SDave May   PetscErrorCode ierr;
491f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
492f349c1fdSJed Brown   Mat            sub;
493d8588912SDave May 
494d8588912SDave May   PetscFunctionBegin;
495f349c1fdSJed Brown   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
496ce94432eSBarry Smith   if (*B != sub) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has not been gotten");
497f349c1fdSJed Brown   if (sub) {
498ce94432eSBarry Smith     if (((PetscObject)sub)->refct <= 1) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has had reference count decremented too many times");
4996bf464f9SBarry Smith     ierr = MatDestroy(B);CHKERRQ(ierr);
500d8588912SDave May   }
501d8588912SDave May   PetscFunctionReturn(0);
502d8588912SDave May }
503d8588912SDave May 
5047874fa86SDave May static PetscErrorCode MatGetDiagonal_Nest(Mat A,Vec v)
5057874fa86SDave May {
5067874fa86SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
5077874fa86SDave May   PetscInt       i;
5087874fa86SDave May   PetscErrorCode ierr;
5097874fa86SDave May 
5107874fa86SDave May   PetscFunctionBegin;
5117874fa86SDave May   for (i=0; i<bA->nr; i++) {
512429bac76SJed Brown     Vec bv;
513429bac76SJed Brown     ierr = VecGetSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
5147874fa86SDave May     if (bA->m[i][i]) {
515429bac76SJed Brown       ierr = MatGetDiagonal(bA->m[i][i],bv);CHKERRQ(ierr);
5167874fa86SDave May     } else {
5175159a857SMatthew G. Knepley       ierr = VecSet(bv,0.0);CHKERRQ(ierr);
5187874fa86SDave May     }
519429bac76SJed Brown     ierr = VecRestoreSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
5207874fa86SDave May   }
5217874fa86SDave May   PetscFunctionReturn(0);
5227874fa86SDave May }
5237874fa86SDave May 
5247874fa86SDave May static PetscErrorCode MatDiagonalScale_Nest(Mat A,Vec l,Vec r)
5257874fa86SDave May {
5267874fa86SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
527429bac76SJed Brown   Vec            bl,*br;
5287874fa86SDave May   PetscInt       i,j;
5297874fa86SDave May   PetscErrorCode ierr;
5307874fa86SDave May 
5317874fa86SDave May   PetscFunctionBegin;
5323f800ebeSJed Brown   ierr = PetscCalloc1(bA->nc,&br);CHKERRQ(ierr);
5332e6472ebSElliott Sales de Andrade   if (r) {
534429bac76SJed Brown     for (j=0; j<bA->nc; j++) {ierr = VecGetSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);}
5352e6472ebSElliott Sales de Andrade   }
5362e6472ebSElliott Sales de Andrade   bl = NULL;
5377874fa86SDave May   for (i=0; i<bA->nr; i++) {
5382e6472ebSElliott Sales de Andrade     if (l) {
539429bac76SJed Brown       ierr = VecGetSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr);
5402e6472ebSElliott Sales de Andrade     }
5417874fa86SDave May     for (j=0; j<bA->nc; j++) {
5427874fa86SDave May       if (bA->m[i][j]) {
543429bac76SJed Brown         ierr = MatDiagonalScale(bA->m[i][j],bl,br[j]);CHKERRQ(ierr);
5447874fa86SDave May       }
5457874fa86SDave May     }
5462e6472ebSElliott Sales de Andrade     if (l) {
547a061e289SJed Brown       ierr = VecRestoreSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr);
5487874fa86SDave May     }
5492e6472ebSElliott Sales de Andrade   }
5502e6472ebSElliott Sales de Andrade   if (r) {
551429bac76SJed Brown     for (j=0; j<bA->nc; j++) {ierr = VecRestoreSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);}
5522e6472ebSElliott Sales de Andrade   }
553429bac76SJed Brown   ierr = PetscFree(br);CHKERRQ(ierr);
5547874fa86SDave May   PetscFunctionReturn(0);
5557874fa86SDave May }
5567874fa86SDave May 
557a061e289SJed Brown static PetscErrorCode MatScale_Nest(Mat A,PetscScalar a)
558a061e289SJed Brown {
559a061e289SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
560a061e289SJed Brown   PetscInt       i,j;
561a061e289SJed Brown   PetscErrorCode ierr;
562a061e289SJed Brown 
563a061e289SJed Brown   PetscFunctionBegin;
564a061e289SJed Brown   for (i=0; i<bA->nr; i++) {
565a061e289SJed Brown     for (j=0; j<bA->nc; j++) {
566a061e289SJed Brown       if (bA->m[i][j]) {
567a061e289SJed Brown         ierr = MatScale(bA->m[i][j],a);CHKERRQ(ierr);
568a061e289SJed Brown       }
569a061e289SJed Brown     }
570a061e289SJed Brown   }
571a061e289SJed Brown   PetscFunctionReturn(0);
572a061e289SJed Brown }
573a061e289SJed Brown 
574a061e289SJed Brown static PetscErrorCode MatShift_Nest(Mat A,PetscScalar a)
575a061e289SJed Brown {
576a061e289SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
577a061e289SJed Brown   PetscInt       i;
578a061e289SJed Brown   PetscErrorCode ierr;
57906a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
580a061e289SJed Brown 
581a061e289SJed Brown   PetscFunctionBegin;
582a061e289SJed Brown   for (i=0; i<bA->nr; i++) {
58306a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
584ce94432eSBarry Smith     if (!bA->m[i][i]) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support for shifting an empty diagonal block, insert a matrix in block (%D,%D)",i,i);
585a061e289SJed Brown     ierr = MatShift(bA->m[i][i],a);CHKERRQ(ierr);
58606a1af2fSStefano Zampini     ierr = MatGetNonzeroState(bA->m[i][i],&subnnzstate);CHKERRQ(ierr);
58706a1af2fSStefano Zampini     nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i*bA->nc+i] != subnnzstate);
58806a1af2fSStefano Zampini     bA->nnzstate[i*bA->nc+i] = subnnzstate;
589a061e289SJed Brown   }
59006a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
591a061e289SJed Brown   PetscFunctionReturn(0);
592a061e289SJed Brown }
593a061e289SJed Brown 
59413135bc6SAlex Fikl static PetscErrorCode MatDiagonalSet_Nest(Mat A,Vec D,InsertMode is)
59513135bc6SAlex Fikl {
59613135bc6SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data;
59713135bc6SAlex Fikl   PetscInt       i;
59813135bc6SAlex Fikl   PetscErrorCode ierr;
59906a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
60013135bc6SAlex Fikl 
60113135bc6SAlex Fikl   PetscFunctionBegin;
60213135bc6SAlex Fikl   for (i=0; i<bA->nr; i++) {
60306a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
60413135bc6SAlex Fikl     Vec              bv;
60513135bc6SAlex Fikl     ierr = VecGetSubVector(D,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
60613135bc6SAlex Fikl     if (bA->m[i][i]) {
60713135bc6SAlex Fikl       ierr = MatDiagonalSet(bA->m[i][i],bv,is);CHKERRQ(ierr);
60806a1af2fSStefano Zampini       ierr = MatGetNonzeroState(bA->m[i][i],&subnnzstate);CHKERRQ(ierr);
60913135bc6SAlex Fikl     }
61013135bc6SAlex Fikl     ierr = VecRestoreSubVector(D,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
61106a1af2fSStefano Zampini     nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i*bA->nc+i] != subnnzstate);
61206a1af2fSStefano Zampini     bA->nnzstate[i*bA->nc+i] = subnnzstate;
61313135bc6SAlex Fikl   }
61406a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
61513135bc6SAlex Fikl   PetscFunctionReturn(0);
61613135bc6SAlex Fikl }
61713135bc6SAlex Fikl 
618f8170845SAlex Fikl static PetscErrorCode MatSetRandom_Nest(Mat A,PetscRandom rctx)
619f8170845SAlex Fikl {
620f8170845SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data;
621f8170845SAlex Fikl   PetscInt       i,j;
622f8170845SAlex Fikl   PetscErrorCode ierr;
623f8170845SAlex Fikl 
624f8170845SAlex Fikl   PetscFunctionBegin;
625f8170845SAlex Fikl   for (i=0; i<bA->nr; i++) {
626f8170845SAlex Fikl     for (j=0; j<bA->nc; j++) {
627f8170845SAlex Fikl       if (bA->m[i][j]) {
628f8170845SAlex Fikl         ierr = MatSetRandom(bA->m[i][j],rctx);CHKERRQ(ierr);
629f8170845SAlex Fikl       }
630f8170845SAlex Fikl     }
631f8170845SAlex Fikl   }
632f8170845SAlex Fikl   PetscFunctionReturn(0);
633f8170845SAlex Fikl }
634f8170845SAlex Fikl 
6352a7a6963SBarry Smith static PetscErrorCode MatCreateVecs_Nest(Mat A,Vec *right,Vec *left)
636d8588912SDave May {
637d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
638d8588912SDave May   Vec            *L,*R;
639d8588912SDave May   MPI_Comm       comm;
640d8588912SDave May   PetscInt       i,j;
641d8588912SDave May   PetscErrorCode ierr;
642d8588912SDave May 
643d8588912SDave May   PetscFunctionBegin;
644ce94432eSBarry Smith   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
645d8588912SDave May   if (right) {
646d8588912SDave May     /* allocate R */
647854ce69bSBarry Smith     ierr = PetscMalloc1(bA->nc, &R);CHKERRQ(ierr);
648d8588912SDave May     /* Create the right vectors */
649d8588912SDave May     for (j=0; j<bA->nc; j++) {
650d8588912SDave May       for (i=0; i<bA->nr; i++) {
651d8588912SDave May         if (bA->m[i][j]) {
6522a7a6963SBarry Smith           ierr = MatCreateVecs(bA->m[i][j],&R[j],NULL);CHKERRQ(ierr);
653d8588912SDave May           break;
654d8588912SDave May         }
655d8588912SDave May       }
6566c4ed002SBarry Smith       if (i==bA->nr) SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
657d8588912SDave May     }
658f349c1fdSJed Brown     ierr = VecCreateNest(comm,bA->nc,bA->isglobal.col,R,right);CHKERRQ(ierr);
659d8588912SDave May     /* hand back control to the nest vector */
660d8588912SDave May     for (j=0; j<bA->nc; j++) {
6616bf464f9SBarry Smith       ierr = VecDestroy(&R[j]);CHKERRQ(ierr);
662d8588912SDave May     }
663d8588912SDave May     ierr = PetscFree(R);CHKERRQ(ierr);
664d8588912SDave May   }
665d8588912SDave May 
666d8588912SDave May   if (left) {
667d8588912SDave May     /* allocate L */
668854ce69bSBarry Smith     ierr = PetscMalloc1(bA->nr, &L);CHKERRQ(ierr);
669d8588912SDave May     /* Create the left vectors */
670d8588912SDave May     for (i=0; i<bA->nr; i++) {
671d8588912SDave May       for (j=0; j<bA->nc; j++) {
672d8588912SDave May         if (bA->m[i][j]) {
6732a7a6963SBarry Smith           ierr = MatCreateVecs(bA->m[i][j],NULL,&L[i]);CHKERRQ(ierr);
674d8588912SDave May           break;
675d8588912SDave May         }
676d8588912SDave May       }
6776c4ed002SBarry Smith       if (j==bA->nc) SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
678d8588912SDave May     }
679d8588912SDave May 
680f349c1fdSJed Brown     ierr = VecCreateNest(comm,bA->nr,bA->isglobal.row,L,left);CHKERRQ(ierr);
681d8588912SDave May     for (i=0; i<bA->nr; i++) {
6826bf464f9SBarry Smith       ierr = VecDestroy(&L[i]);CHKERRQ(ierr);
683d8588912SDave May     }
684d8588912SDave May 
685d8588912SDave May     ierr = PetscFree(L);CHKERRQ(ierr);
686d8588912SDave May   }
687d8588912SDave May   PetscFunctionReturn(0);
688d8588912SDave May }
689d8588912SDave May 
690207556f9SJed Brown static PetscErrorCode MatView_Nest(Mat A,PetscViewer viewer)
691d8588912SDave May {
692d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
69329e60adbSStefano Zampini   PetscBool      isascii,viewSub = PETSC_FALSE;
694d8588912SDave May   PetscInt       i,j;
695d8588912SDave May   PetscErrorCode ierr;
696d8588912SDave May 
697d8588912SDave May   PetscFunctionBegin;
698251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
699d8588912SDave May   if (isascii) {
700d8588912SDave May 
70129e60adbSStefano Zampini     ierr = PetscOptionsGetBool(((PetscObject)A)->options,((PetscObject)A)->prefix,"-mat_view_nest_sub",&viewSub,NULL);CHKERRQ(ierr);
702d86155a6SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"Matrix object: \n");CHKERRQ(ierr);
703d86155a6SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
704d86155a6SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer, "type=nest, rows=%D, cols=%D \n",bA->nr,bA->nc);CHKERRQ(ierr);
705d8588912SDave May 
706d86155a6SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"MatNest structure: \n");CHKERRQ(ierr);
707d8588912SDave May     for (i=0; i<bA->nr; i++) {
708d8588912SDave May       for (j=0; j<bA->nc; j++) {
70919fd82e9SBarry Smith         MatType   type;
710270f95d7SJed Brown         char      name[256] = "",prefix[256] = "";
711d8588912SDave May         PetscInt  NR,NC;
712d8588912SDave May         PetscBool isNest = PETSC_FALSE;
713d8588912SDave May 
714d8588912SDave May         if (!bA->m[i][j]) {
715d86155a6SBarry Smith           CHKERRQ(ierr);PetscViewerASCIIPrintf(viewer, "(%D,%D) : NULL \n",i,j);CHKERRQ(ierr);
716d8588912SDave May           continue;
717d8588912SDave May         }
718d8588912SDave May         ierr = MatGetSize(bA->m[i][j],&NR,&NC);CHKERRQ(ierr);
719d8588912SDave May         ierr = MatGetType(bA->m[i][j], &type);CHKERRQ(ierr);
7208caf3d72SBarry Smith         if (((PetscObject)bA->m[i][j])->name) {ierr = PetscSNPrintf(name,sizeof(name),"name=\"%s\", ",((PetscObject)bA->m[i][j])->name);CHKERRQ(ierr);}
7218caf3d72SBarry Smith         if (((PetscObject)bA->m[i][j])->prefix) {ierr = PetscSNPrintf(prefix,sizeof(prefix),"prefix=\"%s\", ",((PetscObject)bA->m[i][j])->prefix);CHKERRQ(ierr);}
722251f4c67SDmitry Karpeev         ierr = PetscObjectTypeCompare((PetscObject)bA->m[i][j],MATNEST,&isNest);CHKERRQ(ierr);
723d8588912SDave May 
724270f95d7SJed Brown         ierr = PetscViewerASCIIPrintf(viewer,"(%D,%D) : %s%stype=%s, rows=%D, cols=%D \n",i,j,name,prefix,type,NR,NC);CHKERRQ(ierr);
725d8588912SDave May 
72629e60adbSStefano Zampini         if (isNest || viewSub) {
727270f95d7SJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);  /* push1 */
728d8588912SDave May           ierr = MatView(bA->m[i][j],viewer);CHKERRQ(ierr);
729270f95d7SJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);    /* pop1 */
730d8588912SDave May         }
731d8588912SDave May       }
732d8588912SDave May     }
733d86155a6SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);    /* pop0 */
734d8588912SDave May   }
735d8588912SDave May   PetscFunctionReturn(0);
736d8588912SDave May }
737d8588912SDave May 
738207556f9SJed Brown static PetscErrorCode MatZeroEntries_Nest(Mat A)
739d8588912SDave May {
740d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
741d8588912SDave May   PetscInt       i,j;
742d8588912SDave May   PetscErrorCode ierr;
743d8588912SDave May 
744d8588912SDave May   PetscFunctionBegin;
745d8588912SDave May   for (i=0; i<bA->nr; i++) {
746d8588912SDave May     for (j=0; j<bA->nc; j++) {
747d8588912SDave May       if (!bA->m[i][j]) continue;
748d8588912SDave May       ierr = MatZeroEntries(bA->m[i][j]);CHKERRQ(ierr);
749d8588912SDave May     }
750d8588912SDave May   }
751d8588912SDave May   PetscFunctionReturn(0);
752d8588912SDave May }
753d8588912SDave May 
754c222c20dSDavid Ham static PetscErrorCode MatCopy_Nest(Mat A,Mat B,MatStructure str)
755c222c20dSDavid Ham {
756c222c20dSDavid Ham   Mat_Nest       *bA = (Mat_Nest*)A->data,*bB = (Mat_Nest*)B->data;
757c222c20dSDavid Ham   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
758c222c20dSDavid Ham   PetscErrorCode ierr;
75906a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
760c222c20dSDavid Ham 
761c222c20dSDavid Ham   PetscFunctionBegin;
762c222c20dSDavid Ham   if (nr != bB->nr || nc != bB->nc) SETERRQ4(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Cannot copy a Mat_Nest of block size (%D,%D) to a Mat_Nest of block size (%D,%D)",bB->nr,bB->nc,nr,nc);
763c222c20dSDavid Ham   for (i=0; i<nr; i++) {
764c222c20dSDavid Ham     for (j=0; j<nc; j++) {
76506a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
76646a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
767c222c20dSDavid Ham         ierr = MatCopy(bA->m[i][j],bB->m[i][j],str);CHKERRQ(ierr);
76846a2b97cSJed Brown       } else if (bA->m[i][j] || bB->m[i][j]) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Matrix block does not exist at %D,%D",i,j);
76906a1af2fSStefano Zampini       ierr = MatGetNonzeroState(bB->m[i][j],&subnnzstate);CHKERRQ(ierr);
77006a1af2fSStefano Zampini       nnzstate = (PetscBool)(nnzstate || bB->nnzstate[i*nc+j] != subnnzstate);
77106a1af2fSStefano Zampini       bB->nnzstate[i*nc+j] = subnnzstate;
772c222c20dSDavid Ham     }
773c222c20dSDavid Ham   }
77406a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
775c222c20dSDavid Ham   PetscFunctionReturn(0);
776c222c20dSDavid Ham }
777c222c20dSDavid Ham 
7786e76ffeaSPierre Jolivet static PetscErrorCode MatAXPY_Nest(Mat Y,PetscScalar a,Mat X,MatStructure str)
7796e76ffeaSPierre Jolivet {
7806e76ffeaSPierre Jolivet   Mat_Nest       *bY = (Mat_Nest*)Y->data,*bX = (Mat_Nest*)X->data;
7816e76ffeaSPierre Jolivet   PetscInt       i,j,nr = bY->nr,nc = bY->nc;
7826e76ffeaSPierre Jolivet   PetscErrorCode ierr;
78306a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
7846e76ffeaSPierre Jolivet 
7856e76ffeaSPierre Jolivet   PetscFunctionBegin;
7866e76ffeaSPierre Jolivet   if (nr != bX->nr || nc != bX->nc) SETERRQ4(PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Cannot AXPY a MatNest of block size (%D,%D) with a MatNest of block size (%D,%D)",bX->nr,bX->nc,nr,nc);
7876e76ffeaSPierre Jolivet   for (i=0; i<nr; i++) {
7886e76ffeaSPierre Jolivet     for (j=0; j<nc; j++) {
78906a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
7906e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
7916e76ffeaSPierre Jolivet         ierr = MatAXPY(bY->m[i][j],a,bX->m[i][j],str);CHKERRQ(ierr);
792c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
793c066aebcSStefano Zampini         Mat M;
794c066aebcSStefano Zampini 
795c066aebcSStefano Zampini         if (str != DIFFERENT_NONZERO_PATTERN) SETERRQ2(PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Matrix block does not exist at %D,%D",i,j);
796c066aebcSStefano Zampini         ierr = MatDuplicate(bX->m[i][j],MAT_COPY_VALUES,&M);CHKERRQ(ierr);
797c066aebcSStefano Zampini         ierr = MatNestSetSubMat(Y,i,j,M);CHKERRQ(ierr);
798c066aebcSStefano Zampini         ierr = MatDestroy(&M);CHKERRQ(ierr);
799c066aebcSStefano Zampini       }
80006a1af2fSStefano Zampini       ierr = MatGetNonzeroState(bY->m[i][j],&subnnzstate);CHKERRQ(ierr);
80106a1af2fSStefano Zampini       nnzstate = (PetscBool)(nnzstate || bY->nnzstate[i*nc+j] != subnnzstate);
80206a1af2fSStefano Zampini       bY->nnzstate[i*nc+j] = subnnzstate;
8036e76ffeaSPierre Jolivet     }
8046e76ffeaSPierre Jolivet   }
80506a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
8066e76ffeaSPierre Jolivet   PetscFunctionReturn(0);
8076e76ffeaSPierre Jolivet }
8086e76ffeaSPierre Jolivet 
809207556f9SJed Brown static PetscErrorCode MatDuplicate_Nest(Mat A,MatDuplicateOption op,Mat *B)
810d8588912SDave May {
811d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
812841e96a3SJed Brown   Mat            *b;
813841e96a3SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
814d8588912SDave May   PetscErrorCode ierr;
815d8588912SDave May 
816d8588912SDave May   PetscFunctionBegin;
817785e854fSJed Brown   ierr = PetscMalloc1(nr*nc,&b);CHKERRQ(ierr);
818841e96a3SJed Brown   for (i=0; i<nr; i++) {
819841e96a3SJed Brown     for (j=0; j<nc; j++) {
820841e96a3SJed Brown       if (bA->m[i][j]) {
821841e96a3SJed Brown         ierr = MatDuplicate(bA->m[i][j],op,&b[i*nc+j]);CHKERRQ(ierr);
822841e96a3SJed Brown       } else {
8230298fd71SBarry Smith         b[i*nc+j] = NULL;
824d8588912SDave May       }
825d8588912SDave May     }
826d8588912SDave May   }
827ce94432eSBarry Smith   ierr = MatCreateNest(PetscObjectComm((PetscObject)A),nr,bA->isglobal.row,nc,bA->isglobal.col,b,B);CHKERRQ(ierr);
828841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
829841e96a3SJed Brown   for (i=0; i<nr*nc; i++) {
8306bf464f9SBarry Smith     ierr = MatDestroy(&b[i]);CHKERRQ(ierr);
831d8588912SDave May   }
832d8588912SDave May   ierr = PetscFree(b);CHKERRQ(ierr);
833d8588912SDave May 
834841e96a3SJed Brown   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
835841e96a3SJed Brown   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
836d8588912SDave May   PetscFunctionReturn(0);
837d8588912SDave May }
838d8588912SDave May 
839d8588912SDave May /* nest api */
840d8588912SDave May PetscErrorCode MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat *mat)
841d8588912SDave May {
842d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
8435fd66863SKarl Rupp 
844d8588912SDave May   PetscFunctionBegin;
845ce94432eSBarry Smith   if (idxm >= bA->nr) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
846ce94432eSBarry Smith   if (jdxm >= bA->nc) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
847d8588912SDave May   *mat = bA->m[idxm][jdxm];
848d8588912SDave May   PetscFunctionReturn(0);
849d8588912SDave May }
850d8588912SDave May 
8519ba0d327SJed Brown /*@
852d8588912SDave May  MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix.
853d8588912SDave May 
854d8588912SDave May  Not collective
855d8588912SDave May 
856d8588912SDave May  Input Parameters:
857629881c0SJed Brown +   A  - nest matrix
858d8588912SDave May .   idxm - index of the matrix within the nest matrix
859629881c0SJed Brown -   jdxm - index of the matrix within the nest matrix
860d8588912SDave May 
861d8588912SDave May  Output Parameter:
862d8588912SDave May .   sub - matrix at index idxm,jdxm within the nest matrix
863d8588912SDave May 
864d8588912SDave May  Level: developer
865d8588912SDave May 
866d8588912SDave May .seealso: MatNestGetSize(), MatNestGetSubMats()
867d8588912SDave May @*/
8687087cfbeSBarry Smith PetscErrorCode  MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat *sub)
869d8588912SDave May {
870699a902aSJed Brown   PetscErrorCode ierr;
871d8588912SDave May 
872d8588912SDave May   PetscFunctionBegin;
873699a902aSJed Brown   ierr = PetscUseMethod(A,"MatNestGetSubMat_C",(Mat,PetscInt,PetscInt,Mat*),(A,idxm,jdxm,sub));CHKERRQ(ierr);
874d8588912SDave May   PetscFunctionReturn(0);
875d8588912SDave May }
876d8588912SDave May 
8770782ca92SJed Brown PetscErrorCode MatNestSetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat mat)
8780782ca92SJed Brown {
8790782ca92SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
8800782ca92SJed Brown   PetscInt       m,n,M,N,mi,ni,Mi,Ni;
8810782ca92SJed Brown   PetscErrorCode ierr;
8820782ca92SJed Brown 
8830782ca92SJed Brown   PetscFunctionBegin;
884ce94432eSBarry Smith   if (idxm >= bA->nr) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
885ce94432eSBarry Smith   if (jdxm >= bA->nc) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
8860782ca92SJed Brown   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
8870782ca92SJed Brown   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
8880782ca92SJed Brown   ierr = ISGetLocalSize(bA->isglobal.row[idxm],&mi);CHKERRQ(ierr);
8890782ca92SJed Brown   ierr = ISGetSize(bA->isglobal.row[idxm],&Mi);CHKERRQ(ierr);
8900782ca92SJed Brown   ierr = ISGetLocalSize(bA->isglobal.col[jdxm],&ni);CHKERRQ(ierr);
8910782ca92SJed Brown   ierr = ISGetSize(bA->isglobal.col[jdxm],&Ni);CHKERRQ(ierr);
892ce94432eSBarry Smith   if (M != Mi || N != Ni) SETERRQ4(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_INCOMP,"Submatrix dimension (%D,%D) incompatible with nest block (%D,%D)",M,N,Mi,Ni);
893ce94432eSBarry Smith   if (m != mi || n != ni) SETERRQ4(PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_INCOMP,"Submatrix local dimension (%D,%D) incompatible with nest block (%D,%D)",m,n,mi,ni);
89426fbe8dcSKarl Rupp 
89506a1af2fSStefano Zampini   /* do not increase object state */
89606a1af2fSStefano Zampini   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(0);
89706a1af2fSStefano Zampini 
8980782ca92SJed Brown   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
8990782ca92SJed Brown   ierr = MatDestroy(&bA->m[idxm][jdxm]);CHKERRQ(ierr);
9000782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
90106a1af2fSStefano Zampini   ierr = PetscObjectStateIncrease((PetscObject)A);CHKERRQ(ierr);
90206a1af2fSStefano Zampini   ierr = MatGetNonzeroState(mat,&bA->nnzstate[idxm*bA->nc+jdxm]);CHKERRQ(ierr);
90306a1af2fSStefano Zampini   A->nonzerostate++;
9040782ca92SJed Brown   PetscFunctionReturn(0);
9050782ca92SJed Brown }
9060782ca92SJed Brown 
9079ba0d327SJed Brown /*@
9080782ca92SJed Brown  MatNestSetSubMat - Set a single submatrix in the nest matrix.
9090782ca92SJed Brown 
9100782ca92SJed Brown  Logically collective on the submatrix communicator
9110782ca92SJed Brown 
9120782ca92SJed Brown  Input Parameters:
9130782ca92SJed Brown +   A  - nest matrix
9140782ca92SJed Brown .   idxm - index of the matrix within the nest matrix
9150782ca92SJed Brown .   jdxm - index of the matrix within the nest matrix
9160782ca92SJed Brown -   sub - matrix at index idxm,jdxm within the nest matrix
9170782ca92SJed Brown 
9180782ca92SJed Brown  Notes:
9190782ca92SJed Brown  The new submatrix must have the same size and communicator as that block of the nest.
9200782ca92SJed Brown 
9210782ca92SJed Brown  This increments the reference count of the submatrix.
9220782ca92SJed Brown 
9230782ca92SJed Brown  Level: developer
9240782ca92SJed Brown 
925d5dfb694SBarry Smith .seealso: MatNestSetSubMats(), MatNestGetSubMats()
9260782ca92SJed Brown @*/
9270782ca92SJed Brown PetscErrorCode  MatNestSetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat sub)
9280782ca92SJed Brown {
9290782ca92SJed Brown   PetscErrorCode ierr;
9300782ca92SJed Brown 
9310782ca92SJed Brown   PetscFunctionBegin;
9320782ca92SJed Brown   ierr = PetscUseMethod(A,"MatNestSetSubMat_C",(Mat,PetscInt,PetscInt,Mat),(A,idxm,jdxm,sub));CHKERRQ(ierr);
9330782ca92SJed Brown   PetscFunctionReturn(0);
9340782ca92SJed Brown }
9350782ca92SJed Brown 
936d8588912SDave May PetscErrorCode MatNestGetSubMats_Nest(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
937d8588912SDave May {
938d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
9395fd66863SKarl Rupp 
940d8588912SDave May   PetscFunctionBegin;
94126fbe8dcSKarl Rupp   if (M)   *M   = bA->nr;
94226fbe8dcSKarl Rupp   if (N)   *N   = bA->nc;
94326fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
944d8588912SDave May   PetscFunctionReturn(0);
945d8588912SDave May }
946d8588912SDave May 
947d8588912SDave May /*@C
948d8588912SDave May  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix.
949d8588912SDave May 
950d8588912SDave May  Not collective
951d8588912SDave May 
952d8588912SDave May  Input Parameters:
953629881c0SJed Brown .   A  - nest matrix
954d8588912SDave May 
955d8588912SDave May  Output Parameter:
956629881c0SJed Brown +   M - number of rows in the nest matrix
957d8588912SDave May .   N - number of cols in the nest matrix
958629881c0SJed Brown -   mat - 2d array of matrices
959d8588912SDave May 
960d8588912SDave May  Notes:
961d8588912SDave May 
962d8588912SDave May  The user should not free the array mat.
963d8588912SDave May 
964351962e3SVincent Le Chenadec  In Fortran, this routine has a calling sequence
965351962e3SVincent Le Chenadec $   call MatNestGetSubMats(A, M, N, mat, ierr)
966351962e3SVincent Le Chenadec  where the space allocated for the optional argument mat is assumed large enough (if provided).
967351962e3SVincent Le Chenadec 
968d8588912SDave May  Level: developer
969d8588912SDave May 
970d8588912SDave May .seealso: MatNestGetSize(), MatNestGetSubMat()
971d8588912SDave May @*/
9727087cfbeSBarry Smith PetscErrorCode  MatNestGetSubMats(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
973d8588912SDave May {
974699a902aSJed Brown   PetscErrorCode ierr;
975d8588912SDave May 
976d8588912SDave May   PetscFunctionBegin;
977699a902aSJed Brown   ierr = PetscUseMethod(A,"MatNestGetSubMats_C",(Mat,PetscInt*,PetscInt*,Mat***),(A,M,N,mat));CHKERRQ(ierr);
978d8588912SDave May   PetscFunctionReturn(0);
979d8588912SDave May }
980d8588912SDave May 
9817087cfbeSBarry Smith PetscErrorCode  MatNestGetSize_Nest(Mat A,PetscInt *M,PetscInt *N)
982d8588912SDave May {
983d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
984d8588912SDave May 
985d8588912SDave May   PetscFunctionBegin;
98626fbe8dcSKarl Rupp   if (M) *M = bA->nr;
98726fbe8dcSKarl Rupp   if (N) *N = bA->nc;
988d8588912SDave May   PetscFunctionReturn(0);
989d8588912SDave May }
990d8588912SDave May 
9919ba0d327SJed Brown /*@
992d8588912SDave May  MatNestGetSize - Returns the size of the nest matrix.
993d8588912SDave May 
994d8588912SDave May  Not collective
995d8588912SDave May 
996d8588912SDave May  Input Parameters:
997d8588912SDave May .   A  - nest matrix
998d8588912SDave May 
999d8588912SDave May  Output Parameter:
1000629881c0SJed Brown +   M - number of rows in the nested mat
1001629881c0SJed Brown -   N - number of cols in the nested mat
1002d8588912SDave May 
1003d8588912SDave May  Notes:
1004d8588912SDave May 
1005d8588912SDave May  Level: developer
1006d8588912SDave May 
1007d8588912SDave May .seealso: MatNestGetSubMat(), MatNestGetSubMats()
1008d8588912SDave May @*/
10097087cfbeSBarry Smith PetscErrorCode  MatNestGetSize(Mat A,PetscInt *M,PetscInt *N)
1010d8588912SDave May {
1011699a902aSJed Brown   PetscErrorCode ierr;
1012d8588912SDave May 
1013d8588912SDave May   PetscFunctionBegin;
1014699a902aSJed Brown   ierr = PetscUseMethod(A,"MatNestGetSize_C",(Mat,PetscInt*,PetscInt*),(A,M,N));CHKERRQ(ierr);
1015d8588912SDave May   PetscFunctionReturn(0);
1016d8588912SDave May }
1017d8588912SDave May 
1018f7a08781SBarry Smith static PetscErrorCode MatNestGetISs_Nest(Mat A,IS rows[],IS cols[])
1019900e7ff2SJed Brown {
1020900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest*)A->data;
1021900e7ff2SJed Brown   PetscInt i;
1022900e7ff2SJed Brown 
1023900e7ff2SJed Brown   PetscFunctionBegin;
1024900e7ff2SJed Brown   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->isglobal.row[i];
1025900e7ff2SJed Brown   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->isglobal.col[i];
1026900e7ff2SJed Brown   PetscFunctionReturn(0);
1027900e7ff2SJed Brown }
1028900e7ff2SJed Brown 
10293a4d7b9aSSatish Balay /*@C
1030900e7ff2SJed Brown  MatNestGetISs - Returns the index sets partitioning the row and column spaces
1031900e7ff2SJed Brown 
1032900e7ff2SJed Brown  Not collective
1033900e7ff2SJed Brown 
1034900e7ff2SJed Brown  Input Parameters:
1035900e7ff2SJed Brown .   A  - nest matrix
1036900e7ff2SJed Brown 
1037900e7ff2SJed Brown  Output Parameter:
1038900e7ff2SJed Brown +   rows - array of row index sets
1039900e7ff2SJed Brown -   cols - array of column index sets
1040900e7ff2SJed Brown 
1041900e7ff2SJed Brown  Level: advanced
1042900e7ff2SJed Brown 
1043900e7ff2SJed Brown  Notes:
1044900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1045900e7ff2SJed Brown 
1046900e7ff2SJed Brown .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetLocalISs()
1047900e7ff2SJed Brown @*/
1048900e7ff2SJed Brown PetscErrorCode  MatNestGetISs(Mat A,IS rows[],IS cols[])
1049900e7ff2SJed Brown {
1050900e7ff2SJed Brown   PetscErrorCode ierr;
1051900e7ff2SJed Brown 
1052900e7ff2SJed Brown   PetscFunctionBegin;
1053900e7ff2SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1054900e7ff2SJed Brown   ierr = PetscUseMethod(A,"MatNestGetISs_C",(Mat,IS[],IS[]),(A,rows,cols));CHKERRQ(ierr);
1055900e7ff2SJed Brown   PetscFunctionReturn(0);
1056900e7ff2SJed Brown }
1057900e7ff2SJed Brown 
1058f7a08781SBarry Smith static PetscErrorCode MatNestGetLocalISs_Nest(Mat A,IS rows[],IS cols[])
1059900e7ff2SJed Brown {
1060900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest*)A->data;
1061900e7ff2SJed Brown   PetscInt i;
1062900e7ff2SJed Brown 
1063900e7ff2SJed Brown   PetscFunctionBegin;
1064900e7ff2SJed Brown   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->islocal.row[i];
1065900e7ff2SJed Brown   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->islocal.col[i];
1066900e7ff2SJed Brown   PetscFunctionReturn(0);
1067900e7ff2SJed Brown }
1068900e7ff2SJed Brown 
1069900e7ff2SJed Brown /*@C
1070900e7ff2SJed Brown  MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces
1071900e7ff2SJed Brown 
1072900e7ff2SJed Brown  Not collective
1073900e7ff2SJed Brown 
1074900e7ff2SJed Brown  Input Parameters:
1075900e7ff2SJed Brown .   A  - nest matrix
1076900e7ff2SJed Brown 
1077900e7ff2SJed Brown  Output Parameter:
10780298fd71SBarry Smith +   rows - array of row index sets (or NULL to ignore)
10790298fd71SBarry Smith -   cols - array of column index sets (or NULL to ignore)
1080900e7ff2SJed Brown 
1081900e7ff2SJed Brown  Level: advanced
1082900e7ff2SJed Brown 
1083900e7ff2SJed Brown  Notes:
1084900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1085900e7ff2SJed Brown 
1086900e7ff2SJed Brown .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetISs()
1087900e7ff2SJed Brown @*/
1088900e7ff2SJed Brown PetscErrorCode  MatNestGetLocalISs(Mat A,IS rows[],IS cols[])
1089900e7ff2SJed Brown {
1090900e7ff2SJed Brown   PetscErrorCode ierr;
1091900e7ff2SJed Brown 
1092900e7ff2SJed Brown   PetscFunctionBegin;
1093900e7ff2SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1094900e7ff2SJed Brown   ierr = PetscUseMethod(A,"MatNestGetLocalISs_C",(Mat,IS[],IS[]),(A,rows,cols));CHKERRQ(ierr);
1095900e7ff2SJed Brown   PetscFunctionReturn(0);
1096900e7ff2SJed Brown }
1097900e7ff2SJed Brown 
109819fd82e9SBarry Smith PetscErrorCode  MatNestSetVecType_Nest(Mat A,VecType vtype)
1099207556f9SJed Brown {
1100207556f9SJed Brown   PetscErrorCode ierr;
1101207556f9SJed Brown   PetscBool      flg;
1102207556f9SJed Brown 
1103207556f9SJed Brown   PetscFunctionBegin;
1104207556f9SJed Brown   ierr = PetscStrcmp(vtype,VECNEST,&flg);CHKERRQ(ierr);
1105207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
11062a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
110712b53f24SSatish Balay   else A->ops->getvecs = (PetscErrorCode (*)(Mat,Vec*,Vec*)) 0;
1108207556f9SJed Brown   PetscFunctionReturn(0);
1109207556f9SJed Brown }
1110207556f9SJed Brown 
1111207556f9SJed Brown /*@C
11122a7a6963SBarry Smith  MatNestSetVecType - Sets the type of Vec returned by MatCreateVecs()
1113207556f9SJed Brown 
1114207556f9SJed Brown  Not collective
1115207556f9SJed Brown 
1116207556f9SJed Brown  Input Parameters:
1117207556f9SJed Brown +  A  - nest matrix
1118207556f9SJed Brown -  vtype - type to use for creating vectors
1119207556f9SJed Brown 
1120207556f9SJed Brown  Notes:
1121207556f9SJed Brown 
1122207556f9SJed Brown  Level: developer
1123207556f9SJed Brown 
11242a7a6963SBarry Smith .seealso: MatCreateVecs()
1125207556f9SJed Brown @*/
112619fd82e9SBarry Smith PetscErrorCode  MatNestSetVecType(Mat A,VecType vtype)
1127207556f9SJed Brown {
1128207556f9SJed Brown   PetscErrorCode ierr;
1129207556f9SJed Brown 
1130207556f9SJed Brown   PetscFunctionBegin;
113119fd82e9SBarry Smith   ierr = PetscTryMethod(A,"MatNestSetVecType_C",(Mat,VecType),(A,vtype));CHKERRQ(ierr);
1132207556f9SJed Brown   PetscFunctionReturn(0);
1133207556f9SJed Brown }
1134207556f9SJed Brown 
1135c8883902SJed Brown PetscErrorCode MatNestSetSubMats_Nest(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1136d8588912SDave May {
1137c8883902SJed Brown   Mat_Nest       *s = (Mat_Nest*)A->data;
1138c8883902SJed Brown   PetscInt       i,j,m,n,M,N;
1139d8588912SDave May   PetscErrorCode ierr;
114006a1af2fSStefano Zampini   PetscBool      cong;
1141d8588912SDave May 
1142d8588912SDave May   PetscFunctionBegin;
114306a1af2fSStefano Zampini   ierr = MatReset_Nest(A);CHKERRQ(ierr);
114406a1af2fSStefano Zampini 
1145c8883902SJed Brown   s->nr = nr;
1146c8883902SJed Brown   s->nc = nc;
1147d8588912SDave May 
1148c8883902SJed Brown   /* Create space for submatrices */
1149854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&s->m);CHKERRQ(ierr);
1150c8883902SJed Brown   for (i=0; i<nr; i++) {
1151854ce69bSBarry Smith     ierr = PetscMalloc1(nc,&s->m[i]);CHKERRQ(ierr);
1152d8588912SDave May   }
1153c8883902SJed Brown   for (i=0; i<nr; i++) {
1154c8883902SJed Brown     for (j=0; j<nc; j++) {
1155c8883902SJed Brown       s->m[i][j] = a[i*nc+j];
1156c8883902SJed Brown       if (a[i*nc+j]) {
1157c8883902SJed Brown         ierr = PetscObjectReference((PetscObject)a[i*nc+j]);CHKERRQ(ierr);
1158d8588912SDave May       }
1159d8588912SDave May     }
1160d8588912SDave May   }
1161d8588912SDave May 
11628188e55aSJed Brown   ierr = MatSetUp_NestIS_Private(A,nr,is_row,nc,is_col);CHKERRQ(ierr);
1163d8588912SDave May 
1164854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&s->row_len);CHKERRQ(ierr);
1165854ce69bSBarry Smith   ierr = PetscMalloc1(nc,&s->col_len);CHKERRQ(ierr);
1166c8883902SJed Brown   for (i=0; i<nr; i++) s->row_len[i]=-1;
1167c8883902SJed Brown   for (j=0; j<nc; j++) s->col_len[j]=-1;
1168d8588912SDave May 
116906a1af2fSStefano Zampini   ierr = PetscCalloc1(nr*nc,&s->nnzstate);CHKERRQ(ierr);
117006a1af2fSStefano Zampini   for (i=0; i<nr; i++) {
117106a1af2fSStefano Zampini     for (j=0; j<nc; j++) {
117206a1af2fSStefano Zampini       if (s->m[i][j]) {
117306a1af2fSStefano Zampini         ierr = MatGetNonzeroState(s->m[i][j],&s->nnzstate[i*nc+j]);CHKERRQ(ierr);
117406a1af2fSStefano Zampini       }
117506a1af2fSStefano Zampini     }
117606a1af2fSStefano Zampini   }
117706a1af2fSStefano Zampini 
11788188e55aSJed Brown   ierr = MatNestGetSizes_Private(A,&m,&n,&M,&N);CHKERRQ(ierr);
1179d8588912SDave May 
1180c8883902SJed Brown   ierr = PetscLayoutSetSize(A->rmap,M);CHKERRQ(ierr);
1181c8883902SJed Brown   ierr = PetscLayoutSetLocalSize(A->rmap,m);CHKERRQ(ierr);
1182c8883902SJed Brown   ierr = PetscLayoutSetSize(A->cmap,N);CHKERRQ(ierr);
1183c8883902SJed Brown   ierr = PetscLayoutSetLocalSize(A->cmap,n);CHKERRQ(ierr);
1184c8883902SJed Brown 
1185c8883902SJed Brown   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
1186c8883902SJed Brown   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
1187c8883902SJed Brown 
118806a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
118906a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
119006a1af2fSStefano Zampini   ierr = MatHasCongruentLayouts(A,&cong);CHKERRQ(ierr);
119106a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
119206a1af2fSStefano Zampini   if (cong) {
119306a1af2fSStefano Zampini     for (i = 0; cong && i < nr; i++) {
1194*320466b0SStefano Zampini       ierr = ISEqualUnsorted(s->isglobal.row[i],s->isglobal.col[i],&cong);CHKERRQ(ierr);
119506a1af2fSStefano Zampini     }
119606a1af2fSStefano Zampini   }
119706a1af2fSStefano Zampini   if (!cong) {
119806a1af2fSStefano Zampini     A->ops->getdiagonal = NULL;
119906a1af2fSStefano Zampini     A->ops->shift       = NULL;
120006a1af2fSStefano Zampini     A->ops->diagonalset = NULL;
120106a1af2fSStefano Zampini   }
120206a1af2fSStefano Zampini 
12031795a4d1SJed Brown   ierr = PetscCalloc2(nr,&s->left,nc,&s->right);CHKERRQ(ierr);
120406a1af2fSStefano Zampini   ierr = PetscObjectStateIncrease((PetscObject)A);CHKERRQ(ierr);
120506a1af2fSStefano Zampini   A->nonzerostate++;
1206d8588912SDave May   PetscFunctionReturn(0);
1207d8588912SDave May }
1208d8588912SDave May 
1209c8883902SJed Brown /*@
1210c8883902SJed Brown    MatNestSetSubMats - Sets the nested submatrices
1211c8883902SJed Brown 
1212c8883902SJed Brown    Collective on Mat
1213c8883902SJed Brown 
1214c8883902SJed Brown    Input Parameter:
1215ffd6319bSRichard Tran Mills +  A - nested matrix
1216c8883902SJed Brown .  nr - number of nested row blocks
12170298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1218c8883902SJed Brown .  nc - number of nested column blocks
12190298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
12200298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1221c8883902SJed Brown 
122206a1af2fSStefano Zampini    Notes: this always resets any submatrix information previously set
122306a1af2fSStefano Zampini 
1224c8883902SJed Brown    Level: advanced
1225c8883902SJed Brown 
1226c8883902SJed Brown .seealso: MatCreateNest(), MATNEST
1227c8883902SJed Brown @*/
1228c8883902SJed Brown PetscErrorCode MatNestSetSubMats(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1229c8883902SJed Brown {
1230c8883902SJed Brown   PetscErrorCode ierr;
123106a1af2fSStefano Zampini   PetscInt       i;
1232c8883902SJed Brown 
1233c8883902SJed Brown   PetscFunctionBegin;
1234c8883902SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1235ce94432eSBarry Smith   if (nr < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of rows cannot be negative");
1236c8883902SJed Brown   if (nr && is_row) {
1237c8883902SJed Brown     PetscValidPointer(is_row,3);
1238c8883902SJed Brown     for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_row[i],IS_CLASSID,3);
1239c8883902SJed Brown   }
1240ce94432eSBarry Smith   if (nc < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of columns cannot be negative");
12411664e352SJed Brown   if (nc && is_col) {
1242c8883902SJed Brown     PetscValidPointer(is_col,5);
12439b30a8f6SBarry Smith     for (i=0; i<nc; i++) PetscValidHeaderSpecific(is_col[i],IS_CLASSID,5);
1244c8883902SJed Brown   }
124506a1af2fSStefano Zampini   if (nr*nc > 0) PetscValidPointer(a,6);
1246c8883902SJed Brown   ierr = PetscUseMethod(A,"MatNestSetSubMats_C",(Mat,PetscInt,const IS[],PetscInt,const IS[],const Mat[]),(A,nr,is_row,nc,is_col,a));CHKERRQ(ierr);
1247c8883902SJed Brown   PetscFunctionReturn(0);
1248c8883902SJed Brown }
1249d8588912SDave May 
125045b6f7e9SBarry Smith static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A,PetscInt n,const IS islocal[],const IS isglobal[],PetscBool colflg,ISLocalToGlobalMapping *ltog)
125177019fcaSJed Brown {
125277019fcaSJed Brown   PetscErrorCode ierr;
125377019fcaSJed Brown   PetscBool      flg;
125477019fcaSJed Brown   PetscInt       i,j,m,mi,*ix;
125577019fcaSJed Brown 
125677019fcaSJed Brown   PetscFunctionBegin;
125777019fcaSJed Brown   for (i=0,m=0,flg=PETSC_FALSE; i<n; i++) {
125877019fcaSJed Brown     if (islocal[i]) {
125977019fcaSJed Brown       ierr = ISGetSize(islocal[i],&mi);CHKERRQ(ierr);
126077019fcaSJed Brown       flg  = PETSC_TRUE;      /* We found a non-trivial entry */
126177019fcaSJed Brown     } else {
126277019fcaSJed Brown       ierr = ISGetSize(isglobal[i],&mi);CHKERRQ(ierr);
126377019fcaSJed Brown     }
126477019fcaSJed Brown     m += mi;
126577019fcaSJed Brown   }
126677019fcaSJed Brown   if (flg) {
1267785e854fSJed Brown     ierr = PetscMalloc1(m,&ix);CHKERRQ(ierr);
1268165cd838SBarry Smith     for (i=0,m=0; i<n; i++) {
12690298fd71SBarry Smith       ISLocalToGlobalMapping smap = NULL;
1270e108cb99SStefano Zampini       Mat                    sub = NULL;
1271f6d38dbbSStefano Zampini       PetscSF                sf;
1272f6d38dbbSStefano Zampini       PetscLayout            map;
1273f6d38dbbSStefano Zampini       PetscInt               *ix2;
127477019fcaSJed Brown 
1275165cd838SBarry Smith       if (!colflg) {
127677019fcaSJed Brown         ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
127777019fcaSJed Brown       } else {
127877019fcaSJed Brown         ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
127977019fcaSJed Brown       }
1280191fd14bSBarry Smith       if (sub) {
1281191fd14bSBarry Smith         if (!colflg) {
1282191fd14bSBarry Smith           ierr = MatGetLocalToGlobalMapping(sub,&smap,NULL);CHKERRQ(ierr);
1283191fd14bSBarry Smith         } else {
1284191fd14bSBarry Smith           ierr = MatGetLocalToGlobalMapping(sub,NULL,&smap);CHKERRQ(ierr);
1285191fd14bSBarry Smith         }
1286191fd14bSBarry Smith       }
128777019fcaSJed Brown       if (islocal[i]) {
128877019fcaSJed Brown         ierr = ISGetSize(islocal[i],&mi);CHKERRQ(ierr);
128977019fcaSJed Brown       } else {
129077019fcaSJed Brown         ierr = ISGetSize(isglobal[i],&mi);CHKERRQ(ierr);
129177019fcaSJed Brown       }
129277019fcaSJed Brown       for (j=0; j<mi; j++) ix[m+j] = j;
129377019fcaSJed Brown       if (smap) {ierr = ISLocalToGlobalMappingApply(smap,mi,ix+m,ix+m);CHKERRQ(ierr);}
1294165cd838SBarry Smith 
129577019fcaSJed Brown       /*
129677019fcaSJed Brown         Now we need to extract the monolithic global indices that correspond to the given split global indices.
129777019fcaSJed Brown         In many/most cases, we only want MatGetLocalSubMatrix() to work, in which case we only need to know the size of the local spaces.
129877019fcaSJed Brown        */
1299f6d38dbbSStefano Zampini       ierr = PetscMalloc1(mi,&ix2);CHKERRQ(ierr);
1300f6d38dbbSStefano Zampini       ierr = PetscSFCreate(((PetscObject)isglobal[i])->comm,&sf);CHKERRQ(ierr);
1301f6d38dbbSStefano Zampini       ierr = PetscLayoutCreate(((PetscObject)isglobal[i])->comm,&map);CHKERRQ(ierr);
1302f6d38dbbSStefano Zampini       ierr = PetscLayoutSetLocalSize(map,mi);CHKERRQ(ierr);
1303f6d38dbbSStefano Zampini       ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
1304f6d38dbbSStefano Zampini       ierr = PetscSFSetGraphLayout(sf,map,mi,NULL,PETSC_USE_POINTER,ix+m);CHKERRQ(ierr);
1305f6d38dbbSStefano Zampini       ierr = PetscLayoutDestroy(&map);CHKERRQ(ierr);
1306f6d38dbbSStefano Zampini       for (j=0; j<mi; j++) ix2[j] = ix[m+j];
1307f6d38dbbSStefano Zampini       ierr = PetscSFBcastBegin(sf,MPIU_INT,ix2,ix + m);CHKERRQ(ierr);
1308f6d38dbbSStefano Zampini       ierr = PetscSFBcastEnd(sf,MPIU_INT,ix2,ix + m);CHKERRQ(ierr);
1309f6d38dbbSStefano Zampini       ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
1310f6d38dbbSStefano Zampini       ierr = PetscFree(ix2);CHKERRQ(ierr);
131177019fcaSJed Brown       m   += mi;
131277019fcaSJed Brown     }
1313f0413b6fSBarry Smith     ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,m,ix,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
131477019fcaSJed Brown   } else {
13150298fd71SBarry Smith     *ltog = NULL;
131677019fcaSJed Brown   }
131777019fcaSJed Brown   PetscFunctionReturn(0);
131877019fcaSJed Brown }
131977019fcaSJed Brown 
132077019fcaSJed Brown 
1321d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1322d8588912SDave May /*
1323d8588912SDave May   nprocessors = NP
1324d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1325d8588912SDave May        proc 0: => (g_0,h_0,)
1326d8588912SDave May        proc 1: => (g_1,h_1,)
1327d8588912SDave May        ...
1328d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1329d8588912SDave May 
1330d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1331d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1332d8588912SDave May 
1333d8588912SDave May             proc 0:
1334d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1335d8588912SDave May             proc 1:
1336d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1337d8588912SDave May 
1338d8588912SDave May             proc NP-1:
1339d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1340d8588912SDave May */
1341841e96a3SJed Brown static PetscErrorCode MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[])
1342d8588912SDave May {
1343e2d7f03fSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
13448188e55aSJed Brown   PetscInt       i,j,offset,n,nsum,bs;
1345d8588912SDave May   PetscErrorCode ierr;
13460298fd71SBarry Smith   Mat            sub = NULL;
1347d8588912SDave May 
1348d8588912SDave May   PetscFunctionBegin;
1349854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&vs->isglobal.row);CHKERRQ(ierr);
1350854ce69bSBarry Smith   ierr = PetscMalloc1(nc,&vs->isglobal.col);CHKERRQ(ierr);
1351d8588912SDave May   if (is_row) { /* valid IS is passed in */
1352d8588912SDave May     /* refs on is[] are incremeneted */
1353e2d7f03fSJed Brown     for (i=0; i<vs->nr; i++) {
1354d8588912SDave May       ierr = PetscObjectReference((PetscObject)is_row[i]);CHKERRQ(ierr);
135526fbe8dcSKarl Rupp 
1356e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1357d8588912SDave May     }
13582ae74bdbSJed Brown   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each row */
13598188e55aSJed Brown     nsum = 0;
13608188e55aSJed Brown     for (i=0; i<vs->nr; i++) {  /* Add up the local sizes to compute the aggregate offset */
13618188e55aSJed Brown       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1362ce94432eSBarry Smith       if (!sub) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %D",i);
13630298fd71SBarry Smith       ierr = MatGetLocalSize(sub,&n,NULL);CHKERRQ(ierr);
1364ce94432eSBarry Smith       if (n < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
13658188e55aSJed Brown       nsum += n;
13668188e55aSJed Brown     }
1367ce94432eSBarry Smith     ierr    = MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
136830bc264bSJed Brown     offset -= nsum;
1369e2d7f03fSJed Brown     for (i=0; i<vs->nr; i++) {
1370f349c1fdSJed Brown       ierr    = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
13710298fd71SBarry Smith       ierr    = MatGetLocalSize(sub,&n,NULL);CHKERRQ(ierr);
13722ae74bdbSJed Brown       ierr    = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1373ce94432eSBarry Smith       ierr    = ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.row[i]);CHKERRQ(ierr);
1374e2d7f03fSJed Brown       ierr    = ISSetBlockSize(vs->isglobal.row[i],bs);CHKERRQ(ierr);
13752ae74bdbSJed Brown       offset += n;
1376d8588912SDave May     }
1377d8588912SDave May   }
1378d8588912SDave May 
1379d8588912SDave May   if (is_col) { /* valid IS is passed in */
1380d8588912SDave May     /* refs on is[] are incremeneted */
1381e2d7f03fSJed Brown     for (j=0; j<vs->nc; j++) {
1382d8588912SDave May       ierr = PetscObjectReference((PetscObject)is_col[j]);CHKERRQ(ierr);
138326fbe8dcSKarl Rupp 
1384e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1385d8588912SDave May     }
13862ae74bdbSJed Brown   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each column */
13872ae74bdbSJed Brown     offset = A->cmap->rstart;
13888188e55aSJed Brown     nsum   = 0;
13898188e55aSJed Brown     for (j=0; j<vs->nc; j++) {
13908188e55aSJed Brown       ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
1391ce94432eSBarry Smith       if (!sub) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %D",i);
13920298fd71SBarry Smith       ierr = MatGetLocalSize(sub,NULL,&n);CHKERRQ(ierr);
1393ce94432eSBarry Smith       if (n < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
13948188e55aSJed Brown       nsum += n;
13958188e55aSJed Brown     }
1396ce94432eSBarry Smith     ierr    = MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
139730bc264bSJed Brown     offset -= nsum;
1398e2d7f03fSJed Brown     for (j=0; j<vs->nc; j++) {
1399f349c1fdSJed Brown       ierr    = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
14000298fd71SBarry Smith       ierr    = MatGetLocalSize(sub,NULL,&n);CHKERRQ(ierr);
14012ae74bdbSJed Brown       ierr    = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1402ce94432eSBarry Smith       ierr    = ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.col[j]);CHKERRQ(ierr);
1403e2d7f03fSJed Brown       ierr    = ISSetBlockSize(vs->isglobal.col[j],bs);CHKERRQ(ierr);
14042ae74bdbSJed Brown       offset += n;
1405d8588912SDave May     }
1406d8588912SDave May   }
1407e2d7f03fSJed Brown 
1408e2d7f03fSJed Brown   /* Set up the local ISs */
1409785e854fSJed Brown   ierr = PetscMalloc1(vs->nr,&vs->islocal.row);CHKERRQ(ierr);
1410785e854fSJed Brown   ierr = PetscMalloc1(vs->nc,&vs->islocal.col);CHKERRQ(ierr);
1411e2d7f03fSJed Brown   for (i=0,offset=0; i<vs->nr; i++) {
1412e2d7f03fSJed Brown     IS                     isloc;
14130298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1414e2d7f03fSJed Brown     PetscInt               nlocal,bs;
1415e2d7f03fSJed Brown     ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
14160298fd71SBarry Smith     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,&rmap,NULL);CHKERRQ(ierr);}
1417207556f9SJed Brown     if (rmap) {
1418e2d7f03fSJed Brown       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1419e2d7f03fSJed Brown       ierr = ISLocalToGlobalMappingGetSize(rmap,&nlocal);CHKERRQ(ierr);
1420e2d7f03fSJed Brown       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1421e2d7f03fSJed Brown       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1422207556f9SJed Brown     } else {
1423207556f9SJed Brown       nlocal = 0;
14240298fd71SBarry Smith       isloc  = NULL;
1425207556f9SJed Brown     }
1426e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1427e2d7f03fSJed Brown     offset            += nlocal;
1428e2d7f03fSJed Brown   }
14298188e55aSJed Brown   for (i=0,offset=0; i<vs->nc; i++) {
1430e2d7f03fSJed Brown     IS                     isloc;
14310298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1432e2d7f03fSJed Brown     PetscInt               nlocal,bs;
1433e2d7f03fSJed Brown     ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
14340298fd71SBarry Smith     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,NULL,&cmap);CHKERRQ(ierr);}
1435207556f9SJed Brown     if (cmap) {
1436e2d7f03fSJed Brown       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1437e2d7f03fSJed Brown       ierr = ISLocalToGlobalMappingGetSize(cmap,&nlocal);CHKERRQ(ierr);
1438e2d7f03fSJed Brown       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1439e2d7f03fSJed Brown       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1440207556f9SJed Brown     } else {
1441207556f9SJed Brown       nlocal = 0;
14420298fd71SBarry Smith       isloc  = NULL;
1443207556f9SJed Brown     }
1444e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1445e2d7f03fSJed Brown     offset            += nlocal;
1446e2d7f03fSJed Brown   }
14470189643fSJed Brown 
144877019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
144977019fcaSJed Brown   {
145045b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap,cmap;
145145b6f7e9SBarry Smith     ierr = MatNestCreateAggregateL2G_Private(A,vs->nr,vs->islocal.row,vs->isglobal.row,PETSC_FALSE,&rmap);CHKERRQ(ierr);
145245b6f7e9SBarry Smith     ierr = MatNestCreateAggregateL2G_Private(A,vs->nc,vs->islocal.col,vs->isglobal.col,PETSC_TRUE,&cmap);CHKERRQ(ierr);
145377019fcaSJed Brown     if (rmap && cmap) {ierr = MatSetLocalToGlobalMapping(A,rmap,cmap);CHKERRQ(ierr);}
145477019fcaSJed Brown     ierr = ISLocalToGlobalMappingDestroy(&rmap);CHKERRQ(ierr);
145577019fcaSJed Brown     ierr = ISLocalToGlobalMappingDestroy(&cmap);CHKERRQ(ierr);
145677019fcaSJed Brown   }
145777019fcaSJed Brown 
14580189643fSJed Brown #if defined(PETSC_USE_DEBUG)
14590189643fSJed Brown   for (i=0; i<vs->nr; i++) {
14600189643fSJed Brown     for (j=0; j<vs->nc; j++) {
14610189643fSJed Brown       PetscInt m,n,M,N,mi,ni,Mi,Ni;
14620189643fSJed Brown       Mat      B = vs->m[i][j];
14630189643fSJed Brown       if (!B) continue;
14640189643fSJed Brown       ierr = MatGetSize(B,&M,&N);CHKERRQ(ierr);
14650189643fSJed Brown       ierr = MatGetLocalSize(B,&m,&n);CHKERRQ(ierr);
14660189643fSJed Brown       ierr = ISGetSize(vs->isglobal.row[i],&Mi);CHKERRQ(ierr);
14670189643fSJed Brown       ierr = ISGetSize(vs->isglobal.col[j],&Ni);CHKERRQ(ierr);
14680189643fSJed Brown       ierr = ISGetLocalSize(vs->isglobal.row[i],&mi);CHKERRQ(ierr);
14690189643fSJed Brown       ierr = ISGetLocalSize(vs->isglobal.col[j],&ni);CHKERRQ(ierr);
1470ce94432eSBarry Smith       if (M != Mi || N != Ni) SETERRQ6(PetscObjectComm((PetscObject)sub),PETSC_ERR_ARG_INCOMP,"Global sizes (%D,%D) of nested submatrix (%D,%D) do not agree with space defined by index sets (%D,%D)",M,N,i,j,Mi,Ni);
1471ce94432eSBarry Smith       if (m != mi || n != ni) SETERRQ6(PetscObjectComm((PetscObject)sub),PETSC_ERR_ARG_INCOMP,"Local sizes (%D,%D) of nested submatrix (%D,%D) do not agree with space defined by index sets (%D,%D)",m,n,i,j,mi,ni);
14720189643fSJed Brown     }
14730189643fSJed Brown   }
14740189643fSJed Brown #endif
1475a061e289SJed Brown 
1476a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1477a061e289SJed Brown   for (i=0; i<vs->nr; i++) {
1478a061e289SJed Brown     for (j=0; j<vs->nc; j++) {
1479a061e289SJed Brown       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0);
1480a061e289SJed Brown     }
1481a061e289SJed Brown   }
1482a061e289SJed Brown   A->assembled = PETSC_TRUE;
1483d8588912SDave May   PetscFunctionReturn(0);
1484d8588912SDave May }
1485d8588912SDave May 
148645c38901SJed Brown /*@C
1487659c6bb0SJed Brown    MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately
1488659c6bb0SJed Brown 
1489659c6bb0SJed Brown    Collective on Mat
1490659c6bb0SJed Brown 
1491659c6bb0SJed Brown    Input Parameter:
1492659c6bb0SJed Brown +  comm - Communicator for the new Mat
1493659c6bb0SJed Brown .  nr - number of nested row blocks
14940298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1495659c6bb0SJed Brown .  nc - number of nested column blocks
14960298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
14970298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1498659c6bb0SJed Brown 
1499659c6bb0SJed Brown    Output Parameter:
1500659c6bb0SJed Brown .  B - new matrix
1501659c6bb0SJed Brown 
1502659c6bb0SJed Brown    Level: advanced
1503659c6bb0SJed Brown 
1504950540a4SJed Brown .seealso: MatCreate(), VecCreateNest(), DMCreateMatrix(), MATNEST
1505659c6bb0SJed Brown @*/
15067087cfbeSBarry Smith PetscErrorCode MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat *B)
1507d8588912SDave May {
1508d8588912SDave May   Mat            A;
1509d8588912SDave May   PetscErrorCode ierr;
1510d8588912SDave May 
1511d8588912SDave May   PetscFunctionBegin;
1512c8883902SJed Brown   *B   = 0;
1513d8588912SDave May   ierr = MatCreate(comm,&A);CHKERRQ(ierr);
1514c8883902SJed Brown   ierr = MatSetType(A,MATNEST);CHKERRQ(ierr);
151591a28eb3SBarry Smith   A->preallocated = PETSC_TRUE;
1516c8883902SJed Brown   ierr = MatNestSetSubMats(A,nr,is_row,nc,is_col,a);CHKERRQ(ierr);
1517d8588912SDave May   *B   = A;
1518d8588912SDave May   PetscFunctionReturn(0);
1519d8588912SDave May }
1520659c6bb0SJed Brown 
1521b68353e5Sstefano_zampini static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
1522b68353e5Sstefano_zampini {
1523b68353e5Sstefano_zampini   Mat_Nest       *nest = (Mat_Nest*)A->data;
152423875855Sstefano_zampini   Mat            *trans;
1525b68353e5Sstefano_zampini   PetscScalar    **avv;
1526b68353e5Sstefano_zampini   PetscScalar    *vv;
1527b68353e5Sstefano_zampini   PetscInt       **aii,**ajj;
1528b68353e5Sstefano_zampini   PetscInt       *ii,*jj,*ci;
1529b68353e5Sstefano_zampini   PetscInt       nr,nc,nnz,i,j;
1530b68353e5Sstefano_zampini   PetscBool      done;
1531b68353e5Sstefano_zampini   PetscErrorCode ierr;
1532b68353e5Sstefano_zampini 
1533b68353e5Sstefano_zampini   PetscFunctionBegin;
1534b68353e5Sstefano_zampini   ierr = MatGetSize(A,&nr,&nc);CHKERRQ(ierr);
1535b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1536b68353e5Sstefano_zampini     PetscInt rnr;
1537b68353e5Sstefano_zampini 
1538b68353e5Sstefano_zampini     ierr = MatGetRowIJ(*newmat,0,PETSC_FALSE,PETSC_FALSE,&rnr,(const PetscInt**)&ii,(const PetscInt**)&jj,&done);CHKERRQ(ierr);
1539b68353e5Sstefano_zampini     if (!done) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"MatGetRowIJ");
1540b68353e5Sstefano_zampini     if (rnr != nr) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of rows");
1541b68353e5Sstefano_zampini     ierr = MatSeqAIJGetArray(*newmat,&vv);CHKERRQ(ierr);
1542b68353e5Sstefano_zampini   }
1543b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1544b68353e5Sstefano_zampini   nnz  = 0;
154523875855Sstefano_zampini   ierr = PetscCalloc4(nest->nr*nest->nc,&aii,nest->nr*nest->nc,&ajj,nest->nr*nest->nc,&avv,nest->nr*nest->nc,&trans);CHKERRQ(ierr);
1546b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1547b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1548b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1549b68353e5Sstefano_zampini       if (B) {
1550b68353e5Sstefano_zampini         PetscScalar *naa;
1551b68353e5Sstefano_zampini         PetscInt    *nii,*njj,nnr;
155223875855Sstefano_zampini         PetscBool   istrans;
1553b68353e5Sstefano_zampini 
155423875855Sstefano_zampini         ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
155523875855Sstefano_zampini         if (istrans) {
155623875855Sstefano_zampini           Mat Bt;
155723875855Sstefano_zampini 
155823875855Sstefano_zampini           ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
155923875855Sstefano_zampini           ierr = MatTranspose(Bt,MAT_INITIAL_MATRIX,&trans[i*nest->nc+j]);CHKERRQ(ierr);
156023875855Sstefano_zampini           B    = trans[i*nest->nc+j];
156123875855Sstefano_zampini         }
1562b68353e5Sstefano_zampini         ierr = MatGetRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&nii,(const PetscInt**)&njj,&done);CHKERRQ(ierr);
1563b68353e5Sstefano_zampini         if (!done) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatGetRowIJ");
1564b68353e5Sstefano_zampini         ierr = MatSeqAIJGetArray(B,&naa);CHKERRQ(ierr);
1565b68353e5Sstefano_zampini         nnz += nii[nnr];
1566b68353e5Sstefano_zampini 
1567b68353e5Sstefano_zampini         aii[i*nest->nc+j] = nii;
1568b68353e5Sstefano_zampini         ajj[i*nest->nc+j] = njj;
1569b68353e5Sstefano_zampini         avv[i*nest->nc+j] = naa;
1570b68353e5Sstefano_zampini       }
1571b68353e5Sstefano_zampini     }
1572b68353e5Sstefano_zampini   }
1573b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
1574b68353e5Sstefano_zampini     ierr = PetscMalloc1(nr+1,&ii);CHKERRQ(ierr);
1575b68353e5Sstefano_zampini     ierr = PetscMalloc1(nnz,&jj);CHKERRQ(ierr);
1576b68353e5Sstefano_zampini     ierr = PetscMalloc1(nnz,&vv);CHKERRQ(ierr);
1577b68353e5Sstefano_zampini   } else {
1578b68353e5Sstefano_zampini     if (nnz != ii[nr]) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of nonzeros");
1579b68353e5Sstefano_zampini   }
1580b68353e5Sstefano_zampini 
1581b68353e5Sstefano_zampini   /* new row pointer */
1582580bdb30SBarry Smith   ierr = PetscArrayzero(ii,nr+1);CHKERRQ(ierr);
1583b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1584b68353e5Sstefano_zampini     PetscInt       ncr,rst;
1585b68353e5Sstefano_zampini 
1586b68353e5Sstefano_zampini     ierr = ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL);CHKERRQ(ierr);
1587b68353e5Sstefano_zampini     ierr = ISGetLocalSize(nest->isglobal.row[i],&ncr);CHKERRQ(ierr);
1588b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1589b68353e5Sstefano_zampini       if (aii[i*nest->nc+j]) {
1590b68353e5Sstefano_zampini         PetscInt    *nii = aii[i*nest->nc+j];
1591b68353e5Sstefano_zampini         PetscInt    ir;
1592b68353e5Sstefano_zampini 
1593b68353e5Sstefano_zampini         for (ir=rst; ir<ncr+rst; ++ir) {
1594b68353e5Sstefano_zampini           ii[ir+1] += nii[1]-nii[0];
1595b68353e5Sstefano_zampini           nii++;
1596b68353e5Sstefano_zampini         }
1597b68353e5Sstefano_zampini       }
1598b68353e5Sstefano_zampini     }
1599b68353e5Sstefano_zampini   }
1600b68353e5Sstefano_zampini   for (i=0; i<nr; i++) ii[i+1] += ii[i];
1601b68353e5Sstefano_zampini 
1602b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
1603b68353e5Sstefano_zampini   ierr = PetscCalloc1(nr,&ci);CHKERRQ(ierr);
1604b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1605b68353e5Sstefano_zampini     PetscInt       ncr,rst;
1606b68353e5Sstefano_zampini 
1607b68353e5Sstefano_zampini     ierr = ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL);CHKERRQ(ierr);
1608b68353e5Sstefano_zampini     ierr = ISGetLocalSize(nest->isglobal.row[i],&ncr);CHKERRQ(ierr);
1609b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1610b68353e5Sstefano_zampini       if (aii[i*nest->nc+j]) {
1611b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i*nest->nc+j];
1612b68353e5Sstefano_zampini         PetscInt    *nii = aii[i*nest->nc+j];
1613b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i*nest->nc+j];
1614b68353e5Sstefano_zampini         PetscInt    ir,cst;
1615b68353e5Sstefano_zampini 
1616b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.col[j],&cst,NULL);CHKERRQ(ierr);
1617b68353e5Sstefano_zampini         for (ir=rst; ir<ncr+rst; ++ir) {
1618b68353e5Sstefano_zampini           PetscInt ij,rsize = nii[1]-nii[0],ist = ii[ir]+ci[ir];
1619b68353e5Sstefano_zampini 
1620b68353e5Sstefano_zampini           for (ij=0;ij<rsize;ij++) {
1621b68353e5Sstefano_zampini             jj[ist+ij] = *njj+cst;
1622b68353e5Sstefano_zampini             vv[ist+ij] = *nvv;
1623b68353e5Sstefano_zampini             njj++;
1624b68353e5Sstefano_zampini             nvv++;
1625b68353e5Sstefano_zampini           }
1626b68353e5Sstefano_zampini           ci[ir] += rsize;
1627b68353e5Sstefano_zampini           nii++;
1628b68353e5Sstefano_zampini         }
1629b68353e5Sstefano_zampini       }
1630b68353e5Sstefano_zampini     }
1631b68353e5Sstefano_zampini   }
1632b68353e5Sstefano_zampini   ierr = PetscFree(ci);CHKERRQ(ierr);
1633b68353e5Sstefano_zampini 
1634b68353e5Sstefano_zampini   /* restore info */
1635b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1636b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1637b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1638b68353e5Sstefano_zampini       if (B) {
1639b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i*nest->nc+j;
164023875855Sstefano_zampini 
164123875855Sstefano_zampini         B    = (trans[k] ? trans[k] : B);
1642b68353e5Sstefano_zampini         ierr = MatRestoreRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&aii[k],(const PetscInt**)&ajj[k],&done);CHKERRQ(ierr);
1643b68353e5Sstefano_zampini         if (!done) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatRestoreRowIJ");
1644b68353e5Sstefano_zampini         ierr = MatSeqAIJRestoreArray(B,&avv[k]);CHKERRQ(ierr);
164523875855Sstefano_zampini         ierr = MatDestroy(&trans[k]);CHKERRQ(ierr);
1646b68353e5Sstefano_zampini       }
1647b68353e5Sstefano_zampini     }
1648b68353e5Sstefano_zampini   }
164923875855Sstefano_zampini   ierr = PetscFree4(aii,ajj,avv,trans);CHKERRQ(ierr);
1650b68353e5Sstefano_zampini 
1651b68353e5Sstefano_zampini   /* finalize newmat */
1652b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
1653b68353e5Sstefano_zampini     ierr = MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,newmat);CHKERRQ(ierr);
1654b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1655b68353e5Sstefano_zampini     Mat B;
1656b68353e5Sstefano_zampini 
1657b68353e5Sstefano_zampini     ierr = MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,&B);CHKERRQ(ierr);
1658b68353e5Sstefano_zampini     ierr = MatHeaderReplace(A,&B);CHKERRQ(ierr);
1659b68353e5Sstefano_zampini   }
1660b68353e5Sstefano_zampini   ierr = MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1661b68353e5Sstefano_zampini   ierr = MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1662b68353e5Sstefano_zampini   {
1663b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ*)((*newmat)->data);
1664b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1665b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1666b68353e5Sstefano_zampini   }
1667b68353e5Sstefano_zampini   PetscFunctionReturn(0);
1668b68353e5Sstefano_zampini }
1669b68353e5Sstefano_zampini 
1670cc2e6a90SBarry Smith PETSC_INTERN PetscErrorCode MatConvert_Nest_AIJ(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
1671629c3df2SDmitry Karpeev {
1672629c3df2SDmitry Karpeev   PetscErrorCode ierr;
1673629c3df2SDmitry Karpeev   Mat_Nest       *nest = (Mat_Nest*)A->data;
167483b1a929SMark Adams   PetscInt       m,n,M,N,i,j,k,*dnnz,*onnz,rstart;
1675649b366bSFande Kong   PetscInt       cstart,cend;
1676b68353e5Sstefano_zampini   PetscMPIInt    size;
1677629c3df2SDmitry Karpeev   Mat            C;
1678629c3df2SDmitry Karpeev 
1679629c3df2SDmitry Karpeev   PetscFunctionBegin;
1680b68353e5Sstefano_zampini   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr);
1681b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
1682b68353e5Sstefano_zampini     PetscInt  nf;
1683b68353e5Sstefano_zampini     PetscBool fast;
1684b68353e5Sstefano_zampini 
1685b68353e5Sstefano_zampini     ierr = PetscStrcmp(newtype,MATAIJ,&fast);CHKERRQ(ierr);
1686b68353e5Sstefano_zampini     if (!fast) {
1687b68353e5Sstefano_zampini       ierr = PetscStrcmp(newtype,MATSEQAIJ,&fast);CHKERRQ(ierr);
1688b68353e5Sstefano_zampini     }
1689b68353e5Sstefano_zampini     for (i=0; i<nest->nr && fast; ++i) {
1690b68353e5Sstefano_zampini       for (j=0; j<nest->nc && fast; ++j) {
1691b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
1692b68353e5Sstefano_zampini         if (B) {
1693b68353e5Sstefano_zampini           ierr = PetscObjectTypeCompare((PetscObject)B,MATSEQAIJ,&fast);CHKERRQ(ierr);
169423875855Sstefano_zampini           if (!fast) {
169523875855Sstefano_zampini             PetscBool istrans;
169623875855Sstefano_zampini 
169723875855Sstefano_zampini             ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
169823875855Sstefano_zampini             if (istrans) {
169923875855Sstefano_zampini               Mat Bt;
170023875855Sstefano_zampini 
170123875855Sstefano_zampini               ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
170223875855Sstefano_zampini               ierr = PetscObjectTypeCompare((PetscObject)Bt,MATSEQAIJ,&fast);CHKERRQ(ierr);
170323875855Sstefano_zampini             }
1704b68353e5Sstefano_zampini           }
1705b68353e5Sstefano_zampini         }
1706b68353e5Sstefano_zampini       }
1707b68353e5Sstefano_zampini     }
1708b68353e5Sstefano_zampini     for (i=0, nf=0; i<nest->nr && fast; ++i) {
1709b68353e5Sstefano_zampini       ierr = PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i],ISSTRIDE,&fast);CHKERRQ(ierr);
1710b68353e5Sstefano_zampini       if (fast) {
1711b68353e5Sstefano_zampini         PetscInt f,s;
1712b68353e5Sstefano_zampini 
1713b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.row[i],&f,&s);CHKERRQ(ierr);
1714b68353e5Sstefano_zampini         if (f != nf || s != 1) { fast = PETSC_FALSE; }
1715b68353e5Sstefano_zampini         else {
1716b68353e5Sstefano_zampini           ierr = ISGetSize(nest->isglobal.row[i],&f);CHKERRQ(ierr);
1717b68353e5Sstefano_zampini           nf  += f;
1718b68353e5Sstefano_zampini         }
1719b68353e5Sstefano_zampini       }
1720b68353e5Sstefano_zampini     }
1721b68353e5Sstefano_zampini     for (i=0, nf=0; i<nest->nc && fast; ++i) {
1722b68353e5Sstefano_zampini       ierr = PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i],ISSTRIDE,&fast);CHKERRQ(ierr);
1723b68353e5Sstefano_zampini       if (fast) {
1724b68353e5Sstefano_zampini         PetscInt f,s;
1725b68353e5Sstefano_zampini 
1726b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.col[i],&f,&s);CHKERRQ(ierr);
1727b68353e5Sstefano_zampini         if (f != nf || s != 1) { fast = PETSC_FALSE; }
1728b68353e5Sstefano_zampini         else {
1729b68353e5Sstefano_zampini           ierr = ISGetSize(nest->isglobal.col[i],&f);CHKERRQ(ierr);
1730b68353e5Sstefano_zampini           nf  += f;
1731b68353e5Sstefano_zampini         }
1732b68353e5Sstefano_zampini       }
1733b68353e5Sstefano_zampini     }
1734b68353e5Sstefano_zampini     if (fast) {
1735b68353e5Sstefano_zampini       ierr = MatConvert_Nest_SeqAIJ_fast(A,newtype,reuse,newmat);CHKERRQ(ierr);
1736b68353e5Sstefano_zampini       PetscFunctionReturn(0);
1737b68353e5Sstefano_zampini     }
1738b68353e5Sstefano_zampini   }
1739629c3df2SDmitry Karpeev   ierr = MatGetSize(A,&M,&N);CHKERRQ(ierr);
1740629c3df2SDmitry Karpeev   ierr = MatGetLocalSize(A,&m,&n);CHKERRQ(ierr);
1741649b366bSFande Kong   ierr = MatGetOwnershipRangeColumn(A,&cstart,&cend);CHKERRQ(ierr);
1742629c3df2SDmitry Karpeev   switch (reuse) {
1743629c3df2SDmitry Karpeev   case MAT_INITIAL_MATRIX:
1744ce94432eSBarry Smith     ierr    = MatCreate(PetscObjectComm((PetscObject)A),&C);CHKERRQ(ierr);
1745629c3df2SDmitry Karpeev     ierr    = MatSetType(C,newtype);CHKERRQ(ierr);
1746629c3df2SDmitry Karpeev     ierr    = MatSetSizes(C,m,n,M,N);CHKERRQ(ierr);
1747629c3df2SDmitry Karpeev     *newmat = C;
1748629c3df2SDmitry Karpeev     break;
1749629c3df2SDmitry Karpeev   case MAT_REUSE_MATRIX:
1750629c3df2SDmitry Karpeev     C = *newmat;
1751629c3df2SDmitry Karpeev     break;
1752ce94432eSBarry Smith   default: SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MatReuse");
1753629c3df2SDmitry Karpeev   }
1754785e854fSJed Brown   ierr = PetscMalloc1(2*m,&dnnz);CHKERRQ(ierr);
1755629c3df2SDmitry Karpeev   onnz = dnnz + m;
1756629c3df2SDmitry Karpeev   for (k=0; k<m; k++) {
1757629c3df2SDmitry Karpeev     dnnz[k] = 0;
1758629c3df2SDmitry Karpeev     onnz[k] = 0;
1759629c3df2SDmitry Karpeev   }
1760629c3df2SDmitry Karpeev   for (j=0; j<nest->nc; ++j) {
1761629c3df2SDmitry Karpeev     IS             bNis;
1762629c3df2SDmitry Karpeev     PetscInt       bN;
1763629c3df2SDmitry Karpeev     const PetscInt *bNindices;
1764629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
1765629c3df2SDmitry Karpeev     ierr = ISAllGather(nest->isglobal.col[j], &bNis);CHKERRQ(ierr);
1766629c3df2SDmitry Karpeev     ierr = ISGetSize(bNis, &bN);CHKERRQ(ierr);
1767629c3df2SDmitry Karpeev     ierr = ISGetIndices(bNis,&bNindices);CHKERRQ(ierr);
1768629c3df2SDmitry Karpeev     for (i=0; i<nest->nr; ++i) {
1769629c3df2SDmitry Karpeev       PetscSF        bmsf;
1770649b366bSFande Kong       PetscSFNode    *iremote;
1771629c3df2SDmitry Karpeev       Mat            B;
1772649b366bSFande Kong       PetscInt       bm, *sub_dnnz,*sub_onnz, br;
1773629c3df2SDmitry Karpeev       const PetscInt *bmindices;
1774629c3df2SDmitry Karpeev       B = nest->m[i][j];
1775629c3df2SDmitry Karpeev       if (!B) continue;
1776629c3df2SDmitry Karpeev       ierr = ISGetLocalSize(nest->isglobal.row[i],&bm);CHKERRQ(ierr);
1777629c3df2SDmitry Karpeev       ierr = ISGetIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
1778ce94432eSBarry Smith       ierr = PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf);CHKERRQ(ierr);
1779649b366bSFande Kong       ierr = PetscMalloc1(bm,&iremote);CHKERRQ(ierr);
1780649b366bSFande Kong       ierr = PetscMalloc1(bm,&sub_dnnz);CHKERRQ(ierr);
1781649b366bSFande Kong       ierr = PetscMalloc1(bm,&sub_onnz);CHKERRQ(ierr);
1782649b366bSFande Kong       for (k = 0; k < bm; ++k){
1783649b366bSFande Kong     	sub_dnnz[k] = 0;
1784649b366bSFande Kong     	sub_onnz[k] = 0;
1785649b366bSFande Kong       }
1786629c3df2SDmitry Karpeev       /*
1787629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
1788629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
1789629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
1790629c3df2SDmitry Karpeev        */
179183b1a929SMark Adams       ierr = MatGetOwnershipRange(B,&rstart,NULL);CHKERRQ(ierr);
1792629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
1793649b366bSFande Kong         PetscInt       row = bmindices[br], rowowner = 0, brncols, col;
1794629c3df2SDmitry Karpeev         const PetscInt *brcols;
1795a4b3d3acSMatthew G Knepley         PetscInt       rowrel = 0; /* row's relative index on its owner rank */
1796629c3df2SDmitry Karpeev         ierr      = PetscLayoutFindOwnerIndex(A->rmap,row,&rowowner,&rowrel);CHKERRQ(ierr);
1797649b366bSFande Kong         /* how many roots  */
1798649b366bSFande Kong         iremote[br].rank = rowowner; iremote[br].index = rowrel;           /* edge from bmdnnz to dnnz */
1799649b366bSFande Kong         /* get nonzero pattern */
180083b1a929SMark Adams         ierr = MatGetRow(B,br+rstart,&brncols,&brcols,NULL);CHKERRQ(ierr);
1801629c3df2SDmitry Karpeev         for (k=0; k<brncols; k++) {
1802629c3df2SDmitry Karpeev           col  = bNindices[brcols[k]];
1803649b366bSFande Kong           if (col>=A->cmap->range[rowowner] && col<A->cmap->range[rowowner+1]) {
1804649b366bSFande Kong             sub_dnnz[br]++;
1805649b366bSFande Kong           } else {
1806649b366bSFande Kong             sub_onnz[br]++;
1807649b366bSFande Kong           }
1808629c3df2SDmitry Karpeev         }
180983b1a929SMark Adams         ierr = MatRestoreRow(B,br+rstart,&brncols,&brcols,NULL);CHKERRQ(ierr);
1810629c3df2SDmitry Karpeev       }
1811629c3df2SDmitry Karpeev       ierr = ISRestoreIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
1812629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
1813649b366bSFande Kong       ierr = PetscSFSetGraph(bmsf,m,bm,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
1814649b366bSFande Kong       ierr = PetscSFReduceBegin(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM);CHKERRQ(ierr);
1815649b366bSFande Kong       ierr = PetscSFReduceEnd(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM);CHKERRQ(ierr);
1816649b366bSFande Kong       ierr = PetscSFReduceBegin(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM);CHKERRQ(ierr);
1817649b366bSFande Kong       ierr = PetscSFReduceEnd(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM);CHKERRQ(ierr);
1818649b366bSFande Kong       ierr = PetscFree(sub_dnnz);CHKERRQ(ierr);
1819649b366bSFande Kong       ierr = PetscFree(sub_onnz);CHKERRQ(ierr);
1820629c3df2SDmitry Karpeev       ierr = PetscSFDestroy(&bmsf);CHKERRQ(ierr);
1821629c3df2SDmitry Karpeev     }
182222d28d08SBarry Smith     ierr = ISRestoreIndices(bNis,&bNindices);CHKERRQ(ierr);
1823629c3df2SDmitry Karpeev     ierr = ISDestroy(&bNis);CHKERRQ(ierr);
182465a4a0a3Sstefano_zampini   }
182565a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
182665a4a0a3Sstefano_zampini   for (i=0;i<m;i++) {
182765a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i],A->cmap->n);
182865a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i],A->cmap->N - A->cmap->n);
1829629c3df2SDmitry Karpeev   }
1830629c3df2SDmitry Karpeev   ierr = MatSeqAIJSetPreallocation(C,0,dnnz);CHKERRQ(ierr);
1831629c3df2SDmitry Karpeev   ierr = MatMPIAIJSetPreallocation(C,0,dnnz,0,onnz);CHKERRQ(ierr);
1832629c3df2SDmitry Karpeev   ierr = PetscFree(dnnz);CHKERRQ(ierr);
1833629c3df2SDmitry Karpeev 
1834629c3df2SDmitry Karpeev   /* Fill by row */
1835629c3df2SDmitry Karpeev   for (j=0; j<nest->nc; ++j) {
1836629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
1837629c3df2SDmitry Karpeev     IS             bNis;
1838629c3df2SDmitry Karpeev     PetscInt       bN;
1839629c3df2SDmitry Karpeev     const PetscInt *bNindices;
1840629c3df2SDmitry Karpeev     ierr = ISAllGather(nest->isglobal.col[j], &bNis);CHKERRQ(ierr);
1841629c3df2SDmitry Karpeev     ierr = ISGetSize(bNis,&bN);CHKERRQ(ierr);
1842629c3df2SDmitry Karpeev     ierr = ISGetIndices(bNis,&bNindices);CHKERRQ(ierr);
1843629c3df2SDmitry Karpeev     for (i=0; i<nest->nr; ++i) {
1844629c3df2SDmitry Karpeev       Mat            B;
1845629c3df2SDmitry Karpeev       PetscInt       bm, br;
1846629c3df2SDmitry Karpeev       const PetscInt *bmindices;
1847629c3df2SDmitry Karpeev       B = nest->m[i][j];
1848629c3df2SDmitry Karpeev       if (!B) continue;
1849629c3df2SDmitry Karpeev       ierr = ISGetLocalSize(nest->isglobal.row[i],&bm);CHKERRQ(ierr);
1850629c3df2SDmitry Karpeev       ierr = ISGetIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
185183b1a929SMark Adams       ierr = MatGetOwnershipRange(B,&rstart,NULL);CHKERRQ(ierr);
1852629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
1853629c3df2SDmitry Karpeev         PetscInt          row = bmindices[br], brncols,  *cols;
1854629c3df2SDmitry Karpeev         const PetscInt    *brcols;
1855629c3df2SDmitry Karpeev         const PetscScalar *brcoldata;
185683b1a929SMark Adams         ierr = MatGetRow(B,br+rstart,&brncols,&brcols,&brcoldata);CHKERRQ(ierr);
1857785e854fSJed Brown         ierr = PetscMalloc1(brncols,&cols);CHKERRQ(ierr);
185826fbe8dcSKarl Rupp         for (k=0; k<brncols; k++) cols[k] = bNindices[brcols[k]];
1859629c3df2SDmitry Karpeev         /*
1860629c3df2SDmitry Karpeev           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1861629c3df2SDmitry Karpeev           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1862629c3df2SDmitry Karpeev          */
1863a2ea699eSBarry Smith         ierr = MatSetValues(C,1,&row,brncols,cols,brcoldata,ADD_VALUES);CHKERRQ(ierr);
186483b1a929SMark Adams         ierr = MatRestoreRow(B,br+rstart,&brncols,&brcols,&brcoldata);CHKERRQ(ierr);
1865629c3df2SDmitry Karpeev         ierr = PetscFree(cols);CHKERRQ(ierr);
1866629c3df2SDmitry Karpeev       }
1867629c3df2SDmitry Karpeev       ierr = ISRestoreIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
1868629c3df2SDmitry Karpeev     }
1869a2ea699eSBarry Smith     ierr = ISRestoreIndices(bNis,&bNindices);CHKERRQ(ierr);
1870629c3df2SDmitry Karpeev     ierr = ISDestroy(&bNis);CHKERRQ(ierr);
1871629c3df2SDmitry Karpeev   }
1872629c3df2SDmitry Karpeev   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1873629c3df2SDmitry Karpeev   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1874629c3df2SDmitry Karpeev   PetscFunctionReturn(0);
1875629c3df2SDmitry Karpeev }
1876629c3df2SDmitry Karpeev 
18778b7d3b4bSBarry Smith PetscErrorCode  MatHasOperation_Nest(Mat mat,MatOperation op,PetscBool  *has)
18788b7d3b4bSBarry Smith {
18798b7d3b4bSBarry Smith   PetscFunctionBegin;
18808b7d3b4bSBarry Smith   *has = PETSC_FALSE;
18818b7d3b4bSBarry Smith   if (op == MATOP_MULT_TRANSPOSE) {
18828b7d3b4bSBarry Smith     Mat_Nest       *bA = (Mat_Nest*)mat->data;
18838b7d3b4bSBarry Smith     PetscInt       i,j,nr = bA->nr,nc = bA->nc;
18848b7d3b4bSBarry Smith     PetscErrorCode ierr;
18858b7d3b4bSBarry Smith     PetscBool      flg;
18868b7d3b4bSBarry Smith 
18878b7d3b4bSBarry Smith     for (j=0; j<nc; j++) {
18888b7d3b4bSBarry Smith       for (i=0; i<nr; i++) {
18898b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
18908b7d3b4bSBarry Smith         ierr = MatHasOperation(bA->m[i][j],MATOP_MULT_TRANSPOSE_ADD,&flg);CHKERRQ(ierr);
18918b7d3b4bSBarry Smith         if (!flg) PetscFunctionReturn(0);
18928b7d3b4bSBarry Smith       }
18938b7d3b4bSBarry Smith     }
18948b7d3b4bSBarry Smith   }
18958b7d3b4bSBarry Smith   if (((void**)mat->ops)[op]) *has =  PETSC_TRUE;
18968b7d3b4bSBarry Smith   PetscFunctionReturn(0);
18978b7d3b4bSBarry Smith }
18988b7d3b4bSBarry Smith 
1899659c6bb0SJed Brown /*MC
1900659c6bb0SJed Brown   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.
1901659c6bb0SJed Brown 
1902659c6bb0SJed Brown   Level: intermediate
1903659c6bb0SJed Brown 
1904659c6bb0SJed Brown   Notes:
1905659c6bb0SJed Brown   This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices.
1906659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
1907950540a4SJed Brown   It is usually used with DMComposite and DMCreateMatrix()
1908659c6bb0SJed Brown 
19098b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
19108b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
19118b7d3b4bSBarry Smith   than the nest matrix.
19128b7d3b4bSBarry Smith 
1913659c6bb0SJed Brown .seealso: MatCreate(), MatType, MatCreateNest()
1914659c6bb0SJed Brown M*/
19158cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
1916c8883902SJed Brown {
1917c8883902SJed Brown   Mat_Nest       *s;
1918c8883902SJed Brown   PetscErrorCode ierr;
1919c8883902SJed Brown 
1920c8883902SJed Brown   PetscFunctionBegin;
1921b00a9115SJed Brown   ierr    = PetscNewLog(A,&s);CHKERRQ(ierr);
1922c8883902SJed Brown   A->data = (void*)s;
1923e7c19651SJed Brown 
1924e7c19651SJed Brown   s->nr            = -1;
1925e7c19651SJed Brown   s->nc            = -1;
19260298fd71SBarry Smith   s->m             = NULL;
1927e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
1928c8883902SJed Brown 
1929c8883902SJed Brown   ierr = PetscMemzero(A->ops,sizeof(*A->ops));CHKERRQ(ierr);
193026fbe8dcSKarl Rupp 
1931c8883902SJed Brown   A->ops->mult                  = MatMult_Nest;
19329194d70fSJed Brown   A->ops->multadd               = MatMultAdd_Nest;
1933c8883902SJed Brown   A->ops->multtranspose         = MatMultTranspose_Nest;
19349194d70fSJed Brown   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
1935f8170845SAlex Fikl   A->ops->transpose             = MatTranspose_Nest;
1936c8883902SJed Brown   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
1937c8883902SJed Brown   A->ops->assemblyend           = MatAssemblyEnd_Nest;
1938c8883902SJed Brown   A->ops->zeroentries           = MatZeroEntries_Nest;
1939c222c20dSDavid Ham   A->ops->copy                  = MatCopy_Nest;
19406e76ffeaSPierre Jolivet   A->ops->axpy                  = MatAXPY_Nest;
1941c8883902SJed Brown   A->ops->duplicate             = MatDuplicate_Nest;
19427dae84e0SHong Zhang   A->ops->createsubmatrix       = MatCreateSubMatrix_Nest;
1943c8883902SJed Brown   A->ops->destroy               = MatDestroy_Nest;
1944c8883902SJed Brown   A->ops->view                  = MatView_Nest;
1945c8883902SJed Brown   A->ops->getvecs               = 0; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
1946c8883902SJed Brown   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
1947c8883902SJed Brown   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
1948429bac76SJed Brown   A->ops->getdiagonal           = MatGetDiagonal_Nest;
1949429bac76SJed Brown   A->ops->diagonalscale         = MatDiagonalScale_Nest;
1950a061e289SJed Brown   A->ops->scale                 = MatScale_Nest;
1951a061e289SJed Brown   A->ops->shift                 = MatShift_Nest;
195213135bc6SAlex Fikl   A->ops->diagonalset           = MatDiagonalSet_Nest;
1953f8170845SAlex Fikl   A->ops->setrandom             = MatSetRandom_Nest;
19548b7d3b4bSBarry Smith   A->ops->hasoperation          = MatHasOperation_Nest;
1955c8883902SJed Brown 
1956c8883902SJed Brown   A->spptr        = 0;
1957c8883902SJed Brown   A->assembled    = PETSC_FALSE;
1958c8883902SJed Brown 
1959c8883902SJed Brown   /* expose Nest api's */
1960bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",      MatNestGetSubMat_Nest);CHKERRQ(ierr);
1961bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",      MatNestSetSubMat_Nest);CHKERRQ(ierr);
1962bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",     MatNestGetSubMats_Nest);CHKERRQ(ierr);
1963bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",        MatNestGetSize_Nest);CHKERRQ(ierr);
1964bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",         MatNestGetISs_Nest);CHKERRQ(ierr);
1965bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",    MatNestGetLocalISs_Nest);CHKERRQ(ierr);
1966bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",     MatNestSetVecType_Nest);CHKERRQ(ierr);
1967bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",     MatNestSetSubMats_Nest);CHKERRQ(ierr);
19680899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",MatConvert_Nest_AIJ);CHKERRQ(ierr);
19690899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",MatConvert_Nest_AIJ);CHKERRQ(ierr);
197083b1a929SMark Adams   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",   MatConvert_Nest_AIJ);CHKERRQ(ierr);
19715e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",    MatConvert_Nest_IS);CHKERRQ(ierr);
1972c8883902SJed Brown 
1973c8883902SJed Brown   ierr = PetscObjectChangeTypeName((PetscObject)A,MATNEST);CHKERRQ(ierr);
1974c8883902SJed Brown   PetscFunctionReturn(0);
1975c8883902SJed Brown }
1976