xref: /petsc/src/mat/impls/nest/matnest.c (revision 060bfc1970e0e31fbb4e92b33c004358b2d5dc4b)
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;
359320466b0SStefano 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 
795*060bfc19SStefano Zampini         if (str != DIFFERENT_NONZERO_PATTERN) SETERRQ2(PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Matrix block does not exist at %D,%D. Use DIFFERENT_NONZERO_PATTERN",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       }
800*060bfc19SStefano Zampini       if (bY->m[i][j]) { 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++) {
1194320466b0SStefano 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;
1257aea6d515SStefano Zampini   *ltog = NULL;
125877019fcaSJed Brown   for (i=0,m=0,flg=PETSC_FALSE; i<n; i++) {
125977019fcaSJed Brown     if (islocal[i]) {
1260aea6d515SStefano Zampini       ierr = ISGetLocalSize(islocal[i],&mi);CHKERRQ(ierr);
126177019fcaSJed Brown       flg  = PETSC_TRUE;      /* We found a non-trivial entry */
126277019fcaSJed Brown     } else {
1263aea6d515SStefano Zampini       ierr = ISGetLocalSize(isglobal[i],&mi);CHKERRQ(ierr);
126477019fcaSJed Brown     }
126577019fcaSJed Brown     m += mi;
126677019fcaSJed Brown   }
1267aea6d515SStefano Zampini   if (!flg) PetscFunctionReturn(0);
1268aea6d515SStefano Zampini 
1269785e854fSJed Brown   ierr = PetscMalloc1(m,&ix);CHKERRQ(ierr);
1270165cd838SBarry Smith   for (i=0,m=0; i<n; i++) {
12710298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1272e108cb99SStefano Zampini     Mat                    sub = NULL;
1273f6d38dbbSStefano Zampini     PetscSF                sf;
1274f6d38dbbSStefano Zampini     PetscLayout            map;
1275aea6d515SStefano Zampini     const PetscInt         *ix2;
127677019fcaSJed Brown 
1277165cd838SBarry Smith     if (!colflg) {
127877019fcaSJed Brown       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
127977019fcaSJed Brown     } else {
128077019fcaSJed Brown       ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
128177019fcaSJed Brown     }
1282191fd14bSBarry Smith     if (sub) {
1283191fd14bSBarry Smith       if (!colflg) {
1284191fd14bSBarry Smith         ierr = MatGetLocalToGlobalMapping(sub,&smap,NULL);CHKERRQ(ierr);
1285191fd14bSBarry Smith       } else {
1286191fd14bSBarry Smith         ierr = MatGetLocalToGlobalMapping(sub,NULL,&smap);CHKERRQ(ierr);
1287191fd14bSBarry Smith       }
1288191fd14bSBarry Smith     }
128977019fcaSJed Brown     /*
129077019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
129177019fcaSJed 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.
129277019fcaSJed Brown     */
1293aea6d515SStefano Zampini     ierr = ISGetIndices(isglobal[i],&ix2);CHKERRQ(ierr);
1294aea6d515SStefano Zampini     if (islocal[i]) {
1295aea6d515SStefano Zampini       PetscInt *ilocal,*iremote;
1296aea6d515SStefano Zampini       PetscInt mil,nleaves;
1297aea6d515SStefano Zampini 
1298aea6d515SStefano Zampini       ierr = ISGetLocalSize(islocal[i],&mi);CHKERRQ(ierr);
1299aea6d515SStefano Zampini       if (!smap) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing local to global map");
1300aea6d515SStefano Zampini       for (j=0; j<mi; j++) ix[m+j] = j;
1301aea6d515SStefano Zampini       ierr = ISLocalToGlobalMappingApply(smap,mi,ix+m,ix+m);CHKERRQ(ierr);
1302aea6d515SStefano Zampini 
1303aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
1304aea6d515SStefano Zampini       ierr = PetscMalloc2(mi,&ilocal,mi,&iremote);CHKERRQ(ierr);
1305aea6d515SStefano Zampini       for (j=0, nleaves = 0; j<mi; j++) {
1306aea6d515SStefano Zampini         if (ix[m+j] < 0) continue;
1307aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1308aea6d515SStefano Zampini         iremote[nleaves] = ix[m+j];
1309aea6d515SStefano Zampini         nleaves++;
1310aea6d515SStefano Zampini       }
1311aea6d515SStefano Zampini       ierr = ISGetLocalSize(isglobal[i],&mil);CHKERRQ(ierr);
1312aea6d515SStefano Zampini       ierr = PetscSFCreate(PetscObjectComm((PetscObject)A),&sf);CHKERRQ(ierr);
1313aea6d515SStefano Zampini       ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A),&map);CHKERRQ(ierr);
1314aea6d515SStefano Zampini       ierr = PetscLayoutSetLocalSize(map,mil);CHKERRQ(ierr);
1315f6d38dbbSStefano Zampini       ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
1316aea6d515SStefano Zampini       ierr = PetscSFSetGraphLayout(sf,map,nleaves,ilocal,PETSC_USE_POINTER,iremote);CHKERRQ(ierr);
1317f6d38dbbSStefano Zampini       ierr = PetscLayoutDestroy(&map);CHKERRQ(ierr);
1318f6d38dbbSStefano Zampini       ierr = PetscSFBcastBegin(sf,MPIU_INT,ix2,ix + m);CHKERRQ(ierr);
1319f6d38dbbSStefano Zampini       ierr = PetscSFBcastEnd(sf,MPIU_INT,ix2,ix + m);CHKERRQ(ierr);
1320f6d38dbbSStefano Zampini       ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
1321aea6d515SStefano Zampini       ierr = PetscFree2(ilocal,iremote);CHKERRQ(ierr);
1322aea6d515SStefano Zampini     } else {
1323aea6d515SStefano Zampini       ierr = ISGetLocalSize(isglobal[i],&mi);CHKERRQ(ierr);
1324aea6d515SStefano Zampini       for (j=0; j<mi; j++) ix[m+j] = ix2[i];
1325aea6d515SStefano Zampini     }
1326aea6d515SStefano Zampini     ierr = ISRestoreIndices(isglobal[i],&ix2);CHKERRQ(ierr);
132777019fcaSJed Brown     m   += mi;
132877019fcaSJed Brown   }
1329f0413b6fSBarry Smith   ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,m,ix,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
133077019fcaSJed Brown   PetscFunctionReturn(0);
133177019fcaSJed Brown }
133277019fcaSJed Brown 
133377019fcaSJed Brown 
1334d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1335d8588912SDave May /*
1336d8588912SDave May   nprocessors = NP
1337d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1338d8588912SDave May        proc 0: => (g_0,h_0,)
1339d8588912SDave May        proc 1: => (g_1,h_1,)
1340d8588912SDave May        ...
1341d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1342d8588912SDave May 
1343d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1344d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1345d8588912SDave May 
1346d8588912SDave May             proc 0:
1347d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1348d8588912SDave May             proc 1:
1349d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1350d8588912SDave May 
1351d8588912SDave May             proc NP-1:
1352d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1353d8588912SDave May */
1354841e96a3SJed Brown static PetscErrorCode MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[])
1355d8588912SDave May {
1356e2d7f03fSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
13578188e55aSJed Brown   PetscInt       i,j,offset,n,nsum,bs;
1358d8588912SDave May   PetscErrorCode ierr;
13590298fd71SBarry Smith   Mat            sub = NULL;
1360d8588912SDave May 
1361d8588912SDave May   PetscFunctionBegin;
1362854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&vs->isglobal.row);CHKERRQ(ierr);
1363854ce69bSBarry Smith   ierr = PetscMalloc1(nc,&vs->isglobal.col);CHKERRQ(ierr);
1364d8588912SDave May   if (is_row) { /* valid IS is passed in */
1365d8588912SDave May     /* refs on is[] are incremeneted */
1366e2d7f03fSJed Brown     for (i=0; i<vs->nr; i++) {
1367d8588912SDave May       ierr = PetscObjectReference((PetscObject)is_row[i]);CHKERRQ(ierr);
136826fbe8dcSKarl Rupp 
1369e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1370d8588912SDave May     }
13712ae74bdbSJed Brown   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each row */
13728188e55aSJed Brown     nsum = 0;
13738188e55aSJed Brown     for (i=0; i<vs->nr; i++) {  /* Add up the local sizes to compute the aggregate offset */
13748188e55aSJed Brown       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1375ce94432eSBarry Smith       if (!sub) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %D",i);
13760298fd71SBarry Smith       ierr = MatGetLocalSize(sub,&n,NULL);CHKERRQ(ierr);
1377ce94432eSBarry Smith       if (n < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
13788188e55aSJed Brown       nsum += n;
13798188e55aSJed Brown     }
1380ce94432eSBarry Smith     ierr    = MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
138130bc264bSJed Brown     offset -= nsum;
1382e2d7f03fSJed Brown     for (i=0; i<vs->nr; i++) {
1383f349c1fdSJed Brown       ierr    = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
13840298fd71SBarry Smith       ierr    = MatGetLocalSize(sub,&n,NULL);CHKERRQ(ierr);
13852ae74bdbSJed Brown       ierr    = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1386ce94432eSBarry Smith       ierr    = ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.row[i]);CHKERRQ(ierr);
1387e2d7f03fSJed Brown       ierr    = ISSetBlockSize(vs->isglobal.row[i],bs);CHKERRQ(ierr);
13882ae74bdbSJed Brown       offset += n;
1389d8588912SDave May     }
1390d8588912SDave May   }
1391d8588912SDave May 
1392d8588912SDave May   if (is_col) { /* valid IS is passed in */
1393d8588912SDave May     /* refs on is[] are incremeneted */
1394e2d7f03fSJed Brown     for (j=0; j<vs->nc; j++) {
1395d8588912SDave May       ierr = PetscObjectReference((PetscObject)is_col[j]);CHKERRQ(ierr);
139626fbe8dcSKarl Rupp 
1397e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1398d8588912SDave May     }
13992ae74bdbSJed Brown   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each column */
14002ae74bdbSJed Brown     offset = A->cmap->rstart;
14018188e55aSJed Brown     nsum   = 0;
14028188e55aSJed Brown     for (j=0; j<vs->nc; j++) {
14038188e55aSJed Brown       ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
1404ce94432eSBarry Smith       if (!sub) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %D",i);
14050298fd71SBarry Smith       ierr = MatGetLocalSize(sub,NULL,&n);CHKERRQ(ierr);
1406ce94432eSBarry Smith       if (n < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
14078188e55aSJed Brown       nsum += n;
14088188e55aSJed Brown     }
1409ce94432eSBarry Smith     ierr    = MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
141030bc264bSJed Brown     offset -= nsum;
1411e2d7f03fSJed Brown     for (j=0; j<vs->nc; j++) {
1412f349c1fdSJed Brown       ierr    = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
14130298fd71SBarry Smith       ierr    = MatGetLocalSize(sub,NULL,&n);CHKERRQ(ierr);
14142ae74bdbSJed Brown       ierr    = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1415ce94432eSBarry Smith       ierr    = ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.col[j]);CHKERRQ(ierr);
1416e2d7f03fSJed Brown       ierr    = ISSetBlockSize(vs->isglobal.col[j],bs);CHKERRQ(ierr);
14172ae74bdbSJed Brown       offset += n;
1418d8588912SDave May     }
1419d8588912SDave May   }
1420e2d7f03fSJed Brown 
1421e2d7f03fSJed Brown   /* Set up the local ISs */
1422785e854fSJed Brown   ierr = PetscMalloc1(vs->nr,&vs->islocal.row);CHKERRQ(ierr);
1423785e854fSJed Brown   ierr = PetscMalloc1(vs->nc,&vs->islocal.col);CHKERRQ(ierr);
1424e2d7f03fSJed Brown   for (i=0,offset=0; i<vs->nr; i++) {
1425e2d7f03fSJed Brown     IS                     isloc;
14260298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1427e2d7f03fSJed Brown     PetscInt               nlocal,bs;
1428e2d7f03fSJed Brown     ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
14290298fd71SBarry Smith     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,&rmap,NULL);CHKERRQ(ierr);}
1430207556f9SJed Brown     if (rmap) {
1431e2d7f03fSJed Brown       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1432e2d7f03fSJed Brown       ierr = ISLocalToGlobalMappingGetSize(rmap,&nlocal);CHKERRQ(ierr);
1433e2d7f03fSJed Brown       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1434e2d7f03fSJed Brown       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1435207556f9SJed Brown     } else {
1436207556f9SJed Brown       nlocal = 0;
14370298fd71SBarry Smith       isloc  = NULL;
1438207556f9SJed Brown     }
1439e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1440e2d7f03fSJed Brown     offset            += nlocal;
1441e2d7f03fSJed Brown   }
14428188e55aSJed Brown   for (i=0,offset=0; i<vs->nc; i++) {
1443e2d7f03fSJed Brown     IS                     isloc;
14440298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1445e2d7f03fSJed Brown     PetscInt               nlocal,bs;
1446e2d7f03fSJed Brown     ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
14470298fd71SBarry Smith     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,NULL,&cmap);CHKERRQ(ierr);}
1448207556f9SJed Brown     if (cmap) {
1449e2d7f03fSJed Brown       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1450e2d7f03fSJed Brown       ierr = ISLocalToGlobalMappingGetSize(cmap,&nlocal);CHKERRQ(ierr);
1451e2d7f03fSJed Brown       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1452e2d7f03fSJed Brown       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1453207556f9SJed Brown     } else {
1454207556f9SJed Brown       nlocal = 0;
14550298fd71SBarry Smith       isloc  = NULL;
1456207556f9SJed Brown     }
1457e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1458e2d7f03fSJed Brown     offset            += nlocal;
1459e2d7f03fSJed Brown   }
14600189643fSJed Brown 
146177019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
146277019fcaSJed Brown   {
146345b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap,cmap;
146445b6f7e9SBarry Smith     ierr = MatNestCreateAggregateL2G_Private(A,vs->nr,vs->islocal.row,vs->isglobal.row,PETSC_FALSE,&rmap);CHKERRQ(ierr);
146545b6f7e9SBarry Smith     ierr = MatNestCreateAggregateL2G_Private(A,vs->nc,vs->islocal.col,vs->isglobal.col,PETSC_TRUE,&cmap);CHKERRQ(ierr);
146677019fcaSJed Brown     if (rmap && cmap) {ierr = MatSetLocalToGlobalMapping(A,rmap,cmap);CHKERRQ(ierr);}
146777019fcaSJed Brown     ierr = ISLocalToGlobalMappingDestroy(&rmap);CHKERRQ(ierr);
146877019fcaSJed Brown     ierr = ISLocalToGlobalMappingDestroy(&cmap);CHKERRQ(ierr);
146977019fcaSJed Brown   }
147077019fcaSJed Brown 
14710189643fSJed Brown #if defined(PETSC_USE_DEBUG)
14720189643fSJed Brown   for (i=0; i<vs->nr; i++) {
14730189643fSJed Brown     for (j=0; j<vs->nc; j++) {
14740189643fSJed Brown       PetscInt m,n,M,N,mi,ni,Mi,Ni;
14750189643fSJed Brown       Mat      B = vs->m[i][j];
14760189643fSJed Brown       if (!B) continue;
14770189643fSJed Brown       ierr = MatGetSize(B,&M,&N);CHKERRQ(ierr);
14780189643fSJed Brown       ierr = MatGetLocalSize(B,&m,&n);CHKERRQ(ierr);
14790189643fSJed Brown       ierr = ISGetSize(vs->isglobal.row[i],&Mi);CHKERRQ(ierr);
14800189643fSJed Brown       ierr = ISGetSize(vs->isglobal.col[j],&Ni);CHKERRQ(ierr);
14810189643fSJed Brown       ierr = ISGetLocalSize(vs->isglobal.row[i],&mi);CHKERRQ(ierr);
14820189643fSJed Brown       ierr = ISGetLocalSize(vs->isglobal.col[j],&ni);CHKERRQ(ierr);
1483ce94432eSBarry 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);
1484ce94432eSBarry 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);
14850189643fSJed Brown     }
14860189643fSJed Brown   }
14870189643fSJed Brown #endif
1488a061e289SJed Brown 
1489a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1490a061e289SJed Brown   for (i=0; i<vs->nr; i++) {
1491a061e289SJed Brown     for (j=0; j<vs->nc; j++) {
1492a061e289SJed Brown       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0);
1493a061e289SJed Brown     }
1494a061e289SJed Brown   }
1495a061e289SJed Brown   A->assembled = PETSC_TRUE;
1496d8588912SDave May   PetscFunctionReturn(0);
1497d8588912SDave May }
1498d8588912SDave May 
149945c38901SJed Brown /*@C
1500659c6bb0SJed Brown    MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately
1501659c6bb0SJed Brown 
1502659c6bb0SJed Brown    Collective on Mat
1503659c6bb0SJed Brown 
1504659c6bb0SJed Brown    Input Parameter:
1505659c6bb0SJed Brown +  comm - Communicator for the new Mat
1506659c6bb0SJed Brown .  nr - number of nested row blocks
15070298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1508659c6bb0SJed Brown .  nc - number of nested column blocks
15090298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
15100298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1511659c6bb0SJed Brown 
1512659c6bb0SJed Brown    Output Parameter:
1513659c6bb0SJed Brown .  B - new matrix
1514659c6bb0SJed Brown 
1515659c6bb0SJed Brown    Level: advanced
1516659c6bb0SJed Brown 
1517950540a4SJed Brown .seealso: MatCreate(), VecCreateNest(), DMCreateMatrix(), MATNEST
1518659c6bb0SJed Brown @*/
15197087cfbeSBarry Smith PetscErrorCode MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat *B)
1520d8588912SDave May {
1521d8588912SDave May   Mat            A;
1522d8588912SDave May   PetscErrorCode ierr;
1523d8588912SDave May 
1524d8588912SDave May   PetscFunctionBegin;
1525c8883902SJed Brown   *B   = 0;
1526d8588912SDave May   ierr = MatCreate(comm,&A);CHKERRQ(ierr);
1527c8883902SJed Brown   ierr = MatSetType(A,MATNEST);CHKERRQ(ierr);
152891a28eb3SBarry Smith   A->preallocated = PETSC_TRUE;
1529c8883902SJed Brown   ierr = MatNestSetSubMats(A,nr,is_row,nc,is_col,a);CHKERRQ(ierr);
1530d8588912SDave May   *B   = A;
1531d8588912SDave May   PetscFunctionReturn(0);
1532d8588912SDave May }
1533659c6bb0SJed Brown 
1534b68353e5Sstefano_zampini static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
1535b68353e5Sstefano_zampini {
1536b68353e5Sstefano_zampini   Mat_Nest       *nest = (Mat_Nest*)A->data;
153723875855Sstefano_zampini   Mat            *trans;
1538b68353e5Sstefano_zampini   PetscScalar    **avv;
1539b68353e5Sstefano_zampini   PetscScalar    *vv;
1540b68353e5Sstefano_zampini   PetscInt       **aii,**ajj;
1541b68353e5Sstefano_zampini   PetscInt       *ii,*jj,*ci;
1542b68353e5Sstefano_zampini   PetscInt       nr,nc,nnz,i,j;
1543b68353e5Sstefano_zampini   PetscBool      done;
1544b68353e5Sstefano_zampini   PetscErrorCode ierr;
1545b68353e5Sstefano_zampini 
1546b68353e5Sstefano_zampini   PetscFunctionBegin;
1547b68353e5Sstefano_zampini   ierr = MatGetSize(A,&nr,&nc);CHKERRQ(ierr);
1548b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1549b68353e5Sstefano_zampini     PetscInt rnr;
1550b68353e5Sstefano_zampini 
1551b68353e5Sstefano_zampini     ierr = MatGetRowIJ(*newmat,0,PETSC_FALSE,PETSC_FALSE,&rnr,(const PetscInt**)&ii,(const PetscInt**)&jj,&done);CHKERRQ(ierr);
1552b68353e5Sstefano_zampini     if (!done) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"MatGetRowIJ");
1553b68353e5Sstefano_zampini     if (rnr != nr) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of rows");
1554b68353e5Sstefano_zampini     ierr = MatSeqAIJGetArray(*newmat,&vv);CHKERRQ(ierr);
1555b68353e5Sstefano_zampini   }
1556b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1557b68353e5Sstefano_zampini   nnz  = 0;
155823875855Sstefano_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);
1559b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1560b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1561b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1562b68353e5Sstefano_zampini       if (B) {
1563b68353e5Sstefano_zampini         PetscScalar *naa;
1564b68353e5Sstefano_zampini         PetscInt    *nii,*njj,nnr;
156523875855Sstefano_zampini         PetscBool   istrans;
1566b68353e5Sstefano_zampini 
156723875855Sstefano_zampini         ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
156823875855Sstefano_zampini         if (istrans) {
156923875855Sstefano_zampini           Mat Bt;
157023875855Sstefano_zampini 
157123875855Sstefano_zampini           ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
157223875855Sstefano_zampini           ierr = MatTranspose(Bt,MAT_INITIAL_MATRIX,&trans[i*nest->nc+j]);CHKERRQ(ierr);
157323875855Sstefano_zampini           B    = trans[i*nest->nc+j];
157423875855Sstefano_zampini         }
1575b68353e5Sstefano_zampini         ierr = MatGetRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&nii,(const PetscInt**)&njj,&done);CHKERRQ(ierr);
1576b68353e5Sstefano_zampini         if (!done) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatGetRowIJ");
1577b68353e5Sstefano_zampini         ierr = MatSeqAIJGetArray(B,&naa);CHKERRQ(ierr);
1578b68353e5Sstefano_zampini         nnz += nii[nnr];
1579b68353e5Sstefano_zampini 
1580b68353e5Sstefano_zampini         aii[i*nest->nc+j] = nii;
1581b68353e5Sstefano_zampini         ajj[i*nest->nc+j] = njj;
1582b68353e5Sstefano_zampini         avv[i*nest->nc+j] = naa;
1583b68353e5Sstefano_zampini       }
1584b68353e5Sstefano_zampini     }
1585b68353e5Sstefano_zampini   }
1586b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
1587b68353e5Sstefano_zampini     ierr = PetscMalloc1(nr+1,&ii);CHKERRQ(ierr);
1588b68353e5Sstefano_zampini     ierr = PetscMalloc1(nnz,&jj);CHKERRQ(ierr);
1589b68353e5Sstefano_zampini     ierr = PetscMalloc1(nnz,&vv);CHKERRQ(ierr);
1590b68353e5Sstefano_zampini   } else {
1591b68353e5Sstefano_zampini     if (nnz != ii[nr]) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of nonzeros");
1592b68353e5Sstefano_zampini   }
1593b68353e5Sstefano_zampini 
1594b68353e5Sstefano_zampini   /* new row pointer */
1595580bdb30SBarry Smith   ierr = PetscArrayzero(ii,nr+1);CHKERRQ(ierr);
1596b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1597b68353e5Sstefano_zampini     PetscInt       ncr,rst;
1598b68353e5Sstefano_zampini 
1599b68353e5Sstefano_zampini     ierr = ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL);CHKERRQ(ierr);
1600b68353e5Sstefano_zampini     ierr = ISGetLocalSize(nest->isglobal.row[i],&ncr);CHKERRQ(ierr);
1601b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1602b68353e5Sstefano_zampini       if (aii[i*nest->nc+j]) {
1603b68353e5Sstefano_zampini         PetscInt    *nii = aii[i*nest->nc+j];
1604b68353e5Sstefano_zampini         PetscInt    ir;
1605b68353e5Sstefano_zampini 
1606b68353e5Sstefano_zampini         for (ir=rst; ir<ncr+rst; ++ir) {
1607b68353e5Sstefano_zampini           ii[ir+1] += nii[1]-nii[0];
1608b68353e5Sstefano_zampini           nii++;
1609b68353e5Sstefano_zampini         }
1610b68353e5Sstefano_zampini       }
1611b68353e5Sstefano_zampini     }
1612b68353e5Sstefano_zampini   }
1613b68353e5Sstefano_zampini   for (i=0; i<nr; i++) ii[i+1] += ii[i];
1614b68353e5Sstefano_zampini 
1615b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
1616b68353e5Sstefano_zampini   ierr = PetscCalloc1(nr,&ci);CHKERRQ(ierr);
1617b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1618b68353e5Sstefano_zampini     PetscInt       ncr,rst;
1619b68353e5Sstefano_zampini 
1620b68353e5Sstefano_zampini     ierr = ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL);CHKERRQ(ierr);
1621b68353e5Sstefano_zampini     ierr = ISGetLocalSize(nest->isglobal.row[i],&ncr);CHKERRQ(ierr);
1622b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1623b68353e5Sstefano_zampini       if (aii[i*nest->nc+j]) {
1624b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i*nest->nc+j];
1625b68353e5Sstefano_zampini         PetscInt    *nii = aii[i*nest->nc+j];
1626b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i*nest->nc+j];
1627b68353e5Sstefano_zampini         PetscInt    ir,cst;
1628b68353e5Sstefano_zampini 
1629b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.col[j],&cst,NULL);CHKERRQ(ierr);
1630b68353e5Sstefano_zampini         for (ir=rst; ir<ncr+rst; ++ir) {
1631b68353e5Sstefano_zampini           PetscInt ij,rsize = nii[1]-nii[0],ist = ii[ir]+ci[ir];
1632b68353e5Sstefano_zampini 
1633b68353e5Sstefano_zampini           for (ij=0;ij<rsize;ij++) {
1634b68353e5Sstefano_zampini             jj[ist+ij] = *njj+cst;
1635b68353e5Sstefano_zampini             vv[ist+ij] = *nvv;
1636b68353e5Sstefano_zampini             njj++;
1637b68353e5Sstefano_zampini             nvv++;
1638b68353e5Sstefano_zampini           }
1639b68353e5Sstefano_zampini           ci[ir] += rsize;
1640b68353e5Sstefano_zampini           nii++;
1641b68353e5Sstefano_zampini         }
1642b68353e5Sstefano_zampini       }
1643b68353e5Sstefano_zampini     }
1644b68353e5Sstefano_zampini   }
1645b68353e5Sstefano_zampini   ierr = PetscFree(ci);CHKERRQ(ierr);
1646b68353e5Sstefano_zampini 
1647b68353e5Sstefano_zampini   /* restore info */
1648b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1649b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1650b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1651b68353e5Sstefano_zampini       if (B) {
1652b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i*nest->nc+j;
165323875855Sstefano_zampini 
165423875855Sstefano_zampini         B    = (trans[k] ? trans[k] : B);
1655b68353e5Sstefano_zampini         ierr = MatRestoreRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&aii[k],(const PetscInt**)&ajj[k],&done);CHKERRQ(ierr);
1656b68353e5Sstefano_zampini         if (!done) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatRestoreRowIJ");
1657b68353e5Sstefano_zampini         ierr = MatSeqAIJRestoreArray(B,&avv[k]);CHKERRQ(ierr);
165823875855Sstefano_zampini         ierr = MatDestroy(&trans[k]);CHKERRQ(ierr);
1659b68353e5Sstefano_zampini       }
1660b68353e5Sstefano_zampini     }
1661b68353e5Sstefano_zampini   }
166223875855Sstefano_zampini   ierr = PetscFree4(aii,ajj,avv,trans);CHKERRQ(ierr);
1663b68353e5Sstefano_zampini 
1664b68353e5Sstefano_zampini   /* finalize newmat */
1665b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
1666b68353e5Sstefano_zampini     ierr = MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,newmat);CHKERRQ(ierr);
1667b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1668b68353e5Sstefano_zampini     Mat B;
1669b68353e5Sstefano_zampini 
1670b68353e5Sstefano_zampini     ierr = MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,&B);CHKERRQ(ierr);
1671b68353e5Sstefano_zampini     ierr = MatHeaderReplace(A,&B);CHKERRQ(ierr);
1672b68353e5Sstefano_zampini   }
1673b68353e5Sstefano_zampini   ierr = MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1674b68353e5Sstefano_zampini   ierr = MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1675b68353e5Sstefano_zampini   {
1676b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ*)((*newmat)->data);
1677b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1678b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1679b68353e5Sstefano_zampini   }
1680b68353e5Sstefano_zampini   PetscFunctionReturn(0);
1681b68353e5Sstefano_zampini }
1682b68353e5Sstefano_zampini 
1683cc2e6a90SBarry Smith PETSC_INTERN PetscErrorCode MatConvert_Nest_AIJ(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
1684629c3df2SDmitry Karpeev {
1685629c3df2SDmitry Karpeev   PetscErrorCode ierr;
1686629c3df2SDmitry Karpeev   Mat_Nest       *nest = (Mat_Nest*)A->data;
168783b1a929SMark Adams   PetscInt       m,n,M,N,i,j,k,*dnnz,*onnz,rstart;
1688649b366bSFande Kong   PetscInt       cstart,cend;
1689b68353e5Sstefano_zampini   PetscMPIInt    size;
1690629c3df2SDmitry Karpeev   Mat            C;
1691629c3df2SDmitry Karpeev 
1692629c3df2SDmitry Karpeev   PetscFunctionBegin;
1693b68353e5Sstefano_zampini   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr);
1694b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
1695b68353e5Sstefano_zampini     PetscInt  nf;
1696b68353e5Sstefano_zampini     PetscBool fast;
1697b68353e5Sstefano_zampini 
1698b68353e5Sstefano_zampini     ierr = PetscStrcmp(newtype,MATAIJ,&fast);CHKERRQ(ierr);
1699b68353e5Sstefano_zampini     if (!fast) {
1700b68353e5Sstefano_zampini       ierr = PetscStrcmp(newtype,MATSEQAIJ,&fast);CHKERRQ(ierr);
1701b68353e5Sstefano_zampini     }
1702b68353e5Sstefano_zampini     for (i=0; i<nest->nr && fast; ++i) {
1703b68353e5Sstefano_zampini       for (j=0; j<nest->nc && fast; ++j) {
1704b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
1705b68353e5Sstefano_zampini         if (B) {
1706b68353e5Sstefano_zampini           ierr = PetscObjectTypeCompare((PetscObject)B,MATSEQAIJ,&fast);CHKERRQ(ierr);
170723875855Sstefano_zampini           if (!fast) {
170823875855Sstefano_zampini             PetscBool istrans;
170923875855Sstefano_zampini 
171023875855Sstefano_zampini             ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
171123875855Sstefano_zampini             if (istrans) {
171223875855Sstefano_zampini               Mat Bt;
171323875855Sstefano_zampini 
171423875855Sstefano_zampini               ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
171523875855Sstefano_zampini               ierr = PetscObjectTypeCompare((PetscObject)Bt,MATSEQAIJ,&fast);CHKERRQ(ierr);
171623875855Sstefano_zampini             }
1717b68353e5Sstefano_zampini           }
1718b68353e5Sstefano_zampini         }
1719b68353e5Sstefano_zampini       }
1720b68353e5Sstefano_zampini     }
1721b68353e5Sstefano_zampini     for (i=0, nf=0; i<nest->nr && fast; ++i) {
1722b68353e5Sstefano_zampini       ierr = PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i],ISSTRIDE,&fast);CHKERRQ(ierr);
1723b68353e5Sstefano_zampini       if (fast) {
1724b68353e5Sstefano_zampini         PetscInt f,s;
1725b68353e5Sstefano_zampini 
1726b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.row[i],&f,&s);CHKERRQ(ierr);
1727b68353e5Sstefano_zampini         if (f != nf || s != 1) { fast = PETSC_FALSE; }
1728b68353e5Sstefano_zampini         else {
1729b68353e5Sstefano_zampini           ierr = ISGetSize(nest->isglobal.row[i],&f);CHKERRQ(ierr);
1730b68353e5Sstefano_zampini           nf  += f;
1731b68353e5Sstefano_zampini         }
1732b68353e5Sstefano_zampini       }
1733b68353e5Sstefano_zampini     }
1734b68353e5Sstefano_zampini     for (i=0, nf=0; i<nest->nc && fast; ++i) {
1735b68353e5Sstefano_zampini       ierr = PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i],ISSTRIDE,&fast);CHKERRQ(ierr);
1736b68353e5Sstefano_zampini       if (fast) {
1737b68353e5Sstefano_zampini         PetscInt f,s;
1738b68353e5Sstefano_zampini 
1739b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.col[i],&f,&s);CHKERRQ(ierr);
1740b68353e5Sstefano_zampini         if (f != nf || s != 1) { fast = PETSC_FALSE; }
1741b68353e5Sstefano_zampini         else {
1742b68353e5Sstefano_zampini           ierr = ISGetSize(nest->isglobal.col[i],&f);CHKERRQ(ierr);
1743b68353e5Sstefano_zampini           nf  += f;
1744b68353e5Sstefano_zampini         }
1745b68353e5Sstefano_zampini       }
1746b68353e5Sstefano_zampini     }
1747b68353e5Sstefano_zampini     if (fast) {
1748b68353e5Sstefano_zampini       ierr = MatConvert_Nest_SeqAIJ_fast(A,newtype,reuse,newmat);CHKERRQ(ierr);
1749b68353e5Sstefano_zampini       PetscFunctionReturn(0);
1750b68353e5Sstefano_zampini     }
1751b68353e5Sstefano_zampini   }
1752629c3df2SDmitry Karpeev   ierr = MatGetSize(A,&M,&N);CHKERRQ(ierr);
1753629c3df2SDmitry Karpeev   ierr = MatGetLocalSize(A,&m,&n);CHKERRQ(ierr);
1754649b366bSFande Kong   ierr = MatGetOwnershipRangeColumn(A,&cstart,&cend);CHKERRQ(ierr);
1755629c3df2SDmitry Karpeev   switch (reuse) {
1756629c3df2SDmitry Karpeev   case MAT_INITIAL_MATRIX:
1757ce94432eSBarry Smith     ierr    = MatCreate(PetscObjectComm((PetscObject)A),&C);CHKERRQ(ierr);
1758629c3df2SDmitry Karpeev     ierr    = MatSetType(C,newtype);CHKERRQ(ierr);
1759629c3df2SDmitry Karpeev     ierr    = MatSetSizes(C,m,n,M,N);CHKERRQ(ierr);
1760629c3df2SDmitry Karpeev     *newmat = C;
1761629c3df2SDmitry Karpeev     break;
1762629c3df2SDmitry Karpeev   case MAT_REUSE_MATRIX:
1763629c3df2SDmitry Karpeev     C = *newmat;
1764629c3df2SDmitry Karpeev     break;
1765ce94432eSBarry Smith   default: SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MatReuse");
1766629c3df2SDmitry Karpeev   }
1767785e854fSJed Brown   ierr = PetscMalloc1(2*m,&dnnz);CHKERRQ(ierr);
1768629c3df2SDmitry Karpeev   onnz = dnnz + m;
1769629c3df2SDmitry Karpeev   for (k=0; k<m; k++) {
1770629c3df2SDmitry Karpeev     dnnz[k] = 0;
1771629c3df2SDmitry Karpeev     onnz[k] = 0;
1772629c3df2SDmitry Karpeev   }
1773629c3df2SDmitry Karpeev   for (j=0; j<nest->nc; ++j) {
1774629c3df2SDmitry Karpeev     IS             bNis;
1775629c3df2SDmitry Karpeev     PetscInt       bN;
1776629c3df2SDmitry Karpeev     const PetscInt *bNindices;
1777629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
1778629c3df2SDmitry Karpeev     ierr = ISAllGather(nest->isglobal.col[j], &bNis);CHKERRQ(ierr);
1779629c3df2SDmitry Karpeev     ierr = ISGetSize(bNis, &bN);CHKERRQ(ierr);
1780629c3df2SDmitry Karpeev     ierr = ISGetIndices(bNis,&bNindices);CHKERRQ(ierr);
1781629c3df2SDmitry Karpeev     for (i=0; i<nest->nr; ++i) {
1782629c3df2SDmitry Karpeev       PetscSF        bmsf;
1783649b366bSFande Kong       PetscSFNode    *iremote;
1784629c3df2SDmitry Karpeev       Mat            B;
1785649b366bSFande Kong       PetscInt       bm, *sub_dnnz,*sub_onnz, br;
1786629c3df2SDmitry Karpeev       const PetscInt *bmindices;
1787629c3df2SDmitry Karpeev       B = nest->m[i][j];
1788629c3df2SDmitry Karpeev       if (!B) continue;
1789629c3df2SDmitry Karpeev       ierr = ISGetLocalSize(nest->isglobal.row[i],&bm);CHKERRQ(ierr);
1790629c3df2SDmitry Karpeev       ierr = ISGetIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
1791ce94432eSBarry Smith       ierr = PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf);CHKERRQ(ierr);
1792649b366bSFande Kong       ierr = PetscMalloc1(bm,&iremote);CHKERRQ(ierr);
1793649b366bSFande Kong       ierr = PetscMalloc1(bm,&sub_dnnz);CHKERRQ(ierr);
1794649b366bSFande Kong       ierr = PetscMalloc1(bm,&sub_onnz);CHKERRQ(ierr);
1795649b366bSFande Kong       for (k = 0; k < bm; ++k){
1796649b366bSFande Kong     	sub_dnnz[k] = 0;
1797649b366bSFande Kong     	sub_onnz[k] = 0;
1798649b366bSFande Kong       }
1799629c3df2SDmitry Karpeev       /*
1800629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
1801629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
1802629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
1803629c3df2SDmitry Karpeev        */
180483b1a929SMark Adams       ierr = MatGetOwnershipRange(B,&rstart,NULL);CHKERRQ(ierr);
1805629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
1806649b366bSFande Kong         PetscInt       row = bmindices[br], rowowner = 0, brncols, col;
1807629c3df2SDmitry Karpeev         const PetscInt *brcols;
1808a4b3d3acSMatthew G Knepley         PetscInt       rowrel = 0; /* row's relative index on its owner rank */
1809629c3df2SDmitry Karpeev         ierr      = PetscLayoutFindOwnerIndex(A->rmap,row,&rowowner,&rowrel);CHKERRQ(ierr);
1810649b366bSFande Kong         /* how many roots  */
1811649b366bSFande Kong         iremote[br].rank = rowowner; iremote[br].index = rowrel;           /* edge from bmdnnz to dnnz */
1812649b366bSFande Kong         /* get nonzero pattern */
181383b1a929SMark Adams         ierr = MatGetRow(B,br+rstart,&brncols,&brcols,NULL);CHKERRQ(ierr);
1814629c3df2SDmitry Karpeev         for (k=0; k<brncols; k++) {
1815629c3df2SDmitry Karpeev           col  = bNindices[brcols[k]];
1816649b366bSFande Kong           if (col>=A->cmap->range[rowowner] && col<A->cmap->range[rowowner+1]) {
1817649b366bSFande Kong             sub_dnnz[br]++;
1818649b366bSFande Kong           } else {
1819649b366bSFande Kong             sub_onnz[br]++;
1820649b366bSFande Kong           }
1821629c3df2SDmitry Karpeev         }
182283b1a929SMark Adams         ierr = MatRestoreRow(B,br+rstart,&brncols,&brcols,NULL);CHKERRQ(ierr);
1823629c3df2SDmitry Karpeev       }
1824629c3df2SDmitry Karpeev       ierr = ISRestoreIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
1825629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
1826649b366bSFande Kong       ierr = PetscSFSetGraph(bmsf,m,bm,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
1827649b366bSFande Kong       ierr = PetscSFReduceBegin(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM);CHKERRQ(ierr);
1828649b366bSFande Kong       ierr = PetscSFReduceEnd(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM);CHKERRQ(ierr);
1829649b366bSFande Kong       ierr = PetscSFReduceBegin(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM);CHKERRQ(ierr);
1830649b366bSFande Kong       ierr = PetscSFReduceEnd(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM);CHKERRQ(ierr);
1831649b366bSFande Kong       ierr = PetscFree(sub_dnnz);CHKERRQ(ierr);
1832649b366bSFande Kong       ierr = PetscFree(sub_onnz);CHKERRQ(ierr);
1833629c3df2SDmitry Karpeev       ierr = PetscSFDestroy(&bmsf);CHKERRQ(ierr);
1834629c3df2SDmitry Karpeev     }
183522d28d08SBarry Smith     ierr = ISRestoreIndices(bNis,&bNindices);CHKERRQ(ierr);
1836629c3df2SDmitry Karpeev     ierr = ISDestroy(&bNis);CHKERRQ(ierr);
183765a4a0a3Sstefano_zampini   }
183865a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
183965a4a0a3Sstefano_zampini   for (i=0;i<m;i++) {
184065a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i],A->cmap->n);
184165a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i],A->cmap->N - A->cmap->n);
1842629c3df2SDmitry Karpeev   }
1843629c3df2SDmitry Karpeev   ierr = MatSeqAIJSetPreallocation(C,0,dnnz);CHKERRQ(ierr);
1844629c3df2SDmitry Karpeev   ierr = MatMPIAIJSetPreallocation(C,0,dnnz,0,onnz);CHKERRQ(ierr);
1845629c3df2SDmitry Karpeev   ierr = PetscFree(dnnz);CHKERRQ(ierr);
1846629c3df2SDmitry Karpeev 
1847629c3df2SDmitry Karpeev   /* Fill by row */
1848629c3df2SDmitry Karpeev   for (j=0; j<nest->nc; ++j) {
1849629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
1850629c3df2SDmitry Karpeev     IS             bNis;
1851629c3df2SDmitry Karpeev     PetscInt       bN;
1852629c3df2SDmitry Karpeev     const PetscInt *bNindices;
1853629c3df2SDmitry Karpeev     ierr = ISAllGather(nest->isglobal.col[j], &bNis);CHKERRQ(ierr);
1854629c3df2SDmitry Karpeev     ierr = ISGetSize(bNis,&bN);CHKERRQ(ierr);
1855629c3df2SDmitry Karpeev     ierr = ISGetIndices(bNis,&bNindices);CHKERRQ(ierr);
1856629c3df2SDmitry Karpeev     for (i=0; i<nest->nr; ++i) {
1857629c3df2SDmitry Karpeev       Mat            B;
1858629c3df2SDmitry Karpeev       PetscInt       bm, br;
1859629c3df2SDmitry Karpeev       const PetscInt *bmindices;
1860629c3df2SDmitry Karpeev       B = nest->m[i][j];
1861629c3df2SDmitry Karpeev       if (!B) continue;
1862629c3df2SDmitry Karpeev       ierr = ISGetLocalSize(nest->isglobal.row[i],&bm);CHKERRQ(ierr);
1863629c3df2SDmitry Karpeev       ierr = ISGetIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
186483b1a929SMark Adams       ierr = MatGetOwnershipRange(B,&rstart,NULL);CHKERRQ(ierr);
1865629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
1866629c3df2SDmitry Karpeev         PetscInt          row = bmindices[br], brncols,  *cols;
1867629c3df2SDmitry Karpeev         const PetscInt    *brcols;
1868629c3df2SDmitry Karpeev         const PetscScalar *brcoldata;
186983b1a929SMark Adams         ierr = MatGetRow(B,br+rstart,&brncols,&brcols,&brcoldata);CHKERRQ(ierr);
1870785e854fSJed Brown         ierr = PetscMalloc1(brncols,&cols);CHKERRQ(ierr);
187126fbe8dcSKarl Rupp         for (k=0; k<brncols; k++) cols[k] = bNindices[brcols[k]];
1872629c3df2SDmitry Karpeev         /*
1873629c3df2SDmitry Karpeev           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1874629c3df2SDmitry Karpeev           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1875629c3df2SDmitry Karpeev          */
1876a2ea699eSBarry Smith         ierr = MatSetValues(C,1,&row,brncols,cols,brcoldata,ADD_VALUES);CHKERRQ(ierr);
187783b1a929SMark Adams         ierr = MatRestoreRow(B,br+rstart,&brncols,&brcols,&brcoldata);CHKERRQ(ierr);
1878629c3df2SDmitry Karpeev         ierr = PetscFree(cols);CHKERRQ(ierr);
1879629c3df2SDmitry Karpeev       }
1880629c3df2SDmitry Karpeev       ierr = ISRestoreIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
1881629c3df2SDmitry Karpeev     }
1882a2ea699eSBarry Smith     ierr = ISRestoreIndices(bNis,&bNindices);CHKERRQ(ierr);
1883629c3df2SDmitry Karpeev     ierr = ISDestroy(&bNis);CHKERRQ(ierr);
1884629c3df2SDmitry Karpeev   }
1885629c3df2SDmitry Karpeev   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1886629c3df2SDmitry Karpeev   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1887629c3df2SDmitry Karpeev   PetscFunctionReturn(0);
1888629c3df2SDmitry Karpeev }
1889629c3df2SDmitry Karpeev 
18908b7d3b4bSBarry Smith PetscErrorCode  MatHasOperation_Nest(Mat mat,MatOperation op,PetscBool  *has)
18918b7d3b4bSBarry Smith {
18928b7d3b4bSBarry Smith   PetscFunctionBegin;
18938b7d3b4bSBarry Smith   *has = PETSC_FALSE;
18948b7d3b4bSBarry Smith   if (op == MATOP_MULT_TRANSPOSE) {
18958b7d3b4bSBarry Smith     Mat_Nest       *bA = (Mat_Nest*)mat->data;
18968b7d3b4bSBarry Smith     PetscInt       i,j,nr = bA->nr,nc = bA->nc;
18978b7d3b4bSBarry Smith     PetscErrorCode ierr;
18988b7d3b4bSBarry Smith     PetscBool      flg;
18998b7d3b4bSBarry Smith 
19008b7d3b4bSBarry Smith     for (j=0; j<nc; j++) {
19018b7d3b4bSBarry Smith       for (i=0; i<nr; i++) {
19028b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
19038b7d3b4bSBarry Smith         ierr = MatHasOperation(bA->m[i][j],MATOP_MULT_TRANSPOSE_ADD,&flg);CHKERRQ(ierr);
19048b7d3b4bSBarry Smith         if (!flg) PetscFunctionReturn(0);
19058b7d3b4bSBarry Smith       }
19068b7d3b4bSBarry Smith     }
19078b7d3b4bSBarry Smith   }
19088b7d3b4bSBarry Smith   if (((void**)mat->ops)[op]) *has =  PETSC_TRUE;
19098b7d3b4bSBarry Smith   PetscFunctionReturn(0);
19108b7d3b4bSBarry Smith }
19118b7d3b4bSBarry Smith 
1912659c6bb0SJed Brown /*MC
1913659c6bb0SJed Brown   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.
1914659c6bb0SJed Brown 
1915659c6bb0SJed Brown   Level: intermediate
1916659c6bb0SJed Brown 
1917659c6bb0SJed Brown   Notes:
1918659c6bb0SJed Brown   This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices.
1919659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
1920950540a4SJed Brown   It is usually used with DMComposite and DMCreateMatrix()
1921659c6bb0SJed Brown 
19228b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
19238b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
19248b7d3b4bSBarry Smith   than the nest matrix.
19258b7d3b4bSBarry Smith 
1926659c6bb0SJed Brown .seealso: MatCreate(), MatType, MatCreateNest()
1927659c6bb0SJed Brown M*/
19288cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
1929c8883902SJed Brown {
1930c8883902SJed Brown   Mat_Nest       *s;
1931c8883902SJed Brown   PetscErrorCode ierr;
1932c8883902SJed Brown 
1933c8883902SJed Brown   PetscFunctionBegin;
1934b00a9115SJed Brown   ierr    = PetscNewLog(A,&s);CHKERRQ(ierr);
1935c8883902SJed Brown   A->data = (void*)s;
1936e7c19651SJed Brown 
1937e7c19651SJed Brown   s->nr            = -1;
1938e7c19651SJed Brown   s->nc            = -1;
19390298fd71SBarry Smith   s->m             = NULL;
1940e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
1941c8883902SJed Brown 
1942c8883902SJed Brown   ierr = PetscMemzero(A->ops,sizeof(*A->ops));CHKERRQ(ierr);
194326fbe8dcSKarl Rupp 
1944c8883902SJed Brown   A->ops->mult                  = MatMult_Nest;
19459194d70fSJed Brown   A->ops->multadd               = MatMultAdd_Nest;
1946c8883902SJed Brown   A->ops->multtranspose         = MatMultTranspose_Nest;
19479194d70fSJed Brown   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
1948f8170845SAlex Fikl   A->ops->transpose             = MatTranspose_Nest;
1949c8883902SJed Brown   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
1950c8883902SJed Brown   A->ops->assemblyend           = MatAssemblyEnd_Nest;
1951c8883902SJed Brown   A->ops->zeroentries           = MatZeroEntries_Nest;
1952c222c20dSDavid Ham   A->ops->copy                  = MatCopy_Nest;
19536e76ffeaSPierre Jolivet   A->ops->axpy                  = MatAXPY_Nest;
1954c8883902SJed Brown   A->ops->duplicate             = MatDuplicate_Nest;
19557dae84e0SHong Zhang   A->ops->createsubmatrix       = MatCreateSubMatrix_Nest;
1956c8883902SJed Brown   A->ops->destroy               = MatDestroy_Nest;
1957c8883902SJed Brown   A->ops->view                  = MatView_Nest;
1958c8883902SJed Brown   A->ops->getvecs               = 0; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
1959c8883902SJed Brown   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
1960c8883902SJed Brown   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
1961429bac76SJed Brown   A->ops->getdiagonal           = MatGetDiagonal_Nest;
1962429bac76SJed Brown   A->ops->diagonalscale         = MatDiagonalScale_Nest;
1963a061e289SJed Brown   A->ops->scale                 = MatScale_Nest;
1964a061e289SJed Brown   A->ops->shift                 = MatShift_Nest;
196513135bc6SAlex Fikl   A->ops->diagonalset           = MatDiagonalSet_Nest;
1966f8170845SAlex Fikl   A->ops->setrandom             = MatSetRandom_Nest;
19678b7d3b4bSBarry Smith   A->ops->hasoperation          = MatHasOperation_Nest;
1968c8883902SJed Brown 
1969c8883902SJed Brown   A->spptr        = 0;
1970c8883902SJed Brown   A->assembled    = PETSC_FALSE;
1971c8883902SJed Brown 
1972c8883902SJed Brown   /* expose Nest api's */
1973bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",      MatNestGetSubMat_Nest);CHKERRQ(ierr);
1974bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",      MatNestSetSubMat_Nest);CHKERRQ(ierr);
1975bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",     MatNestGetSubMats_Nest);CHKERRQ(ierr);
1976bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",        MatNestGetSize_Nest);CHKERRQ(ierr);
1977bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",         MatNestGetISs_Nest);CHKERRQ(ierr);
1978bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",    MatNestGetLocalISs_Nest);CHKERRQ(ierr);
1979bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",     MatNestSetVecType_Nest);CHKERRQ(ierr);
1980bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",     MatNestSetSubMats_Nest);CHKERRQ(ierr);
19810899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",MatConvert_Nest_AIJ);CHKERRQ(ierr);
19820899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",MatConvert_Nest_AIJ);CHKERRQ(ierr);
198383b1a929SMark Adams   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",   MatConvert_Nest_AIJ);CHKERRQ(ierr);
19845e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",    MatConvert_Nest_IS);CHKERRQ(ierr);
1985c8883902SJed Brown 
1986c8883902SJed Brown   ierr = PetscObjectChangeTypeName((PetscObject)A,MATNEST);CHKERRQ(ierr);
1987c8883902SJed Brown   PetscFunctionReturn(0);
1988c8883902SJed Brown }
1989