xref: /petsc/src/mat/impls/nest/matnest.c (revision 131c27b51385618aeb3ab8b6c7ebfa82d73c45d8)
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[]);
72a7a6963SBarry Smith static PetscErrorCode MatCreateVecs_Nest(Mat A,Vec *right,Vec *left);
85e3038f0Sstefano_zampini PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat,MatType,MatReuse,Mat*);
9c8883902SJed Brown 
10d8588912SDave May /* private functions */
118188e55aSJed Brown static PetscErrorCode MatNestGetSizes_Private(Mat A,PetscInt *m,PetscInt *n,PetscInt *M,PetscInt *N)
12d8588912SDave May {
13d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
148188e55aSJed Brown   PetscInt       i,j;
15d8588912SDave May   PetscErrorCode ierr;
16d8588912SDave May 
17d8588912SDave May   PetscFunctionBegin;
188188e55aSJed Brown   *m = *n = *M = *N = 0;
198188e55aSJed Brown   for (i=0; i<bA->nr; i++) {  /* rows */
208188e55aSJed Brown     PetscInt sm,sM;
218188e55aSJed Brown     ierr = ISGetLocalSize(bA->isglobal.row[i],&sm);CHKERRQ(ierr);
228188e55aSJed Brown     ierr = ISGetSize(bA->isglobal.row[i],&sM);CHKERRQ(ierr);
238188e55aSJed Brown     *m  += sm;
248188e55aSJed Brown     *M  += sM;
25d8588912SDave May   }
268188e55aSJed Brown   for (j=0; j<bA->nc; j++) {  /* cols */
278188e55aSJed Brown     PetscInt sn,sN;
288188e55aSJed Brown     ierr = ISGetLocalSize(bA->isglobal.col[j],&sn);CHKERRQ(ierr);
298188e55aSJed Brown     ierr = ISGetSize(bA->isglobal.col[j],&sN);CHKERRQ(ierr);
308188e55aSJed Brown     *n  += sn;
318188e55aSJed Brown     *N  += sN;
32d8588912SDave May   }
33d8588912SDave May   PetscFunctionReturn(0);
34d8588912SDave May }
35d8588912SDave May 
36d8588912SDave May /* operations */
37207556f9SJed Brown static PetscErrorCode MatMult_Nest(Mat A,Vec x,Vec y)
38d8588912SDave May {
39d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
40207556f9SJed Brown   Vec            *bx = bA->right,*by = bA->left;
41207556f9SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
42d8588912SDave May   PetscErrorCode ierr;
43d8588912SDave May 
44d8588912SDave May   PetscFunctionBegin;
45207556f9SJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(y,bA->isglobal.row[i],&by[i]);CHKERRQ(ierr);}
46207556f9SJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
47207556f9SJed Brown   for (i=0; i<nr; i++) {
48d8588912SDave May     ierr = VecZeroEntries(by[i]);CHKERRQ(ierr);
49207556f9SJed Brown     for (j=0; j<nc; j++) {
50207556f9SJed Brown       if (!bA->m[i][j]) continue;
51d8588912SDave May       /* y[i] <- y[i] + A[i][j] * x[j] */
52d8588912SDave May       ierr = MatMultAdd(bA->m[i][j],bx[j],by[i],by[i]);CHKERRQ(ierr);
53d8588912SDave May     }
54d8588912SDave May   }
55207556f9SJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.row[i],&by[i]);CHKERRQ(ierr);}
56207556f9SJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
57d8588912SDave May   PetscFunctionReturn(0);
58d8588912SDave May }
59d8588912SDave May 
609194d70fSJed Brown static PetscErrorCode MatMultAdd_Nest(Mat A,Vec x,Vec y,Vec z)
619194d70fSJed Brown {
629194d70fSJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
639194d70fSJed Brown   Vec            *bx = bA->right,*bz = bA->left;
649194d70fSJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
659194d70fSJed Brown   PetscErrorCode ierr;
669194d70fSJed Brown 
679194d70fSJed Brown   PetscFunctionBegin;
689194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(z,bA->isglobal.row[i],&bz[i]);CHKERRQ(ierr);}
699194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
709194d70fSJed Brown   for (i=0; i<nr; i++) {
719194d70fSJed Brown     if (y != z) {
729194d70fSJed Brown       Vec by;
739194d70fSJed Brown       ierr = VecGetSubVector(y,bA->isglobal.row[i],&by);CHKERRQ(ierr);
749194d70fSJed Brown       ierr = VecCopy(by,bz[i]);CHKERRQ(ierr);
75336d21e7SJed Brown       ierr = VecRestoreSubVector(y,bA->isglobal.row[i],&by);CHKERRQ(ierr);
769194d70fSJed Brown     }
779194d70fSJed Brown     for (j=0; j<nc; j++) {
789194d70fSJed Brown       if (!bA->m[i][j]) continue;
799194d70fSJed Brown       /* y[i] <- y[i] + A[i][j] * x[j] */
809194d70fSJed Brown       ierr = MatMultAdd(bA->m[i][j],bx[j],bz[i],bz[i]);CHKERRQ(ierr);
819194d70fSJed Brown     }
829194d70fSJed Brown   }
839194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(z,bA->isglobal.row[i],&bz[i]);CHKERRQ(ierr);}
849194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
859194d70fSJed Brown   PetscFunctionReturn(0);
869194d70fSJed Brown }
879194d70fSJed Brown 
8852c5f739Sprj- typedef struct {
8952c5f739Sprj-   Mat          *workC;    /* array of Mat with specific containers depending on the underlying MatMatMult implementation */
9052c5f739Sprj-   PetscScalar  *tarray;   /* buffer for storing all temporary products A[i][j] B[j] */
9152c5f739Sprj-   PetscInt     *dm,*dn,k; /* displacements and number of submatrices */
9252c5f739Sprj- } Nest_Dense;
9352c5f739Sprj- 
9452c5f739Sprj- PETSC_INTERN PetscErrorCode MatMatMultNumeric_Nest_Dense(Mat A,Mat B,Mat C)
9552c5f739Sprj- {
9652c5f739Sprj-   Mat_Nest          *bA = (Mat_Nest*)A->data;
9752c5f739Sprj-   PetscContainer    container;
9852c5f739Sprj-   Nest_Dense        *contents;
9952c5f739Sprj-   Mat               viewB,viewC,seq;
10052c5f739Sprj-   const PetscScalar *barray;
10152c5f739Sprj-   PetscScalar       *carray;
10252c5f739Sprj-   PetscInt          i,j,M,N,nr = bA->nr,nc = bA->nc,ldb,ldc;
10352c5f739Sprj-   PetscErrorCode    ierr;
10452c5f739Sprj- 
10552c5f739Sprj-   PetscFunctionBegin;
10652c5f739Sprj-   ierr = PetscObjectQuery((PetscObject)C,"workC",(PetscObject*)&container);CHKERRQ(ierr);
10752c5f739Sprj-   if (!container) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Container does not exist");
10852c5f739Sprj-   ierr = PetscContainerGetPointer(container,(void**)&contents);CHKERRQ(ierr);
10952c5f739Sprj-   ierr = MatDenseGetLDA(B,&ldb);CHKERRQ(ierr);
11052c5f739Sprj-   ierr = MatDenseGetLDA(C,&ldc);CHKERRQ(ierr);
11152c5f739Sprj-   ierr = MatGetSize(B,NULL,&N);CHKERRQ(ierr);
11252c5f739Sprj-   ierr = MatZeroEntries(C);CHKERRQ(ierr);
11352c5f739Sprj-   ierr = MatDenseGetArrayRead(B,&barray);CHKERRQ(ierr);
11452c5f739Sprj-   ierr = MatDenseGetArray(C,&carray);CHKERRQ(ierr);
11552c5f739Sprj-   for (i=0; i<nr; i++) {
11652c5f739Sprj-     ierr = ISGetSize(bA->isglobal.row[i],&M);CHKERRQ(ierr);
11752c5f739Sprj-     ierr = MatCreateDense(PetscObjectComm((PetscObject)A),contents->dm[i+1]-contents->dm[i],PETSC_DECIDE,M,N,carray+contents->dm[i],&viewC);CHKERRQ(ierr);
11852c5f739Sprj-     ierr = MatDenseGetLocalMatrix(viewC,&seq);CHKERRQ(ierr);
11952c5f739Sprj-     ierr = MatSeqDenseSetLDA(seq,ldc);CHKERRQ(ierr);
12052c5f739Sprj-     for (j=0; j<nc; j++) {
12152c5f739Sprj-       if (!bA->m[i][j]) continue;
12252c5f739Sprj-       ierr = ISGetSize(bA->isglobal.col[j],&M);CHKERRQ(ierr);
12352c5f739Sprj-       ierr = MatCreateDense(PetscObjectComm((PetscObject)A),contents->dn[j+1]-contents->dn[j],PETSC_DECIDE,M,N,(PetscScalar*)(barray+contents->dn[j]),&viewB);CHKERRQ(ierr);
12452c5f739Sprj-       ierr = MatDenseGetLocalMatrix(viewB,&seq);CHKERRQ(ierr);
12552c5f739Sprj-       ierr = MatSeqDenseSetLDA(seq,ldb);CHKERRQ(ierr);
12652c5f739Sprj-       /* workC <- A[i][j] * B[j] */
12752c5f739Sprj-       ierr = MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]);CHKERRQ(ierr);
12852c5f739Sprj-       ierr = MatDestroy(&viewB);CHKERRQ(ierr);
12952c5f739Sprj-        /* C[i] <- workC + C[i] */
13052c5f739Sprj-       ierr = MatAXPY(viewC,1.0,contents->workC[i*nc + j],SAME_NONZERO_PATTERN);CHKERRQ(ierr);
13152c5f739Sprj-     }
13252c5f739Sprj-     ierr = MatDestroy(&viewC);CHKERRQ(ierr);
13352c5f739Sprj-   }
13452c5f739Sprj-   ierr = MatDenseRestoreArray(C,&carray);CHKERRQ(ierr);
13552c5f739Sprj-   ierr = MatDenseRestoreArrayRead(B,&barray);CHKERRQ(ierr);
13652c5f739Sprj-   PetscFunctionReturn(0);
13752c5f739Sprj- }
13852c5f739Sprj- 
13952c5f739Sprj- PetscErrorCode MatNest_DenseDestroy(void *ctx)
14052c5f739Sprj- {
14152c5f739Sprj-   Nest_Dense     *contents = (Nest_Dense*)ctx;
14252c5f739Sprj-   PetscInt       i;
14352c5f739Sprj-   PetscErrorCode ierr;
14452c5f739Sprj- 
14552c5f739Sprj-   PetscFunctionBegin;
14652c5f739Sprj-   ierr = PetscFree(contents->tarray);CHKERRQ(ierr);
14752c5f739Sprj-   for (i=0; i<contents->k; i++) {
14852c5f739Sprj-     ierr = MatDestroy(contents->workC + i);CHKERRQ(ierr);
14952c5f739Sprj-   }
15052c5f739Sprj-   ierr = PetscFree3(contents->dm,contents->dn,contents->workC);CHKERRQ(ierr);
15152c5f739Sprj-   ierr = PetscFree(contents);CHKERRQ(ierr);
15252c5f739Sprj-   PetscFunctionReturn(0);
15352c5f739Sprj- }
15452c5f739Sprj- 
15552c5f739Sprj- PETSC_INTERN PetscErrorCode MatMatMultSymbolic_Nest_Dense(Mat A,Mat B,PetscReal fill,Mat *C)
15652c5f739Sprj- {
15752c5f739Sprj-   Mat_Nest          *bA = (Mat_Nest*)A->data;
15852c5f739Sprj-   Mat               viewB,viewSeq;
15952c5f739Sprj-   const PetscScalar *barray;
16052c5f739Sprj-   PetscInt          i,j,M,N,m,nr = bA->nr,nc = bA->nc,maxm = 0,ldb;
16152c5f739Sprj-   PetscContainer    container;
16252c5f739Sprj-   Nest_Dense        *contents;
16352c5f739Sprj-   PetscErrorCode    ierr;
16452c5f739Sprj- 
16552c5f739Sprj-   PetscFunctionBegin;
16652c5f739Sprj-   ierr = MatGetSize(B,NULL,&N);CHKERRQ(ierr);
16752c5f739Sprj-   if (!(*C)) {
16852c5f739Sprj-     ierr = MatGetLocalSize(A,&m,NULL);CHKERRQ(ierr);
16952c5f739Sprj-     ierr = MatGetSize(A,&M,NULL);CHKERRQ(ierr);
17052c5f739Sprj-     ierr = MatCreateDense(PetscObjectComm((PetscObject)A),m,PETSC_DECIDE,M,N,NULL,C);CHKERRQ(ierr);
17152c5f739Sprj-   } else {
17252c5f739Sprj-     if ((*C)->rmap->n != A->rmap->n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Matrix local row dimensions are incompatible, %D != %D",(*C)->rmap->n,A->rmap->n);
17352c5f739Sprj-     if ((*C)->cmap->n != B->cmap->n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"Matrix local column dimensions are incompatible, %D != %D",(*C)->cmap->n,B->cmap->n);
17452c5f739Sprj-   }
17552c5f739Sprj- 
17652c5f739Sprj-   ierr = PetscNew(&contents);CHKERRQ(ierr);
17752c5f739Sprj-   ierr = PetscContainerCreate(PetscObjectComm((PetscObject)A),&container);CHKERRQ(ierr);
17852c5f739Sprj-   ierr = PetscContainerSetPointer(container,contents);CHKERRQ(ierr);
17952c5f739Sprj-   ierr = PetscContainerSetUserDestroy(container,MatNest_DenseDestroy);CHKERRQ(ierr);
18052c5f739Sprj-   ierr = PetscObjectCompose((PetscObject)*C,"workC",(PetscObject)container);CHKERRQ(ierr);
18152c5f739Sprj-   ierr = PetscContainerDestroy(&container);CHKERRQ(ierr);
18252c5f739Sprj-   ierr = PetscCalloc3(nr+1,&contents->dm,nc+1,&contents->dn,nr*nc,&contents->workC);CHKERRQ(ierr);
18352c5f739Sprj-   contents->k = nr*nc;
18452c5f739Sprj-   for (i=0; i<nr; i++) {
18552c5f739Sprj-     ierr = ISGetLocalSize(bA->isglobal.row[i],contents->dm + i+1);CHKERRQ(ierr);
18652c5f739Sprj-     maxm = PetscMax(maxm,contents->dm[i+1]);
18752c5f739Sprj-     contents->dm[i+1] += contents->dm[i];
18852c5f739Sprj-   }
18952c5f739Sprj-   for (i=0; i<nc; i++) {
19052c5f739Sprj-     ierr = ISGetLocalSize(bA->isglobal.col[i],contents->dn + i+1);CHKERRQ(ierr);
19152c5f739Sprj-     contents->dn[i+1] += contents->dn[i];
19252c5f739Sprj-   }
19352c5f739Sprj-   ierr = PetscMalloc1(maxm*N,&contents->tarray);CHKERRQ(ierr);
19452c5f739Sprj-   ierr = MatDenseGetLDA(B,&ldb);CHKERRQ(ierr);
19552c5f739Sprj-   ierr = MatGetSize(B,NULL,&N);CHKERRQ(ierr);
19652c5f739Sprj-   ierr = MatDenseGetArrayRead(B,&barray);CHKERRQ(ierr);
19752c5f739Sprj-   /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */
19852c5f739Sprj-   for (j=0; j<nc; j++) {
19952c5f739Sprj-     ierr = ISGetSize(bA->isglobal.col[j],&M);CHKERRQ(ierr);
20052c5f739Sprj-     ierr = MatCreateDense(PetscObjectComm((PetscObject)A),contents->dn[j+1]-contents->dn[j],PETSC_DECIDE,M,N,(PetscScalar*)(barray+contents->dn[j]),&viewB);CHKERRQ(ierr);
20152c5f739Sprj-     ierr = MatDenseGetLocalMatrix(viewB,&viewSeq);CHKERRQ(ierr);
20252c5f739Sprj-     ierr = MatSeqDenseSetLDA(viewSeq,ldb);CHKERRQ(ierr);
20352c5f739Sprj-     for (i=0; i<nr; i++) {
20452c5f739Sprj-       if (!bA->m[i][j]) continue;
20552c5f739Sprj-       /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */
20652c5f739Sprj-       ierr = MatMatMultSymbolic(bA->m[i][j],viewB,fill,contents->workC + i*nc + j);CHKERRQ(ierr);
20752c5f739Sprj-       ierr = MatDenseGetLocalMatrix(contents->workC[i*nc + j],&viewSeq);CHKERRQ(ierr);
20852c5f739Sprj-       /* free the memory allocated in MatMatMultSymbolic, since tarray will be shared by all Mat */
20952c5f739Sprj-       ierr = MatSeqDenseSetPreallocation(viewSeq,contents->tarray);CHKERRQ(ierr);
21052c5f739Sprj-     }
21152c5f739Sprj-     ierr = MatDestroy(&viewB);CHKERRQ(ierr);
21252c5f739Sprj-   }
21352c5f739Sprj-   ierr = MatDenseRestoreArrayRead(B,&barray);CHKERRQ(ierr);
21452c5f739Sprj- 
21552c5f739Sprj-   (*C)->ops->matmultnumeric = MatMatMultNumeric_Nest_Dense;
21652c5f739Sprj-   PetscFunctionReturn(0);
21752c5f739Sprj- }
21852c5f739Sprj- 
21952c5f739Sprj- PETSC_INTERN PetscErrorCode MatMatMult_Nest_Dense(Mat A,Mat B,MatReuse scall,PetscReal fill,Mat *C)
22052c5f739Sprj- {
22152c5f739Sprj-   PetscErrorCode ierr;
22252c5f739Sprj- 
22352c5f739Sprj-   PetscFunctionBegin;
22452c5f739Sprj-   if (scall == MAT_INITIAL_MATRIX) {
22552c5f739Sprj-     *C = NULL;
22652c5f739Sprj-     ierr = PetscLogEventBegin(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr);
22752c5f739Sprj-     ierr = MatMatMultSymbolic_Nest_Dense(A,B,fill,C);CHKERRQ(ierr);
22852c5f739Sprj-     ierr = PetscLogEventEnd(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr);
22952c5f739Sprj-   }
23052c5f739Sprj-   ierr = PetscLogEventBegin(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
23152c5f739Sprj-   ierr = MatMatMultNumeric_Nest_Dense(A,B,*C);CHKERRQ(ierr);
23252c5f739Sprj-   ierr = PetscLogEventEnd(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
23352c5f739Sprj-   PetscFunctionReturn(0);
23452c5f739Sprj- }
23552c5f739Sprj- 
236207556f9SJed Brown static PetscErrorCode MatMultTranspose_Nest(Mat A,Vec x,Vec y)
237d8588912SDave May {
238d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
239207556f9SJed Brown   Vec            *bx = bA->left,*by = bA->right;
240207556f9SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
241d8588912SDave May   PetscErrorCode ierr;
242d8588912SDave May 
243d8588912SDave May   PetscFunctionBegin;
244609e31cbSJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
245609e31cbSJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(y,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);}
246207556f9SJed Brown   for (j=0; j<nc; j++) {
247609e31cbSJed Brown     ierr = VecZeroEntries(by[j]);CHKERRQ(ierr);
248609e31cbSJed Brown     for (i=0; i<nr; i++) {
2496c75ac25SJed Brown       if (!bA->m[i][j]) continue;
250609e31cbSJed Brown       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
251609e31cbSJed Brown       ierr = MatMultTransposeAdd(bA->m[i][j],bx[i],by[j],by[j]);CHKERRQ(ierr);
252d8588912SDave May     }
253d8588912SDave May   }
254609e31cbSJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
255609e31cbSJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);}
256d8588912SDave May   PetscFunctionReturn(0);
257d8588912SDave May }
258d8588912SDave May 
2599194d70fSJed Brown static PetscErrorCode MatMultTransposeAdd_Nest(Mat A,Vec x,Vec y,Vec z)
2609194d70fSJed Brown {
2619194d70fSJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
2629194d70fSJed Brown   Vec            *bx = bA->left,*bz = bA->right;
2639194d70fSJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
2649194d70fSJed Brown   PetscErrorCode ierr;
2659194d70fSJed Brown 
2669194d70fSJed Brown   PetscFunctionBegin;
2679194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
2689194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(z,bA->isglobal.col[i],&bz[i]);CHKERRQ(ierr);}
2699194d70fSJed Brown   for (j=0; j<nc; j++) {
2709194d70fSJed Brown     if (y != z) {
2719194d70fSJed Brown       Vec by;
2729194d70fSJed Brown       ierr = VecGetSubVector(y,bA->isglobal.col[j],&by);CHKERRQ(ierr);
2739194d70fSJed Brown       ierr = VecCopy(by,bz[j]);CHKERRQ(ierr);
2749194d70fSJed Brown       ierr = VecRestoreSubVector(y,bA->isglobal.col[j],&by);CHKERRQ(ierr);
2759194d70fSJed Brown     }
2769194d70fSJed Brown     for (i=0; i<nr; i++) {
2776c75ac25SJed Brown       if (!bA->m[i][j]) continue;
2789194d70fSJed Brown       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
2799194d70fSJed Brown       ierr = MatMultTransposeAdd(bA->m[i][j],bx[i],bz[j],bz[j]);CHKERRQ(ierr);
2809194d70fSJed Brown     }
2819194d70fSJed Brown   }
2829194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
2839194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(z,bA->isglobal.col[i],&bz[i]);CHKERRQ(ierr);}
2849194d70fSJed Brown   PetscFunctionReturn(0);
2859194d70fSJed Brown }
2869194d70fSJed Brown 
287f8170845SAlex Fikl static PetscErrorCode MatTranspose_Nest(Mat A,MatReuse reuse,Mat *B)
288f8170845SAlex Fikl {
289f8170845SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data, *bC;
290f8170845SAlex Fikl   Mat            C;
291f8170845SAlex Fikl   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
292f8170845SAlex Fikl   PetscErrorCode ierr;
293f8170845SAlex Fikl 
294f8170845SAlex Fikl   PetscFunctionBegin;
295cf37664fSBarry Smith   if (reuse == MAT_INPLACE_MATRIX && nr != nc) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Square nested matrix only for in-place");
296f8170845SAlex Fikl 
297cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
298f8170845SAlex Fikl     Mat *subs;
299f8170845SAlex Fikl     IS  *is_row,*is_col;
300f8170845SAlex Fikl 
301f8170845SAlex Fikl     ierr = PetscCalloc1(nr * nc,&subs);CHKERRQ(ierr);
302f8170845SAlex Fikl     ierr = PetscMalloc2(nr,&is_row,nc,&is_col);CHKERRQ(ierr);
303f8170845SAlex Fikl     ierr = MatNestGetISs(A,is_row,is_col);CHKERRQ(ierr);
304cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
305ddeb9bd8SAlex Fikl       for (i=0; i<nr; i++) {
306ddeb9bd8SAlex Fikl         for (j=0; j<nc; j++) {
307ddeb9bd8SAlex Fikl           subs[i + nr * j] = bA->m[i][j];
308ddeb9bd8SAlex Fikl         }
309ddeb9bd8SAlex Fikl       }
310ddeb9bd8SAlex Fikl     }
311ddeb9bd8SAlex Fikl 
312f8170845SAlex Fikl     ierr = MatCreateNest(PetscObjectComm((PetscObject)A),nc,is_col,nr,is_row,subs,&C);CHKERRQ(ierr);
313f8170845SAlex Fikl     ierr = PetscFree(subs);CHKERRQ(ierr);
3143d994f23SBarry Smith     ierr = PetscFree2(is_row,is_col);CHKERRQ(ierr);
315f8170845SAlex Fikl   } else {
316f8170845SAlex Fikl     C = *B;
317f8170845SAlex Fikl   }
318f8170845SAlex Fikl 
319f8170845SAlex Fikl   bC = (Mat_Nest*)C->data;
320f8170845SAlex Fikl   for (i=0; i<nr; i++) {
321f8170845SAlex Fikl     for (j=0; j<nc; j++) {
322f8170845SAlex Fikl       if (bA->m[i][j]) {
323f8170845SAlex Fikl         ierr = MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i]));CHKERRQ(ierr);
324f8170845SAlex Fikl       } else {
325f8170845SAlex Fikl         bC->m[j][i] = NULL;
326f8170845SAlex Fikl       }
327f8170845SAlex Fikl     }
328f8170845SAlex Fikl   }
329f8170845SAlex Fikl 
330cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
331f8170845SAlex Fikl     *B = C;
332f8170845SAlex Fikl   } else {
333f8170845SAlex Fikl     ierr = MatHeaderMerge(A, &C);CHKERRQ(ierr);
334f8170845SAlex Fikl   }
335f8170845SAlex Fikl   PetscFunctionReturn(0);
336f8170845SAlex Fikl }
337f8170845SAlex Fikl 
338e2d7f03fSJed Brown static PetscErrorCode MatNestDestroyISList(PetscInt n,IS **list)
339e2d7f03fSJed Brown {
340e2d7f03fSJed Brown   PetscErrorCode ierr;
341e2d7f03fSJed Brown   IS             *lst = *list;
342e2d7f03fSJed Brown   PetscInt       i;
343e2d7f03fSJed Brown 
344e2d7f03fSJed Brown   PetscFunctionBegin;
345e2d7f03fSJed Brown   if (!lst) PetscFunctionReturn(0);
3466bf464f9SBarry Smith   for (i=0; i<n; i++) if (lst[i]) {ierr = ISDestroy(&lst[i]);CHKERRQ(ierr);}
347e2d7f03fSJed Brown   ierr  = PetscFree(lst);CHKERRQ(ierr);
3480298fd71SBarry Smith   *list = NULL;
349e2d7f03fSJed Brown   PetscFunctionReturn(0);
350e2d7f03fSJed Brown }
351e2d7f03fSJed Brown 
352207556f9SJed Brown static PetscErrorCode MatDestroy_Nest(Mat A)
353d8588912SDave May {
354d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
355d8588912SDave May   PetscInt       i,j;
356d8588912SDave May   PetscErrorCode ierr;
357d8588912SDave May 
358d8588912SDave May   PetscFunctionBegin;
359d8588912SDave May   /* release the matrices and the place holders */
360e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nr,&vs->isglobal.row);CHKERRQ(ierr);
361e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nc,&vs->isglobal.col);CHKERRQ(ierr);
362e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nr,&vs->islocal.row);CHKERRQ(ierr);
363e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nc,&vs->islocal.col);CHKERRQ(ierr);
364d8588912SDave May 
365d8588912SDave May   ierr = PetscFree(vs->row_len);CHKERRQ(ierr);
366d8588912SDave May   ierr = PetscFree(vs->col_len);CHKERRQ(ierr);
367d8588912SDave May 
368207556f9SJed Brown   ierr = PetscFree2(vs->left,vs->right);CHKERRQ(ierr);
369207556f9SJed Brown 
370d8588912SDave May   /* release the matrices and the place holders */
371d8588912SDave May   if (vs->m) {
372d8588912SDave May     for (i=0; i<vs->nr; i++) {
373d8588912SDave May       for (j=0; j<vs->nc; j++) {
3746bf464f9SBarry Smith         ierr = MatDestroy(&vs->m[i][j]);CHKERRQ(ierr);
375d8588912SDave May       }
376d8588912SDave May       ierr = PetscFree(vs->m[i]);CHKERRQ(ierr);
377d8588912SDave May     }
378d8588912SDave May     ierr = PetscFree(vs->m);CHKERRQ(ierr);
379d8588912SDave May   }
380bf0cc555SLisandro Dalcin   ierr = PetscFree(A->data);CHKERRQ(ierr);
381d8588912SDave May 
382bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",0);CHKERRQ(ierr);
383bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",0);CHKERRQ(ierr);
384bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",0);CHKERRQ(ierr);
385bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",0);CHKERRQ(ierr);
386bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",0);CHKERRQ(ierr);
387bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",0);CHKERRQ(ierr);
388bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",0);CHKERRQ(ierr);
389bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",0);CHKERRQ(ierr);
3900899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",0);CHKERRQ(ierr);
3910899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",0);CHKERRQ(ierr);
3925e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",0);CHKERRQ(ierr);
3935e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",0);CHKERRQ(ierr);
39452c5f739Sprj-   ierr = PetscObjectComposeFunction((PetscObject)A,"MatMatMult_nest_mpidense_C",0);CHKERRQ(ierr);
39552c5f739Sprj-   ierr = PetscObjectComposeFunction((PetscObject)A,"MatMatMult_nest_seqdense_C",0);CHKERRQ(ierr);
39652c5f739Sprj-   ierr = PetscObjectComposeFunction((PetscObject)A,"MatMatMult_nest_dense_C",0);CHKERRQ(ierr);
397d8588912SDave May   PetscFunctionReturn(0);
398d8588912SDave May }
399d8588912SDave May 
400207556f9SJed Brown static PetscErrorCode MatAssemblyBegin_Nest(Mat A,MatAssemblyType type)
401d8588912SDave May {
402d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
403d8588912SDave May   PetscInt       i,j;
404d8588912SDave May   PetscErrorCode ierr;
405d8588912SDave May 
406d8588912SDave May   PetscFunctionBegin;
407d8588912SDave May   for (i=0; i<vs->nr; i++) {
408d8588912SDave May     for (j=0; j<vs->nc; j++) {
409e7c19651SJed Brown       if (vs->m[i][j]) {
410e7c19651SJed Brown         ierr = MatAssemblyBegin(vs->m[i][j],type);CHKERRQ(ierr);
411e7c19651SJed Brown         if (!vs->splitassembly) {
412e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
413e7c19651SJed 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
414e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
415e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
416e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
417e7c19651SJed Brown            */
418e7c19651SJed Brown           ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr);
419e7c19651SJed Brown         }
420e7c19651SJed Brown       }
421d8588912SDave May     }
422d8588912SDave May   }
423d8588912SDave May   PetscFunctionReturn(0);
424d8588912SDave May }
425d8588912SDave May 
426207556f9SJed Brown static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
427d8588912SDave May {
428d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
429d8588912SDave May   PetscInt       i,j;
430d8588912SDave May   PetscErrorCode ierr;
431d8588912SDave May 
432d8588912SDave May   PetscFunctionBegin;
433d8588912SDave May   for (i=0; i<vs->nr; i++) {
434d8588912SDave May     for (j=0; j<vs->nc; j++) {
435e7c19651SJed Brown       if (vs->m[i][j]) {
436e7c19651SJed Brown         if (vs->splitassembly) {
437e7c19651SJed Brown           ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr);
438e7c19651SJed Brown         }
439e7c19651SJed Brown       }
440d8588912SDave May     }
441d8588912SDave May   }
442d8588912SDave May   PetscFunctionReturn(0);
443d8588912SDave May }
444d8588912SDave May 
445f349c1fdSJed Brown static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat *B)
446d8588912SDave May {
447207556f9SJed Brown   PetscErrorCode ierr;
448f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
449f349c1fdSJed Brown   PetscInt       j;
450f349c1fdSJed Brown   Mat            sub;
451d8588912SDave May 
452d8588912SDave May   PetscFunctionBegin;
4530298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
454f349c1fdSJed Brown   for (j=0; !sub && j<vs->nc; j++) sub = vs->m[row][j];
4554994cf47SJed Brown   if (sub) {ierr = MatSetUp(sub);CHKERRQ(ierr);}       /* Ensure that the sizes are available */
456f349c1fdSJed Brown   *B = sub;
457f349c1fdSJed Brown   PetscFunctionReturn(0);
458d8588912SDave May }
459d8588912SDave May 
460f349c1fdSJed Brown static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat *B)
461f349c1fdSJed Brown {
462207556f9SJed Brown   PetscErrorCode ierr;
463f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
464f349c1fdSJed Brown   PetscInt       i;
465f349c1fdSJed Brown   Mat            sub;
466f349c1fdSJed Brown 
467f349c1fdSJed Brown   PetscFunctionBegin;
4680298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
469f349c1fdSJed Brown   for (i=0; !sub && i<vs->nr; i++) sub = vs->m[i][col];
4704994cf47SJed Brown   if (sub) {ierr = MatSetUp(sub);CHKERRQ(ierr);}       /* Ensure that the sizes are available */
471f349c1fdSJed Brown   *B = sub;
472f349c1fdSJed Brown   PetscFunctionReturn(0);
473d8588912SDave May }
474d8588912SDave May 
475f349c1fdSJed Brown static PetscErrorCode MatNestFindIS(Mat A,PetscInt n,const IS list[],IS is,PetscInt *found)
476f349c1fdSJed Brown {
477f349c1fdSJed Brown   PetscErrorCode ierr;
478f349c1fdSJed Brown   PetscInt       i;
479f349c1fdSJed Brown   PetscBool      flg;
480f349c1fdSJed Brown 
481f349c1fdSJed Brown   PetscFunctionBegin;
482f349c1fdSJed Brown   PetscValidPointer(list,3);
483f349c1fdSJed Brown   PetscValidHeaderSpecific(is,IS_CLASSID,4);
484f349c1fdSJed Brown   PetscValidIntPointer(found,5);
485f349c1fdSJed Brown   *found = -1;
486f349c1fdSJed Brown   for (i=0; i<n; i++) {
487207556f9SJed Brown     if (!list[i]) continue;
488f349c1fdSJed Brown     ierr = ISEqual(list[i],is,&flg);CHKERRQ(ierr);
489f349c1fdSJed Brown     if (flg) {
490f349c1fdSJed Brown       *found = i;
491f349c1fdSJed Brown       PetscFunctionReturn(0);
492f349c1fdSJed Brown     }
493f349c1fdSJed Brown   }
494ce94432eSBarry Smith   SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Could not find index set");
495f349c1fdSJed Brown   PetscFunctionReturn(0);
496f349c1fdSJed Brown }
497f349c1fdSJed Brown 
4988188e55aSJed Brown /* Get a block row as a new MatNest */
4998188e55aSJed Brown static PetscErrorCode MatNestGetRow(Mat A,PetscInt row,Mat *B)
5008188e55aSJed Brown {
5018188e55aSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
5028188e55aSJed Brown   char           keyname[256];
5038188e55aSJed Brown   PetscErrorCode ierr;
5048188e55aSJed Brown 
5058188e55aSJed Brown   PetscFunctionBegin;
5060298fd71SBarry Smith   *B   = NULL;
5078caf3d72SBarry Smith   ierr = PetscSNPrintf(keyname,sizeof(keyname),"NestRow_%D",row);CHKERRQ(ierr);
5088188e55aSJed Brown   ierr = PetscObjectQuery((PetscObject)A,keyname,(PetscObject*)B);CHKERRQ(ierr);
5098188e55aSJed Brown   if (*B) PetscFunctionReturn(0);
5108188e55aSJed Brown 
511ce94432eSBarry Smith   ierr = MatCreateNest(PetscObjectComm((PetscObject)A),1,NULL,vs->nc,vs->isglobal.col,vs->m[row],B);CHKERRQ(ierr);
51226fbe8dcSKarl Rupp 
5138188e55aSJed Brown   (*B)->assembled = A->assembled;
51426fbe8dcSKarl Rupp 
5158188e55aSJed Brown   ierr = PetscObjectCompose((PetscObject)A,keyname,(PetscObject)*B);CHKERRQ(ierr);
5168188e55aSJed Brown   ierr = PetscObjectDereference((PetscObject)*B);CHKERRQ(ierr); /* Leave the only remaining reference in the composition */
5178188e55aSJed Brown   PetscFunctionReturn(0);
5188188e55aSJed Brown }
5198188e55aSJed Brown 
520f349c1fdSJed Brown static PetscErrorCode MatNestFindSubMat(Mat A,struct MatNestISPair *is,IS isrow,IS iscol,Mat *B)
521f349c1fdSJed Brown {
522f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
5238188e55aSJed Brown   PetscErrorCode ierr;
5246b3a5b13SJed Brown   PetscInt       row,col;
525e072481dSJed Brown   PetscBool      same,isFullCol,isFullColGlobal;
526f349c1fdSJed Brown 
527f349c1fdSJed Brown   PetscFunctionBegin;
5288188e55aSJed Brown   /* Check if full column space. This is a hack */
5298188e55aSJed Brown   isFullCol = PETSC_FALSE;
530251f4c67SDmitry Karpeev   ierr      = PetscObjectTypeCompare((PetscObject)iscol,ISSTRIDE,&same);CHKERRQ(ierr);
5318188e55aSJed Brown   if (same) {
53277019fcaSJed Brown     PetscInt n,first,step,i,an,am,afirst,astep;
5338188e55aSJed Brown     ierr      = ISStrideGetInfo(iscol,&first,&step);CHKERRQ(ierr);
5348188e55aSJed Brown     ierr      = ISGetLocalSize(iscol,&n);CHKERRQ(ierr);
53577019fcaSJed Brown     isFullCol = PETSC_TRUE;
53605ce4453SJed Brown     for (i=0,an=A->cmap->rstart; i<vs->nc; i++) {
53777019fcaSJed Brown       ierr = ISStrideGetInfo(is->col[i],&afirst,&astep);CHKERRQ(ierr);
53877019fcaSJed Brown       ierr = ISGetLocalSize(is->col[i],&am);CHKERRQ(ierr);
53977019fcaSJed Brown       if (afirst != an || astep != step) isFullCol = PETSC_FALSE;
54077019fcaSJed Brown       an += am;
54177019fcaSJed Brown     }
54205ce4453SJed Brown     if (an != A->cmap->rstart+n) isFullCol = PETSC_FALSE;
5438188e55aSJed Brown   }
544b2566f29SBarry Smith   ierr = MPIU_Allreduce(&isFullCol,&isFullColGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)iscol));CHKERRQ(ierr);
5458188e55aSJed Brown 
546427230ceSLisandro Dalcin   if (isFullColGlobal && vs->nc > 1) {
5478188e55aSJed Brown     PetscInt row;
5488188e55aSJed Brown     ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr);
5498188e55aSJed Brown     ierr = MatNestGetRow(A,row,B);CHKERRQ(ierr);
5508188e55aSJed Brown   } else {
551f349c1fdSJed Brown     ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr);
552f349c1fdSJed Brown     ierr = MatNestFindIS(A,vs->nc,is->col,iscol,&col);CHKERRQ(ierr);
553b6480e04SStefano Zampini     if (!vs->m[row][col]) {
554b6480e04SStefano Zampini       PetscInt lr,lc;
555b6480e04SStefano Zampini 
556b6480e04SStefano Zampini       ierr = MatCreate(PetscObjectComm((PetscObject)A),&vs->m[row][col]);CHKERRQ(ierr);
557b6480e04SStefano Zampini       ierr = ISGetLocalSize(vs->isglobal.row[row],&lr);CHKERRQ(ierr);
558b6480e04SStefano Zampini       ierr = ISGetLocalSize(vs->isglobal.col[col],&lc);CHKERRQ(ierr);
559b6480e04SStefano Zampini       ierr = MatSetSizes(vs->m[row][col],lr,lc,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
560b6480e04SStefano Zampini       ierr = MatSetUp(vs->m[row][col]);CHKERRQ(ierr);
561b6480e04SStefano Zampini       ierr = MatAssemblyBegin(vs->m[row][col],MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
562b6480e04SStefano Zampini       ierr = MatAssemblyEnd(vs->m[row][col],MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
563b6480e04SStefano Zampini     }
564f349c1fdSJed Brown     *B = vs->m[row][col];
5658188e55aSJed Brown   }
566f349c1fdSJed Brown   PetscFunctionReturn(0);
567f349c1fdSJed Brown }
568f349c1fdSJed Brown 
5697dae84e0SHong Zhang static PetscErrorCode MatCreateSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat *B)
570f349c1fdSJed Brown {
571f349c1fdSJed Brown   PetscErrorCode ierr;
572f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
573f349c1fdSJed Brown   Mat            sub;
574f349c1fdSJed Brown 
575f349c1fdSJed Brown   PetscFunctionBegin;
576f349c1fdSJed Brown   ierr = MatNestFindSubMat(A,&vs->isglobal,isrow,iscol,&sub);CHKERRQ(ierr);
577f349c1fdSJed Brown   switch (reuse) {
578f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
5797874fa86SDave May     if (sub) { ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr); }
580f349c1fdSJed Brown     *B = sub;
581f349c1fdSJed Brown     break;
582f349c1fdSJed Brown   case MAT_REUSE_MATRIX:
583ce94432eSBarry Smith     if (sub != *B) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Submatrix was not used before in this call");
584f349c1fdSJed Brown     break;
585f349c1fdSJed Brown   case MAT_IGNORE_MATRIX:       /* Nothing to do */
586f349c1fdSJed Brown     break;
587511c6705SHong Zhang   case MAT_INPLACE_MATRIX:       /* Nothing to do */
588511c6705SHong Zhang     SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MAT_INPLACE_MATRIX is not supported yet");
589511c6705SHong Zhang     break;
590f349c1fdSJed Brown   }
591f349c1fdSJed Brown   PetscFunctionReturn(0);
592f349c1fdSJed Brown }
593f349c1fdSJed Brown 
594f349c1fdSJed Brown PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
595f349c1fdSJed Brown {
596f349c1fdSJed Brown   PetscErrorCode ierr;
597f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
598f349c1fdSJed Brown   Mat            sub;
599f349c1fdSJed Brown 
600f349c1fdSJed Brown   PetscFunctionBegin;
601f349c1fdSJed Brown   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
602f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
603f349c1fdSJed Brown   if (sub) {ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr);}
604f349c1fdSJed Brown   *B = sub;
605d8588912SDave May   PetscFunctionReturn(0);
606d8588912SDave May }
607d8588912SDave May 
608207556f9SJed Brown static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
609d8588912SDave May {
610d8588912SDave May   PetscErrorCode ierr;
611f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
612f349c1fdSJed Brown   Mat            sub;
613d8588912SDave May 
614d8588912SDave May   PetscFunctionBegin;
615f349c1fdSJed Brown   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
616ce94432eSBarry Smith   if (*B != sub) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has not been gotten");
617f349c1fdSJed Brown   if (sub) {
618ce94432eSBarry Smith     if (((PetscObject)sub)->refct <= 1) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has had reference count decremented too many times");
6196bf464f9SBarry Smith     ierr = MatDestroy(B);CHKERRQ(ierr);
620d8588912SDave May   }
621d8588912SDave May   PetscFunctionReturn(0);
622d8588912SDave May }
623d8588912SDave May 
6247874fa86SDave May static PetscErrorCode MatGetDiagonal_Nest(Mat A,Vec v)
6257874fa86SDave May {
6267874fa86SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
6277874fa86SDave May   PetscInt       i;
6287874fa86SDave May   PetscErrorCode ierr;
6297874fa86SDave May 
6307874fa86SDave May   PetscFunctionBegin;
6317874fa86SDave May   for (i=0; i<bA->nr; i++) {
632429bac76SJed Brown     Vec bv;
633429bac76SJed Brown     ierr = VecGetSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
6347874fa86SDave May     if (bA->m[i][i]) {
635429bac76SJed Brown       ierr = MatGetDiagonal(bA->m[i][i],bv);CHKERRQ(ierr);
6367874fa86SDave May     } else {
6375159a857SMatthew G. Knepley       ierr = VecSet(bv,0.0);CHKERRQ(ierr);
6387874fa86SDave May     }
639429bac76SJed Brown     ierr = VecRestoreSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
6407874fa86SDave May   }
6417874fa86SDave May   PetscFunctionReturn(0);
6427874fa86SDave May }
6437874fa86SDave May 
6447874fa86SDave May static PetscErrorCode MatDiagonalScale_Nest(Mat A,Vec l,Vec r)
6457874fa86SDave May {
6467874fa86SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
647429bac76SJed Brown   Vec            bl,*br;
6487874fa86SDave May   PetscInt       i,j;
6497874fa86SDave May   PetscErrorCode ierr;
6507874fa86SDave May 
6517874fa86SDave May   PetscFunctionBegin;
6523f800ebeSJed Brown   ierr = PetscCalloc1(bA->nc,&br);CHKERRQ(ierr);
6532e6472ebSElliott Sales de Andrade   if (r) {
654429bac76SJed Brown     for (j=0; j<bA->nc; j++) {ierr = VecGetSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);}
6552e6472ebSElliott Sales de Andrade   }
6562e6472ebSElliott Sales de Andrade   bl = NULL;
6577874fa86SDave May   for (i=0; i<bA->nr; i++) {
6582e6472ebSElliott Sales de Andrade     if (l) {
659429bac76SJed Brown       ierr = VecGetSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr);
6602e6472ebSElliott Sales de Andrade     }
6617874fa86SDave May     for (j=0; j<bA->nc; j++) {
6627874fa86SDave May       if (bA->m[i][j]) {
663429bac76SJed Brown         ierr = MatDiagonalScale(bA->m[i][j],bl,br[j]);CHKERRQ(ierr);
6647874fa86SDave May       }
6657874fa86SDave May     }
6662e6472ebSElliott Sales de Andrade     if (l) {
667a061e289SJed Brown       ierr = VecRestoreSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr);
6687874fa86SDave May     }
6692e6472ebSElliott Sales de Andrade   }
6702e6472ebSElliott Sales de Andrade   if (r) {
671429bac76SJed Brown     for (j=0; j<bA->nc; j++) {ierr = VecRestoreSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);}
6722e6472ebSElliott Sales de Andrade   }
673429bac76SJed Brown   ierr = PetscFree(br);CHKERRQ(ierr);
6747874fa86SDave May   PetscFunctionReturn(0);
6757874fa86SDave May }
6767874fa86SDave May 
677a061e289SJed Brown static PetscErrorCode MatScale_Nest(Mat A,PetscScalar a)
678a061e289SJed Brown {
679a061e289SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
680a061e289SJed Brown   PetscInt       i,j;
681a061e289SJed Brown   PetscErrorCode ierr;
682a061e289SJed Brown 
683a061e289SJed Brown   PetscFunctionBegin;
684a061e289SJed Brown   for (i=0; i<bA->nr; i++) {
685a061e289SJed Brown     for (j=0; j<bA->nc; j++) {
686a061e289SJed Brown       if (bA->m[i][j]) {
687a061e289SJed Brown         ierr = MatScale(bA->m[i][j],a);CHKERRQ(ierr);
688a061e289SJed Brown       }
689a061e289SJed Brown     }
690a061e289SJed Brown   }
691a061e289SJed Brown   PetscFunctionReturn(0);
692a061e289SJed Brown }
693a061e289SJed Brown 
694a061e289SJed Brown static PetscErrorCode MatShift_Nest(Mat A,PetscScalar a)
695a061e289SJed Brown {
696a061e289SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
697a061e289SJed Brown   PetscInt       i;
698a061e289SJed Brown   PetscErrorCode ierr;
699a061e289SJed Brown 
700a061e289SJed Brown   PetscFunctionBegin;
701a061e289SJed Brown   for (i=0; i<bA->nr; i++) {
702ce94432eSBarry 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);
703a061e289SJed Brown     ierr = MatShift(bA->m[i][i],a);CHKERRQ(ierr);
704a061e289SJed Brown   }
705a061e289SJed Brown   PetscFunctionReturn(0);
706a061e289SJed Brown }
707a061e289SJed Brown 
70813135bc6SAlex Fikl static PetscErrorCode MatDiagonalSet_Nest(Mat A,Vec D,InsertMode is)
70913135bc6SAlex Fikl {
71013135bc6SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data;
71113135bc6SAlex Fikl   PetscInt       i;
71213135bc6SAlex Fikl   PetscErrorCode ierr;
71313135bc6SAlex Fikl 
71413135bc6SAlex Fikl   PetscFunctionBegin;
71513135bc6SAlex Fikl   for (i=0; i<bA->nr; i++) {
71613135bc6SAlex Fikl     Vec bv;
71713135bc6SAlex Fikl     ierr = VecGetSubVector(D,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
71813135bc6SAlex Fikl     if (bA->m[i][i]) {
71913135bc6SAlex Fikl       ierr = MatDiagonalSet(bA->m[i][i],bv,is);CHKERRQ(ierr);
72013135bc6SAlex Fikl     }
72113135bc6SAlex Fikl     ierr = VecRestoreSubVector(D,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
72213135bc6SAlex Fikl   }
72313135bc6SAlex Fikl   PetscFunctionReturn(0);
72413135bc6SAlex Fikl }
72513135bc6SAlex Fikl 
726f8170845SAlex Fikl static PetscErrorCode MatSetRandom_Nest(Mat A,PetscRandom rctx)
727f8170845SAlex Fikl {
728f8170845SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data;
729f8170845SAlex Fikl   PetscInt       i,j;
730f8170845SAlex Fikl   PetscErrorCode ierr;
731f8170845SAlex Fikl 
732f8170845SAlex Fikl   PetscFunctionBegin;
733f8170845SAlex Fikl   for (i=0; i<bA->nr; i++) {
734f8170845SAlex Fikl     for (j=0; j<bA->nc; j++) {
735f8170845SAlex Fikl       if (bA->m[i][j]) {
736f8170845SAlex Fikl         ierr = MatSetRandom(bA->m[i][j],rctx);CHKERRQ(ierr);
737f8170845SAlex Fikl       }
738f8170845SAlex Fikl     }
739f8170845SAlex Fikl   }
740f8170845SAlex Fikl   PetscFunctionReturn(0);
741f8170845SAlex Fikl }
742f8170845SAlex Fikl 
7432a7a6963SBarry Smith static PetscErrorCode MatCreateVecs_Nest(Mat A,Vec *right,Vec *left)
744d8588912SDave May {
745d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
746d8588912SDave May   Vec            *L,*R;
747d8588912SDave May   MPI_Comm       comm;
748d8588912SDave May   PetscInt       i,j;
749d8588912SDave May   PetscErrorCode ierr;
750d8588912SDave May 
751d8588912SDave May   PetscFunctionBegin;
752ce94432eSBarry Smith   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
753d8588912SDave May   if (right) {
754d8588912SDave May     /* allocate R */
755854ce69bSBarry Smith     ierr = PetscMalloc1(bA->nc, &R);CHKERRQ(ierr);
756d8588912SDave May     /* Create the right vectors */
757d8588912SDave May     for (j=0; j<bA->nc; j++) {
758d8588912SDave May       for (i=0; i<bA->nr; i++) {
759d8588912SDave May         if (bA->m[i][j]) {
7602a7a6963SBarry Smith           ierr = MatCreateVecs(bA->m[i][j],&R[j],NULL);CHKERRQ(ierr);
761d8588912SDave May           break;
762d8588912SDave May         }
763d8588912SDave May       }
7646c4ed002SBarry Smith       if (i==bA->nr) SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
765d8588912SDave May     }
766f349c1fdSJed Brown     ierr = VecCreateNest(comm,bA->nc,bA->isglobal.col,R,right);CHKERRQ(ierr);
767d8588912SDave May     /* hand back control to the nest vector */
768d8588912SDave May     for (j=0; j<bA->nc; j++) {
7696bf464f9SBarry Smith       ierr = VecDestroy(&R[j]);CHKERRQ(ierr);
770d8588912SDave May     }
771d8588912SDave May     ierr = PetscFree(R);CHKERRQ(ierr);
772d8588912SDave May   }
773d8588912SDave May 
774d8588912SDave May   if (left) {
775d8588912SDave May     /* allocate L */
776854ce69bSBarry Smith     ierr = PetscMalloc1(bA->nr, &L);CHKERRQ(ierr);
777d8588912SDave May     /* Create the left vectors */
778d8588912SDave May     for (i=0; i<bA->nr; i++) {
779d8588912SDave May       for (j=0; j<bA->nc; j++) {
780d8588912SDave May         if (bA->m[i][j]) {
7812a7a6963SBarry Smith           ierr = MatCreateVecs(bA->m[i][j],NULL,&L[i]);CHKERRQ(ierr);
782d8588912SDave May           break;
783d8588912SDave May         }
784d8588912SDave May       }
7856c4ed002SBarry Smith       if (j==bA->nc) SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
786d8588912SDave May     }
787d8588912SDave May 
788f349c1fdSJed Brown     ierr = VecCreateNest(comm,bA->nr,bA->isglobal.row,L,left);CHKERRQ(ierr);
789d8588912SDave May     for (i=0; i<bA->nr; i++) {
7906bf464f9SBarry Smith       ierr = VecDestroy(&L[i]);CHKERRQ(ierr);
791d8588912SDave May     }
792d8588912SDave May 
793d8588912SDave May     ierr = PetscFree(L);CHKERRQ(ierr);
794d8588912SDave May   }
795d8588912SDave May   PetscFunctionReturn(0);
796d8588912SDave May }
797d8588912SDave May 
798207556f9SJed Brown static PetscErrorCode MatView_Nest(Mat A,PetscViewer viewer)
799d8588912SDave May {
800d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
80129e60adbSStefano Zampini   PetscBool      isascii,viewSub = PETSC_FALSE;
802d8588912SDave May   PetscInt       i,j;
803d8588912SDave May   PetscErrorCode ierr;
804d8588912SDave May 
805d8588912SDave May   PetscFunctionBegin;
806251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
807d8588912SDave May   if (isascii) {
808d8588912SDave May 
80929e60adbSStefano Zampini     ierr = PetscOptionsGetBool(((PetscObject)A)->options,((PetscObject)A)->prefix,"-mat_view_nest_sub",&viewSub,NULL);CHKERRQ(ierr);
810d86155a6SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"Matrix object: \n");CHKERRQ(ierr);
811d86155a6SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
812d86155a6SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer, "type=nest, rows=%D, cols=%D \n",bA->nr,bA->nc);CHKERRQ(ierr);
813d8588912SDave May 
814d86155a6SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"MatNest structure: \n");CHKERRQ(ierr);
815d8588912SDave May     for (i=0; i<bA->nr; i++) {
816d8588912SDave May       for (j=0; j<bA->nc; j++) {
81719fd82e9SBarry Smith         MatType   type;
818270f95d7SJed Brown         char      name[256] = "",prefix[256] = "";
819d8588912SDave May         PetscInt  NR,NC;
820d8588912SDave May         PetscBool isNest = PETSC_FALSE;
821d8588912SDave May 
822d8588912SDave May         if (!bA->m[i][j]) {
823d86155a6SBarry Smith           CHKERRQ(ierr);PetscViewerASCIIPrintf(viewer, "(%D,%D) : NULL \n",i,j);CHKERRQ(ierr);
824d8588912SDave May           continue;
825d8588912SDave May         }
826d8588912SDave May         ierr = MatGetSize(bA->m[i][j],&NR,&NC);CHKERRQ(ierr);
827d8588912SDave May         ierr = MatGetType(bA->m[i][j], &type);CHKERRQ(ierr);
8288caf3d72SBarry Smith         if (((PetscObject)bA->m[i][j])->name) {ierr = PetscSNPrintf(name,sizeof(name),"name=\"%s\", ",((PetscObject)bA->m[i][j])->name);CHKERRQ(ierr);}
8298caf3d72SBarry Smith         if (((PetscObject)bA->m[i][j])->prefix) {ierr = PetscSNPrintf(prefix,sizeof(prefix),"prefix=\"%s\", ",((PetscObject)bA->m[i][j])->prefix);CHKERRQ(ierr);}
830251f4c67SDmitry Karpeev         ierr = PetscObjectTypeCompare((PetscObject)bA->m[i][j],MATNEST,&isNest);CHKERRQ(ierr);
831d8588912SDave May 
832270f95d7SJed Brown         ierr = PetscViewerASCIIPrintf(viewer,"(%D,%D) : %s%stype=%s, rows=%D, cols=%D \n",i,j,name,prefix,type,NR,NC);CHKERRQ(ierr);
833d8588912SDave May 
83429e60adbSStefano Zampini         if (isNest || viewSub) {
835270f95d7SJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);  /* push1 */
836d8588912SDave May           ierr = MatView(bA->m[i][j],viewer);CHKERRQ(ierr);
837270f95d7SJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);    /* pop1 */
838d8588912SDave May         }
839d8588912SDave May       }
840d8588912SDave May     }
841d86155a6SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);    /* pop0 */
842d8588912SDave May   }
843d8588912SDave May   PetscFunctionReturn(0);
844d8588912SDave May }
845d8588912SDave May 
846207556f9SJed Brown static PetscErrorCode MatZeroEntries_Nest(Mat A)
847d8588912SDave May {
848d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
849d8588912SDave May   PetscInt       i,j;
850d8588912SDave May   PetscErrorCode ierr;
851d8588912SDave May 
852d8588912SDave May   PetscFunctionBegin;
853d8588912SDave May   for (i=0; i<bA->nr; i++) {
854d8588912SDave May     for (j=0; j<bA->nc; j++) {
855d8588912SDave May       if (!bA->m[i][j]) continue;
856d8588912SDave May       ierr = MatZeroEntries(bA->m[i][j]);CHKERRQ(ierr);
857d8588912SDave May     }
858d8588912SDave May   }
859d8588912SDave May   PetscFunctionReturn(0);
860d8588912SDave May }
861d8588912SDave May 
862c222c20dSDavid Ham static PetscErrorCode MatCopy_Nest(Mat A,Mat B,MatStructure str)
863c222c20dSDavid Ham {
864c222c20dSDavid Ham   Mat_Nest       *bA = (Mat_Nest*)A->data,*bB = (Mat_Nest*)B->data;
865c222c20dSDavid Ham   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
866c222c20dSDavid Ham   PetscErrorCode ierr;
867c222c20dSDavid Ham 
868c222c20dSDavid Ham   PetscFunctionBegin;
869c222c20dSDavid 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);
870c222c20dSDavid Ham   for (i=0; i<nr; i++) {
871c222c20dSDavid Ham     for (j=0; j<nc; j++) {
87246a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
873c222c20dSDavid Ham         ierr = MatCopy(bA->m[i][j],bB->m[i][j],str);CHKERRQ(ierr);
87446a2b97cSJed 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);
875c222c20dSDavid Ham     }
876c222c20dSDavid Ham   }
877cdc753b6SBarry Smith   ierr = PetscObjectStateIncrease((PetscObject)B);CHKERRQ(ierr);
878c222c20dSDavid Ham   PetscFunctionReturn(0);
879c222c20dSDavid Ham }
880c222c20dSDavid Ham 
8816e76ffeaSPierre Jolivet static PetscErrorCode MatAXPY_Nest(Mat Y,PetscScalar a,Mat X,MatStructure str)
8826e76ffeaSPierre Jolivet {
8836e76ffeaSPierre Jolivet   Mat_Nest       *bY = (Mat_Nest*)Y->data,*bX = (Mat_Nest*)X->data;
8846e76ffeaSPierre Jolivet   PetscInt       i,j,nr = bY->nr,nc = bY->nc;
8856e76ffeaSPierre Jolivet   PetscErrorCode ierr;
8866e76ffeaSPierre Jolivet 
8876e76ffeaSPierre Jolivet   PetscFunctionBegin;
8886e76ffeaSPierre 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);
8896e76ffeaSPierre Jolivet   for (i=0; i<nr; i++) {
8906e76ffeaSPierre Jolivet     for (j=0; j<nc; j++) {
8916e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
8926e76ffeaSPierre Jolivet         ierr = MatAXPY(bY->m[i][j],a,bX->m[i][j],str);CHKERRQ(ierr);
893c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
894c066aebcSStefano Zampini         Mat M;
895c066aebcSStefano Zampini 
896c066aebcSStefano Zampini         if (str != DIFFERENT_NONZERO_PATTERN) SETERRQ2(PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Matrix block does not exist at %D,%D",i,j);
897c066aebcSStefano Zampini         ierr = MatDuplicate(bX->m[i][j],MAT_COPY_VALUES,&M);CHKERRQ(ierr);
898c066aebcSStefano Zampini         ierr = MatNestSetSubMat(Y,i,j,M);CHKERRQ(ierr);
899c066aebcSStefano Zampini         ierr = MatDestroy(&M);CHKERRQ(ierr);
900c066aebcSStefano Zampini       }
9016e76ffeaSPierre Jolivet     }
9026e76ffeaSPierre Jolivet   }
9036e76ffeaSPierre Jolivet   PetscFunctionReturn(0);
9046e76ffeaSPierre Jolivet }
9056e76ffeaSPierre Jolivet 
906207556f9SJed Brown static PetscErrorCode MatDuplicate_Nest(Mat A,MatDuplicateOption op,Mat *B)
907d8588912SDave May {
908d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
909841e96a3SJed Brown   Mat            *b;
910841e96a3SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
911d8588912SDave May   PetscErrorCode ierr;
912d8588912SDave May 
913d8588912SDave May   PetscFunctionBegin;
914785e854fSJed Brown   ierr = PetscMalloc1(nr*nc,&b);CHKERRQ(ierr);
915841e96a3SJed Brown   for (i=0; i<nr; i++) {
916841e96a3SJed Brown     for (j=0; j<nc; j++) {
917841e96a3SJed Brown       if (bA->m[i][j]) {
918841e96a3SJed Brown         ierr = MatDuplicate(bA->m[i][j],op,&b[i*nc+j]);CHKERRQ(ierr);
919841e96a3SJed Brown       } else {
9200298fd71SBarry Smith         b[i*nc+j] = NULL;
921d8588912SDave May       }
922d8588912SDave May     }
923d8588912SDave May   }
924ce94432eSBarry Smith   ierr = MatCreateNest(PetscObjectComm((PetscObject)A),nr,bA->isglobal.row,nc,bA->isglobal.col,b,B);CHKERRQ(ierr);
925841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
926841e96a3SJed Brown   for (i=0; i<nr*nc; i++) {
9276bf464f9SBarry Smith     ierr = MatDestroy(&b[i]);CHKERRQ(ierr);
928d8588912SDave May   }
929d8588912SDave May   ierr = PetscFree(b);CHKERRQ(ierr);
930d8588912SDave May 
931841e96a3SJed Brown   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
932841e96a3SJed Brown   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
933d8588912SDave May   PetscFunctionReturn(0);
934d8588912SDave May }
935d8588912SDave May 
936d8588912SDave May /* nest api */
937d8588912SDave May PetscErrorCode MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat *mat)
938d8588912SDave May {
939d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
9405fd66863SKarl Rupp 
941d8588912SDave May   PetscFunctionBegin;
942ce94432eSBarry Smith   if (idxm >= bA->nr) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
943ce94432eSBarry Smith   if (jdxm >= bA->nc) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
944d8588912SDave May   *mat = bA->m[idxm][jdxm];
945d8588912SDave May   PetscFunctionReturn(0);
946d8588912SDave May }
947d8588912SDave May 
9489ba0d327SJed Brown /*@
949d8588912SDave May  MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix.
950d8588912SDave May 
951d8588912SDave May  Not collective
952d8588912SDave May 
953d8588912SDave May  Input Parameters:
954629881c0SJed Brown +   A  - nest matrix
955d8588912SDave May .   idxm - index of the matrix within the nest matrix
956629881c0SJed Brown -   jdxm - index of the matrix within the nest matrix
957d8588912SDave May 
958d8588912SDave May  Output Parameter:
959d8588912SDave May .   sub - matrix at index idxm,jdxm within the nest matrix
960d8588912SDave May 
961d8588912SDave May  Level: developer
962d8588912SDave May 
963d8588912SDave May .seealso: MatNestGetSize(), MatNestGetSubMats()
964d8588912SDave May @*/
9657087cfbeSBarry Smith PetscErrorCode  MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat *sub)
966d8588912SDave May {
967699a902aSJed Brown   PetscErrorCode ierr;
968d8588912SDave May 
969d8588912SDave May   PetscFunctionBegin;
970699a902aSJed Brown   ierr = PetscUseMethod(A,"MatNestGetSubMat_C",(Mat,PetscInt,PetscInt,Mat*),(A,idxm,jdxm,sub));CHKERRQ(ierr);
971d8588912SDave May   PetscFunctionReturn(0);
972d8588912SDave May }
973d8588912SDave May 
9740782ca92SJed Brown PetscErrorCode MatNestSetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat mat)
9750782ca92SJed Brown {
9760782ca92SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
9770782ca92SJed Brown   PetscInt       m,n,M,N,mi,ni,Mi,Ni;
9780782ca92SJed Brown   PetscErrorCode ierr;
9790782ca92SJed Brown 
9800782ca92SJed Brown   PetscFunctionBegin;
981ce94432eSBarry Smith   if (idxm >= bA->nr) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
982ce94432eSBarry Smith   if (jdxm >= bA->nc) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
9830782ca92SJed Brown   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
9840782ca92SJed Brown   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
9850782ca92SJed Brown   ierr = ISGetLocalSize(bA->isglobal.row[idxm],&mi);CHKERRQ(ierr);
9860782ca92SJed Brown   ierr = ISGetSize(bA->isglobal.row[idxm],&Mi);CHKERRQ(ierr);
9870782ca92SJed Brown   ierr = ISGetLocalSize(bA->isglobal.col[jdxm],&ni);CHKERRQ(ierr);
9880782ca92SJed Brown   ierr = ISGetSize(bA->isglobal.col[jdxm],&Ni);CHKERRQ(ierr);
989ce94432eSBarry 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);
990ce94432eSBarry 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);
99126fbe8dcSKarl Rupp 
9920782ca92SJed Brown   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
9930782ca92SJed Brown   ierr = MatDestroy(&bA->m[idxm][jdxm]);CHKERRQ(ierr);
9940782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
9950782ca92SJed Brown   PetscFunctionReturn(0);
9960782ca92SJed Brown }
9970782ca92SJed Brown 
9989ba0d327SJed Brown /*@
9990782ca92SJed Brown  MatNestSetSubMat - Set a single submatrix in the nest matrix.
10000782ca92SJed Brown 
10010782ca92SJed Brown  Logically collective on the submatrix communicator
10020782ca92SJed Brown 
10030782ca92SJed Brown  Input Parameters:
10040782ca92SJed Brown +   A  - nest matrix
10050782ca92SJed Brown .   idxm - index of the matrix within the nest matrix
10060782ca92SJed Brown .   jdxm - index of the matrix within the nest matrix
10070782ca92SJed Brown -   sub - matrix at index idxm,jdxm within the nest matrix
10080782ca92SJed Brown 
10090782ca92SJed Brown  Notes:
10100782ca92SJed Brown  The new submatrix must have the same size and communicator as that block of the nest.
10110782ca92SJed Brown 
10120782ca92SJed Brown  This increments the reference count of the submatrix.
10130782ca92SJed Brown 
10140782ca92SJed Brown  Level: developer
10150782ca92SJed Brown 
1016d5dfb694SBarry Smith .seealso: MatNestSetSubMats(), MatNestGetSubMats()
10170782ca92SJed Brown @*/
10180782ca92SJed Brown PetscErrorCode  MatNestSetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat sub)
10190782ca92SJed Brown {
10200782ca92SJed Brown   PetscErrorCode ierr;
10210782ca92SJed Brown 
10220782ca92SJed Brown   PetscFunctionBegin;
10230782ca92SJed Brown   ierr = PetscUseMethod(A,"MatNestSetSubMat_C",(Mat,PetscInt,PetscInt,Mat),(A,idxm,jdxm,sub));CHKERRQ(ierr);
10240782ca92SJed Brown   PetscFunctionReturn(0);
10250782ca92SJed Brown }
10260782ca92SJed Brown 
1027d8588912SDave May PetscErrorCode MatNestGetSubMats_Nest(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
1028d8588912SDave May {
1029d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
10305fd66863SKarl Rupp 
1031d8588912SDave May   PetscFunctionBegin;
103226fbe8dcSKarl Rupp   if (M)   *M   = bA->nr;
103326fbe8dcSKarl Rupp   if (N)   *N   = bA->nc;
103426fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
1035d8588912SDave May   PetscFunctionReturn(0);
1036d8588912SDave May }
1037d8588912SDave May 
1038d8588912SDave May /*@C
1039d8588912SDave May  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix.
1040d8588912SDave May 
1041d8588912SDave May  Not collective
1042d8588912SDave May 
1043d8588912SDave May  Input Parameters:
1044629881c0SJed Brown .   A  - nest matrix
1045d8588912SDave May 
1046d8588912SDave May  Output Parameter:
1047629881c0SJed Brown +   M - number of rows in the nest matrix
1048d8588912SDave May .   N - number of cols in the nest matrix
1049629881c0SJed Brown -   mat - 2d array of matrices
1050d8588912SDave May 
1051d8588912SDave May  Notes:
1052d8588912SDave May 
1053d8588912SDave May  The user should not free the array mat.
1054d8588912SDave May 
1055351962e3SVincent Le Chenadec  In Fortran, this routine has a calling sequence
1056351962e3SVincent Le Chenadec $   call MatNestGetSubMats(A, M, N, mat, ierr)
1057351962e3SVincent Le Chenadec  where the space allocated for the optional argument mat is assumed large enough (if provided).
1058351962e3SVincent Le Chenadec 
1059d8588912SDave May  Level: developer
1060d8588912SDave May 
1061d8588912SDave May .seealso: MatNestGetSize(), MatNestGetSubMat()
1062d8588912SDave May @*/
10637087cfbeSBarry Smith PetscErrorCode  MatNestGetSubMats(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
1064d8588912SDave May {
1065699a902aSJed Brown   PetscErrorCode ierr;
1066d8588912SDave May 
1067d8588912SDave May   PetscFunctionBegin;
1068699a902aSJed Brown   ierr = PetscUseMethod(A,"MatNestGetSubMats_C",(Mat,PetscInt*,PetscInt*,Mat***),(A,M,N,mat));CHKERRQ(ierr);
1069d8588912SDave May   PetscFunctionReturn(0);
1070d8588912SDave May }
1071d8588912SDave May 
10727087cfbeSBarry Smith PetscErrorCode  MatNestGetSize_Nest(Mat A,PetscInt *M,PetscInt *N)
1073d8588912SDave May {
1074d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
1075d8588912SDave May 
1076d8588912SDave May   PetscFunctionBegin;
107726fbe8dcSKarl Rupp   if (M) *M = bA->nr;
107826fbe8dcSKarl Rupp   if (N) *N = bA->nc;
1079d8588912SDave May   PetscFunctionReturn(0);
1080d8588912SDave May }
1081d8588912SDave May 
10829ba0d327SJed Brown /*@
1083d8588912SDave May  MatNestGetSize - Returns the size of the nest matrix.
1084d8588912SDave May 
1085d8588912SDave May  Not collective
1086d8588912SDave May 
1087d8588912SDave May  Input Parameters:
1088d8588912SDave May .   A  - nest matrix
1089d8588912SDave May 
1090d8588912SDave May  Output Parameter:
1091629881c0SJed Brown +   M - number of rows in the nested mat
1092629881c0SJed Brown -   N - number of cols in the nested mat
1093d8588912SDave May 
1094d8588912SDave May  Notes:
1095d8588912SDave May 
1096d8588912SDave May  Level: developer
1097d8588912SDave May 
1098d8588912SDave May .seealso: MatNestGetSubMat(), MatNestGetSubMats()
1099d8588912SDave May @*/
11007087cfbeSBarry Smith PetscErrorCode  MatNestGetSize(Mat A,PetscInt *M,PetscInt *N)
1101d8588912SDave May {
1102699a902aSJed Brown   PetscErrorCode ierr;
1103d8588912SDave May 
1104d8588912SDave May   PetscFunctionBegin;
1105699a902aSJed Brown   ierr = PetscUseMethod(A,"MatNestGetSize_C",(Mat,PetscInt*,PetscInt*),(A,M,N));CHKERRQ(ierr);
1106d8588912SDave May   PetscFunctionReturn(0);
1107d8588912SDave May }
1108d8588912SDave May 
1109f7a08781SBarry Smith static PetscErrorCode MatNestGetISs_Nest(Mat A,IS rows[],IS cols[])
1110900e7ff2SJed Brown {
1111900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest*)A->data;
1112900e7ff2SJed Brown   PetscInt i;
1113900e7ff2SJed Brown 
1114900e7ff2SJed Brown   PetscFunctionBegin;
1115900e7ff2SJed Brown   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->isglobal.row[i];
1116900e7ff2SJed Brown   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->isglobal.col[i];
1117900e7ff2SJed Brown   PetscFunctionReturn(0);
1118900e7ff2SJed Brown }
1119900e7ff2SJed Brown 
11203a4d7b9aSSatish Balay /*@C
1121900e7ff2SJed Brown  MatNestGetISs - Returns the index sets partitioning the row and column spaces
1122900e7ff2SJed Brown 
1123900e7ff2SJed Brown  Not collective
1124900e7ff2SJed Brown 
1125900e7ff2SJed Brown  Input Parameters:
1126900e7ff2SJed Brown .   A  - nest matrix
1127900e7ff2SJed Brown 
1128900e7ff2SJed Brown  Output Parameter:
1129900e7ff2SJed Brown +   rows - array of row index sets
1130900e7ff2SJed Brown -   cols - array of column index sets
1131900e7ff2SJed Brown 
1132900e7ff2SJed Brown  Level: advanced
1133900e7ff2SJed Brown 
1134900e7ff2SJed Brown  Notes:
1135900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1136900e7ff2SJed Brown 
1137900e7ff2SJed Brown .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetLocalISs()
1138900e7ff2SJed Brown @*/
1139900e7ff2SJed Brown PetscErrorCode  MatNestGetISs(Mat A,IS rows[],IS cols[])
1140900e7ff2SJed Brown {
1141900e7ff2SJed Brown   PetscErrorCode ierr;
1142900e7ff2SJed Brown 
1143900e7ff2SJed Brown   PetscFunctionBegin;
1144900e7ff2SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1145900e7ff2SJed Brown   ierr = PetscUseMethod(A,"MatNestGetISs_C",(Mat,IS[],IS[]),(A,rows,cols));CHKERRQ(ierr);
1146900e7ff2SJed Brown   PetscFunctionReturn(0);
1147900e7ff2SJed Brown }
1148900e7ff2SJed Brown 
1149f7a08781SBarry Smith static PetscErrorCode MatNestGetLocalISs_Nest(Mat A,IS rows[],IS cols[])
1150900e7ff2SJed Brown {
1151900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest*)A->data;
1152900e7ff2SJed Brown   PetscInt i;
1153900e7ff2SJed Brown 
1154900e7ff2SJed Brown   PetscFunctionBegin;
1155900e7ff2SJed Brown   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->islocal.row[i];
1156900e7ff2SJed Brown   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->islocal.col[i];
1157900e7ff2SJed Brown   PetscFunctionReturn(0);
1158900e7ff2SJed Brown }
1159900e7ff2SJed Brown 
1160900e7ff2SJed Brown /*@C
1161900e7ff2SJed Brown  MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces
1162900e7ff2SJed Brown 
1163900e7ff2SJed Brown  Not collective
1164900e7ff2SJed Brown 
1165900e7ff2SJed Brown  Input Parameters:
1166900e7ff2SJed Brown .   A  - nest matrix
1167900e7ff2SJed Brown 
1168900e7ff2SJed Brown  Output Parameter:
11690298fd71SBarry Smith +   rows - array of row index sets (or NULL to ignore)
11700298fd71SBarry Smith -   cols - array of column index sets (or NULL to ignore)
1171900e7ff2SJed Brown 
1172900e7ff2SJed Brown  Level: advanced
1173900e7ff2SJed Brown 
1174900e7ff2SJed Brown  Notes:
1175900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1176900e7ff2SJed Brown 
1177900e7ff2SJed Brown .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetISs()
1178900e7ff2SJed Brown @*/
1179900e7ff2SJed Brown PetscErrorCode  MatNestGetLocalISs(Mat A,IS rows[],IS cols[])
1180900e7ff2SJed Brown {
1181900e7ff2SJed Brown   PetscErrorCode ierr;
1182900e7ff2SJed Brown 
1183900e7ff2SJed Brown   PetscFunctionBegin;
1184900e7ff2SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1185900e7ff2SJed Brown   ierr = PetscUseMethod(A,"MatNestGetLocalISs_C",(Mat,IS[],IS[]),(A,rows,cols));CHKERRQ(ierr);
1186900e7ff2SJed Brown   PetscFunctionReturn(0);
1187900e7ff2SJed Brown }
1188900e7ff2SJed Brown 
118919fd82e9SBarry Smith PetscErrorCode  MatNestSetVecType_Nest(Mat A,VecType vtype)
1190207556f9SJed Brown {
1191207556f9SJed Brown   PetscErrorCode ierr;
1192207556f9SJed Brown   PetscBool      flg;
1193207556f9SJed Brown 
1194207556f9SJed Brown   PetscFunctionBegin;
1195207556f9SJed Brown   ierr = PetscStrcmp(vtype,VECNEST,&flg);CHKERRQ(ierr);
1196207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
11972a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
119812b53f24SSatish Balay   else A->ops->getvecs = (PetscErrorCode (*)(Mat,Vec*,Vec*)) 0;
1199207556f9SJed Brown   PetscFunctionReturn(0);
1200207556f9SJed Brown }
1201207556f9SJed Brown 
1202207556f9SJed Brown /*@C
12032a7a6963SBarry Smith  MatNestSetVecType - Sets the type of Vec returned by MatCreateVecs()
1204207556f9SJed Brown 
1205207556f9SJed Brown  Not collective
1206207556f9SJed Brown 
1207207556f9SJed Brown  Input Parameters:
1208207556f9SJed Brown +  A  - nest matrix
1209207556f9SJed Brown -  vtype - type to use for creating vectors
1210207556f9SJed Brown 
1211207556f9SJed Brown  Notes:
1212207556f9SJed Brown 
1213207556f9SJed Brown  Level: developer
1214207556f9SJed Brown 
12152a7a6963SBarry Smith .seealso: MatCreateVecs()
1216207556f9SJed Brown @*/
121719fd82e9SBarry Smith PetscErrorCode  MatNestSetVecType(Mat A,VecType vtype)
1218207556f9SJed Brown {
1219207556f9SJed Brown   PetscErrorCode ierr;
1220207556f9SJed Brown 
1221207556f9SJed Brown   PetscFunctionBegin;
122219fd82e9SBarry Smith   ierr = PetscTryMethod(A,"MatNestSetVecType_C",(Mat,VecType),(A,vtype));CHKERRQ(ierr);
1223207556f9SJed Brown   PetscFunctionReturn(0);
1224207556f9SJed Brown }
1225207556f9SJed Brown 
1226c8883902SJed Brown PetscErrorCode MatNestSetSubMats_Nest(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1227d8588912SDave May {
1228c8883902SJed Brown   Mat_Nest       *s = (Mat_Nest*)A->data;
1229c8883902SJed Brown   PetscInt       i,j,m,n,M,N;
1230d8588912SDave May   PetscErrorCode ierr;
1231d8588912SDave May 
1232d8588912SDave May   PetscFunctionBegin;
1233c8883902SJed Brown   s->nr = nr;
1234c8883902SJed Brown   s->nc = nc;
1235d8588912SDave May 
1236c8883902SJed Brown   /* Create space for submatrices */
1237854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&s->m);CHKERRQ(ierr);
1238c8883902SJed Brown   for (i=0; i<nr; i++) {
1239854ce69bSBarry Smith     ierr = PetscMalloc1(nc,&s->m[i]);CHKERRQ(ierr);
1240d8588912SDave May   }
1241c8883902SJed Brown   for (i=0; i<nr; i++) {
1242c8883902SJed Brown     for (j=0; j<nc; j++) {
1243c8883902SJed Brown       s->m[i][j] = a[i*nc+j];
1244c8883902SJed Brown       if (a[i*nc+j]) {
1245c8883902SJed Brown         ierr = PetscObjectReference((PetscObject)a[i*nc+j]);CHKERRQ(ierr);
1246d8588912SDave May       }
1247d8588912SDave May     }
1248d8588912SDave May   }
1249d8588912SDave May 
12508188e55aSJed Brown   ierr = MatSetUp_NestIS_Private(A,nr,is_row,nc,is_col);CHKERRQ(ierr);
1251d8588912SDave May 
1252854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&s->row_len);CHKERRQ(ierr);
1253854ce69bSBarry Smith   ierr = PetscMalloc1(nc,&s->col_len);CHKERRQ(ierr);
1254c8883902SJed Brown   for (i=0; i<nr; i++) s->row_len[i]=-1;
1255c8883902SJed Brown   for (j=0; j<nc; j++) s->col_len[j]=-1;
1256d8588912SDave May 
12578188e55aSJed Brown   ierr = MatNestGetSizes_Private(A,&m,&n,&M,&N);CHKERRQ(ierr);
1258d8588912SDave May 
1259c8883902SJed Brown   ierr = PetscLayoutSetSize(A->rmap,M);CHKERRQ(ierr);
1260c8883902SJed Brown   ierr = PetscLayoutSetLocalSize(A->rmap,m);CHKERRQ(ierr);
1261c8883902SJed Brown   ierr = PetscLayoutSetSize(A->cmap,N);CHKERRQ(ierr);
1262c8883902SJed Brown   ierr = PetscLayoutSetLocalSize(A->cmap,n);CHKERRQ(ierr);
1263c8883902SJed Brown 
1264c8883902SJed Brown   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
1265c8883902SJed Brown   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
1266c8883902SJed Brown 
12671795a4d1SJed Brown   ierr = PetscCalloc2(nr,&s->left,nc,&s->right);CHKERRQ(ierr);
1268d8588912SDave May   PetscFunctionReturn(0);
1269d8588912SDave May }
1270d8588912SDave May 
1271c8883902SJed Brown /*@
1272c8883902SJed Brown    MatNestSetSubMats - Sets the nested submatrices
1273c8883902SJed Brown 
1274c8883902SJed Brown    Collective on Mat
1275c8883902SJed Brown 
1276c8883902SJed Brown    Input Parameter:
1277ffd6319bSRichard Tran Mills +  A - nested matrix
1278c8883902SJed Brown .  nr - number of nested row blocks
12790298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1280c8883902SJed Brown .  nc - number of nested column blocks
12810298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
12820298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1283c8883902SJed Brown 
1284c8883902SJed Brown    Level: advanced
1285c8883902SJed Brown 
1286c8883902SJed Brown .seealso: MatCreateNest(), MATNEST
1287c8883902SJed Brown @*/
1288c8883902SJed Brown PetscErrorCode MatNestSetSubMats(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1289c8883902SJed Brown {
1290c8883902SJed Brown   PetscErrorCode ierr;
1291eb6c2100SSatish Balay   PetscInt       i,nr_nc;
1292c8883902SJed Brown 
1293c8883902SJed Brown   PetscFunctionBegin;
1294c8883902SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1295ce94432eSBarry Smith   if (nr < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of rows cannot be negative");
1296c8883902SJed Brown   if (nr && is_row) {
1297c8883902SJed Brown     PetscValidPointer(is_row,3);
1298c8883902SJed Brown     for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_row[i],IS_CLASSID,3);
1299c8883902SJed Brown   }
1300ce94432eSBarry Smith   if (nc < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of columns cannot be negative");
13011664e352SJed Brown   if (nc && is_col) {
1302c8883902SJed Brown     PetscValidPointer(is_col,5);
13039b30a8f6SBarry Smith     for (i=0; i<nc; i++) PetscValidHeaderSpecific(is_col[i],IS_CLASSID,5);
1304c8883902SJed Brown   }
1305eb6c2100SSatish Balay   nr_nc=nr*nc;
1306eb6c2100SSatish Balay   if (nr_nc) PetscValidPointer(a,6);
1307c8883902SJed 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);
1308c8883902SJed Brown   PetscFunctionReturn(0);
1309c8883902SJed Brown }
1310d8588912SDave May 
131145b6f7e9SBarry Smith static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A,PetscInt n,const IS islocal[],const IS isglobal[],PetscBool colflg,ISLocalToGlobalMapping *ltog)
131277019fcaSJed Brown {
131377019fcaSJed Brown   PetscErrorCode ierr;
131477019fcaSJed Brown   PetscBool      flg;
131577019fcaSJed Brown   PetscInt       i,j,m,mi,*ix;
131677019fcaSJed Brown 
131777019fcaSJed Brown   PetscFunctionBegin;
131877019fcaSJed Brown   for (i=0,m=0,flg=PETSC_FALSE; i<n; i++) {
131977019fcaSJed Brown     if (islocal[i]) {
132077019fcaSJed Brown       ierr = ISGetSize(islocal[i],&mi);CHKERRQ(ierr);
132177019fcaSJed Brown       flg  = PETSC_TRUE;      /* We found a non-trivial entry */
132277019fcaSJed Brown     } else {
132377019fcaSJed Brown       ierr = ISGetSize(isglobal[i],&mi);CHKERRQ(ierr);
132477019fcaSJed Brown     }
132577019fcaSJed Brown     m += mi;
132677019fcaSJed Brown   }
132777019fcaSJed Brown   if (flg) {
1328785e854fSJed Brown     ierr = PetscMalloc1(m,&ix);CHKERRQ(ierr);
1329165cd838SBarry Smith     for (i=0,m=0; i<n; i++) {
13300298fd71SBarry Smith       ISLocalToGlobalMapping smap = NULL;
1331e108cb99SStefano Zampini       Mat                    sub = NULL;
1332f6d38dbbSStefano Zampini       PetscSF                sf;
1333f6d38dbbSStefano Zampini       PetscLayout            map;
1334f6d38dbbSStefano Zampini       PetscInt               *ix2;
133577019fcaSJed Brown 
1336165cd838SBarry Smith       if (!colflg) {
133777019fcaSJed Brown         ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
133877019fcaSJed Brown       } else {
133977019fcaSJed Brown         ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
134077019fcaSJed Brown       }
1341191fd14bSBarry Smith       if (sub) {
1342191fd14bSBarry Smith         if (!colflg) {
1343191fd14bSBarry Smith           ierr = MatGetLocalToGlobalMapping(sub,&smap,NULL);CHKERRQ(ierr);
1344191fd14bSBarry Smith         } else {
1345191fd14bSBarry Smith           ierr = MatGetLocalToGlobalMapping(sub,NULL,&smap);CHKERRQ(ierr);
1346191fd14bSBarry Smith         }
1347191fd14bSBarry Smith       }
134877019fcaSJed Brown       if (islocal[i]) {
134977019fcaSJed Brown         ierr = ISGetSize(islocal[i],&mi);CHKERRQ(ierr);
135077019fcaSJed Brown       } else {
135177019fcaSJed Brown         ierr = ISGetSize(isglobal[i],&mi);CHKERRQ(ierr);
135277019fcaSJed Brown       }
135377019fcaSJed Brown       for (j=0; j<mi; j++) ix[m+j] = j;
135477019fcaSJed Brown       if (smap) {ierr = ISLocalToGlobalMappingApply(smap,mi,ix+m,ix+m);CHKERRQ(ierr);}
1355165cd838SBarry Smith 
135677019fcaSJed Brown       /*
135777019fcaSJed Brown         Now we need to extract the monolithic global indices that correspond to the given split global indices.
135877019fcaSJed 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.
135977019fcaSJed Brown        */
1360f6d38dbbSStefano Zampini       ierr = PetscMalloc1(mi,&ix2);CHKERRQ(ierr);
1361f6d38dbbSStefano Zampini       ierr = PetscSFCreate(((PetscObject)isglobal[i])->comm,&sf);CHKERRQ(ierr);
1362f6d38dbbSStefano Zampini       ierr = PetscLayoutCreate(((PetscObject)isglobal[i])->comm,&map);CHKERRQ(ierr);
1363f6d38dbbSStefano Zampini       ierr = PetscLayoutSetLocalSize(map,mi);CHKERRQ(ierr);
1364f6d38dbbSStefano Zampini       ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
1365f6d38dbbSStefano Zampini       ierr = PetscSFSetGraphLayout(sf,map,mi,NULL,PETSC_USE_POINTER,ix+m);CHKERRQ(ierr);
1366f6d38dbbSStefano Zampini       ierr = PetscLayoutDestroy(&map);CHKERRQ(ierr);
1367f6d38dbbSStefano Zampini       for (j=0; j<mi; j++) ix2[j] = ix[m+j];
1368f6d38dbbSStefano Zampini       ierr = PetscSFBcastBegin(sf,MPIU_INT,ix2,ix + m);CHKERRQ(ierr);
1369f6d38dbbSStefano Zampini       ierr = PetscSFBcastEnd(sf,MPIU_INT,ix2,ix + m);CHKERRQ(ierr);
1370f6d38dbbSStefano Zampini       ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
1371f6d38dbbSStefano Zampini       ierr = PetscFree(ix2);CHKERRQ(ierr);
137277019fcaSJed Brown       m   += mi;
137377019fcaSJed Brown     }
1374f0413b6fSBarry Smith     ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,m,ix,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
137577019fcaSJed Brown   } else {
13760298fd71SBarry Smith     *ltog = NULL;
137777019fcaSJed Brown   }
137877019fcaSJed Brown   PetscFunctionReturn(0);
137977019fcaSJed Brown }
138077019fcaSJed Brown 
138177019fcaSJed Brown 
1382d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1383d8588912SDave May /*
1384d8588912SDave May   nprocessors = NP
1385d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1386d8588912SDave May        proc 0: => (g_0,h_0,)
1387d8588912SDave May        proc 1: => (g_1,h_1,)
1388d8588912SDave May        ...
1389d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1390d8588912SDave May 
1391d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1392d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1393d8588912SDave May 
1394d8588912SDave May             proc 0:
1395d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1396d8588912SDave May             proc 1:
1397d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1398d8588912SDave May 
1399d8588912SDave May             proc NP-1:
1400d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1401d8588912SDave May */
1402841e96a3SJed Brown static PetscErrorCode MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[])
1403d8588912SDave May {
1404e2d7f03fSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
14058188e55aSJed Brown   PetscInt       i,j,offset,n,nsum,bs;
1406d8588912SDave May   PetscErrorCode ierr;
14070298fd71SBarry Smith   Mat            sub = NULL;
1408d8588912SDave May 
1409d8588912SDave May   PetscFunctionBegin;
1410854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&vs->isglobal.row);CHKERRQ(ierr);
1411854ce69bSBarry Smith   ierr = PetscMalloc1(nc,&vs->isglobal.col);CHKERRQ(ierr);
1412d8588912SDave May   if (is_row) { /* valid IS is passed in */
1413d8588912SDave May     /* refs on is[] are incremeneted */
1414e2d7f03fSJed Brown     for (i=0; i<vs->nr; i++) {
1415d8588912SDave May       ierr = PetscObjectReference((PetscObject)is_row[i]);CHKERRQ(ierr);
141626fbe8dcSKarl Rupp 
1417e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1418d8588912SDave May     }
14192ae74bdbSJed Brown   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each row */
14208188e55aSJed Brown     nsum = 0;
14218188e55aSJed Brown     for (i=0; i<vs->nr; i++) {  /* Add up the local sizes to compute the aggregate offset */
14228188e55aSJed Brown       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1423ce94432eSBarry Smith       if (!sub) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %D",i);
14240298fd71SBarry Smith       ierr = MatGetLocalSize(sub,&n,NULL);CHKERRQ(ierr);
1425ce94432eSBarry Smith       if (n < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
14268188e55aSJed Brown       nsum += n;
14278188e55aSJed Brown     }
1428ce94432eSBarry Smith     ierr    = MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
142930bc264bSJed Brown     offset -= nsum;
1430e2d7f03fSJed Brown     for (i=0; i<vs->nr; i++) {
1431f349c1fdSJed Brown       ierr    = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
14320298fd71SBarry Smith       ierr    = MatGetLocalSize(sub,&n,NULL);CHKERRQ(ierr);
14332ae74bdbSJed Brown       ierr    = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1434ce94432eSBarry Smith       ierr    = ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.row[i]);CHKERRQ(ierr);
1435e2d7f03fSJed Brown       ierr    = ISSetBlockSize(vs->isglobal.row[i],bs);CHKERRQ(ierr);
14362ae74bdbSJed Brown       offset += n;
1437d8588912SDave May     }
1438d8588912SDave May   }
1439d8588912SDave May 
1440d8588912SDave May   if (is_col) { /* valid IS is passed in */
1441d8588912SDave May     /* refs on is[] are incremeneted */
1442e2d7f03fSJed Brown     for (j=0; j<vs->nc; j++) {
1443d8588912SDave May       ierr = PetscObjectReference((PetscObject)is_col[j]);CHKERRQ(ierr);
144426fbe8dcSKarl Rupp 
1445e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1446d8588912SDave May     }
14472ae74bdbSJed Brown   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each column */
14482ae74bdbSJed Brown     offset = A->cmap->rstart;
14498188e55aSJed Brown     nsum   = 0;
14508188e55aSJed Brown     for (j=0; j<vs->nc; j++) {
14518188e55aSJed Brown       ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
1452ce94432eSBarry Smith       if (!sub) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %D",i);
14530298fd71SBarry Smith       ierr = MatGetLocalSize(sub,NULL,&n);CHKERRQ(ierr);
1454ce94432eSBarry Smith       if (n < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
14558188e55aSJed Brown       nsum += n;
14568188e55aSJed Brown     }
1457ce94432eSBarry Smith     ierr    = MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
145830bc264bSJed Brown     offset -= nsum;
1459e2d7f03fSJed Brown     for (j=0; j<vs->nc; j++) {
1460f349c1fdSJed Brown       ierr    = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
14610298fd71SBarry Smith       ierr    = MatGetLocalSize(sub,NULL,&n);CHKERRQ(ierr);
14622ae74bdbSJed Brown       ierr    = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1463ce94432eSBarry Smith       ierr    = ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.col[j]);CHKERRQ(ierr);
1464e2d7f03fSJed Brown       ierr    = ISSetBlockSize(vs->isglobal.col[j],bs);CHKERRQ(ierr);
14652ae74bdbSJed Brown       offset += n;
1466d8588912SDave May     }
1467d8588912SDave May   }
1468e2d7f03fSJed Brown 
1469e2d7f03fSJed Brown   /* Set up the local ISs */
1470785e854fSJed Brown   ierr = PetscMalloc1(vs->nr,&vs->islocal.row);CHKERRQ(ierr);
1471785e854fSJed Brown   ierr = PetscMalloc1(vs->nc,&vs->islocal.col);CHKERRQ(ierr);
1472e2d7f03fSJed Brown   for (i=0,offset=0; i<vs->nr; i++) {
1473e2d7f03fSJed Brown     IS                     isloc;
14740298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1475e2d7f03fSJed Brown     PetscInt               nlocal,bs;
1476e2d7f03fSJed Brown     ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
14770298fd71SBarry Smith     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,&rmap,NULL);CHKERRQ(ierr);}
1478207556f9SJed Brown     if (rmap) {
1479e2d7f03fSJed Brown       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1480e2d7f03fSJed Brown       ierr = ISLocalToGlobalMappingGetSize(rmap,&nlocal);CHKERRQ(ierr);
1481e2d7f03fSJed Brown       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1482e2d7f03fSJed Brown       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1483207556f9SJed Brown     } else {
1484207556f9SJed Brown       nlocal = 0;
14850298fd71SBarry Smith       isloc  = NULL;
1486207556f9SJed Brown     }
1487e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1488e2d7f03fSJed Brown     offset            += nlocal;
1489e2d7f03fSJed Brown   }
14908188e55aSJed Brown   for (i=0,offset=0; i<vs->nc; i++) {
1491e2d7f03fSJed Brown     IS                     isloc;
14920298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1493e2d7f03fSJed Brown     PetscInt               nlocal,bs;
1494e2d7f03fSJed Brown     ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
14950298fd71SBarry Smith     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,NULL,&cmap);CHKERRQ(ierr);}
1496207556f9SJed Brown     if (cmap) {
1497e2d7f03fSJed Brown       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1498e2d7f03fSJed Brown       ierr = ISLocalToGlobalMappingGetSize(cmap,&nlocal);CHKERRQ(ierr);
1499e2d7f03fSJed Brown       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1500e2d7f03fSJed Brown       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1501207556f9SJed Brown     } else {
1502207556f9SJed Brown       nlocal = 0;
15030298fd71SBarry Smith       isloc  = NULL;
1504207556f9SJed Brown     }
1505e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1506e2d7f03fSJed Brown     offset            += nlocal;
1507e2d7f03fSJed Brown   }
15080189643fSJed Brown 
150977019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
151077019fcaSJed Brown   {
151145b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap,cmap;
151245b6f7e9SBarry Smith     ierr = MatNestCreateAggregateL2G_Private(A,vs->nr,vs->islocal.row,vs->isglobal.row,PETSC_FALSE,&rmap);CHKERRQ(ierr);
151345b6f7e9SBarry Smith     ierr = MatNestCreateAggregateL2G_Private(A,vs->nc,vs->islocal.col,vs->isglobal.col,PETSC_TRUE,&cmap);CHKERRQ(ierr);
151477019fcaSJed Brown     if (rmap && cmap) {ierr = MatSetLocalToGlobalMapping(A,rmap,cmap);CHKERRQ(ierr);}
151577019fcaSJed Brown     ierr = ISLocalToGlobalMappingDestroy(&rmap);CHKERRQ(ierr);
151677019fcaSJed Brown     ierr = ISLocalToGlobalMappingDestroy(&cmap);CHKERRQ(ierr);
151777019fcaSJed Brown   }
151877019fcaSJed Brown 
15190189643fSJed Brown #if defined(PETSC_USE_DEBUG)
15200189643fSJed Brown   for (i=0; i<vs->nr; i++) {
15210189643fSJed Brown     for (j=0; j<vs->nc; j++) {
15220189643fSJed Brown       PetscInt m,n,M,N,mi,ni,Mi,Ni;
15230189643fSJed Brown       Mat      B = vs->m[i][j];
15240189643fSJed Brown       if (!B) continue;
15250189643fSJed Brown       ierr = MatGetSize(B,&M,&N);CHKERRQ(ierr);
15260189643fSJed Brown       ierr = MatGetLocalSize(B,&m,&n);CHKERRQ(ierr);
15270189643fSJed Brown       ierr = ISGetSize(vs->isglobal.row[i],&Mi);CHKERRQ(ierr);
15280189643fSJed Brown       ierr = ISGetSize(vs->isglobal.col[j],&Ni);CHKERRQ(ierr);
15290189643fSJed Brown       ierr = ISGetLocalSize(vs->isglobal.row[i],&mi);CHKERRQ(ierr);
15300189643fSJed Brown       ierr = ISGetLocalSize(vs->isglobal.col[j],&ni);CHKERRQ(ierr);
1531ce94432eSBarry 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);
1532ce94432eSBarry 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);
15330189643fSJed Brown     }
15340189643fSJed Brown   }
15350189643fSJed Brown #endif
1536a061e289SJed Brown 
1537a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1538a061e289SJed Brown   for (i=0; i<vs->nr; i++) {
1539a061e289SJed Brown     for (j=0; j<vs->nc; j++) {
1540a061e289SJed Brown       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0);
1541a061e289SJed Brown     }
1542a061e289SJed Brown   }
1543a061e289SJed Brown   A->assembled = PETSC_TRUE;
1544d8588912SDave May   PetscFunctionReturn(0);
1545d8588912SDave May }
1546d8588912SDave May 
154745c38901SJed Brown /*@C
1548659c6bb0SJed Brown    MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately
1549659c6bb0SJed Brown 
1550659c6bb0SJed Brown    Collective on Mat
1551659c6bb0SJed Brown 
1552659c6bb0SJed Brown    Input Parameter:
1553659c6bb0SJed Brown +  comm - Communicator for the new Mat
1554659c6bb0SJed Brown .  nr - number of nested row blocks
15550298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1556659c6bb0SJed Brown .  nc - number of nested column blocks
15570298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
15580298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1559659c6bb0SJed Brown 
1560659c6bb0SJed Brown    Output Parameter:
1561659c6bb0SJed Brown .  B - new matrix
1562659c6bb0SJed Brown 
1563659c6bb0SJed Brown    Level: advanced
1564659c6bb0SJed Brown 
1565950540a4SJed Brown .seealso: MatCreate(), VecCreateNest(), DMCreateMatrix(), MATNEST
1566659c6bb0SJed Brown @*/
15677087cfbeSBarry Smith PetscErrorCode MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat *B)
1568d8588912SDave May {
1569d8588912SDave May   Mat            A;
1570d8588912SDave May   PetscErrorCode ierr;
1571d8588912SDave May 
1572d8588912SDave May   PetscFunctionBegin;
1573c8883902SJed Brown   *B   = 0;
1574d8588912SDave May   ierr = MatCreate(comm,&A);CHKERRQ(ierr);
1575c8883902SJed Brown   ierr = MatSetType(A,MATNEST);CHKERRQ(ierr);
157691a28eb3SBarry Smith   A->preallocated = PETSC_TRUE;
1577c8883902SJed Brown   ierr = MatNestSetSubMats(A,nr,is_row,nc,is_col,a);CHKERRQ(ierr);
1578d8588912SDave May   *B   = A;
1579d8588912SDave May   PetscFunctionReturn(0);
1580d8588912SDave May }
1581659c6bb0SJed Brown 
1582b68353e5Sstefano_zampini static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
1583b68353e5Sstefano_zampini {
1584b68353e5Sstefano_zampini   Mat_Nest       *nest = (Mat_Nest*)A->data;
158523875855Sstefano_zampini   Mat            *trans;
1586b68353e5Sstefano_zampini   PetscScalar    **avv;
1587b68353e5Sstefano_zampini   PetscScalar    *vv;
1588b68353e5Sstefano_zampini   PetscInt       **aii,**ajj;
1589b68353e5Sstefano_zampini   PetscInt       *ii,*jj,*ci;
1590b68353e5Sstefano_zampini   PetscInt       nr,nc,nnz,i,j;
1591b68353e5Sstefano_zampini   PetscBool      done;
1592b68353e5Sstefano_zampini   PetscErrorCode ierr;
1593b68353e5Sstefano_zampini 
1594b68353e5Sstefano_zampini   PetscFunctionBegin;
1595b68353e5Sstefano_zampini   ierr = MatGetSize(A,&nr,&nc);CHKERRQ(ierr);
1596b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1597b68353e5Sstefano_zampini     PetscInt rnr;
1598b68353e5Sstefano_zampini 
1599b68353e5Sstefano_zampini     ierr = MatGetRowIJ(*newmat,0,PETSC_FALSE,PETSC_FALSE,&rnr,(const PetscInt**)&ii,(const PetscInt**)&jj,&done);CHKERRQ(ierr);
1600b68353e5Sstefano_zampini     if (!done) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"MatGetRowIJ");
1601b68353e5Sstefano_zampini     if (rnr != nr) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of rows");
1602b68353e5Sstefano_zampini     ierr = MatSeqAIJGetArray(*newmat,&vv);CHKERRQ(ierr);
1603b68353e5Sstefano_zampini   }
1604b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1605b68353e5Sstefano_zampini   nnz  = 0;
160623875855Sstefano_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);
1607b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1608b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1609b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1610b68353e5Sstefano_zampini       if (B) {
1611b68353e5Sstefano_zampini         PetscScalar *naa;
1612b68353e5Sstefano_zampini         PetscInt    *nii,*njj,nnr;
161323875855Sstefano_zampini         PetscBool   istrans;
1614b68353e5Sstefano_zampini 
161523875855Sstefano_zampini         ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
161623875855Sstefano_zampini         if (istrans) {
161723875855Sstefano_zampini           Mat Bt;
161823875855Sstefano_zampini 
161923875855Sstefano_zampini           ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
162023875855Sstefano_zampini           ierr = MatTranspose(Bt,MAT_INITIAL_MATRIX,&trans[i*nest->nc+j]);CHKERRQ(ierr);
162123875855Sstefano_zampini           B    = trans[i*nest->nc+j];
162223875855Sstefano_zampini         }
1623b68353e5Sstefano_zampini         ierr = MatGetRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&nii,(const PetscInt**)&njj,&done);CHKERRQ(ierr);
1624b68353e5Sstefano_zampini         if (!done) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatGetRowIJ");
1625b68353e5Sstefano_zampini         ierr = MatSeqAIJGetArray(B,&naa);CHKERRQ(ierr);
1626b68353e5Sstefano_zampini         nnz += nii[nnr];
1627b68353e5Sstefano_zampini 
1628b68353e5Sstefano_zampini         aii[i*nest->nc+j] = nii;
1629b68353e5Sstefano_zampini         ajj[i*nest->nc+j] = njj;
1630b68353e5Sstefano_zampini         avv[i*nest->nc+j] = naa;
1631b68353e5Sstefano_zampini       }
1632b68353e5Sstefano_zampini     }
1633b68353e5Sstefano_zampini   }
1634b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
1635b68353e5Sstefano_zampini     ierr = PetscMalloc1(nr+1,&ii);CHKERRQ(ierr);
1636b68353e5Sstefano_zampini     ierr = PetscMalloc1(nnz,&jj);CHKERRQ(ierr);
1637b68353e5Sstefano_zampini     ierr = PetscMalloc1(nnz,&vv);CHKERRQ(ierr);
1638b68353e5Sstefano_zampini   } else {
1639b68353e5Sstefano_zampini     if (nnz != ii[nr]) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of nonzeros");
1640b68353e5Sstefano_zampini   }
1641b68353e5Sstefano_zampini 
1642b68353e5Sstefano_zampini   /* new row pointer */
1643580bdb30SBarry Smith   ierr = PetscArrayzero(ii,nr+1);CHKERRQ(ierr);
1644b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1645b68353e5Sstefano_zampini     PetscInt       ncr,rst;
1646b68353e5Sstefano_zampini 
1647b68353e5Sstefano_zampini     ierr = ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL);CHKERRQ(ierr);
1648b68353e5Sstefano_zampini     ierr = ISGetLocalSize(nest->isglobal.row[i],&ncr);CHKERRQ(ierr);
1649b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1650b68353e5Sstefano_zampini       if (aii[i*nest->nc+j]) {
1651b68353e5Sstefano_zampini         PetscInt    *nii = aii[i*nest->nc+j];
1652b68353e5Sstefano_zampini         PetscInt    ir;
1653b68353e5Sstefano_zampini 
1654b68353e5Sstefano_zampini         for (ir=rst; ir<ncr+rst; ++ir) {
1655b68353e5Sstefano_zampini           ii[ir+1] += nii[1]-nii[0];
1656b68353e5Sstefano_zampini           nii++;
1657b68353e5Sstefano_zampini         }
1658b68353e5Sstefano_zampini       }
1659b68353e5Sstefano_zampini     }
1660b68353e5Sstefano_zampini   }
1661b68353e5Sstefano_zampini   for (i=0; i<nr; i++) ii[i+1] += ii[i];
1662b68353e5Sstefano_zampini 
1663b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
1664b68353e5Sstefano_zampini   ierr = PetscCalloc1(nr,&ci);CHKERRQ(ierr);
1665b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1666b68353e5Sstefano_zampini     PetscInt       ncr,rst;
1667b68353e5Sstefano_zampini 
1668b68353e5Sstefano_zampini     ierr = ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL);CHKERRQ(ierr);
1669b68353e5Sstefano_zampini     ierr = ISGetLocalSize(nest->isglobal.row[i],&ncr);CHKERRQ(ierr);
1670b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1671b68353e5Sstefano_zampini       if (aii[i*nest->nc+j]) {
1672b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i*nest->nc+j];
1673b68353e5Sstefano_zampini         PetscInt    *nii = aii[i*nest->nc+j];
1674b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i*nest->nc+j];
1675b68353e5Sstefano_zampini         PetscInt    ir,cst;
1676b68353e5Sstefano_zampini 
1677b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.col[j],&cst,NULL);CHKERRQ(ierr);
1678b68353e5Sstefano_zampini         for (ir=rst; ir<ncr+rst; ++ir) {
1679b68353e5Sstefano_zampini           PetscInt ij,rsize = nii[1]-nii[0],ist = ii[ir]+ci[ir];
1680b68353e5Sstefano_zampini 
1681b68353e5Sstefano_zampini           for (ij=0;ij<rsize;ij++) {
1682b68353e5Sstefano_zampini             jj[ist+ij] = *njj+cst;
1683b68353e5Sstefano_zampini             vv[ist+ij] = *nvv;
1684b68353e5Sstefano_zampini             njj++;
1685b68353e5Sstefano_zampini             nvv++;
1686b68353e5Sstefano_zampini           }
1687b68353e5Sstefano_zampini           ci[ir] += rsize;
1688b68353e5Sstefano_zampini           nii++;
1689b68353e5Sstefano_zampini         }
1690b68353e5Sstefano_zampini       }
1691b68353e5Sstefano_zampini     }
1692b68353e5Sstefano_zampini   }
1693b68353e5Sstefano_zampini   ierr = PetscFree(ci);CHKERRQ(ierr);
1694b68353e5Sstefano_zampini 
1695b68353e5Sstefano_zampini   /* restore info */
1696b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1697b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1698b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1699b68353e5Sstefano_zampini       if (B) {
1700b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i*nest->nc+j;
170123875855Sstefano_zampini 
170223875855Sstefano_zampini         B    = (trans[k] ? trans[k] : B);
1703b68353e5Sstefano_zampini         ierr = MatRestoreRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&aii[k],(const PetscInt**)&ajj[k],&done);CHKERRQ(ierr);
1704b68353e5Sstefano_zampini         if (!done) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatRestoreRowIJ");
1705b68353e5Sstefano_zampini         ierr = MatSeqAIJRestoreArray(B,&avv[k]);CHKERRQ(ierr);
170623875855Sstefano_zampini         ierr = MatDestroy(&trans[k]);CHKERRQ(ierr);
1707b68353e5Sstefano_zampini       }
1708b68353e5Sstefano_zampini     }
1709b68353e5Sstefano_zampini   }
171023875855Sstefano_zampini   ierr = PetscFree4(aii,ajj,avv,trans);CHKERRQ(ierr);
1711b68353e5Sstefano_zampini 
1712b68353e5Sstefano_zampini   /* finalize newmat */
1713b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
1714b68353e5Sstefano_zampini     ierr = MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,newmat);CHKERRQ(ierr);
1715b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1716b68353e5Sstefano_zampini     Mat B;
1717b68353e5Sstefano_zampini 
1718b68353e5Sstefano_zampini     ierr = MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,&B);CHKERRQ(ierr);
1719b68353e5Sstefano_zampini     ierr = MatHeaderReplace(A,&B);CHKERRQ(ierr);
1720b68353e5Sstefano_zampini   }
1721b68353e5Sstefano_zampini   ierr = MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1722b68353e5Sstefano_zampini   ierr = MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1723b68353e5Sstefano_zampini   {
1724b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ*)((*newmat)->data);
1725b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1726b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1727b68353e5Sstefano_zampini   }
1728b68353e5Sstefano_zampini   PetscFunctionReturn(0);
1729b68353e5Sstefano_zampini }
1730b68353e5Sstefano_zampini 
1731cc2e6a90SBarry Smith PETSC_INTERN PetscErrorCode MatConvert_Nest_AIJ(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
1732629c3df2SDmitry Karpeev {
1733629c3df2SDmitry Karpeev   PetscErrorCode ierr;
1734629c3df2SDmitry Karpeev   Mat_Nest       *nest = (Mat_Nest*)A->data;
173583b1a929SMark Adams   PetscInt       m,n,M,N,i,j,k,*dnnz,*onnz,rstart;
1736649b366bSFande Kong   PetscInt       cstart,cend;
1737b68353e5Sstefano_zampini   PetscMPIInt    size;
1738629c3df2SDmitry Karpeev   Mat            C;
1739629c3df2SDmitry Karpeev 
1740629c3df2SDmitry Karpeev   PetscFunctionBegin;
1741b68353e5Sstefano_zampini   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr);
1742b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
1743b68353e5Sstefano_zampini     PetscInt  nf;
1744b68353e5Sstefano_zampini     PetscBool fast;
1745b68353e5Sstefano_zampini 
1746b68353e5Sstefano_zampini     ierr = PetscStrcmp(newtype,MATAIJ,&fast);CHKERRQ(ierr);
1747b68353e5Sstefano_zampini     if (!fast) {
1748b68353e5Sstefano_zampini       ierr = PetscStrcmp(newtype,MATSEQAIJ,&fast);CHKERRQ(ierr);
1749b68353e5Sstefano_zampini     }
1750b68353e5Sstefano_zampini     for (i=0; i<nest->nr && fast; ++i) {
1751b68353e5Sstefano_zampini       for (j=0; j<nest->nc && fast; ++j) {
1752b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
1753b68353e5Sstefano_zampini         if (B) {
1754b68353e5Sstefano_zampini           ierr = PetscObjectTypeCompare((PetscObject)B,MATSEQAIJ,&fast);CHKERRQ(ierr);
175523875855Sstefano_zampini           if (!fast) {
175623875855Sstefano_zampini             PetscBool istrans;
175723875855Sstefano_zampini 
175823875855Sstefano_zampini             ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
175923875855Sstefano_zampini             if (istrans) {
176023875855Sstefano_zampini               Mat Bt;
176123875855Sstefano_zampini 
176223875855Sstefano_zampini               ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
176323875855Sstefano_zampini               ierr = PetscObjectTypeCompare((PetscObject)Bt,MATSEQAIJ,&fast);CHKERRQ(ierr);
176423875855Sstefano_zampini             }
1765b68353e5Sstefano_zampini           }
1766b68353e5Sstefano_zampini         }
1767b68353e5Sstefano_zampini       }
1768b68353e5Sstefano_zampini     }
1769b68353e5Sstefano_zampini     for (i=0, nf=0; i<nest->nr && fast; ++i) {
1770b68353e5Sstefano_zampini       ierr = PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i],ISSTRIDE,&fast);CHKERRQ(ierr);
1771b68353e5Sstefano_zampini       if (fast) {
1772b68353e5Sstefano_zampini         PetscInt f,s;
1773b68353e5Sstefano_zampini 
1774b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.row[i],&f,&s);CHKERRQ(ierr);
1775b68353e5Sstefano_zampini         if (f != nf || s != 1) { fast = PETSC_FALSE; }
1776b68353e5Sstefano_zampini         else {
1777b68353e5Sstefano_zampini           ierr = ISGetSize(nest->isglobal.row[i],&f);CHKERRQ(ierr);
1778b68353e5Sstefano_zampini           nf  += f;
1779b68353e5Sstefano_zampini         }
1780b68353e5Sstefano_zampini       }
1781b68353e5Sstefano_zampini     }
1782b68353e5Sstefano_zampini     for (i=0, nf=0; i<nest->nc && fast; ++i) {
1783b68353e5Sstefano_zampini       ierr = PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i],ISSTRIDE,&fast);CHKERRQ(ierr);
1784b68353e5Sstefano_zampini       if (fast) {
1785b68353e5Sstefano_zampini         PetscInt f,s;
1786b68353e5Sstefano_zampini 
1787b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.col[i],&f,&s);CHKERRQ(ierr);
1788b68353e5Sstefano_zampini         if (f != nf || s != 1) { fast = PETSC_FALSE; }
1789b68353e5Sstefano_zampini         else {
1790b68353e5Sstefano_zampini           ierr = ISGetSize(nest->isglobal.col[i],&f);CHKERRQ(ierr);
1791b68353e5Sstefano_zampini           nf  += f;
1792b68353e5Sstefano_zampini         }
1793b68353e5Sstefano_zampini       }
1794b68353e5Sstefano_zampini     }
1795b68353e5Sstefano_zampini     if (fast) {
1796b68353e5Sstefano_zampini       ierr = MatConvert_Nest_SeqAIJ_fast(A,newtype,reuse,newmat);CHKERRQ(ierr);
1797b68353e5Sstefano_zampini       PetscFunctionReturn(0);
1798b68353e5Sstefano_zampini     }
1799b68353e5Sstefano_zampini   }
1800629c3df2SDmitry Karpeev   ierr = MatGetSize(A,&M,&N);CHKERRQ(ierr);
1801629c3df2SDmitry Karpeev   ierr = MatGetLocalSize(A,&m,&n);CHKERRQ(ierr);
1802649b366bSFande Kong   ierr = MatGetOwnershipRangeColumn(A,&cstart,&cend);CHKERRQ(ierr);
1803629c3df2SDmitry Karpeev   switch (reuse) {
1804629c3df2SDmitry Karpeev   case MAT_INITIAL_MATRIX:
1805ce94432eSBarry Smith     ierr    = MatCreate(PetscObjectComm((PetscObject)A),&C);CHKERRQ(ierr);
1806629c3df2SDmitry Karpeev     ierr    = MatSetType(C,newtype);CHKERRQ(ierr);
1807629c3df2SDmitry Karpeev     ierr    = MatSetSizes(C,m,n,M,N);CHKERRQ(ierr);
1808629c3df2SDmitry Karpeev     *newmat = C;
1809629c3df2SDmitry Karpeev     break;
1810629c3df2SDmitry Karpeev   case MAT_REUSE_MATRIX:
1811629c3df2SDmitry Karpeev     C = *newmat;
1812629c3df2SDmitry Karpeev     break;
1813ce94432eSBarry Smith   default: SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MatReuse");
1814629c3df2SDmitry Karpeev   }
1815785e854fSJed Brown   ierr = PetscMalloc1(2*m,&dnnz);CHKERRQ(ierr);
1816629c3df2SDmitry Karpeev   onnz = dnnz + m;
1817629c3df2SDmitry Karpeev   for (k=0; k<m; k++) {
1818629c3df2SDmitry Karpeev     dnnz[k] = 0;
1819629c3df2SDmitry Karpeev     onnz[k] = 0;
1820629c3df2SDmitry Karpeev   }
1821629c3df2SDmitry Karpeev   for (j=0; j<nest->nc; ++j) {
1822629c3df2SDmitry Karpeev     IS             bNis;
1823629c3df2SDmitry Karpeev     PetscInt       bN;
1824629c3df2SDmitry Karpeev     const PetscInt *bNindices;
1825629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
1826629c3df2SDmitry Karpeev     ierr = ISAllGather(nest->isglobal.col[j], &bNis);CHKERRQ(ierr);
1827629c3df2SDmitry Karpeev     ierr = ISGetSize(bNis, &bN);CHKERRQ(ierr);
1828629c3df2SDmitry Karpeev     ierr = ISGetIndices(bNis,&bNindices);CHKERRQ(ierr);
1829629c3df2SDmitry Karpeev     for (i=0; i<nest->nr; ++i) {
1830629c3df2SDmitry Karpeev       PetscSF        bmsf;
1831649b366bSFande Kong       PetscSFNode    *iremote;
1832629c3df2SDmitry Karpeev       Mat            B;
1833649b366bSFande Kong       PetscInt       bm, *sub_dnnz,*sub_onnz, br;
1834629c3df2SDmitry Karpeev       const PetscInt *bmindices;
1835629c3df2SDmitry Karpeev       B = nest->m[i][j];
1836629c3df2SDmitry Karpeev       if (!B) continue;
1837629c3df2SDmitry Karpeev       ierr = ISGetLocalSize(nest->isglobal.row[i],&bm);CHKERRQ(ierr);
1838629c3df2SDmitry Karpeev       ierr = ISGetIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
1839ce94432eSBarry Smith       ierr = PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf);CHKERRQ(ierr);
1840649b366bSFande Kong       ierr = PetscMalloc1(bm,&iremote);CHKERRQ(ierr);
1841649b366bSFande Kong       ierr = PetscMalloc1(bm,&sub_dnnz);CHKERRQ(ierr);
1842649b366bSFande Kong       ierr = PetscMalloc1(bm,&sub_onnz);CHKERRQ(ierr);
1843649b366bSFande Kong       for (k = 0; k < bm; ++k){
1844649b366bSFande Kong     	sub_dnnz[k] = 0;
1845649b366bSFande Kong     	sub_onnz[k] = 0;
1846649b366bSFande Kong       }
1847629c3df2SDmitry Karpeev       /*
1848629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
1849629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
1850629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
1851629c3df2SDmitry Karpeev        */
185283b1a929SMark Adams       ierr = MatGetOwnershipRange(B,&rstart,NULL);CHKERRQ(ierr);
1853629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
1854*131c27b5Sprj-         PetscInt       row = bmindices[br], brncols, col;
1855629c3df2SDmitry Karpeev         const PetscInt *brcols;
1856a4b3d3acSMatthew G Knepley         PetscInt       rowrel = 0; /* row's relative index on its owner rank */
1857*131c27b5Sprj-         PetscMPIInt    rowowner = 0;
1858629c3df2SDmitry Karpeev         ierr      = PetscLayoutFindOwnerIndex(A->rmap,row,&rowowner,&rowrel);CHKERRQ(ierr);
1859649b366bSFande Kong         /* how many roots  */
1860649b366bSFande Kong         iremote[br].rank = rowowner; iremote[br].index = rowrel;           /* edge from bmdnnz to dnnz */
1861649b366bSFande Kong         /* get nonzero pattern */
186283b1a929SMark Adams         ierr = MatGetRow(B,br+rstart,&brncols,&brcols,NULL);CHKERRQ(ierr);
1863629c3df2SDmitry Karpeev         for (k=0; k<brncols; k++) {
1864629c3df2SDmitry Karpeev           col  = bNindices[brcols[k]];
1865649b366bSFande Kong           if (col>=A->cmap->range[rowowner] && col<A->cmap->range[rowowner+1]) {
1866649b366bSFande Kong             sub_dnnz[br]++;
1867649b366bSFande Kong           } else {
1868649b366bSFande Kong             sub_onnz[br]++;
1869649b366bSFande Kong           }
1870629c3df2SDmitry Karpeev         }
187183b1a929SMark Adams         ierr = MatRestoreRow(B,br+rstart,&brncols,&brcols,NULL);CHKERRQ(ierr);
1872629c3df2SDmitry Karpeev       }
1873629c3df2SDmitry Karpeev       ierr = ISRestoreIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
1874629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
1875649b366bSFande Kong       ierr = PetscSFSetGraph(bmsf,m,bm,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
1876649b366bSFande Kong       ierr = PetscSFReduceBegin(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM);CHKERRQ(ierr);
1877649b366bSFande Kong       ierr = PetscSFReduceEnd(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM);CHKERRQ(ierr);
1878649b366bSFande Kong       ierr = PetscSFReduceBegin(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM);CHKERRQ(ierr);
1879649b366bSFande Kong       ierr = PetscSFReduceEnd(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM);CHKERRQ(ierr);
1880649b366bSFande Kong       ierr = PetscFree(sub_dnnz);CHKERRQ(ierr);
1881649b366bSFande Kong       ierr = PetscFree(sub_onnz);CHKERRQ(ierr);
1882629c3df2SDmitry Karpeev       ierr = PetscSFDestroy(&bmsf);CHKERRQ(ierr);
1883629c3df2SDmitry Karpeev     }
188422d28d08SBarry Smith     ierr = ISRestoreIndices(bNis,&bNindices);CHKERRQ(ierr);
1885629c3df2SDmitry Karpeev     ierr = ISDestroy(&bNis);CHKERRQ(ierr);
188665a4a0a3Sstefano_zampini   }
188765a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
188865a4a0a3Sstefano_zampini   for (i=0;i<m;i++) {
188965a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i],A->cmap->n);
189065a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i],A->cmap->N - A->cmap->n);
1891629c3df2SDmitry Karpeev   }
1892629c3df2SDmitry Karpeev   ierr = MatSeqAIJSetPreallocation(C,0,dnnz);CHKERRQ(ierr);
1893629c3df2SDmitry Karpeev   ierr = MatMPIAIJSetPreallocation(C,0,dnnz,0,onnz);CHKERRQ(ierr);
1894629c3df2SDmitry Karpeev   ierr = PetscFree(dnnz);CHKERRQ(ierr);
1895629c3df2SDmitry Karpeev 
1896629c3df2SDmitry Karpeev   /* Fill by row */
1897629c3df2SDmitry Karpeev   for (j=0; j<nest->nc; ++j) {
1898629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
1899629c3df2SDmitry Karpeev     IS             bNis;
1900629c3df2SDmitry Karpeev     PetscInt       bN;
1901629c3df2SDmitry Karpeev     const PetscInt *bNindices;
1902629c3df2SDmitry Karpeev     ierr = ISAllGather(nest->isglobal.col[j], &bNis);CHKERRQ(ierr);
1903629c3df2SDmitry Karpeev     ierr = ISGetSize(bNis,&bN);CHKERRQ(ierr);
1904629c3df2SDmitry Karpeev     ierr = ISGetIndices(bNis,&bNindices);CHKERRQ(ierr);
1905629c3df2SDmitry Karpeev     for (i=0; i<nest->nr; ++i) {
1906629c3df2SDmitry Karpeev       Mat            B;
1907629c3df2SDmitry Karpeev       PetscInt       bm, br;
1908629c3df2SDmitry Karpeev       const PetscInt *bmindices;
1909629c3df2SDmitry Karpeev       B = nest->m[i][j];
1910629c3df2SDmitry Karpeev       if (!B) continue;
1911629c3df2SDmitry Karpeev       ierr = ISGetLocalSize(nest->isglobal.row[i],&bm);CHKERRQ(ierr);
1912629c3df2SDmitry Karpeev       ierr = ISGetIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
191383b1a929SMark Adams       ierr = MatGetOwnershipRange(B,&rstart,NULL);CHKERRQ(ierr);
1914629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
1915629c3df2SDmitry Karpeev         PetscInt          row = bmindices[br], brncols,  *cols;
1916629c3df2SDmitry Karpeev         const PetscInt    *brcols;
1917629c3df2SDmitry Karpeev         const PetscScalar *brcoldata;
191883b1a929SMark Adams         ierr = MatGetRow(B,br+rstart,&brncols,&brcols,&brcoldata);CHKERRQ(ierr);
1919785e854fSJed Brown         ierr = PetscMalloc1(brncols,&cols);CHKERRQ(ierr);
192026fbe8dcSKarl Rupp         for (k=0; k<brncols; k++) cols[k] = bNindices[brcols[k]];
1921629c3df2SDmitry Karpeev         /*
1922629c3df2SDmitry Karpeev           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1923629c3df2SDmitry Karpeev           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1924629c3df2SDmitry Karpeev          */
1925a2ea699eSBarry Smith         ierr = MatSetValues(C,1,&row,brncols,cols,brcoldata,ADD_VALUES);CHKERRQ(ierr);
192683b1a929SMark Adams         ierr = MatRestoreRow(B,br+rstart,&brncols,&brcols,&brcoldata);CHKERRQ(ierr);
1927629c3df2SDmitry Karpeev         ierr = PetscFree(cols);CHKERRQ(ierr);
1928629c3df2SDmitry Karpeev       }
1929629c3df2SDmitry Karpeev       ierr = ISRestoreIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
1930629c3df2SDmitry Karpeev     }
1931a2ea699eSBarry Smith     ierr = ISRestoreIndices(bNis,&bNindices);CHKERRQ(ierr);
1932629c3df2SDmitry Karpeev     ierr = ISDestroy(&bNis);CHKERRQ(ierr);
1933629c3df2SDmitry Karpeev   }
1934629c3df2SDmitry Karpeev   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1935629c3df2SDmitry Karpeev   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1936629c3df2SDmitry Karpeev   PetscFunctionReturn(0);
1937629c3df2SDmitry Karpeev }
1938629c3df2SDmitry Karpeev 
19398b7d3b4bSBarry Smith PetscErrorCode MatHasOperation_Nest(Mat mat,MatOperation op,PetscBool *has)
19408b7d3b4bSBarry Smith {
19418b7d3b4bSBarry Smith   Mat_Nest       *bA = (Mat_Nest*)mat->data;
19428b7d3b4bSBarry Smith   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
19438b7d3b4bSBarry Smith   PetscBool      flg;
194452c5f739Sprj-   PetscErrorCode ierr;
194552c5f739Sprj-   PetscFunctionBegin;
19468b7d3b4bSBarry Smith 
194752c5f739Sprj-   *has = PETSC_FALSE;
194852c5f739Sprj-   if (op == MATOP_MULT_TRANSPOSE || op == MATOP_MAT_MULT) {
19498b7d3b4bSBarry Smith     for (j=0; j<nc; j++) {
19508b7d3b4bSBarry Smith       for (i=0; i<nr; i++) {
19518b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
195252c5f739Sprj-         ierr = MatHasOperation(bA->m[i][j],op,&flg);CHKERRQ(ierr);
19538b7d3b4bSBarry Smith         if (!flg) PetscFunctionReturn(0);
19548b7d3b4bSBarry Smith       }
19558b7d3b4bSBarry Smith     }
19568b7d3b4bSBarry Smith   }
195752c5f739Sprj-   if (((void**)mat->ops)[op] || (op == MATOP_MAT_MULT && flg)) *has = PETSC_TRUE;
19588b7d3b4bSBarry Smith   PetscFunctionReturn(0);
19598b7d3b4bSBarry Smith }
19608b7d3b4bSBarry Smith 
1961659c6bb0SJed Brown /*MC
1962659c6bb0SJed Brown   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.
1963659c6bb0SJed Brown 
1964659c6bb0SJed Brown   Level: intermediate
1965659c6bb0SJed Brown 
1966659c6bb0SJed Brown   Notes:
1967659c6bb0SJed Brown   This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices.
1968659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
1969950540a4SJed Brown   It is usually used with DMComposite and DMCreateMatrix()
1970659c6bb0SJed Brown 
19718b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
19728b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
19738b7d3b4bSBarry Smith   than the nest matrix.
19748b7d3b4bSBarry Smith 
1975659c6bb0SJed Brown .seealso: MatCreate(), MatType, MatCreateNest()
1976659c6bb0SJed Brown M*/
19778cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
1978c8883902SJed Brown {
1979c8883902SJed Brown   Mat_Nest       *s;
1980c8883902SJed Brown   PetscErrorCode ierr;
1981c8883902SJed Brown 
1982c8883902SJed Brown   PetscFunctionBegin;
1983b00a9115SJed Brown   ierr    = PetscNewLog(A,&s);CHKERRQ(ierr);
1984c8883902SJed Brown   A->data = (void*)s;
1985e7c19651SJed Brown 
1986e7c19651SJed Brown   s->nr            = -1;
1987e7c19651SJed Brown   s->nc            = -1;
19880298fd71SBarry Smith   s->m             = NULL;
1989e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
1990c8883902SJed Brown 
1991c8883902SJed Brown   ierr = PetscMemzero(A->ops,sizeof(*A->ops));CHKERRQ(ierr);
199226fbe8dcSKarl Rupp 
1993c8883902SJed Brown   A->ops->mult                  = MatMult_Nest;
19949194d70fSJed Brown   A->ops->multadd               = MatMultAdd_Nest;
1995c8883902SJed Brown   A->ops->multtranspose         = MatMultTranspose_Nest;
19969194d70fSJed Brown   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
1997f8170845SAlex Fikl   A->ops->transpose             = MatTranspose_Nest;
1998c8883902SJed Brown   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
1999c8883902SJed Brown   A->ops->assemblyend           = MatAssemblyEnd_Nest;
2000c8883902SJed Brown   A->ops->zeroentries           = MatZeroEntries_Nest;
2001c222c20dSDavid Ham   A->ops->copy                  = MatCopy_Nest;
20026e76ffeaSPierre Jolivet   A->ops->axpy                  = MatAXPY_Nest;
2003c8883902SJed Brown   A->ops->duplicate             = MatDuplicate_Nest;
20047dae84e0SHong Zhang   A->ops->createsubmatrix       = MatCreateSubMatrix_Nest;
2005c8883902SJed Brown   A->ops->destroy               = MatDestroy_Nest;
2006c8883902SJed Brown   A->ops->view                  = MatView_Nest;
2007c8883902SJed Brown   A->ops->getvecs               = 0; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2008c8883902SJed Brown   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
2009c8883902SJed Brown   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
2010429bac76SJed Brown   A->ops->getdiagonal           = MatGetDiagonal_Nest;
2011429bac76SJed Brown   A->ops->diagonalscale         = MatDiagonalScale_Nest;
2012a061e289SJed Brown   A->ops->scale                 = MatScale_Nest;
2013a061e289SJed Brown   A->ops->shift                 = MatShift_Nest;
201413135bc6SAlex Fikl   A->ops->diagonalset           = MatDiagonalSet_Nest;
2015f8170845SAlex Fikl   A->ops->setrandom             = MatSetRandom_Nest;
20168b7d3b4bSBarry Smith   A->ops->hasoperation          = MatHasOperation_Nest;
2017c8883902SJed Brown 
2018c8883902SJed Brown   A->spptr        = 0;
2019c8883902SJed Brown   A->assembled    = PETSC_FALSE;
2020c8883902SJed Brown 
2021c8883902SJed Brown   /* expose Nest api's */
2022bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",        MatNestGetSubMat_Nest);CHKERRQ(ierr);
2023bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",        MatNestSetSubMat_Nest);CHKERRQ(ierr);
2024bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",       MatNestGetSubMats_Nest);CHKERRQ(ierr);
2025bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",          MatNestGetSize_Nest);CHKERRQ(ierr);
2026bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",           MatNestGetISs_Nest);CHKERRQ(ierr);
2027bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",      MatNestGetLocalISs_Nest);CHKERRQ(ierr);
2028bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",       MatNestSetVecType_Nest);CHKERRQ(ierr);
2029bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",       MatNestSetSubMats_Nest);CHKERRQ(ierr);
20300899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",  MatConvert_Nest_AIJ);CHKERRQ(ierr);
20310899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",  MatConvert_Nest_AIJ);CHKERRQ(ierr);
203283b1a929SMark Adams   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",     MatConvert_Nest_AIJ);CHKERRQ(ierr);
20335e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",      MatConvert_Nest_IS);CHKERRQ(ierr);
203452c5f739Sprj-   ierr = PetscObjectComposeFunction((PetscObject)A,"MatMatMult_nest_mpidense_C",MatMatMult_Nest_Dense);CHKERRQ(ierr);
203552c5f739Sprj-   ierr = PetscObjectComposeFunction((PetscObject)A,"MatMatMult_nest_seqdense_C",MatMatMult_Nest_Dense);CHKERRQ(ierr);
203652c5f739Sprj-   ierr = PetscObjectComposeFunction((PetscObject)A,"MatMatMult_nest_dense_C",   MatMatMult_Nest_Dense);CHKERRQ(ierr);
2037c8883902SJed Brown 
2038c8883902SJed Brown   ierr = PetscObjectChangeTypeName((PetscObject)A,MATNEST);CHKERRQ(ierr);
2039c8883902SJed Brown   PetscFunctionReturn(0);
2040c8883902SJed Brown }
2041