xref: /petsc/src/mat/impls/nest/matnest.c (revision 381b8e50c406fbb7312fbe77b1194669af1455f1)
1aaa7dc30SBarry Smith #include <../src/mat/impls/nest/matnestimpl.h> /*I   "petscmat.h"   I*/
2b68353e5Sstefano_zampini #include <../src/mat/impls/aij/seq/aij.h>
30c312b8eSJed Brown #include <petscsf.h>
4d8588912SDave May 
5c8883902SJed Brown static PetscErrorCode MatSetUp_NestIS_Private(Mat,PetscInt,const IS[],PetscInt,const IS[]);
606a1af2fSStefano Zampini static PetscErrorCode MatCreateVecs_Nest(Mat,Vec*,Vec*);
706a1af2fSStefano Zampini static PetscErrorCode MatReset_Nest(Mat);
806a1af2fSStefano Zampini 
95e3038f0Sstefano_zampini PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat,MatType,MatReuse,Mat*);
10c8883902SJed Brown 
11d8588912SDave May /* private functions */
128188e55aSJed Brown static PetscErrorCode MatNestGetSizes_Private(Mat A,PetscInt *m,PetscInt *n,PetscInt *M,PetscInt *N)
13d8588912SDave May {
14d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
158188e55aSJed Brown   PetscInt       i,j;
16d8588912SDave May   PetscErrorCode ierr;
17d8588912SDave May 
18d8588912SDave May   PetscFunctionBegin;
198188e55aSJed Brown   *m = *n = *M = *N = 0;
208188e55aSJed Brown   for (i=0; i<bA->nr; i++) {  /* rows */
218188e55aSJed Brown     PetscInt sm,sM;
228188e55aSJed Brown     ierr = ISGetLocalSize(bA->isglobal.row[i],&sm);CHKERRQ(ierr);
238188e55aSJed Brown     ierr = ISGetSize(bA->isglobal.row[i],&sM);CHKERRQ(ierr);
248188e55aSJed Brown     *m  += sm;
258188e55aSJed Brown     *M  += sM;
26d8588912SDave May   }
278188e55aSJed Brown   for (j=0; j<bA->nc; j++) {  /* cols */
288188e55aSJed Brown     PetscInt sn,sN;
298188e55aSJed Brown     ierr = ISGetLocalSize(bA->isglobal.col[j],&sn);CHKERRQ(ierr);
308188e55aSJed Brown     ierr = ISGetSize(bA->isglobal.col[j],&sN);CHKERRQ(ierr);
318188e55aSJed Brown     *n  += sn;
328188e55aSJed Brown     *N  += sN;
33d8588912SDave May   }
34d8588912SDave May   PetscFunctionReturn(0);
35d8588912SDave May }
36d8588912SDave May 
37d8588912SDave May /* operations */
38207556f9SJed Brown static PetscErrorCode MatMult_Nest(Mat A,Vec x,Vec y)
39d8588912SDave May {
40d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
41207556f9SJed Brown   Vec            *bx = bA->right,*by = bA->left;
42207556f9SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
43d8588912SDave May   PetscErrorCode ierr;
44d8588912SDave May 
45d8588912SDave May   PetscFunctionBegin;
46207556f9SJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(y,bA->isglobal.row[i],&by[i]);CHKERRQ(ierr);}
47207556f9SJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
48207556f9SJed Brown   for (i=0; i<nr; i++) {
49d8588912SDave May     ierr = VecZeroEntries(by[i]);CHKERRQ(ierr);
50207556f9SJed Brown     for (j=0; j<nc; j++) {
51207556f9SJed Brown       if (!bA->m[i][j]) continue;
52d8588912SDave May       /* y[i] <- y[i] + A[i][j] * x[j] */
53d8588912SDave May       ierr = MatMultAdd(bA->m[i][j],bx[j],by[i],by[i]);CHKERRQ(ierr);
54d8588912SDave May     }
55d8588912SDave May   }
56207556f9SJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.row[i],&by[i]);CHKERRQ(ierr);}
57207556f9SJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
58d8588912SDave May   PetscFunctionReturn(0);
59d8588912SDave May }
60d8588912SDave May 
619194d70fSJed Brown static PetscErrorCode MatMultAdd_Nest(Mat A,Vec x,Vec y,Vec z)
629194d70fSJed Brown {
639194d70fSJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
649194d70fSJed Brown   Vec            *bx = bA->right,*bz = bA->left;
659194d70fSJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
669194d70fSJed Brown   PetscErrorCode ierr;
679194d70fSJed Brown 
689194d70fSJed Brown   PetscFunctionBegin;
699194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(z,bA->isglobal.row[i],&bz[i]);CHKERRQ(ierr);}
709194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
719194d70fSJed Brown   for (i=0; i<nr; i++) {
729194d70fSJed Brown     if (y != z) {
739194d70fSJed Brown       Vec by;
749194d70fSJed Brown       ierr = VecGetSubVector(y,bA->isglobal.row[i],&by);CHKERRQ(ierr);
759194d70fSJed Brown       ierr = VecCopy(by,bz[i]);CHKERRQ(ierr);
76336d21e7SJed Brown       ierr = VecRestoreSubVector(y,bA->isglobal.row[i],&by);CHKERRQ(ierr);
779194d70fSJed Brown     }
789194d70fSJed Brown     for (j=0; j<nc; j++) {
799194d70fSJed Brown       if (!bA->m[i][j]) continue;
809194d70fSJed Brown       /* y[i] <- y[i] + A[i][j] * x[j] */
819194d70fSJed Brown       ierr = MatMultAdd(bA->m[i][j],bx[j],bz[i],bz[i]);CHKERRQ(ierr);
829194d70fSJed Brown     }
839194d70fSJed Brown   }
849194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(z,bA->isglobal.row[i],&bz[i]);CHKERRQ(ierr);}
859194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]);CHKERRQ(ierr);}
869194d70fSJed Brown   PetscFunctionReturn(0);
879194d70fSJed Brown }
889194d70fSJed Brown 
8952c5f739Sprj- typedef struct {
9052c5f739Sprj-   Mat          *workC;    /* array of Mat with specific containers depending on the underlying MatMatMult implementation */
9152c5f739Sprj-   PetscScalar  *tarray;   /* buffer for storing all temporary products A[i][j] B[j] */
9252c5f739Sprj-   PetscInt     *dm,*dn,k; /* displacements and number of submatrices */
9352c5f739Sprj- } Nest_Dense;
9452c5f739Sprj- 
9552c5f739Sprj- PETSC_INTERN PetscErrorCode MatMatMultNumeric_Nest_Dense(Mat A,Mat B,Mat C)
9652c5f739Sprj- {
9752c5f739Sprj-   Mat_Nest          *bA = (Mat_Nest*)A->data;
9852c5f739Sprj-   PetscContainer    container;
9952c5f739Sprj-   Nest_Dense        *contents;
10052c5f739Sprj-   Mat               viewB,viewC,seq;
10152c5f739Sprj-   const PetscScalar *barray;
10252c5f739Sprj-   PetscScalar       *carray;
10352c5f739Sprj-   PetscInt          i,j,M,N,nr = bA->nr,nc = bA->nc,ldb,ldc;
10452c5f739Sprj-   PetscErrorCode    ierr;
10552c5f739Sprj- 
10652c5f739Sprj-   PetscFunctionBegin;
10752c5f739Sprj-   ierr = PetscObjectQuery((PetscObject)C,"workC",(PetscObject*)&container);CHKERRQ(ierr);
10852c5f739Sprj-   if (!container) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Container does not exist");
10952c5f739Sprj-   ierr = PetscContainerGetPointer(container,(void**)&contents);CHKERRQ(ierr);
11052c5f739Sprj-   ierr = MatDenseGetLDA(B,&ldb);CHKERRQ(ierr);
11152c5f739Sprj-   ierr = MatDenseGetLDA(C,&ldc);CHKERRQ(ierr);
11252c5f739Sprj-   ierr = MatGetSize(B,NULL,&N);CHKERRQ(ierr);
11352c5f739Sprj-   ierr = MatZeroEntries(C);CHKERRQ(ierr);
11452c5f739Sprj-   ierr = MatDenseGetArrayRead(B,&barray);CHKERRQ(ierr);
11552c5f739Sprj-   ierr = MatDenseGetArray(C,&carray);CHKERRQ(ierr);
11652c5f739Sprj-   for (i=0; i<nr; i++) {
11752c5f739Sprj-     ierr = ISGetSize(bA->isglobal.row[i],&M);CHKERRQ(ierr);
11852c5f739Sprj-     ierr = MatCreateDense(PetscObjectComm((PetscObject)A),contents->dm[i+1]-contents->dm[i],PETSC_DECIDE,M,N,carray+contents->dm[i],&viewC);CHKERRQ(ierr);
11952c5f739Sprj-     ierr = MatDenseGetLocalMatrix(viewC,&seq);CHKERRQ(ierr);
12052c5f739Sprj-     ierr = MatSeqDenseSetLDA(seq,ldc);CHKERRQ(ierr);
12152c5f739Sprj-     for (j=0; j<nc; j++) {
12252c5f739Sprj-       if (!bA->m[i][j]) continue;
12352c5f739Sprj-       ierr = ISGetSize(bA->isglobal.col[j],&M);CHKERRQ(ierr);
12452c5f739Sprj-       ierr = MatCreateDense(PetscObjectComm((PetscObject)A),contents->dn[j+1]-contents->dn[j],PETSC_DECIDE,M,N,(PetscScalar*)(barray+contents->dn[j]),&viewB);CHKERRQ(ierr);
12552c5f739Sprj-       ierr = MatDenseGetLocalMatrix(viewB,&seq);CHKERRQ(ierr);
12652c5f739Sprj-       ierr = MatSeqDenseSetLDA(seq,ldb);CHKERRQ(ierr);
12752c5f739Sprj-       /* workC <- A[i][j] * B[j] */
12852c5f739Sprj-       ierr = MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]);CHKERRQ(ierr);
12952c5f739Sprj-       ierr = MatDestroy(&viewB);CHKERRQ(ierr);
13052c5f739Sprj-        /* C[i] <- workC + C[i] */
13152c5f739Sprj-       ierr = MatAXPY(viewC,1.0,contents->workC[i*nc + j],SAME_NONZERO_PATTERN);CHKERRQ(ierr);
13252c5f739Sprj-     }
13352c5f739Sprj-     ierr = MatDestroy(&viewC);CHKERRQ(ierr);
13452c5f739Sprj-   }
13552c5f739Sprj-   ierr = MatDenseRestoreArray(C,&carray);CHKERRQ(ierr);
13652c5f739Sprj-   ierr = MatDenseRestoreArrayRead(B,&barray);CHKERRQ(ierr);
13752c5f739Sprj-   PetscFunctionReturn(0);
13852c5f739Sprj- }
13952c5f739Sprj- 
14052c5f739Sprj- PetscErrorCode MatNest_DenseDestroy(void *ctx)
14152c5f739Sprj- {
14252c5f739Sprj-   Nest_Dense     *contents = (Nest_Dense*)ctx;
14352c5f739Sprj-   PetscInt       i;
14452c5f739Sprj-   PetscErrorCode ierr;
14552c5f739Sprj- 
14652c5f739Sprj-   PetscFunctionBegin;
14752c5f739Sprj-   ierr = PetscFree(contents->tarray);CHKERRQ(ierr);
14852c5f739Sprj-   for (i=0; i<contents->k; i++) {
14952c5f739Sprj-     ierr = MatDestroy(contents->workC + i);CHKERRQ(ierr);
15052c5f739Sprj-   }
15152c5f739Sprj-   ierr = PetscFree3(contents->dm,contents->dn,contents->workC);CHKERRQ(ierr);
15252c5f739Sprj-   ierr = PetscFree(contents);CHKERRQ(ierr);
15352c5f739Sprj-   PetscFunctionReturn(0);
15452c5f739Sprj- }
15552c5f739Sprj- 
15652c5f739Sprj- PETSC_INTERN PetscErrorCode MatMatMultSymbolic_Nest_Dense(Mat A,Mat B,PetscReal fill,Mat *C)
15752c5f739Sprj- {
15852c5f739Sprj-   Mat_Nest          *bA = (Mat_Nest*)A->data;
15952c5f739Sprj-   Mat               viewB,viewSeq;
16052c5f739Sprj-   const PetscScalar *barray;
16152c5f739Sprj-   PetscInt          i,j,M,N,m,nr = bA->nr,nc = bA->nc,maxm = 0,ldb;
16252c5f739Sprj-   PetscContainer    container;
16352c5f739Sprj-   Nest_Dense        *contents;
16452c5f739Sprj-   PetscErrorCode    ierr;
16552c5f739Sprj- 
16652c5f739Sprj-   PetscFunctionBegin;
16752c5f739Sprj-   ierr = MatGetSize(B,NULL,&N);CHKERRQ(ierr);
16852c5f739Sprj-   if (!(*C)) {
16952c5f739Sprj-     ierr = MatGetLocalSize(A,&m,NULL);CHKERRQ(ierr);
17052c5f739Sprj-     ierr = MatGetSize(A,&M,NULL);CHKERRQ(ierr);
17152c5f739Sprj-     ierr = MatCreateDense(PetscObjectComm((PetscObject)A),m,PETSC_DECIDE,M,N,NULL,C);CHKERRQ(ierr);
17252c5f739Sprj-   } else {
17352c5f739Sprj-     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);
17452c5f739Sprj-     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);
17552c5f739Sprj-   }
17652c5f739Sprj- 
17752c5f739Sprj-   ierr = PetscNew(&contents);CHKERRQ(ierr);
17852c5f739Sprj-   ierr = PetscContainerCreate(PetscObjectComm((PetscObject)A),&container);CHKERRQ(ierr);
17952c5f739Sprj-   ierr = PetscContainerSetPointer(container,contents);CHKERRQ(ierr);
18052c5f739Sprj-   ierr = PetscContainerSetUserDestroy(container,MatNest_DenseDestroy);CHKERRQ(ierr);
18152c5f739Sprj-   ierr = PetscObjectCompose((PetscObject)*C,"workC",(PetscObject)container);CHKERRQ(ierr);
18252c5f739Sprj-   ierr = PetscContainerDestroy(&container);CHKERRQ(ierr);
18352c5f739Sprj-   ierr = PetscCalloc3(nr+1,&contents->dm,nc+1,&contents->dn,nr*nc,&contents->workC);CHKERRQ(ierr);
18452c5f739Sprj-   contents->k = nr*nc;
18552c5f739Sprj-   for (i=0; i<nr; i++) {
18652c5f739Sprj-     ierr = ISGetLocalSize(bA->isglobal.row[i],contents->dm + i+1);CHKERRQ(ierr);
18752c5f739Sprj-     maxm = PetscMax(maxm,contents->dm[i+1]);
18852c5f739Sprj-     contents->dm[i+1] += contents->dm[i];
18952c5f739Sprj-   }
19052c5f739Sprj-   for (i=0; i<nc; i++) {
19152c5f739Sprj-     ierr = ISGetLocalSize(bA->isglobal.col[i],contents->dn + i+1);CHKERRQ(ierr);
19252c5f739Sprj-     contents->dn[i+1] += contents->dn[i];
19352c5f739Sprj-   }
19452c5f739Sprj-   ierr = PetscMalloc1(maxm*N,&contents->tarray);CHKERRQ(ierr);
19552c5f739Sprj-   ierr = MatDenseGetLDA(B,&ldb);CHKERRQ(ierr);
19652c5f739Sprj-   ierr = MatGetSize(B,NULL,&N);CHKERRQ(ierr);
19752c5f739Sprj-   ierr = MatDenseGetArrayRead(B,&barray);CHKERRQ(ierr);
19852c5f739Sprj-   /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */
19952c5f739Sprj-   for (j=0; j<nc; j++) {
20052c5f739Sprj-     ierr = ISGetSize(bA->isglobal.col[j],&M);CHKERRQ(ierr);
20152c5f739Sprj-     ierr = MatCreateDense(PetscObjectComm((PetscObject)A),contents->dn[j+1]-contents->dn[j],PETSC_DECIDE,M,N,(PetscScalar*)(barray+contents->dn[j]),&viewB);CHKERRQ(ierr);
20252c5f739Sprj-     ierr = MatDenseGetLocalMatrix(viewB,&viewSeq);CHKERRQ(ierr);
20352c5f739Sprj-     ierr = MatSeqDenseSetLDA(viewSeq,ldb);CHKERRQ(ierr);
20452c5f739Sprj-     for (i=0; i<nr; i++) {
20552c5f739Sprj-       if (!bA->m[i][j]) continue;
20652c5f739Sprj-       /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */
20752c5f739Sprj-       ierr = MatMatMultSymbolic(bA->m[i][j],viewB,fill,contents->workC + i*nc + j);CHKERRQ(ierr);
20852c5f739Sprj-       ierr = MatDenseGetLocalMatrix(contents->workC[i*nc + j],&viewSeq);CHKERRQ(ierr);
20952c5f739Sprj-       /* free the memory allocated in MatMatMultSymbolic, since tarray will be shared by all Mat */
21052c5f739Sprj-       ierr = MatSeqDenseSetPreallocation(viewSeq,contents->tarray);CHKERRQ(ierr);
21152c5f739Sprj-     }
21252c5f739Sprj-     ierr = MatDestroy(&viewB);CHKERRQ(ierr);
21352c5f739Sprj-   }
21452c5f739Sprj-   ierr = MatDenseRestoreArrayRead(B,&barray);CHKERRQ(ierr);
21552c5f739Sprj- 
21652c5f739Sprj-   (*C)->ops->matmultnumeric = MatMatMultNumeric_Nest_Dense;
21752c5f739Sprj-   PetscFunctionReturn(0);
21852c5f739Sprj- }
21952c5f739Sprj- 
22052c5f739Sprj- PETSC_INTERN PetscErrorCode MatMatMult_Nest_Dense(Mat A,Mat B,MatReuse scall,PetscReal fill,Mat *C)
22152c5f739Sprj- {
22252c5f739Sprj-   PetscErrorCode ierr;
22352c5f739Sprj- 
22452c5f739Sprj-   PetscFunctionBegin;
22552c5f739Sprj-   if (scall == MAT_INITIAL_MATRIX) {
22652c5f739Sprj-     *C = NULL;
22752c5f739Sprj-     ierr = PetscLogEventBegin(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr);
22852c5f739Sprj-     ierr = MatMatMultSymbolic_Nest_Dense(A,B,fill,C);CHKERRQ(ierr);
22952c5f739Sprj-     ierr = PetscLogEventEnd(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr);
23052c5f739Sprj-   }
23152c5f739Sprj-   ierr = PetscLogEventBegin(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
23252c5f739Sprj-   ierr = MatMatMultNumeric_Nest_Dense(A,B,*C);CHKERRQ(ierr);
23352c5f739Sprj-   ierr = PetscLogEventEnd(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr);
23452c5f739Sprj-   PetscFunctionReturn(0);
23552c5f739Sprj- }
23652c5f739Sprj- 
237207556f9SJed Brown static PetscErrorCode MatMultTranspose_Nest(Mat A,Vec x,Vec y)
238d8588912SDave May {
239d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
240207556f9SJed Brown   Vec            *bx = bA->left,*by = bA->right;
241207556f9SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
242d8588912SDave May   PetscErrorCode ierr;
243d8588912SDave May 
244d8588912SDave May   PetscFunctionBegin;
245609e31cbSJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
246609e31cbSJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(y,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);}
247207556f9SJed Brown   for (j=0; j<nc; j++) {
248609e31cbSJed Brown     ierr = VecZeroEntries(by[j]);CHKERRQ(ierr);
249609e31cbSJed Brown     for (i=0; i<nr; i++) {
2506c75ac25SJed Brown       if (!bA->m[i][j]) continue;
251609e31cbSJed Brown       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
252609e31cbSJed Brown       ierr = MatMultTransposeAdd(bA->m[i][j],bx[i],by[j],by[j]);CHKERRQ(ierr);
253d8588912SDave May     }
254d8588912SDave May   }
255609e31cbSJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
256609e31cbSJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);}
257d8588912SDave May   PetscFunctionReturn(0);
258d8588912SDave May }
259d8588912SDave May 
2609194d70fSJed Brown static PetscErrorCode MatMultTransposeAdd_Nest(Mat A,Vec x,Vec y,Vec z)
2619194d70fSJed Brown {
2629194d70fSJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
2639194d70fSJed Brown   Vec            *bx = bA->left,*bz = bA->right;
2649194d70fSJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
2659194d70fSJed Brown   PetscErrorCode ierr;
2669194d70fSJed Brown 
2679194d70fSJed Brown   PetscFunctionBegin;
2689194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
2699194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(z,bA->isglobal.col[i],&bz[i]);CHKERRQ(ierr);}
2709194d70fSJed Brown   for (j=0; j<nc; j++) {
2719194d70fSJed Brown     if (y != z) {
2729194d70fSJed Brown       Vec by;
2739194d70fSJed Brown       ierr = VecGetSubVector(y,bA->isglobal.col[j],&by);CHKERRQ(ierr);
2749194d70fSJed Brown       ierr = VecCopy(by,bz[j]);CHKERRQ(ierr);
2759194d70fSJed Brown       ierr = VecRestoreSubVector(y,bA->isglobal.col[j],&by);CHKERRQ(ierr);
2769194d70fSJed Brown     }
2779194d70fSJed Brown     for (i=0; i<nr; i++) {
2786c75ac25SJed Brown       if (!bA->m[i][j]) continue;
2799194d70fSJed Brown       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
2809194d70fSJed Brown       ierr = MatMultTransposeAdd(bA->m[i][j],bx[i],bz[j],bz[j]);CHKERRQ(ierr);
2819194d70fSJed Brown     }
2829194d70fSJed Brown   }
2839194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
2849194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(z,bA->isglobal.col[i],&bz[i]);CHKERRQ(ierr);}
2859194d70fSJed Brown   PetscFunctionReturn(0);
2869194d70fSJed Brown }
2879194d70fSJed Brown 
288f8170845SAlex Fikl static PetscErrorCode MatTranspose_Nest(Mat A,MatReuse reuse,Mat *B)
289f8170845SAlex Fikl {
290f8170845SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data, *bC;
291f8170845SAlex Fikl   Mat            C;
292f8170845SAlex Fikl   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
293f8170845SAlex Fikl   PetscErrorCode ierr;
294f8170845SAlex Fikl 
295f8170845SAlex Fikl   PetscFunctionBegin;
296cf37664fSBarry Smith   if (reuse == MAT_INPLACE_MATRIX && nr != nc) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Square nested matrix only for in-place");
297f8170845SAlex Fikl 
298cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
299f8170845SAlex Fikl     Mat *subs;
300f8170845SAlex Fikl     IS  *is_row,*is_col;
301f8170845SAlex Fikl 
302f8170845SAlex Fikl     ierr = PetscCalloc1(nr * nc,&subs);CHKERRQ(ierr);
303f8170845SAlex Fikl     ierr = PetscMalloc2(nr,&is_row,nc,&is_col);CHKERRQ(ierr);
304f8170845SAlex Fikl     ierr = MatNestGetISs(A,is_row,is_col);CHKERRQ(ierr);
305cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
306ddeb9bd8SAlex Fikl       for (i=0; i<nr; i++) {
307ddeb9bd8SAlex Fikl         for (j=0; j<nc; j++) {
308ddeb9bd8SAlex Fikl           subs[i + nr * j] = bA->m[i][j];
309ddeb9bd8SAlex Fikl         }
310ddeb9bd8SAlex Fikl       }
311ddeb9bd8SAlex Fikl     }
312ddeb9bd8SAlex Fikl 
313f8170845SAlex Fikl     ierr = MatCreateNest(PetscObjectComm((PetscObject)A),nc,is_col,nr,is_row,subs,&C);CHKERRQ(ierr);
314f8170845SAlex Fikl     ierr = PetscFree(subs);CHKERRQ(ierr);
3153d994f23SBarry Smith     ierr = PetscFree2(is_row,is_col);CHKERRQ(ierr);
316f8170845SAlex Fikl   } else {
317f8170845SAlex Fikl     C = *B;
318f8170845SAlex Fikl   }
319f8170845SAlex Fikl 
320f8170845SAlex Fikl   bC = (Mat_Nest*)C->data;
321f8170845SAlex Fikl   for (i=0; i<nr; i++) {
322f8170845SAlex Fikl     for (j=0; j<nc; j++) {
323f8170845SAlex Fikl       if (bA->m[i][j]) {
324f8170845SAlex Fikl         ierr = MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i]));CHKERRQ(ierr);
325f8170845SAlex Fikl       } else {
326f8170845SAlex Fikl         bC->m[j][i] = NULL;
327f8170845SAlex Fikl       }
328f8170845SAlex Fikl     }
329f8170845SAlex Fikl   }
330f8170845SAlex Fikl 
331cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
332f8170845SAlex Fikl     *B = C;
333f8170845SAlex Fikl   } else {
334f8170845SAlex Fikl     ierr = MatHeaderMerge(A, &C);CHKERRQ(ierr);
335f8170845SAlex Fikl   }
336f8170845SAlex Fikl   PetscFunctionReturn(0);
337f8170845SAlex Fikl }
338f8170845SAlex Fikl 
339e2d7f03fSJed Brown static PetscErrorCode MatNestDestroyISList(PetscInt n,IS **list)
340e2d7f03fSJed Brown {
341e2d7f03fSJed Brown   PetscErrorCode ierr;
342e2d7f03fSJed Brown   IS             *lst = *list;
343e2d7f03fSJed Brown   PetscInt       i;
344e2d7f03fSJed Brown 
345e2d7f03fSJed Brown   PetscFunctionBegin;
346e2d7f03fSJed Brown   if (!lst) PetscFunctionReturn(0);
3476bf464f9SBarry Smith   for (i=0; i<n; i++) if (lst[i]) {ierr = ISDestroy(&lst[i]);CHKERRQ(ierr);}
348e2d7f03fSJed Brown   ierr  = PetscFree(lst);CHKERRQ(ierr);
3490298fd71SBarry Smith   *list = NULL;
350e2d7f03fSJed Brown   PetscFunctionReturn(0);
351e2d7f03fSJed Brown }
352e2d7f03fSJed Brown 
35306a1af2fSStefano Zampini static PetscErrorCode MatReset_Nest(Mat A)
354d8588912SDave May {
355d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
356d8588912SDave May   PetscInt       i,j;
357d8588912SDave May   PetscErrorCode ierr;
358d8588912SDave May 
359d8588912SDave May   PetscFunctionBegin;
360d8588912SDave May   /* release the matrices and the place holders */
361e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nr,&vs->isglobal.row);CHKERRQ(ierr);
362e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nc,&vs->isglobal.col);CHKERRQ(ierr);
363e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nr,&vs->islocal.row);CHKERRQ(ierr);
364e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nc,&vs->islocal.col);CHKERRQ(ierr);
365d8588912SDave May 
366d8588912SDave May   ierr = PetscFree(vs->row_len);CHKERRQ(ierr);
367d8588912SDave May   ierr = PetscFree(vs->col_len);CHKERRQ(ierr);
36806a1af2fSStefano Zampini   ierr = PetscFree(vs->nnzstate);CHKERRQ(ierr);
369d8588912SDave May 
370207556f9SJed Brown   ierr = PetscFree2(vs->left,vs->right);CHKERRQ(ierr);
371207556f9SJed Brown 
372d8588912SDave May   /* release the matrices and the place holders */
373d8588912SDave May   if (vs->m) {
374d8588912SDave May     for (i=0; i<vs->nr; i++) {
375d8588912SDave May       for (j=0; j<vs->nc; j++) {
3766bf464f9SBarry Smith         ierr = MatDestroy(&vs->m[i][j]);CHKERRQ(ierr);
377d8588912SDave May       }
378d8588912SDave May       ierr = PetscFree(vs->m[i]);CHKERRQ(ierr);
379d8588912SDave May     }
380d8588912SDave May     ierr = PetscFree(vs->m);CHKERRQ(ierr);
381d8588912SDave May   }
38206a1af2fSStefano Zampini 
38306a1af2fSStefano Zampini   /* restore defaults */
38406a1af2fSStefano Zampini   vs->nr = 0;
38506a1af2fSStefano Zampini   vs->nc = 0;
38606a1af2fSStefano Zampini   vs->splitassembly = PETSC_FALSE;
38706a1af2fSStefano Zampini   PetscFunctionReturn(0);
38806a1af2fSStefano Zampini }
38906a1af2fSStefano Zampini 
39006a1af2fSStefano Zampini static PetscErrorCode MatDestroy_Nest(Mat A)
39106a1af2fSStefano Zampini {
39206a1af2fSStefano Zampini   PetscErrorCode ierr;
39306a1af2fSStefano Zampini 
39406a1af2fSStefano Zampini   ierr = MatReset_Nest(A);CHKERRQ(ierr);
395bf0cc555SLisandro Dalcin   ierr = PetscFree(A->data);CHKERRQ(ierr);
396d8588912SDave May 
397bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",0);CHKERRQ(ierr);
398bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",0);CHKERRQ(ierr);
399bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",0);CHKERRQ(ierr);
400bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",0);CHKERRQ(ierr);
401bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",0);CHKERRQ(ierr);
402bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",0);CHKERRQ(ierr);
403bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",0);CHKERRQ(ierr);
404bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",0);CHKERRQ(ierr);
4050899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",0);CHKERRQ(ierr);
4060899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",0);CHKERRQ(ierr);
4075e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",0);CHKERRQ(ierr);
4085e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",0);CHKERRQ(ierr);
40952c5f739Sprj-   ierr = PetscObjectComposeFunction((PetscObject)A,"MatMatMult_nest_mpidense_C",0);CHKERRQ(ierr);
41052c5f739Sprj-   ierr = PetscObjectComposeFunction((PetscObject)A,"MatMatMult_nest_seqdense_C",0);CHKERRQ(ierr);
41152c5f739Sprj-   ierr = PetscObjectComposeFunction((PetscObject)A,"MatMatMult_nest_dense_C",0);CHKERRQ(ierr);
412d8588912SDave May   PetscFunctionReturn(0);
413d8588912SDave May }
414d8588912SDave May 
415*381b8e50SStefano Zampini static PetscErrorCode MatMissingDiagonal_Nest(Mat mat,PetscBool *missing,PetscInt *dd)
416*381b8e50SStefano Zampini {
417*381b8e50SStefano Zampini   Mat_Nest       *vs = (Mat_Nest*)mat->data;
418*381b8e50SStefano Zampini   PetscInt       i;
419*381b8e50SStefano Zampini   PetscErrorCode ierr;
420*381b8e50SStefano Zampini 
421*381b8e50SStefano Zampini   PetscFunctionBegin;
422*381b8e50SStefano Zampini   if (dd) *dd = 0;
423*381b8e50SStefano Zampini   if (!vs->nr) {
424*381b8e50SStefano Zampini     *missing = PETSC_TRUE;
425*381b8e50SStefano Zampini     PetscFunctionReturn(0);
426*381b8e50SStefano Zampini   }
427*381b8e50SStefano Zampini   *missing = PETSC_FALSE;
428*381b8e50SStefano Zampini   for (i = 0; i < vs->nr && !(*missing); i++) {
429*381b8e50SStefano Zampini     *missing = PETSC_TRUE;
430*381b8e50SStefano Zampini     if (vs->m[i][i]) {
431*381b8e50SStefano Zampini       ierr = MatMissingDiagonal(vs->m[i][i],missing,NULL);CHKERRQ(ierr);
432*381b8e50SStefano Zampini       if (*missing && dd) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"First missing entry not yet implemented");
433*381b8e50SStefano Zampini     }
434*381b8e50SStefano Zampini   }
435*381b8e50SStefano Zampini   PetscFunctionReturn(0);
436*381b8e50SStefano Zampini }
437*381b8e50SStefano Zampini 
438207556f9SJed Brown static PetscErrorCode MatAssemblyBegin_Nest(Mat A,MatAssemblyType type)
439d8588912SDave May {
440d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
441d8588912SDave May   PetscInt       i,j;
442d8588912SDave May   PetscErrorCode ierr;
44306a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
444d8588912SDave May 
445d8588912SDave May   PetscFunctionBegin;
446d8588912SDave May   for (i=0; i<vs->nr; i++) {
447d8588912SDave May     for (j=0; j<vs->nc; j++) {
44806a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
449e7c19651SJed Brown       if (vs->m[i][j]) {
450e7c19651SJed Brown         ierr = MatAssemblyBegin(vs->m[i][j],type);CHKERRQ(ierr);
451e7c19651SJed Brown         if (!vs->splitassembly) {
452e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
453e7c19651SJed 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
454e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
455e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
456e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
457e7c19651SJed Brown            */
458e7c19651SJed Brown           ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr);
45906a1af2fSStefano Zampini           ierr = MatGetNonzeroState(vs->m[i][j],&subnnzstate);CHKERRQ(ierr);
460e7c19651SJed Brown         }
461e7c19651SJed Brown       }
46206a1af2fSStefano Zampini       nnzstate = (PetscBool)(nnzstate || vs->nnzstate[i*vs->nc+j] != subnnzstate);
46306a1af2fSStefano Zampini       vs->nnzstate[i*vs->nc+j] = subnnzstate;
464d8588912SDave May     }
465d8588912SDave May   }
46606a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
467d8588912SDave May   PetscFunctionReturn(0);
468d8588912SDave May }
469d8588912SDave May 
470207556f9SJed Brown static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
471d8588912SDave May {
472d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
473d8588912SDave May   PetscInt       i,j;
474d8588912SDave May   PetscErrorCode ierr;
475d8588912SDave May 
476d8588912SDave May   PetscFunctionBegin;
477d8588912SDave May   for (i=0; i<vs->nr; i++) {
478d8588912SDave May     for (j=0; j<vs->nc; j++) {
479e7c19651SJed Brown       if (vs->m[i][j]) {
480e7c19651SJed Brown         if (vs->splitassembly) {
481e7c19651SJed Brown           ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr);
482e7c19651SJed Brown         }
483e7c19651SJed Brown       }
484d8588912SDave May     }
485d8588912SDave May   }
486d8588912SDave May   PetscFunctionReturn(0);
487d8588912SDave May }
488d8588912SDave May 
489f349c1fdSJed Brown static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat *B)
490d8588912SDave May {
491207556f9SJed Brown   PetscErrorCode ierr;
492f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
493f349c1fdSJed Brown   PetscInt       j;
494f349c1fdSJed Brown   Mat            sub;
495d8588912SDave May 
496d8588912SDave May   PetscFunctionBegin;
4970298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
498f349c1fdSJed Brown   for (j=0; !sub && j<vs->nc; j++) sub = vs->m[row][j];
4994994cf47SJed Brown   if (sub) {ierr = MatSetUp(sub);CHKERRQ(ierr);}       /* Ensure that the sizes are available */
500f349c1fdSJed Brown   *B = sub;
501f349c1fdSJed Brown   PetscFunctionReturn(0);
502d8588912SDave May }
503d8588912SDave May 
504f349c1fdSJed Brown static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat *B)
505f349c1fdSJed Brown {
506207556f9SJed Brown   PetscErrorCode ierr;
507f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
508f349c1fdSJed Brown   PetscInt       i;
509f349c1fdSJed Brown   Mat            sub;
510f349c1fdSJed Brown 
511f349c1fdSJed Brown   PetscFunctionBegin;
5120298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
513f349c1fdSJed Brown   for (i=0; !sub && i<vs->nr; i++) sub = vs->m[i][col];
5144994cf47SJed Brown   if (sub) {ierr = MatSetUp(sub);CHKERRQ(ierr);}       /* Ensure that the sizes are available */
515f349c1fdSJed Brown   *B = sub;
516f349c1fdSJed Brown   PetscFunctionReturn(0);
517d8588912SDave May }
518d8588912SDave May 
519f349c1fdSJed Brown static PetscErrorCode MatNestFindIS(Mat A,PetscInt n,const IS list[],IS is,PetscInt *found)
520f349c1fdSJed Brown {
521f349c1fdSJed Brown   PetscErrorCode ierr;
522f349c1fdSJed Brown   PetscInt       i;
523f349c1fdSJed Brown   PetscBool      flg;
524f349c1fdSJed Brown 
525f349c1fdSJed Brown   PetscFunctionBegin;
526f349c1fdSJed Brown   PetscValidPointer(list,3);
527f349c1fdSJed Brown   PetscValidHeaderSpecific(is,IS_CLASSID,4);
528f349c1fdSJed Brown   PetscValidIntPointer(found,5);
529f349c1fdSJed Brown   *found = -1;
530f349c1fdSJed Brown   for (i=0; i<n; i++) {
531207556f9SJed Brown     if (!list[i]) continue;
532320466b0SStefano Zampini     ierr = ISEqualUnsorted(list[i],is,&flg);CHKERRQ(ierr);
533f349c1fdSJed Brown     if (flg) {
534f349c1fdSJed Brown       *found = i;
535f349c1fdSJed Brown       PetscFunctionReturn(0);
536f349c1fdSJed Brown     }
537f349c1fdSJed Brown   }
538ce94432eSBarry Smith   SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Could not find index set");
539f349c1fdSJed Brown   PetscFunctionReturn(0);
540f349c1fdSJed Brown }
541f349c1fdSJed Brown 
5428188e55aSJed Brown /* Get a block row as a new MatNest */
5438188e55aSJed Brown static PetscErrorCode MatNestGetRow(Mat A,PetscInt row,Mat *B)
5448188e55aSJed Brown {
5458188e55aSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
5468188e55aSJed Brown   char           keyname[256];
5478188e55aSJed Brown   PetscErrorCode ierr;
5488188e55aSJed Brown 
5498188e55aSJed Brown   PetscFunctionBegin;
5500298fd71SBarry Smith   *B   = NULL;
5518caf3d72SBarry Smith   ierr = PetscSNPrintf(keyname,sizeof(keyname),"NestRow_%D",row);CHKERRQ(ierr);
5528188e55aSJed Brown   ierr = PetscObjectQuery((PetscObject)A,keyname,(PetscObject*)B);CHKERRQ(ierr);
5538188e55aSJed Brown   if (*B) PetscFunctionReturn(0);
5548188e55aSJed Brown 
555ce94432eSBarry Smith   ierr = MatCreateNest(PetscObjectComm((PetscObject)A),1,NULL,vs->nc,vs->isglobal.col,vs->m[row],B);CHKERRQ(ierr);
55626fbe8dcSKarl Rupp 
5578188e55aSJed Brown   (*B)->assembled = A->assembled;
55826fbe8dcSKarl Rupp 
5598188e55aSJed Brown   ierr = PetscObjectCompose((PetscObject)A,keyname,(PetscObject)*B);CHKERRQ(ierr);
5608188e55aSJed Brown   ierr = PetscObjectDereference((PetscObject)*B);CHKERRQ(ierr); /* Leave the only remaining reference in the composition */
5618188e55aSJed Brown   PetscFunctionReturn(0);
5628188e55aSJed Brown }
5638188e55aSJed Brown 
564f349c1fdSJed Brown static PetscErrorCode MatNestFindSubMat(Mat A,struct MatNestISPair *is,IS isrow,IS iscol,Mat *B)
565f349c1fdSJed Brown {
566f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
5678188e55aSJed Brown   PetscErrorCode ierr;
5686b3a5b13SJed Brown   PetscInt       row,col;
569e072481dSJed Brown   PetscBool      same,isFullCol,isFullColGlobal;
570f349c1fdSJed Brown 
571f349c1fdSJed Brown   PetscFunctionBegin;
5728188e55aSJed Brown   /* Check if full column space. This is a hack */
5738188e55aSJed Brown   isFullCol = PETSC_FALSE;
574251f4c67SDmitry Karpeev   ierr      = PetscObjectTypeCompare((PetscObject)iscol,ISSTRIDE,&same);CHKERRQ(ierr);
5758188e55aSJed Brown   if (same) {
57677019fcaSJed Brown     PetscInt n,first,step,i,an,am,afirst,astep;
5778188e55aSJed Brown     ierr      = ISStrideGetInfo(iscol,&first,&step);CHKERRQ(ierr);
5788188e55aSJed Brown     ierr      = ISGetLocalSize(iscol,&n);CHKERRQ(ierr);
57977019fcaSJed Brown     isFullCol = PETSC_TRUE;
58005ce4453SJed Brown     for (i=0,an=A->cmap->rstart; i<vs->nc; i++) {
58106a1af2fSStefano Zampini       ierr = PetscObjectTypeCompare((PetscObject)is->col[i],ISSTRIDE,&same);CHKERRQ(ierr);
58277019fcaSJed Brown       ierr = ISGetLocalSize(is->col[i],&am);CHKERRQ(ierr);
58306a1af2fSStefano Zampini       if (same) {
58406a1af2fSStefano Zampini         ierr = ISStrideGetInfo(is->col[i],&afirst,&astep);CHKERRQ(ierr);
58577019fcaSJed Brown         if (afirst != an || astep != step) isFullCol = PETSC_FALSE;
58606a1af2fSStefano Zampini       } else isFullCol = PETSC_FALSE;
58777019fcaSJed Brown       an += am;
58877019fcaSJed Brown     }
58905ce4453SJed Brown     if (an != A->cmap->rstart+n) isFullCol = PETSC_FALSE;
5908188e55aSJed Brown   }
591b2566f29SBarry Smith   ierr = MPIU_Allreduce(&isFullCol,&isFullColGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)iscol));CHKERRQ(ierr);
5928188e55aSJed Brown 
593427230ceSLisandro Dalcin   if (isFullColGlobal && vs->nc > 1) {
5948188e55aSJed Brown     PetscInt row;
5958188e55aSJed Brown     ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr);
5968188e55aSJed Brown     ierr = MatNestGetRow(A,row,B);CHKERRQ(ierr);
5978188e55aSJed Brown   } else {
598f349c1fdSJed Brown     ierr = MatNestFindIS(A,vs->nr,is->row,isrow,&row);CHKERRQ(ierr);
599f349c1fdSJed Brown     ierr = MatNestFindIS(A,vs->nc,is->col,iscol,&col);CHKERRQ(ierr);
600b6480e04SStefano Zampini     if (!vs->m[row][col]) {
601b6480e04SStefano Zampini       PetscInt lr,lc;
602b6480e04SStefano Zampini 
603b6480e04SStefano Zampini       ierr = MatCreate(PetscObjectComm((PetscObject)A),&vs->m[row][col]);CHKERRQ(ierr);
604b6480e04SStefano Zampini       ierr = ISGetLocalSize(vs->isglobal.row[row],&lr);CHKERRQ(ierr);
605b6480e04SStefano Zampini       ierr = ISGetLocalSize(vs->isglobal.col[col],&lc);CHKERRQ(ierr);
606b6480e04SStefano Zampini       ierr = MatSetSizes(vs->m[row][col],lr,lc,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
607fa9f0909SStefano Zampini       ierr = MatSetType(vs->m[row][col],MATAIJ);CHKERRQ(ierr);
608fa9f0909SStefano Zampini       ierr = MatSeqAIJSetPreallocation(vs->m[row][col],0,NULL);CHKERRQ(ierr);
609fa9f0909SStefano Zampini       ierr = MatMPIAIJSetPreallocation(vs->m[row][col],0,NULL,0,NULL);CHKERRQ(ierr);
610b6480e04SStefano Zampini       ierr = MatSetUp(vs->m[row][col]);CHKERRQ(ierr);
611b6480e04SStefano Zampini       ierr = MatAssemblyBegin(vs->m[row][col],MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
612b6480e04SStefano Zampini       ierr = MatAssemblyEnd(vs->m[row][col],MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
613b6480e04SStefano Zampini     }
614f349c1fdSJed Brown     *B = vs->m[row][col];
6158188e55aSJed Brown   }
616f349c1fdSJed Brown   PetscFunctionReturn(0);
617f349c1fdSJed Brown }
618f349c1fdSJed Brown 
61906a1af2fSStefano Zampini /*
62006a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
62106a1af2fSStefano Zampini */
6227dae84e0SHong Zhang static PetscErrorCode MatCreateSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat *B)
623f349c1fdSJed Brown {
624f349c1fdSJed Brown   PetscErrorCode ierr;
625f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
626f349c1fdSJed Brown   Mat            sub;
627f349c1fdSJed Brown 
628f349c1fdSJed Brown   PetscFunctionBegin;
629f349c1fdSJed Brown   ierr = MatNestFindSubMat(A,&vs->isglobal,isrow,iscol,&sub);CHKERRQ(ierr);
630f349c1fdSJed Brown   switch (reuse) {
631f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
6327874fa86SDave May     if (sub) { ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr); }
633f349c1fdSJed Brown     *B = sub;
634f349c1fdSJed Brown     break;
635f349c1fdSJed Brown   case MAT_REUSE_MATRIX:
636ce94432eSBarry Smith     if (sub != *B) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Submatrix was not used before in this call");
637f349c1fdSJed Brown     break;
638f349c1fdSJed Brown   case MAT_IGNORE_MATRIX:       /* Nothing to do */
639f349c1fdSJed Brown     break;
640511c6705SHong Zhang   case MAT_INPLACE_MATRIX:       /* Nothing to do */
641511c6705SHong Zhang     SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MAT_INPLACE_MATRIX is not supported yet");
642511c6705SHong Zhang     break;
643f349c1fdSJed Brown   }
644f349c1fdSJed Brown   PetscFunctionReturn(0);
645f349c1fdSJed Brown }
646f349c1fdSJed Brown 
647f349c1fdSJed Brown PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
648f349c1fdSJed Brown {
649f349c1fdSJed Brown   PetscErrorCode ierr;
650f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
651f349c1fdSJed Brown   Mat            sub;
652f349c1fdSJed Brown 
653f349c1fdSJed Brown   PetscFunctionBegin;
654f349c1fdSJed Brown   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
655f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
656f349c1fdSJed Brown   if (sub) {ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr);}
657f349c1fdSJed Brown   *B = sub;
658d8588912SDave May   PetscFunctionReturn(0);
659d8588912SDave May }
660d8588912SDave May 
661207556f9SJed Brown static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
662d8588912SDave May {
663d8588912SDave May   PetscErrorCode ierr;
664f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
665f349c1fdSJed Brown   Mat            sub;
666d8588912SDave May 
667d8588912SDave May   PetscFunctionBegin;
668f349c1fdSJed Brown   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
669ce94432eSBarry Smith   if (*B != sub) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has not been gotten");
670f349c1fdSJed Brown   if (sub) {
671ce94432eSBarry Smith     if (((PetscObject)sub)->refct <= 1) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has had reference count decremented too many times");
6726bf464f9SBarry Smith     ierr = MatDestroy(B);CHKERRQ(ierr);
673d8588912SDave May   }
674d8588912SDave May   PetscFunctionReturn(0);
675d8588912SDave May }
676d8588912SDave May 
6777874fa86SDave May static PetscErrorCode MatGetDiagonal_Nest(Mat A,Vec v)
6787874fa86SDave May {
6797874fa86SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
6807874fa86SDave May   PetscInt       i;
6817874fa86SDave May   PetscErrorCode ierr;
6827874fa86SDave May 
6837874fa86SDave May   PetscFunctionBegin;
6847874fa86SDave May   for (i=0; i<bA->nr; i++) {
685429bac76SJed Brown     Vec bv;
686429bac76SJed Brown     ierr = VecGetSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
6877874fa86SDave May     if (bA->m[i][i]) {
688429bac76SJed Brown       ierr = MatGetDiagonal(bA->m[i][i],bv);CHKERRQ(ierr);
6897874fa86SDave May     } else {
6905159a857SMatthew G. Knepley       ierr = VecSet(bv,0.0);CHKERRQ(ierr);
6917874fa86SDave May     }
692429bac76SJed Brown     ierr = VecRestoreSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
6937874fa86SDave May   }
6947874fa86SDave May   PetscFunctionReturn(0);
6957874fa86SDave May }
6967874fa86SDave May 
6977874fa86SDave May static PetscErrorCode MatDiagonalScale_Nest(Mat A,Vec l,Vec r)
6987874fa86SDave May {
6997874fa86SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
700429bac76SJed Brown   Vec            bl,*br;
7017874fa86SDave May   PetscInt       i,j;
7027874fa86SDave May   PetscErrorCode ierr;
7037874fa86SDave May 
7047874fa86SDave May   PetscFunctionBegin;
7053f800ebeSJed Brown   ierr = PetscCalloc1(bA->nc,&br);CHKERRQ(ierr);
7062e6472ebSElliott Sales de Andrade   if (r) {
707429bac76SJed Brown     for (j=0; j<bA->nc; j++) {ierr = VecGetSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);}
7082e6472ebSElliott Sales de Andrade   }
7092e6472ebSElliott Sales de Andrade   bl = NULL;
7107874fa86SDave May   for (i=0; i<bA->nr; i++) {
7112e6472ebSElliott Sales de Andrade     if (l) {
712429bac76SJed Brown       ierr = VecGetSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr);
7132e6472ebSElliott Sales de Andrade     }
7147874fa86SDave May     for (j=0; j<bA->nc; j++) {
7157874fa86SDave May       if (bA->m[i][j]) {
716429bac76SJed Brown         ierr = MatDiagonalScale(bA->m[i][j],bl,br[j]);CHKERRQ(ierr);
7177874fa86SDave May       }
7187874fa86SDave May     }
7192e6472ebSElliott Sales de Andrade     if (l) {
720a061e289SJed Brown       ierr = VecRestoreSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr);
7217874fa86SDave May     }
7222e6472ebSElliott Sales de Andrade   }
7232e6472ebSElliott Sales de Andrade   if (r) {
724429bac76SJed Brown     for (j=0; j<bA->nc; j++) {ierr = VecRestoreSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);}
7252e6472ebSElliott Sales de Andrade   }
726429bac76SJed Brown   ierr = PetscFree(br);CHKERRQ(ierr);
7277874fa86SDave May   PetscFunctionReturn(0);
7287874fa86SDave May }
7297874fa86SDave May 
730a061e289SJed Brown static PetscErrorCode MatScale_Nest(Mat A,PetscScalar a)
731a061e289SJed Brown {
732a061e289SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
733a061e289SJed Brown   PetscInt       i,j;
734a061e289SJed Brown   PetscErrorCode ierr;
735a061e289SJed Brown 
736a061e289SJed Brown   PetscFunctionBegin;
737a061e289SJed Brown   for (i=0; i<bA->nr; i++) {
738a061e289SJed Brown     for (j=0; j<bA->nc; j++) {
739a061e289SJed Brown       if (bA->m[i][j]) {
740a061e289SJed Brown         ierr = MatScale(bA->m[i][j],a);CHKERRQ(ierr);
741a061e289SJed Brown       }
742a061e289SJed Brown     }
743a061e289SJed Brown   }
744a061e289SJed Brown   PetscFunctionReturn(0);
745a061e289SJed Brown }
746a061e289SJed Brown 
747a061e289SJed Brown static PetscErrorCode MatShift_Nest(Mat A,PetscScalar a)
748a061e289SJed Brown {
749a061e289SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
750a061e289SJed Brown   PetscInt       i;
751a061e289SJed Brown   PetscErrorCode ierr;
75206a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
753a061e289SJed Brown 
754a061e289SJed Brown   PetscFunctionBegin;
755a061e289SJed Brown   for (i=0; i<bA->nr; i++) {
75606a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
757ce94432eSBarry 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);
758a061e289SJed Brown     ierr = MatShift(bA->m[i][i],a);CHKERRQ(ierr);
75906a1af2fSStefano Zampini     ierr = MatGetNonzeroState(bA->m[i][i],&subnnzstate);CHKERRQ(ierr);
76006a1af2fSStefano Zampini     nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i*bA->nc+i] != subnnzstate);
76106a1af2fSStefano Zampini     bA->nnzstate[i*bA->nc+i] = subnnzstate;
762a061e289SJed Brown   }
76306a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
764a061e289SJed Brown   PetscFunctionReturn(0);
765a061e289SJed Brown }
766a061e289SJed Brown 
76713135bc6SAlex Fikl static PetscErrorCode MatDiagonalSet_Nest(Mat A,Vec D,InsertMode is)
76813135bc6SAlex Fikl {
76913135bc6SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data;
77013135bc6SAlex Fikl   PetscInt       i;
77113135bc6SAlex Fikl   PetscErrorCode ierr;
77206a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
77313135bc6SAlex Fikl 
77413135bc6SAlex Fikl   PetscFunctionBegin;
77513135bc6SAlex Fikl   for (i=0; i<bA->nr; i++) {
77606a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
77713135bc6SAlex Fikl     Vec              bv;
77813135bc6SAlex Fikl     ierr = VecGetSubVector(D,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
77913135bc6SAlex Fikl     if (bA->m[i][i]) {
78013135bc6SAlex Fikl       ierr = MatDiagonalSet(bA->m[i][i],bv,is);CHKERRQ(ierr);
78106a1af2fSStefano Zampini       ierr = MatGetNonzeroState(bA->m[i][i],&subnnzstate);CHKERRQ(ierr);
78213135bc6SAlex Fikl     }
78313135bc6SAlex Fikl     ierr = VecRestoreSubVector(D,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
78406a1af2fSStefano Zampini     nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i*bA->nc+i] != subnnzstate);
78506a1af2fSStefano Zampini     bA->nnzstate[i*bA->nc+i] = subnnzstate;
78613135bc6SAlex Fikl   }
78706a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
78813135bc6SAlex Fikl   PetscFunctionReturn(0);
78913135bc6SAlex Fikl }
79013135bc6SAlex Fikl 
791f8170845SAlex Fikl static PetscErrorCode MatSetRandom_Nest(Mat A,PetscRandom rctx)
792f8170845SAlex Fikl {
793f8170845SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data;
794f8170845SAlex Fikl   PetscInt       i,j;
795f8170845SAlex Fikl   PetscErrorCode ierr;
796f8170845SAlex Fikl 
797f8170845SAlex Fikl   PetscFunctionBegin;
798f8170845SAlex Fikl   for (i=0; i<bA->nr; i++) {
799f8170845SAlex Fikl     for (j=0; j<bA->nc; j++) {
800f8170845SAlex Fikl       if (bA->m[i][j]) {
801f8170845SAlex Fikl         ierr = MatSetRandom(bA->m[i][j],rctx);CHKERRQ(ierr);
802f8170845SAlex Fikl       }
803f8170845SAlex Fikl     }
804f8170845SAlex Fikl   }
805f8170845SAlex Fikl   PetscFunctionReturn(0);
806f8170845SAlex Fikl }
807f8170845SAlex Fikl 
8082a7a6963SBarry Smith static PetscErrorCode MatCreateVecs_Nest(Mat A,Vec *right,Vec *left)
809d8588912SDave May {
810d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
811d8588912SDave May   Vec            *L,*R;
812d8588912SDave May   MPI_Comm       comm;
813d8588912SDave May   PetscInt       i,j;
814d8588912SDave May   PetscErrorCode ierr;
815d8588912SDave May 
816d8588912SDave May   PetscFunctionBegin;
817ce94432eSBarry Smith   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
818d8588912SDave May   if (right) {
819d8588912SDave May     /* allocate R */
820854ce69bSBarry Smith     ierr = PetscMalloc1(bA->nc, &R);CHKERRQ(ierr);
821d8588912SDave May     /* Create the right vectors */
822d8588912SDave May     for (j=0; j<bA->nc; j++) {
823d8588912SDave May       for (i=0; i<bA->nr; i++) {
824d8588912SDave May         if (bA->m[i][j]) {
8252a7a6963SBarry Smith           ierr = MatCreateVecs(bA->m[i][j],&R[j],NULL);CHKERRQ(ierr);
826d8588912SDave May           break;
827d8588912SDave May         }
828d8588912SDave May       }
8296c4ed002SBarry Smith       if (i==bA->nr) SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
830d8588912SDave May     }
831f349c1fdSJed Brown     ierr = VecCreateNest(comm,bA->nc,bA->isglobal.col,R,right);CHKERRQ(ierr);
832d8588912SDave May     /* hand back control to the nest vector */
833d8588912SDave May     for (j=0; j<bA->nc; j++) {
8346bf464f9SBarry Smith       ierr = VecDestroy(&R[j]);CHKERRQ(ierr);
835d8588912SDave May     }
836d8588912SDave May     ierr = PetscFree(R);CHKERRQ(ierr);
837d8588912SDave May   }
838d8588912SDave May 
839d8588912SDave May   if (left) {
840d8588912SDave May     /* allocate L */
841854ce69bSBarry Smith     ierr = PetscMalloc1(bA->nr, &L);CHKERRQ(ierr);
842d8588912SDave May     /* Create the left vectors */
843d8588912SDave May     for (i=0; i<bA->nr; i++) {
844d8588912SDave May       for (j=0; j<bA->nc; j++) {
845d8588912SDave May         if (bA->m[i][j]) {
8462a7a6963SBarry Smith           ierr = MatCreateVecs(bA->m[i][j],NULL,&L[i]);CHKERRQ(ierr);
847d8588912SDave May           break;
848d8588912SDave May         }
849d8588912SDave May       }
8506c4ed002SBarry Smith       if (j==bA->nc) SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
851d8588912SDave May     }
852d8588912SDave May 
853f349c1fdSJed Brown     ierr = VecCreateNest(comm,bA->nr,bA->isglobal.row,L,left);CHKERRQ(ierr);
854d8588912SDave May     for (i=0; i<bA->nr; i++) {
8556bf464f9SBarry Smith       ierr = VecDestroy(&L[i]);CHKERRQ(ierr);
856d8588912SDave May     }
857d8588912SDave May 
858d8588912SDave May     ierr = PetscFree(L);CHKERRQ(ierr);
859d8588912SDave May   }
860d8588912SDave May   PetscFunctionReturn(0);
861d8588912SDave May }
862d8588912SDave May 
863207556f9SJed Brown static PetscErrorCode MatView_Nest(Mat A,PetscViewer viewer)
864d8588912SDave May {
865d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
86629e60adbSStefano Zampini   PetscBool      isascii,viewSub = PETSC_FALSE;
867d8588912SDave May   PetscInt       i,j;
868d8588912SDave May   PetscErrorCode ierr;
869d8588912SDave May 
870d8588912SDave May   PetscFunctionBegin;
871251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
872d8588912SDave May   if (isascii) {
873d8588912SDave May 
87429e60adbSStefano Zampini     ierr = PetscOptionsGetBool(((PetscObject)A)->options,((PetscObject)A)->prefix,"-mat_view_nest_sub",&viewSub,NULL);CHKERRQ(ierr);
875d86155a6SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"Matrix object: \n");CHKERRQ(ierr);
876d86155a6SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
877d86155a6SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer, "type=nest, rows=%D, cols=%D \n",bA->nr,bA->nc);CHKERRQ(ierr);
878d8588912SDave May 
879d86155a6SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"MatNest structure: \n");CHKERRQ(ierr);
880d8588912SDave May     for (i=0; i<bA->nr; i++) {
881d8588912SDave May       for (j=0; j<bA->nc; j++) {
88219fd82e9SBarry Smith         MatType   type;
883270f95d7SJed Brown         char      name[256] = "",prefix[256] = "";
884d8588912SDave May         PetscInt  NR,NC;
885d8588912SDave May         PetscBool isNest = PETSC_FALSE;
886d8588912SDave May 
887d8588912SDave May         if (!bA->m[i][j]) {
888d86155a6SBarry Smith           CHKERRQ(ierr);PetscViewerASCIIPrintf(viewer, "(%D,%D) : NULL \n",i,j);CHKERRQ(ierr);
889d8588912SDave May           continue;
890d8588912SDave May         }
891d8588912SDave May         ierr = MatGetSize(bA->m[i][j],&NR,&NC);CHKERRQ(ierr);
892d8588912SDave May         ierr = MatGetType(bA->m[i][j], &type);CHKERRQ(ierr);
8938caf3d72SBarry Smith         if (((PetscObject)bA->m[i][j])->name) {ierr = PetscSNPrintf(name,sizeof(name),"name=\"%s\", ",((PetscObject)bA->m[i][j])->name);CHKERRQ(ierr);}
8948caf3d72SBarry Smith         if (((PetscObject)bA->m[i][j])->prefix) {ierr = PetscSNPrintf(prefix,sizeof(prefix),"prefix=\"%s\", ",((PetscObject)bA->m[i][j])->prefix);CHKERRQ(ierr);}
895251f4c67SDmitry Karpeev         ierr = PetscObjectTypeCompare((PetscObject)bA->m[i][j],MATNEST,&isNest);CHKERRQ(ierr);
896d8588912SDave May 
897270f95d7SJed Brown         ierr = PetscViewerASCIIPrintf(viewer,"(%D,%D) : %s%stype=%s, rows=%D, cols=%D \n",i,j,name,prefix,type,NR,NC);CHKERRQ(ierr);
898d8588912SDave May 
89929e60adbSStefano Zampini         if (isNest || viewSub) {
900270f95d7SJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);  /* push1 */
901d8588912SDave May           ierr = MatView(bA->m[i][j],viewer);CHKERRQ(ierr);
902270f95d7SJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);    /* pop1 */
903d8588912SDave May         }
904d8588912SDave May       }
905d8588912SDave May     }
906d86155a6SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);    /* pop0 */
907d8588912SDave May   }
908d8588912SDave May   PetscFunctionReturn(0);
909d8588912SDave May }
910d8588912SDave May 
911207556f9SJed Brown static PetscErrorCode MatZeroEntries_Nest(Mat A)
912d8588912SDave May {
913d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
914d8588912SDave May   PetscInt       i,j;
915d8588912SDave May   PetscErrorCode ierr;
916d8588912SDave May 
917d8588912SDave May   PetscFunctionBegin;
918d8588912SDave May   for (i=0; i<bA->nr; i++) {
919d8588912SDave May     for (j=0; j<bA->nc; j++) {
920d8588912SDave May       if (!bA->m[i][j]) continue;
921d8588912SDave May       ierr = MatZeroEntries(bA->m[i][j]);CHKERRQ(ierr);
922d8588912SDave May     }
923d8588912SDave May   }
924d8588912SDave May   PetscFunctionReturn(0);
925d8588912SDave May }
926d8588912SDave May 
927c222c20dSDavid Ham static PetscErrorCode MatCopy_Nest(Mat A,Mat B,MatStructure str)
928c222c20dSDavid Ham {
929c222c20dSDavid Ham   Mat_Nest       *bA = (Mat_Nest*)A->data,*bB = (Mat_Nest*)B->data;
930c222c20dSDavid Ham   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
931c222c20dSDavid Ham   PetscErrorCode ierr;
93206a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
933c222c20dSDavid Ham 
934c222c20dSDavid Ham   PetscFunctionBegin;
935c222c20dSDavid 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);
936c222c20dSDavid Ham   for (i=0; i<nr; i++) {
937c222c20dSDavid Ham     for (j=0; j<nc; j++) {
93806a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
93946a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
940c222c20dSDavid Ham         ierr = MatCopy(bA->m[i][j],bB->m[i][j],str);CHKERRQ(ierr);
94146a2b97cSJed 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);
94206a1af2fSStefano Zampini       ierr = MatGetNonzeroState(bB->m[i][j],&subnnzstate);CHKERRQ(ierr);
94306a1af2fSStefano Zampini       nnzstate = (PetscBool)(nnzstate || bB->nnzstate[i*nc+j] != subnnzstate);
94406a1af2fSStefano Zampini       bB->nnzstate[i*nc+j] = subnnzstate;
945c222c20dSDavid Ham     }
946c222c20dSDavid Ham   }
94706a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
948c222c20dSDavid Ham   PetscFunctionReturn(0);
949c222c20dSDavid Ham }
950c222c20dSDavid Ham 
9516e76ffeaSPierre Jolivet static PetscErrorCode MatAXPY_Nest(Mat Y,PetscScalar a,Mat X,MatStructure str)
9526e76ffeaSPierre Jolivet {
9536e76ffeaSPierre Jolivet   Mat_Nest       *bY = (Mat_Nest*)Y->data,*bX = (Mat_Nest*)X->data;
9546e76ffeaSPierre Jolivet   PetscInt       i,j,nr = bY->nr,nc = bY->nc;
9556e76ffeaSPierre Jolivet   PetscErrorCode ierr;
95606a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
9576e76ffeaSPierre Jolivet 
9586e76ffeaSPierre Jolivet   PetscFunctionBegin;
9596e76ffeaSPierre 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);
9606e76ffeaSPierre Jolivet   for (i=0; i<nr; i++) {
9616e76ffeaSPierre Jolivet     for (j=0; j<nc; j++) {
96206a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
9636e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
9646e76ffeaSPierre Jolivet         ierr = MatAXPY(bY->m[i][j],a,bX->m[i][j],str);CHKERRQ(ierr);
965c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
966c066aebcSStefano Zampini         Mat M;
967c066aebcSStefano Zampini 
968060bfc19SStefano Zampini         if (str != DIFFERENT_NONZERO_PATTERN) SETERRQ2(PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Matrix block does not exist at %D,%D. Use DIFFERENT_NONZERO_PATTERN",i,j);
969c066aebcSStefano Zampini         ierr = MatDuplicate(bX->m[i][j],MAT_COPY_VALUES,&M);CHKERRQ(ierr);
970c066aebcSStefano Zampini         ierr = MatNestSetSubMat(Y,i,j,M);CHKERRQ(ierr);
971c066aebcSStefano Zampini         ierr = MatDestroy(&M);CHKERRQ(ierr);
972c066aebcSStefano Zampini       }
973060bfc19SStefano Zampini       if (bY->m[i][j]) { ierr = MatGetNonzeroState(bY->m[i][j],&subnnzstate);CHKERRQ(ierr); }
97406a1af2fSStefano Zampini       nnzstate = (PetscBool)(nnzstate || bY->nnzstate[i*nc+j] != subnnzstate);
97506a1af2fSStefano Zampini       bY->nnzstate[i*nc+j] = subnnzstate;
9766e76ffeaSPierre Jolivet     }
9776e76ffeaSPierre Jolivet   }
97806a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
9796e76ffeaSPierre Jolivet   PetscFunctionReturn(0);
9806e76ffeaSPierre Jolivet }
9816e76ffeaSPierre Jolivet 
982207556f9SJed Brown static PetscErrorCode MatDuplicate_Nest(Mat A,MatDuplicateOption op,Mat *B)
983d8588912SDave May {
984d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
985841e96a3SJed Brown   Mat            *b;
986841e96a3SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
987d8588912SDave May   PetscErrorCode ierr;
988d8588912SDave May 
989d8588912SDave May   PetscFunctionBegin;
990785e854fSJed Brown   ierr = PetscMalloc1(nr*nc,&b);CHKERRQ(ierr);
991841e96a3SJed Brown   for (i=0; i<nr; i++) {
992841e96a3SJed Brown     for (j=0; j<nc; j++) {
993841e96a3SJed Brown       if (bA->m[i][j]) {
994841e96a3SJed Brown         ierr = MatDuplicate(bA->m[i][j],op,&b[i*nc+j]);CHKERRQ(ierr);
995841e96a3SJed Brown       } else {
9960298fd71SBarry Smith         b[i*nc+j] = NULL;
997d8588912SDave May       }
998d8588912SDave May     }
999d8588912SDave May   }
1000ce94432eSBarry Smith   ierr = MatCreateNest(PetscObjectComm((PetscObject)A),nr,bA->isglobal.row,nc,bA->isglobal.col,b,B);CHKERRQ(ierr);
1001841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
1002841e96a3SJed Brown   for (i=0; i<nr*nc; i++) {
10036bf464f9SBarry Smith     ierr = MatDestroy(&b[i]);CHKERRQ(ierr);
1004d8588912SDave May   }
1005d8588912SDave May   ierr = PetscFree(b);CHKERRQ(ierr);
1006d8588912SDave May 
1007841e96a3SJed Brown   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1008841e96a3SJed Brown   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1009d8588912SDave May   PetscFunctionReturn(0);
1010d8588912SDave May }
1011d8588912SDave May 
1012d8588912SDave May /* nest api */
1013d8588912SDave May PetscErrorCode MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat *mat)
1014d8588912SDave May {
1015d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
10165fd66863SKarl Rupp 
1017d8588912SDave May   PetscFunctionBegin;
1018ce94432eSBarry Smith   if (idxm >= bA->nr) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
1019ce94432eSBarry Smith   if (jdxm >= bA->nc) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
1020d8588912SDave May   *mat = bA->m[idxm][jdxm];
1021d8588912SDave May   PetscFunctionReturn(0);
1022d8588912SDave May }
1023d8588912SDave May 
10249ba0d327SJed Brown /*@
1025d8588912SDave May  MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix.
1026d8588912SDave May 
1027d8588912SDave May  Not collective
1028d8588912SDave May 
1029d8588912SDave May  Input Parameters:
1030629881c0SJed Brown +   A  - nest matrix
1031d8588912SDave May .   idxm - index of the matrix within the nest matrix
1032629881c0SJed Brown -   jdxm - index of the matrix within the nest matrix
1033d8588912SDave May 
1034d8588912SDave May  Output Parameter:
1035d8588912SDave May .   sub - matrix at index idxm,jdxm within the nest matrix
1036d8588912SDave May 
1037d8588912SDave May  Level: developer
1038d8588912SDave May 
103979798668SBarry Smith .seealso: MatNestGetSize(), MatNestGetSubMats(), MatNestCreate(), MATNEST, MatNestSetSubMat(),
104079798668SBarry Smith           MatNestGetLocalISs(), MatNestGetISs()
1041d8588912SDave May @*/
10427087cfbeSBarry Smith PetscErrorCode  MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat *sub)
1043d8588912SDave May {
1044699a902aSJed Brown   PetscErrorCode ierr;
1045d8588912SDave May 
1046d8588912SDave May   PetscFunctionBegin;
1047699a902aSJed Brown   ierr = PetscUseMethod(A,"MatNestGetSubMat_C",(Mat,PetscInt,PetscInt,Mat*),(A,idxm,jdxm,sub));CHKERRQ(ierr);
1048d8588912SDave May   PetscFunctionReturn(0);
1049d8588912SDave May }
1050d8588912SDave May 
10510782ca92SJed Brown PetscErrorCode MatNestSetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat mat)
10520782ca92SJed Brown {
10530782ca92SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
10540782ca92SJed Brown   PetscInt       m,n,M,N,mi,ni,Mi,Ni;
10550782ca92SJed Brown   PetscErrorCode ierr;
10560782ca92SJed Brown 
10570782ca92SJed Brown   PetscFunctionBegin;
1058ce94432eSBarry Smith   if (idxm >= bA->nr) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
1059ce94432eSBarry Smith   if (jdxm >= bA->nc) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
10600782ca92SJed Brown   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
10610782ca92SJed Brown   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
10620782ca92SJed Brown   ierr = ISGetLocalSize(bA->isglobal.row[idxm],&mi);CHKERRQ(ierr);
10630782ca92SJed Brown   ierr = ISGetSize(bA->isglobal.row[idxm],&Mi);CHKERRQ(ierr);
10640782ca92SJed Brown   ierr = ISGetLocalSize(bA->isglobal.col[jdxm],&ni);CHKERRQ(ierr);
10650782ca92SJed Brown   ierr = ISGetSize(bA->isglobal.col[jdxm],&Ni);CHKERRQ(ierr);
1066ce94432eSBarry 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);
1067ce94432eSBarry 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);
106826fbe8dcSKarl Rupp 
106906a1af2fSStefano Zampini   /* do not increase object state */
107006a1af2fSStefano Zampini   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(0);
107106a1af2fSStefano Zampini 
10720782ca92SJed Brown   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
10730782ca92SJed Brown   ierr = MatDestroy(&bA->m[idxm][jdxm]);CHKERRQ(ierr);
10740782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
107506a1af2fSStefano Zampini   ierr = PetscObjectStateIncrease((PetscObject)A);CHKERRQ(ierr);
107606a1af2fSStefano Zampini   ierr = MatGetNonzeroState(mat,&bA->nnzstate[idxm*bA->nc+jdxm]);CHKERRQ(ierr);
107706a1af2fSStefano Zampini   A->nonzerostate++;
10780782ca92SJed Brown   PetscFunctionReturn(0);
10790782ca92SJed Brown }
10800782ca92SJed Brown 
10819ba0d327SJed Brown /*@
10820782ca92SJed Brown  MatNestSetSubMat - Set a single submatrix in the nest matrix.
10830782ca92SJed Brown 
10840782ca92SJed Brown  Logically collective on the submatrix communicator
10850782ca92SJed Brown 
10860782ca92SJed Brown  Input Parameters:
10870782ca92SJed Brown +   A  - nest matrix
10880782ca92SJed Brown .   idxm - index of the matrix within the nest matrix
10890782ca92SJed Brown .   jdxm - index of the matrix within the nest matrix
10900782ca92SJed Brown -   sub - matrix at index idxm,jdxm within the nest matrix
10910782ca92SJed Brown 
10920782ca92SJed Brown  Notes:
10930782ca92SJed Brown  The new submatrix must have the same size and communicator as that block of the nest.
10940782ca92SJed Brown 
10950782ca92SJed Brown  This increments the reference count of the submatrix.
10960782ca92SJed Brown 
10970782ca92SJed Brown  Level: developer
10980782ca92SJed Brown 
109979798668SBarry Smith .seealso: MatNestSetSubMats(), MatNestGetSubMats(), MatNestGetLocalISs(), MATNEST, MatNestCreate(),
110079798668SBarry Smith           MatNestGetSubMat(), MatNestGetISs(), MatNestGetSize()
11010782ca92SJed Brown @*/
11020782ca92SJed Brown PetscErrorCode  MatNestSetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat sub)
11030782ca92SJed Brown {
11040782ca92SJed Brown   PetscErrorCode ierr;
11050782ca92SJed Brown 
11060782ca92SJed Brown   PetscFunctionBegin;
11070782ca92SJed Brown   ierr = PetscUseMethod(A,"MatNestSetSubMat_C",(Mat,PetscInt,PetscInt,Mat),(A,idxm,jdxm,sub));CHKERRQ(ierr);
11080782ca92SJed Brown   PetscFunctionReturn(0);
11090782ca92SJed Brown }
11100782ca92SJed Brown 
1111d8588912SDave May PetscErrorCode MatNestGetSubMats_Nest(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
1112d8588912SDave May {
1113d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
11145fd66863SKarl Rupp 
1115d8588912SDave May   PetscFunctionBegin;
111626fbe8dcSKarl Rupp   if (M)   *M   = bA->nr;
111726fbe8dcSKarl Rupp   if (N)   *N   = bA->nc;
111826fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
1119d8588912SDave May   PetscFunctionReturn(0);
1120d8588912SDave May }
1121d8588912SDave May 
1122d8588912SDave May /*@C
1123d8588912SDave May  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix.
1124d8588912SDave May 
1125d8588912SDave May  Not collective
1126d8588912SDave May 
1127d8588912SDave May  Input Parameters:
1128629881c0SJed Brown .   A  - nest matrix
1129d8588912SDave May 
1130d8588912SDave May  Output Parameter:
1131629881c0SJed Brown +   M - number of rows in the nest matrix
1132d8588912SDave May .   N - number of cols in the nest matrix
1133629881c0SJed Brown -   mat - 2d array of matrices
1134d8588912SDave May 
1135d8588912SDave May  Notes:
1136d8588912SDave May 
1137d8588912SDave May  The user should not free the array mat.
1138d8588912SDave May 
1139351962e3SVincent Le Chenadec  In Fortran, this routine has a calling sequence
1140351962e3SVincent Le Chenadec $   call MatNestGetSubMats(A, M, N, mat, ierr)
1141351962e3SVincent Le Chenadec  where the space allocated for the optional argument mat is assumed large enough (if provided).
1142351962e3SVincent Le Chenadec 
1143d8588912SDave May  Level: developer
1144d8588912SDave May 
114579798668SBarry Smith .seealso: MatNestGetSize(), MatNestGetSubMat(), MatNestGetLocalISs(), MATNEST, MatNestCreate(),
114679798668SBarry Smith           MatNestSetSubMats(), MatNestGetISs(), MatNestSetSubMat()
1147d8588912SDave May @*/
11487087cfbeSBarry Smith PetscErrorCode  MatNestGetSubMats(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
1149d8588912SDave May {
1150699a902aSJed Brown   PetscErrorCode ierr;
1151d8588912SDave May 
1152d8588912SDave May   PetscFunctionBegin;
1153699a902aSJed Brown   ierr = PetscUseMethod(A,"MatNestGetSubMats_C",(Mat,PetscInt*,PetscInt*,Mat***),(A,M,N,mat));CHKERRQ(ierr);
1154d8588912SDave May   PetscFunctionReturn(0);
1155d8588912SDave May }
1156d8588912SDave May 
11577087cfbeSBarry Smith PetscErrorCode  MatNestGetSize_Nest(Mat A,PetscInt *M,PetscInt *N)
1158d8588912SDave May {
1159d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
1160d8588912SDave May 
1161d8588912SDave May   PetscFunctionBegin;
116226fbe8dcSKarl Rupp   if (M) *M = bA->nr;
116326fbe8dcSKarl Rupp   if (N) *N = bA->nc;
1164d8588912SDave May   PetscFunctionReturn(0);
1165d8588912SDave May }
1166d8588912SDave May 
11679ba0d327SJed Brown /*@
1168d8588912SDave May  MatNestGetSize - Returns the size of the nest matrix.
1169d8588912SDave May 
1170d8588912SDave May  Not collective
1171d8588912SDave May 
1172d8588912SDave May  Input Parameters:
1173d8588912SDave May .   A  - nest matrix
1174d8588912SDave May 
1175d8588912SDave May  Output Parameter:
1176629881c0SJed Brown +   M - number of rows in the nested mat
1177629881c0SJed Brown -   N - number of cols in the nested mat
1178d8588912SDave May 
1179d8588912SDave May  Notes:
1180d8588912SDave May 
1181d8588912SDave May  Level: developer
1182d8588912SDave May 
118379798668SBarry Smith .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MATNEST, MatNestCreate(), MatNestGetLocalISs(),
118479798668SBarry Smith           MatNestGetISs()
1185d8588912SDave May @*/
11867087cfbeSBarry Smith PetscErrorCode  MatNestGetSize(Mat A,PetscInt *M,PetscInt *N)
1187d8588912SDave May {
1188699a902aSJed Brown   PetscErrorCode ierr;
1189d8588912SDave May 
1190d8588912SDave May   PetscFunctionBegin;
1191699a902aSJed Brown   ierr = PetscUseMethod(A,"MatNestGetSize_C",(Mat,PetscInt*,PetscInt*),(A,M,N));CHKERRQ(ierr);
1192d8588912SDave May   PetscFunctionReturn(0);
1193d8588912SDave May }
1194d8588912SDave May 
1195f7a08781SBarry Smith static PetscErrorCode MatNestGetISs_Nest(Mat A,IS rows[],IS cols[])
1196900e7ff2SJed Brown {
1197900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest*)A->data;
1198900e7ff2SJed Brown   PetscInt i;
1199900e7ff2SJed Brown 
1200900e7ff2SJed Brown   PetscFunctionBegin;
1201900e7ff2SJed Brown   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->isglobal.row[i];
1202900e7ff2SJed Brown   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->isglobal.col[i];
1203900e7ff2SJed Brown   PetscFunctionReturn(0);
1204900e7ff2SJed Brown }
1205900e7ff2SJed Brown 
12063a4d7b9aSSatish Balay /*@C
1207900e7ff2SJed Brown  MatNestGetISs - Returns the index sets partitioning the row and column spaces
1208900e7ff2SJed Brown 
1209900e7ff2SJed Brown  Not collective
1210900e7ff2SJed Brown 
1211900e7ff2SJed Brown  Input Parameters:
1212900e7ff2SJed Brown .   A  - nest matrix
1213900e7ff2SJed Brown 
1214900e7ff2SJed Brown  Output Parameter:
1215900e7ff2SJed Brown +   rows - array of row index sets
1216900e7ff2SJed Brown -   cols - array of column index sets
1217900e7ff2SJed Brown 
1218900e7ff2SJed Brown  Level: advanced
1219900e7ff2SJed Brown 
1220900e7ff2SJed Brown  Notes:
1221900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1222900e7ff2SJed Brown 
122379798668SBarry Smith .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetLocalISs(), MATNEST,
122479798668SBarry Smith           MatNestCreate(), MatNestGetSubMats(), MatNestSetSubMats()
1225900e7ff2SJed Brown @*/
1226900e7ff2SJed Brown PetscErrorCode  MatNestGetISs(Mat A,IS rows[],IS cols[])
1227900e7ff2SJed Brown {
1228900e7ff2SJed Brown   PetscErrorCode ierr;
1229900e7ff2SJed Brown 
1230900e7ff2SJed Brown   PetscFunctionBegin;
1231900e7ff2SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1232900e7ff2SJed Brown   ierr = PetscUseMethod(A,"MatNestGetISs_C",(Mat,IS[],IS[]),(A,rows,cols));CHKERRQ(ierr);
1233900e7ff2SJed Brown   PetscFunctionReturn(0);
1234900e7ff2SJed Brown }
1235900e7ff2SJed Brown 
1236f7a08781SBarry Smith static PetscErrorCode MatNestGetLocalISs_Nest(Mat A,IS rows[],IS cols[])
1237900e7ff2SJed Brown {
1238900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest*)A->data;
1239900e7ff2SJed Brown   PetscInt i;
1240900e7ff2SJed Brown 
1241900e7ff2SJed Brown   PetscFunctionBegin;
1242900e7ff2SJed Brown   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->islocal.row[i];
1243900e7ff2SJed Brown   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->islocal.col[i];
1244900e7ff2SJed Brown   PetscFunctionReturn(0);
1245900e7ff2SJed Brown }
1246900e7ff2SJed Brown 
1247900e7ff2SJed Brown /*@C
1248900e7ff2SJed Brown  MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces
1249900e7ff2SJed Brown 
1250900e7ff2SJed Brown  Not collective
1251900e7ff2SJed Brown 
1252900e7ff2SJed Brown  Input Parameters:
1253900e7ff2SJed Brown .   A  - nest matrix
1254900e7ff2SJed Brown 
1255900e7ff2SJed Brown  Output Parameter:
12560298fd71SBarry Smith +   rows - array of row index sets (or NULL to ignore)
12570298fd71SBarry Smith -   cols - array of column index sets (or NULL to ignore)
1258900e7ff2SJed Brown 
1259900e7ff2SJed Brown  Level: advanced
1260900e7ff2SJed Brown 
1261900e7ff2SJed Brown  Notes:
1262900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1263900e7ff2SJed Brown 
126479798668SBarry Smith .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetISs(), MatNestCreate(),
126579798668SBarry Smith           MATNEST, MatNestSetSubMats(), MatNestSetSubMat()
1266900e7ff2SJed Brown @*/
1267900e7ff2SJed Brown PetscErrorCode  MatNestGetLocalISs(Mat A,IS rows[],IS cols[])
1268900e7ff2SJed Brown {
1269900e7ff2SJed Brown   PetscErrorCode ierr;
1270900e7ff2SJed Brown 
1271900e7ff2SJed Brown   PetscFunctionBegin;
1272900e7ff2SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1273900e7ff2SJed Brown   ierr = PetscUseMethod(A,"MatNestGetLocalISs_C",(Mat,IS[],IS[]),(A,rows,cols));CHKERRQ(ierr);
1274900e7ff2SJed Brown   PetscFunctionReturn(0);
1275900e7ff2SJed Brown }
1276900e7ff2SJed Brown 
127719fd82e9SBarry Smith PetscErrorCode  MatNestSetVecType_Nest(Mat A,VecType vtype)
1278207556f9SJed Brown {
1279207556f9SJed Brown   PetscErrorCode ierr;
1280207556f9SJed Brown   PetscBool      flg;
1281207556f9SJed Brown 
1282207556f9SJed Brown   PetscFunctionBegin;
1283207556f9SJed Brown   ierr = PetscStrcmp(vtype,VECNEST,&flg);CHKERRQ(ierr);
1284207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
12852a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
128612b53f24SSatish Balay   else A->ops->getvecs = (PetscErrorCode (*)(Mat,Vec*,Vec*)) 0;
1287207556f9SJed Brown   PetscFunctionReturn(0);
1288207556f9SJed Brown }
1289207556f9SJed Brown 
1290207556f9SJed Brown /*@C
12912a7a6963SBarry Smith  MatNestSetVecType - Sets the type of Vec returned by MatCreateVecs()
1292207556f9SJed Brown 
1293207556f9SJed Brown  Not collective
1294207556f9SJed Brown 
1295207556f9SJed Brown  Input Parameters:
1296207556f9SJed Brown +  A  - nest matrix
1297207556f9SJed Brown -  vtype - type to use for creating vectors
1298207556f9SJed Brown 
1299207556f9SJed Brown  Notes:
1300207556f9SJed Brown 
1301207556f9SJed Brown  Level: developer
1302207556f9SJed Brown 
130379798668SBarry Smith .seealso: MatCreateVecs(), MATNEST, MatNestCreate()
1304207556f9SJed Brown @*/
130519fd82e9SBarry Smith PetscErrorCode  MatNestSetVecType(Mat A,VecType vtype)
1306207556f9SJed Brown {
1307207556f9SJed Brown   PetscErrorCode ierr;
1308207556f9SJed Brown 
1309207556f9SJed Brown   PetscFunctionBegin;
131019fd82e9SBarry Smith   ierr = PetscTryMethod(A,"MatNestSetVecType_C",(Mat,VecType),(A,vtype));CHKERRQ(ierr);
1311207556f9SJed Brown   PetscFunctionReturn(0);
1312207556f9SJed Brown }
1313207556f9SJed Brown 
1314c8883902SJed Brown PetscErrorCode MatNestSetSubMats_Nest(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1315d8588912SDave May {
1316c8883902SJed Brown   Mat_Nest       *s = (Mat_Nest*)A->data;
1317c8883902SJed Brown   PetscInt       i,j,m,n,M,N;
1318d8588912SDave May   PetscErrorCode ierr;
131906a1af2fSStefano Zampini   PetscBool      cong;
1320d8588912SDave May 
1321d8588912SDave May   PetscFunctionBegin;
132206a1af2fSStefano Zampini   ierr = MatReset_Nest(A);CHKERRQ(ierr);
132306a1af2fSStefano Zampini 
1324c8883902SJed Brown   s->nr = nr;
1325c8883902SJed Brown   s->nc = nc;
1326d8588912SDave May 
1327c8883902SJed Brown   /* Create space for submatrices */
1328854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&s->m);CHKERRQ(ierr);
1329c8883902SJed Brown   for (i=0; i<nr; i++) {
1330854ce69bSBarry Smith     ierr = PetscMalloc1(nc,&s->m[i]);CHKERRQ(ierr);
1331d8588912SDave May   }
1332c8883902SJed Brown   for (i=0; i<nr; i++) {
1333c8883902SJed Brown     for (j=0; j<nc; j++) {
1334c8883902SJed Brown       s->m[i][j] = a[i*nc+j];
1335c8883902SJed Brown       if (a[i*nc+j]) {
1336c8883902SJed Brown         ierr = PetscObjectReference((PetscObject)a[i*nc+j]);CHKERRQ(ierr);
1337d8588912SDave May       }
1338d8588912SDave May     }
1339d8588912SDave May   }
1340d8588912SDave May 
13418188e55aSJed Brown   ierr = MatSetUp_NestIS_Private(A,nr,is_row,nc,is_col);CHKERRQ(ierr);
1342d8588912SDave May 
1343854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&s->row_len);CHKERRQ(ierr);
1344854ce69bSBarry Smith   ierr = PetscMalloc1(nc,&s->col_len);CHKERRQ(ierr);
1345c8883902SJed Brown   for (i=0; i<nr; i++) s->row_len[i]=-1;
1346c8883902SJed Brown   for (j=0; j<nc; j++) s->col_len[j]=-1;
1347d8588912SDave May 
134806a1af2fSStefano Zampini   ierr = PetscCalloc1(nr*nc,&s->nnzstate);CHKERRQ(ierr);
134906a1af2fSStefano Zampini   for (i=0; i<nr; i++) {
135006a1af2fSStefano Zampini     for (j=0; j<nc; j++) {
135106a1af2fSStefano Zampini       if (s->m[i][j]) {
135206a1af2fSStefano Zampini         ierr = MatGetNonzeroState(s->m[i][j],&s->nnzstate[i*nc+j]);CHKERRQ(ierr);
135306a1af2fSStefano Zampini       }
135406a1af2fSStefano Zampini     }
135506a1af2fSStefano Zampini   }
135606a1af2fSStefano Zampini 
13578188e55aSJed Brown   ierr = MatNestGetSizes_Private(A,&m,&n,&M,&N);CHKERRQ(ierr);
1358d8588912SDave May 
1359c8883902SJed Brown   ierr = PetscLayoutSetSize(A->rmap,M);CHKERRQ(ierr);
1360c8883902SJed Brown   ierr = PetscLayoutSetLocalSize(A->rmap,m);CHKERRQ(ierr);
1361c8883902SJed Brown   ierr = PetscLayoutSetSize(A->cmap,N);CHKERRQ(ierr);
1362c8883902SJed Brown   ierr = PetscLayoutSetLocalSize(A->cmap,n);CHKERRQ(ierr);
1363c8883902SJed Brown 
1364c8883902SJed Brown   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
1365c8883902SJed Brown   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
1366c8883902SJed Brown 
136706a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
136806a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
136906a1af2fSStefano Zampini   ierr = MatHasCongruentLayouts(A,&cong);CHKERRQ(ierr);
137006a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
137106a1af2fSStefano Zampini   if (cong) {
137206a1af2fSStefano Zampini     for (i = 0; cong && i < nr; i++) {
1373320466b0SStefano Zampini       ierr = ISEqualUnsorted(s->isglobal.row[i],s->isglobal.col[i],&cong);CHKERRQ(ierr);
137406a1af2fSStefano Zampini     }
137506a1af2fSStefano Zampini   }
137606a1af2fSStefano Zampini   if (!cong) {
1377*381b8e50SStefano Zampini     A->ops->missingdiagonal = NULL;
137806a1af2fSStefano Zampini     A->ops->getdiagonal     = NULL;
137906a1af2fSStefano Zampini     A->ops->shift           = NULL;
138006a1af2fSStefano Zampini     A->ops->diagonalset     = NULL;
138106a1af2fSStefano Zampini   }
138206a1af2fSStefano Zampini 
13831795a4d1SJed Brown   ierr = PetscCalloc2(nr,&s->left,nc,&s->right);CHKERRQ(ierr);
138406a1af2fSStefano Zampini   ierr = PetscObjectStateIncrease((PetscObject)A);CHKERRQ(ierr);
138506a1af2fSStefano Zampini   A->nonzerostate++;
1386d8588912SDave May   PetscFunctionReturn(0);
1387d8588912SDave May }
1388d8588912SDave May 
1389c8883902SJed Brown /*@
1390c8883902SJed Brown    MatNestSetSubMats - Sets the nested submatrices
1391c8883902SJed Brown 
1392c8883902SJed Brown    Collective on Mat
1393c8883902SJed Brown 
1394c8883902SJed Brown    Input Parameter:
1395ffd6319bSRichard Tran Mills +  A - nested matrix
1396c8883902SJed Brown .  nr - number of nested row blocks
13970298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1398c8883902SJed Brown .  nc - number of nested column blocks
13990298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
14000298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1401c8883902SJed Brown 
140206a1af2fSStefano Zampini    Notes: this always resets any submatrix information previously set
140306a1af2fSStefano Zampini 
1404c8883902SJed Brown    Level: advanced
1405c8883902SJed Brown 
140679798668SBarry Smith .seealso: MatCreateNest(), MATNEST, MatNestSetSubMat(), MatNestGetSubMat(), MatNestGetSubMats()
1407c8883902SJed Brown @*/
1408c8883902SJed Brown PetscErrorCode MatNestSetSubMats(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1409c8883902SJed Brown {
1410c8883902SJed Brown   PetscErrorCode ierr;
141106a1af2fSStefano Zampini   PetscInt       i;
1412c8883902SJed Brown 
1413c8883902SJed Brown   PetscFunctionBegin;
1414c8883902SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1415ce94432eSBarry Smith   if (nr < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of rows cannot be negative");
1416c8883902SJed Brown   if (nr && is_row) {
1417c8883902SJed Brown     PetscValidPointer(is_row,3);
1418c8883902SJed Brown     for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_row[i],IS_CLASSID,3);
1419c8883902SJed Brown   }
1420ce94432eSBarry Smith   if (nc < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of columns cannot be negative");
14211664e352SJed Brown   if (nc && is_col) {
1422c8883902SJed Brown     PetscValidPointer(is_col,5);
14239b30a8f6SBarry Smith     for (i=0; i<nc; i++) PetscValidHeaderSpecific(is_col[i],IS_CLASSID,5);
1424c8883902SJed Brown   }
142506a1af2fSStefano Zampini   if (nr*nc > 0) PetscValidPointer(a,6);
1426c8883902SJed 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);
1427c8883902SJed Brown   PetscFunctionReturn(0);
1428c8883902SJed Brown }
1429d8588912SDave May 
143045b6f7e9SBarry Smith static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A,PetscInt n,const IS islocal[],const IS isglobal[],PetscBool colflg,ISLocalToGlobalMapping *ltog)
143177019fcaSJed Brown {
143277019fcaSJed Brown   PetscErrorCode ierr;
143377019fcaSJed Brown   PetscBool      flg;
143477019fcaSJed Brown   PetscInt       i,j,m,mi,*ix;
143577019fcaSJed Brown 
143677019fcaSJed Brown   PetscFunctionBegin;
1437aea6d515SStefano Zampini   *ltog = NULL;
143877019fcaSJed Brown   for (i=0,m=0,flg=PETSC_FALSE; i<n; i++) {
143977019fcaSJed Brown     if (islocal[i]) {
1440aea6d515SStefano Zampini       ierr = ISGetLocalSize(islocal[i],&mi);CHKERRQ(ierr);
144177019fcaSJed Brown       flg  = PETSC_TRUE;      /* We found a non-trivial entry */
144277019fcaSJed Brown     } else {
1443aea6d515SStefano Zampini       ierr = ISGetLocalSize(isglobal[i],&mi);CHKERRQ(ierr);
144477019fcaSJed Brown     }
144577019fcaSJed Brown     m += mi;
144677019fcaSJed Brown   }
1447aea6d515SStefano Zampini   if (!flg) PetscFunctionReturn(0);
1448aea6d515SStefano Zampini 
1449785e854fSJed Brown   ierr = PetscMalloc1(m,&ix);CHKERRQ(ierr);
1450165cd838SBarry Smith   for (i=0,m=0; i<n; i++) {
14510298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1452e108cb99SStefano Zampini     Mat                    sub = NULL;
1453f6d38dbbSStefano Zampini     PetscSF                sf;
1454f6d38dbbSStefano Zampini     PetscLayout            map;
1455aea6d515SStefano Zampini     const PetscInt         *ix2;
145677019fcaSJed Brown 
1457165cd838SBarry Smith     if (!colflg) {
145877019fcaSJed Brown       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
145977019fcaSJed Brown     } else {
146077019fcaSJed Brown       ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
146177019fcaSJed Brown     }
1462191fd14bSBarry Smith     if (sub) {
1463191fd14bSBarry Smith       if (!colflg) {
1464191fd14bSBarry Smith         ierr = MatGetLocalToGlobalMapping(sub,&smap,NULL);CHKERRQ(ierr);
1465191fd14bSBarry Smith       } else {
1466191fd14bSBarry Smith         ierr = MatGetLocalToGlobalMapping(sub,NULL,&smap);CHKERRQ(ierr);
1467191fd14bSBarry Smith       }
1468191fd14bSBarry Smith     }
146977019fcaSJed Brown     /*
147077019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
147177019fcaSJed 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.
147277019fcaSJed Brown     */
1473aea6d515SStefano Zampini     ierr = ISGetIndices(isglobal[i],&ix2);CHKERRQ(ierr);
1474aea6d515SStefano Zampini     if (islocal[i]) {
1475aea6d515SStefano Zampini       PetscInt *ilocal,*iremote;
1476aea6d515SStefano Zampini       PetscInt mil,nleaves;
1477aea6d515SStefano Zampini 
1478aea6d515SStefano Zampini       ierr = ISGetLocalSize(islocal[i],&mi);CHKERRQ(ierr);
1479aea6d515SStefano Zampini       if (!smap) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing local to global map");
1480aea6d515SStefano Zampini       for (j=0; j<mi; j++) ix[m+j] = j;
1481aea6d515SStefano Zampini       ierr = ISLocalToGlobalMappingApply(smap,mi,ix+m,ix+m);CHKERRQ(ierr);
1482aea6d515SStefano Zampini 
1483aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
1484aea6d515SStefano Zampini       ierr = PetscMalloc2(mi,&ilocal,mi,&iremote);CHKERRQ(ierr);
1485aea6d515SStefano Zampini       for (j=0, nleaves = 0; j<mi; j++) {
1486aea6d515SStefano Zampini         if (ix[m+j] < 0) continue;
1487aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1488aea6d515SStefano Zampini         iremote[nleaves] = ix[m+j];
1489aea6d515SStefano Zampini         nleaves++;
1490aea6d515SStefano Zampini       }
1491aea6d515SStefano Zampini       ierr = ISGetLocalSize(isglobal[i],&mil);CHKERRQ(ierr);
1492aea6d515SStefano Zampini       ierr = PetscSFCreate(PetscObjectComm((PetscObject)A),&sf);CHKERRQ(ierr);
1493aea6d515SStefano Zampini       ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A),&map);CHKERRQ(ierr);
1494aea6d515SStefano Zampini       ierr = PetscLayoutSetLocalSize(map,mil);CHKERRQ(ierr);
1495f6d38dbbSStefano Zampini       ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
1496aea6d515SStefano Zampini       ierr = PetscSFSetGraphLayout(sf,map,nleaves,ilocal,PETSC_USE_POINTER,iremote);CHKERRQ(ierr);
1497f6d38dbbSStefano Zampini       ierr = PetscLayoutDestroy(&map);CHKERRQ(ierr);
1498f6d38dbbSStefano Zampini       ierr = PetscSFBcastBegin(sf,MPIU_INT,ix2,ix + m);CHKERRQ(ierr);
1499f6d38dbbSStefano Zampini       ierr = PetscSFBcastEnd(sf,MPIU_INT,ix2,ix + m);CHKERRQ(ierr);
1500f6d38dbbSStefano Zampini       ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
1501aea6d515SStefano Zampini       ierr = PetscFree2(ilocal,iremote);CHKERRQ(ierr);
1502aea6d515SStefano Zampini     } else {
1503aea6d515SStefano Zampini       ierr = ISGetLocalSize(isglobal[i],&mi);CHKERRQ(ierr);
1504aea6d515SStefano Zampini       for (j=0; j<mi; j++) ix[m+j] = ix2[i];
1505aea6d515SStefano Zampini     }
1506aea6d515SStefano Zampini     ierr = ISRestoreIndices(isglobal[i],&ix2);CHKERRQ(ierr);
150777019fcaSJed Brown     m   += mi;
150877019fcaSJed Brown   }
1509f0413b6fSBarry Smith   ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,m,ix,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
151077019fcaSJed Brown   PetscFunctionReturn(0);
151177019fcaSJed Brown }
151277019fcaSJed Brown 
151377019fcaSJed Brown 
1514d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1515d8588912SDave May /*
1516d8588912SDave May   nprocessors = NP
1517d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1518d8588912SDave May        proc 0: => (g_0,h_0,)
1519d8588912SDave May        proc 1: => (g_1,h_1,)
1520d8588912SDave May        ...
1521d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1522d8588912SDave May 
1523d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1524d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1525d8588912SDave May 
1526d8588912SDave May             proc 0:
1527d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1528d8588912SDave May             proc 1:
1529d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1530d8588912SDave May 
1531d8588912SDave May             proc NP-1:
1532d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1533d8588912SDave May */
1534841e96a3SJed Brown static PetscErrorCode MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[])
1535d8588912SDave May {
1536e2d7f03fSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
15378188e55aSJed Brown   PetscInt       i,j,offset,n,nsum,bs;
1538d8588912SDave May   PetscErrorCode ierr;
15390298fd71SBarry Smith   Mat            sub = NULL;
1540d8588912SDave May 
1541d8588912SDave May   PetscFunctionBegin;
1542854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&vs->isglobal.row);CHKERRQ(ierr);
1543854ce69bSBarry Smith   ierr = PetscMalloc1(nc,&vs->isglobal.col);CHKERRQ(ierr);
1544d8588912SDave May   if (is_row) { /* valid IS is passed in */
1545d8588912SDave May     /* refs on is[] are incremeneted */
1546e2d7f03fSJed Brown     for (i=0; i<vs->nr; i++) {
1547d8588912SDave May       ierr = PetscObjectReference((PetscObject)is_row[i]);CHKERRQ(ierr);
154826fbe8dcSKarl Rupp 
1549e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1550d8588912SDave May     }
15512ae74bdbSJed Brown   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each row */
15528188e55aSJed Brown     nsum = 0;
15538188e55aSJed Brown     for (i=0; i<vs->nr; i++) {  /* Add up the local sizes to compute the aggregate offset */
15548188e55aSJed Brown       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1555ce94432eSBarry Smith       if (!sub) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %D",i);
15560298fd71SBarry Smith       ierr = MatGetLocalSize(sub,&n,NULL);CHKERRQ(ierr);
1557ce94432eSBarry Smith       if (n < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
15588188e55aSJed Brown       nsum += n;
15598188e55aSJed Brown     }
1560ce94432eSBarry Smith     ierr    = MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
156130bc264bSJed Brown     offset -= nsum;
1562e2d7f03fSJed Brown     for (i=0; i<vs->nr; i++) {
1563f349c1fdSJed Brown       ierr    = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
15640298fd71SBarry Smith       ierr    = MatGetLocalSize(sub,&n,NULL);CHKERRQ(ierr);
15652ae74bdbSJed Brown       ierr    = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1566ce94432eSBarry Smith       ierr    = ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.row[i]);CHKERRQ(ierr);
1567e2d7f03fSJed Brown       ierr    = ISSetBlockSize(vs->isglobal.row[i],bs);CHKERRQ(ierr);
15682ae74bdbSJed Brown       offset += n;
1569d8588912SDave May     }
1570d8588912SDave May   }
1571d8588912SDave May 
1572d8588912SDave May   if (is_col) { /* valid IS is passed in */
1573d8588912SDave May     /* refs on is[] are incremeneted */
1574e2d7f03fSJed Brown     for (j=0; j<vs->nc; j++) {
1575d8588912SDave May       ierr = PetscObjectReference((PetscObject)is_col[j]);CHKERRQ(ierr);
157626fbe8dcSKarl Rupp 
1577e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1578d8588912SDave May     }
15792ae74bdbSJed Brown   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each column */
15802ae74bdbSJed Brown     offset = A->cmap->rstart;
15818188e55aSJed Brown     nsum   = 0;
15828188e55aSJed Brown     for (j=0; j<vs->nc; j++) {
15838188e55aSJed Brown       ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
1584ce94432eSBarry Smith       if (!sub) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %D",i);
15850298fd71SBarry Smith       ierr = MatGetLocalSize(sub,NULL,&n);CHKERRQ(ierr);
1586ce94432eSBarry Smith       if (n < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
15878188e55aSJed Brown       nsum += n;
15888188e55aSJed Brown     }
1589ce94432eSBarry Smith     ierr    = MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A));CHKERRQ(ierr);
159030bc264bSJed Brown     offset -= nsum;
1591e2d7f03fSJed Brown     for (j=0; j<vs->nc; j++) {
1592f349c1fdSJed Brown       ierr    = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
15930298fd71SBarry Smith       ierr    = MatGetLocalSize(sub,NULL,&n);CHKERRQ(ierr);
15942ae74bdbSJed Brown       ierr    = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1595ce94432eSBarry Smith       ierr    = ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.col[j]);CHKERRQ(ierr);
1596e2d7f03fSJed Brown       ierr    = ISSetBlockSize(vs->isglobal.col[j],bs);CHKERRQ(ierr);
15972ae74bdbSJed Brown       offset += n;
1598d8588912SDave May     }
1599d8588912SDave May   }
1600e2d7f03fSJed Brown 
1601e2d7f03fSJed Brown   /* Set up the local ISs */
1602785e854fSJed Brown   ierr = PetscMalloc1(vs->nr,&vs->islocal.row);CHKERRQ(ierr);
1603785e854fSJed Brown   ierr = PetscMalloc1(vs->nc,&vs->islocal.col);CHKERRQ(ierr);
1604e2d7f03fSJed Brown   for (i=0,offset=0; i<vs->nr; i++) {
1605e2d7f03fSJed Brown     IS                     isloc;
16060298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1607e2d7f03fSJed Brown     PetscInt               nlocal,bs;
1608e2d7f03fSJed Brown     ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
16090298fd71SBarry Smith     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,&rmap,NULL);CHKERRQ(ierr);}
1610207556f9SJed Brown     if (rmap) {
1611e2d7f03fSJed Brown       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1612e2d7f03fSJed Brown       ierr = ISLocalToGlobalMappingGetSize(rmap,&nlocal);CHKERRQ(ierr);
1613e2d7f03fSJed Brown       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1614e2d7f03fSJed Brown       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1615207556f9SJed Brown     } else {
1616207556f9SJed Brown       nlocal = 0;
16170298fd71SBarry Smith       isloc  = NULL;
1618207556f9SJed Brown     }
1619e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1620e2d7f03fSJed Brown     offset            += nlocal;
1621e2d7f03fSJed Brown   }
16228188e55aSJed Brown   for (i=0,offset=0; i<vs->nc; i++) {
1623e2d7f03fSJed Brown     IS                     isloc;
16240298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1625e2d7f03fSJed Brown     PetscInt               nlocal,bs;
1626e2d7f03fSJed Brown     ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
16270298fd71SBarry Smith     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,NULL,&cmap);CHKERRQ(ierr);}
1628207556f9SJed Brown     if (cmap) {
1629e2d7f03fSJed Brown       ierr = MatGetBlockSize(sub,&bs);CHKERRQ(ierr);
1630e2d7f03fSJed Brown       ierr = ISLocalToGlobalMappingGetSize(cmap,&nlocal);CHKERRQ(ierr);
1631e2d7f03fSJed Brown       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1632e2d7f03fSJed Brown       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1633207556f9SJed Brown     } else {
1634207556f9SJed Brown       nlocal = 0;
16350298fd71SBarry Smith       isloc  = NULL;
1636207556f9SJed Brown     }
1637e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1638e2d7f03fSJed Brown     offset            += nlocal;
1639e2d7f03fSJed Brown   }
16400189643fSJed Brown 
164177019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
164277019fcaSJed Brown   {
164345b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap,cmap;
164445b6f7e9SBarry Smith     ierr = MatNestCreateAggregateL2G_Private(A,vs->nr,vs->islocal.row,vs->isglobal.row,PETSC_FALSE,&rmap);CHKERRQ(ierr);
164545b6f7e9SBarry Smith     ierr = MatNestCreateAggregateL2G_Private(A,vs->nc,vs->islocal.col,vs->isglobal.col,PETSC_TRUE,&cmap);CHKERRQ(ierr);
164677019fcaSJed Brown     if (rmap && cmap) {ierr = MatSetLocalToGlobalMapping(A,rmap,cmap);CHKERRQ(ierr);}
164777019fcaSJed Brown     ierr = ISLocalToGlobalMappingDestroy(&rmap);CHKERRQ(ierr);
164877019fcaSJed Brown     ierr = ISLocalToGlobalMappingDestroy(&cmap);CHKERRQ(ierr);
164977019fcaSJed Brown   }
165077019fcaSJed Brown 
16510189643fSJed Brown #if defined(PETSC_USE_DEBUG)
16520189643fSJed Brown   for (i=0; i<vs->nr; i++) {
16530189643fSJed Brown     for (j=0; j<vs->nc; j++) {
16540189643fSJed Brown       PetscInt m,n,M,N,mi,ni,Mi,Ni;
16550189643fSJed Brown       Mat      B = vs->m[i][j];
16560189643fSJed Brown       if (!B) continue;
16570189643fSJed Brown       ierr = MatGetSize(B,&M,&N);CHKERRQ(ierr);
16580189643fSJed Brown       ierr = MatGetLocalSize(B,&m,&n);CHKERRQ(ierr);
16590189643fSJed Brown       ierr = ISGetSize(vs->isglobal.row[i],&Mi);CHKERRQ(ierr);
16600189643fSJed Brown       ierr = ISGetSize(vs->isglobal.col[j],&Ni);CHKERRQ(ierr);
16610189643fSJed Brown       ierr = ISGetLocalSize(vs->isglobal.row[i],&mi);CHKERRQ(ierr);
16620189643fSJed Brown       ierr = ISGetLocalSize(vs->isglobal.col[j],&ni);CHKERRQ(ierr);
1663ce94432eSBarry 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);
1664ce94432eSBarry 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);
16650189643fSJed Brown     }
16660189643fSJed Brown   }
16670189643fSJed Brown #endif
1668a061e289SJed Brown 
1669a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1670a061e289SJed Brown   for (i=0; i<vs->nr; i++) {
1671a061e289SJed Brown     for (j=0; j<vs->nc; j++) {
1672a061e289SJed Brown       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0);
1673a061e289SJed Brown     }
1674a061e289SJed Brown   }
1675a061e289SJed Brown   A->assembled = PETSC_TRUE;
1676d8588912SDave May   PetscFunctionReturn(0);
1677d8588912SDave May }
1678d8588912SDave May 
167945c38901SJed Brown /*@C
1680659c6bb0SJed Brown    MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately
1681659c6bb0SJed Brown 
1682659c6bb0SJed Brown    Collective on Mat
1683659c6bb0SJed Brown 
1684659c6bb0SJed Brown    Input Parameter:
1685659c6bb0SJed Brown +  comm - Communicator for the new Mat
1686659c6bb0SJed Brown .  nr - number of nested row blocks
16870298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1688659c6bb0SJed Brown .  nc - number of nested column blocks
16890298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
16900298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1691659c6bb0SJed Brown 
1692659c6bb0SJed Brown    Output Parameter:
1693659c6bb0SJed Brown .  B - new matrix
1694659c6bb0SJed Brown 
1695659c6bb0SJed Brown    Level: advanced
1696659c6bb0SJed Brown 
169779798668SBarry Smith .seealso: MatCreate(), VecCreateNest(), DMCreateMatrix(), MATNEST, MatNestSetSubMat(),
169879798668SBarry Smith           MatNestGetSubMat(), MatNestGetLocalISs(), MatNestGetSize(),
169979798668SBarry Smith           MatNestGetISs(), MatNestSetSubMats(), MatNestGetSubMats()
1700659c6bb0SJed Brown @*/
17017087cfbeSBarry Smith PetscErrorCode MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat *B)
1702d8588912SDave May {
1703d8588912SDave May   Mat            A;
1704d8588912SDave May   PetscErrorCode ierr;
1705d8588912SDave May 
1706d8588912SDave May   PetscFunctionBegin;
1707c8883902SJed Brown   *B   = 0;
1708d8588912SDave May   ierr = MatCreate(comm,&A);CHKERRQ(ierr);
1709c8883902SJed Brown   ierr = MatSetType(A,MATNEST);CHKERRQ(ierr);
171091a28eb3SBarry Smith   A->preallocated = PETSC_TRUE;
1711c8883902SJed Brown   ierr = MatNestSetSubMats(A,nr,is_row,nc,is_col,a);CHKERRQ(ierr);
1712d8588912SDave May   *B   = A;
1713d8588912SDave May   PetscFunctionReturn(0);
1714d8588912SDave May }
1715659c6bb0SJed Brown 
1716b68353e5Sstefano_zampini static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
1717b68353e5Sstefano_zampini {
1718b68353e5Sstefano_zampini   Mat_Nest       *nest = (Mat_Nest*)A->data;
171923875855Sstefano_zampini   Mat            *trans;
1720b68353e5Sstefano_zampini   PetscScalar    **avv;
1721b68353e5Sstefano_zampini   PetscScalar    *vv;
1722b68353e5Sstefano_zampini   PetscInt       **aii,**ajj;
1723b68353e5Sstefano_zampini   PetscInt       *ii,*jj,*ci;
1724b68353e5Sstefano_zampini   PetscInt       nr,nc,nnz,i,j;
1725b68353e5Sstefano_zampini   PetscBool      done;
1726b68353e5Sstefano_zampini   PetscErrorCode ierr;
1727b68353e5Sstefano_zampini 
1728b68353e5Sstefano_zampini   PetscFunctionBegin;
1729b68353e5Sstefano_zampini   ierr = MatGetSize(A,&nr,&nc);CHKERRQ(ierr);
1730b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1731b68353e5Sstefano_zampini     PetscInt rnr;
1732b68353e5Sstefano_zampini 
1733b68353e5Sstefano_zampini     ierr = MatGetRowIJ(*newmat,0,PETSC_FALSE,PETSC_FALSE,&rnr,(const PetscInt**)&ii,(const PetscInt**)&jj,&done);CHKERRQ(ierr);
1734b68353e5Sstefano_zampini     if (!done) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"MatGetRowIJ");
1735b68353e5Sstefano_zampini     if (rnr != nr) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of rows");
1736b68353e5Sstefano_zampini     ierr = MatSeqAIJGetArray(*newmat,&vv);CHKERRQ(ierr);
1737b68353e5Sstefano_zampini   }
1738b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1739b68353e5Sstefano_zampini   nnz  = 0;
174023875855Sstefano_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);
1741b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1742b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1743b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1744b68353e5Sstefano_zampini       if (B) {
1745b68353e5Sstefano_zampini         PetscScalar *naa;
1746b68353e5Sstefano_zampini         PetscInt    *nii,*njj,nnr;
174723875855Sstefano_zampini         PetscBool   istrans;
1748b68353e5Sstefano_zampini 
174923875855Sstefano_zampini         ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
175023875855Sstefano_zampini         if (istrans) {
175123875855Sstefano_zampini           Mat Bt;
175223875855Sstefano_zampini 
175323875855Sstefano_zampini           ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
175423875855Sstefano_zampini           ierr = MatTranspose(Bt,MAT_INITIAL_MATRIX,&trans[i*nest->nc+j]);CHKERRQ(ierr);
175523875855Sstefano_zampini           B    = trans[i*nest->nc+j];
175623875855Sstefano_zampini         }
1757b68353e5Sstefano_zampini         ierr = MatGetRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&nii,(const PetscInt**)&njj,&done);CHKERRQ(ierr);
1758b68353e5Sstefano_zampini         if (!done) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatGetRowIJ");
1759b68353e5Sstefano_zampini         ierr = MatSeqAIJGetArray(B,&naa);CHKERRQ(ierr);
1760b68353e5Sstefano_zampini         nnz += nii[nnr];
1761b68353e5Sstefano_zampini 
1762b68353e5Sstefano_zampini         aii[i*nest->nc+j] = nii;
1763b68353e5Sstefano_zampini         ajj[i*nest->nc+j] = njj;
1764b68353e5Sstefano_zampini         avv[i*nest->nc+j] = naa;
1765b68353e5Sstefano_zampini       }
1766b68353e5Sstefano_zampini     }
1767b68353e5Sstefano_zampini   }
1768b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
1769b68353e5Sstefano_zampini     ierr = PetscMalloc1(nr+1,&ii);CHKERRQ(ierr);
1770b68353e5Sstefano_zampini     ierr = PetscMalloc1(nnz,&jj);CHKERRQ(ierr);
1771b68353e5Sstefano_zampini     ierr = PetscMalloc1(nnz,&vv);CHKERRQ(ierr);
1772b68353e5Sstefano_zampini   } else {
1773b68353e5Sstefano_zampini     if (nnz != ii[nr]) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of nonzeros");
1774b68353e5Sstefano_zampini   }
1775b68353e5Sstefano_zampini 
1776b68353e5Sstefano_zampini   /* new row pointer */
1777580bdb30SBarry Smith   ierr = PetscArrayzero(ii,nr+1);CHKERRQ(ierr);
1778b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1779b68353e5Sstefano_zampini     PetscInt       ncr,rst;
1780b68353e5Sstefano_zampini 
1781b68353e5Sstefano_zampini     ierr = ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL);CHKERRQ(ierr);
1782b68353e5Sstefano_zampini     ierr = ISGetLocalSize(nest->isglobal.row[i],&ncr);CHKERRQ(ierr);
1783b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1784b68353e5Sstefano_zampini       if (aii[i*nest->nc+j]) {
1785b68353e5Sstefano_zampini         PetscInt    *nii = aii[i*nest->nc+j];
1786b68353e5Sstefano_zampini         PetscInt    ir;
1787b68353e5Sstefano_zampini 
1788b68353e5Sstefano_zampini         for (ir=rst; ir<ncr+rst; ++ir) {
1789b68353e5Sstefano_zampini           ii[ir+1] += nii[1]-nii[0];
1790b68353e5Sstefano_zampini           nii++;
1791b68353e5Sstefano_zampini         }
1792b68353e5Sstefano_zampini       }
1793b68353e5Sstefano_zampini     }
1794b68353e5Sstefano_zampini   }
1795b68353e5Sstefano_zampini   for (i=0; i<nr; i++) ii[i+1] += ii[i];
1796b68353e5Sstefano_zampini 
1797b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
1798b68353e5Sstefano_zampini   ierr = PetscCalloc1(nr,&ci);CHKERRQ(ierr);
1799b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1800b68353e5Sstefano_zampini     PetscInt       ncr,rst;
1801b68353e5Sstefano_zampini 
1802b68353e5Sstefano_zampini     ierr = ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL);CHKERRQ(ierr);
1803b68353e5Sstefano_zampini     ierr = ISGetLocalSize(nest->isglobal.row[i],&ncr);CHKERRQ(ierr);
1804b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1805b68353e5Sstefano_zampini       if (aii[i*nest->nc+j]) {
1806b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i*nest->nc+j];
1807b68353e5Sstefano_zampini         PetscInt    *nii = aii[i*nest->nc+j];
1808b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i*nest->nc+j];
1809b68353e5Sstefano_zampini         PetscInt    ir,cst;
1810b68353e5Sstefano_zampini 
1811b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.col[j],&cst,NULL);CHKERRQ(ierr);
1812b68353e5Sstefano_zampini         for (ir=rst; ir<ncr+rst; ++ir) {
1813b68353e5Sstefano_zampini           PetscInt ij,rsize = nii[1]-nii[0],ist = ii[ir]+ci[ir];
1814b68353e5Sstefano_zampini 
1815b68353e5Sstefano_zampini           for (ij=0;ij<rsize;ij++) {
1816b68353e5Sstefano_zampini             jj[ist+ij] = *njj+cst;
1817b68353e5Sstefano_zampini             vv[ist+ij] = *nvv;
1818b68353e5Sstefano_zampini             njj++;
1819b68353e5Sstefano_zampini             nvv++;
1820b68353e5Sstefano_zampini           }
1821b68353e5Sstefano_zampini           ci[ir] += rsize;
1822b68353e5Sstefano_zampini           nii++;
1823b68353e5Sstefano_zampini         }
1824b68353e5Sstefano_zampini       }
1825b68353e5Sstefano_zampini     }
1826b68353e5Sstefano_zampini   }
1827b68353e5Sstefano_zampini   ierr = PetscFree(ci);CHKERRQ(ierr);
1828b68353e5Sstefano_zampini 
1829b68353e5Sstefano_zampini   /* restore info */
1830b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1831b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1832b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1833b68353e5Sstefano_zampini       if (B) {
1834b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i*nest->nc+j;
183523875855Sstefano_zampini 
183623875855Sstefano_zampini         B    = (trans[k] ? trans[k] : B);
1837b68353e5Sstefano_zampini         ierr = MatRestoreRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&aii[k],(const PetscInt**)&ajj[k],&done);CHKERRQ(ierr);
1838b68353e5Sstefano_zampini         if (!done) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatRestoreRowIJ");
1839b68353e5Sstefano_zampini         ierr = MatSeqAIJRestoreArray(B,&avv[k]);CHKERRQ(ierr);
184023875855Sstefano_zampini         ierr = MatDestroy(&trans[k]);CHKERRQ(ierr);
1841b68353e5Sstefano_zampini       }
1842b68353e5Sstefano_zampini     }
1843b68353e5Sstefano_zampini   }
184423875855Sstefano_zampini   ierr = PetscFree4(aii,ajj,avv,trans);CHKERRQ(ierr);
1845b68353e5Sstefano_zampini 
1846b68353e5Sstefano_zampini   /* finalize newmat */
1847b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
1848b68353e5Sstefano_zampini     ierr = MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,newmat);CHKERRQ(ierr);
1849b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1850b68353e5Sstefano_zampini     Mat B;
1851b68353e5Sstefano_zampini 
1852b68353e5Sstefano_zampini     ierr = MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,&B);CHKERRQ(ierr);
1853b68353e5Sstefano_zampini     ierr = MatHeaderReplace(A,&B);CHKERRQ(ierr);
1854b68353e5Sstefano_zampini   }
1855b68353e5Sstefano_zampini   ierr = MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1856b68353e5Sstefano_zampini   ierr = MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1857b68353e5Sstefano_zampini   {
1858b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ*)((*newmat)->data);
1859b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1860b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1861b68353e5Sstefano_zampini   }
1862b68353e5Sstefano_zampini   PetscFunctionReturn(0);
1863b68353e5Sstefano_zampini }
1864b68353e5Sstefano_zampini 
1865cc2e6a90SBarry Smith PETSC_INTERN PetscErrorCode MatConvert_Nest_AIJ(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
1866629c3df2SDmitry Karpeev {
1867629c3df2SDmitry Karpeev   PetscErrorCode ierr;
1868629c3df2SDmitry Karpeev   Mat_Nest       *nest = (Mat_Nest*)A->data;
186983b1a929SMark Adams   PetscInt       m,n,M,N,i,j,k,*dnnz,*onnz,rstart;
1870649b366bSFande Kong   PetscInt       cstart,cend;
1871b68353e5Sstefano_zampini   PetscMPIInt    size;
1872629c3df2SDmitry Karpeev   Mat            C;
1873629c3df2SDmitry Karpeev 
1874629c3df2SDmitry Karpeev   PetscFunctionBegin;
1875b68353e5Sstefano_zampini   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRQ(ierr);
1876b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
1877b68353e5Sstefano_zampini     PetscInt  nf;
1878b68353e5Sstefano_zampini     PetscBool fast;
1879b68353e5Sstefano_zampini 
1880b68353e5Sstefano_zampini     ierr = PetscStrcmp(newtype,MATAIJ,&fast);CHKERRQ(ierr);
1881b68353e5Sstefano_zampini     if (!fast) {
1882b68353e5Sstefano_zampini       ierr = PetscStrcmp(newtype,MATSEQAIJ,&fast);CHKERRQ(ierr);
1883b68353e5Sstefano_zampini     }
1884b68353e5Sstefano_zampini     for (i=0; i<nest->nr && fast; ++i) {
1885b68353e5Sstefano_zampini       for (j=0; j<nest->nc && fast; ++j) {
1886b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
1887b68353e5Sstefano_zampini         if (B) {
1888b68353e5Sstefano_zampini           ierr = PetscObjectTypeCompare((PetscObject)B,MATSEQAIJ,&fast);CHKERRQ(ierr);
188923875855Sstefano_zampini           if (!fast) {
189023875855Sstefano_zampini             PetscBool istrans;
189123875855Sstefano_zampini 
189223875855Sstefano_zampini             ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
189323875855Sstefano_zampini             if (istrans) {
189423875855Sstefano_zampini               Mat Bt;
189523875855Sstefano_zampini 
189623875855Sstefano_zampini               ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
189723875855Sstefano_zampini               ierr = PetscObjectTypeCompare((PetscObject)Bt,MATSEQAIJ,&fast);CHKERRQ(ierr);
189823875855Sstefano_zampini             }
1899b68353e5Sstefano_zampini           }
1900b68353e5Sstefano_zampini         }
1901b68353e5Sstefano_zampini       }
1902b68353e5Sstefano_zampini     }
1903b68353e5Sstefano_zampini     for (i=0, nf=0; i<nest->nr && fast; ++i) {
1904b68353e5Sstefano_zampini       ierr = PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i],ISSTRIDE,&fast);CHKERRQ(ierr);
1905b68353e5Sstefano_zampini       if (fast) {
1906b68353e5Sstefano_zampini         PetscInt f,s;
1907b68353e5Sstefano_zampini 
1908b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.row[i],&f,&s);CHKERRQ(ierr);
1909b68353e5Sstefano_zampini         if (f != nf || s != 1) { fast = PETSC_FALSE; }
1910b68353e5Sstefano_zampini         else {
1911b68353e5Sstefano_zampini           ierr = ISGetSize(nest->isglobal.row[i],&f);CHKERRQ(ierr);
1912b68353e5Sstefano_zampini           nf  += f;
1913b68353e5Sstefano_zampini         }
1914b68353e5Sstefano_zampini       }
1915b68353e5Sstefano_zampini     }
1916b68353e5Sstefano_zampini     for (i=0, nf=0; i<nest->nc && fast; ++i) {
1917b68353e5Sstefano_zampini       ierr = PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i],ISSTRIDE,&fast);CHKERRQ(ierr);
1918b68353e5Sstefano_zampini       if (fast) {
1919b68353e5Sstefano_zampini         PetscInt f,s;
1920b68353e5Sstefano_zampini 
1921b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.col[i],&f,&s);CHKERRQ(ierr);
1922b68353e5Sstefano_zampini         if (f != nf || s != 1) { fast = PETSC_FALSE; }
1923b68353e5Sstefano_zampini         else {
1924b68353e5Sstefano_zampini           ierr = ISGetSize(nest->isglobal.col[i],&f);CHKERRQ(ierr);
1925b68353e5Sstefano_zampini           nf  += f;
1926b68353e5Sstefano_zampini         }
1927b68353e5Sstefano_zampini       }
1928b68353e5Sstefano_zampini     }
1929b68353e5Sstefano_zampini     if (fast) {
1930b68353e5Sstefano_zampini       ierr = MatConvert_Nest_SeqAIJ_fast(A,newtype,reuse,newmat);CHKERRQ(ierr);
1931b68353e5Sstefano_zampini       PetscFunctionReturn(0);
1932b68353e5Sstefano_zampini     }
1933b68353e5Sstefano_zampini   }
1934629c3df2SDmitry Karpeev   ierr = MatGetSize(A,&M,&N);CHKERRQ(ierr);
1935629c3df2SDmitry Karpeev   ierr = MatGetLocalSize(A,&m,&n);CHKERRQ(ierr);
1936649b366bSFande Kong   ierr = MatGetOwnershipRangeColumn(A,&cstart,&cend);CHKERRQ(ierr);
1937629c3df2SDmitry Karpeev   switch (reuse) {
1938629c3df2SDmitry Karpeev   case MAT_INITIAL_MATRIX:
1939ce94432eSBarry Smith     ierr    = MatCreate(PetscObjectComm((PetscObject)A),&C);CHKERRQ(ierr);
1940629c3df2SDmitry Karpeev     ierr    = MatSetType(C,newtype);CHKERRQ(ierr);
1941629c3df2SDmitry Karpeev     ierr    = MatSetSizes(C,m,n,M,N);CHKERRQ(ierr);
1942629c3df2SDmitry Karpeev     *newmat = C;
1943629c3df2SDmitry Karpeev     break;
1944629c3df2SDmitry Karpeev   case MAT_REUSE_MATRIX:
1945629c3df2SDmitry Karpeev     C = *newmat;
1946629c3df2SDmitry Karpeev     break;
1947ce94432eSBarry Smith   default: SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MatReuse");
1948629c3df2SDmitry Karpeev   }
1949785e854fSJed Brown   ierr = PetscMalloc1(2*m,&dnnz);CHKERRQ(ierr);
1950629c3df2SDmitry Karpeev   onnz = dnnz + m;
1951629c3df2SDmitry Karpeev   for (k=0; k<m; k++) {
1952629c3df2SDmitry Karpeev     dnnz[k] = 0;
1953629c3df2SDmitry Karpeev     onnz[k] = 0;
1954629c3df2SDmitry Karpeev   }
1955629c3df2SDmitry Karpeev   for (j=0; j<nest->nc; ++j) {
1956629c3df2SDmitry Karpeev     IS             bNis;
1957629c3df2SDmitry Karpeev     PetscInt       bN;
1958629c3df2SDmitry Karpeev     const PetscInt *bNindices;
1959629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
1960629c3df2SDmitry Karpeev     ierr = ISAllGather(nest->isglobal.col[j], &bNis);CHKERRQ(ierr);
1961629c3df2SDmitry Karpeev     ierr = ISGetSize(bNis, &bN);CHKERRQ(ierr);
1962629c3df2SDmitry Karpeev     ierr = ISGetIndices(bNis,&bNindices);CHKERRQ(ierr);
1963629c3df2SDmitry Karpeev     for (i=0; i<nest->nr; ++i) {
1964629c3df2SDmitry Karpeev       PetscSF        bmsf;
1965649b366bSFande Kong       PetscSFNode    *iremote;
1966629c3df2SDmitry Karpeev       Mat            B;
1967649b366bSFande Kong       PetscInt       bm, *sub_dnnz,*sub_onnz, br;
1968629c3df2SDmitry Karpeev       const PetscInt *bmindices;
1969629c3df2SDmitry Karpeev       B = nest->m[i][j];
1970629c3df2SDmitry Karpeev       if (!B) continue;
1971629c3df2SDmitry Karpeev       ierr = ISGetLocalSize(nest->isglobal.row[i],&bm);CHKERRQ(ierr);
1972629c3df2SDmitry Karpeev       ierr = ISGetIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
1973ce94432eSBarry Smith       ierr = PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf);CHKERRQ(ierr);
1974649b366bSFande Kong       ierr = PetscMalloc1(bm,&iremote);CHKERRQ(ierr);
1975649b366bSFande Kong       ierr = PetscMalloc1(bm,&sub_dnnz);CHKERRQ(ierr);
1976649b366bSFande Kong       ierr = PetscMalloc1(bm,&sub_onnz);CHKERRQ(ierr);
1977649b366bSFande Kong       for (k = 0; k < bm; ++k){
1978649b366bSFande Kong     	sub_dnnz[k] = 0;
1979649b366bSFande Kong     	sub_onnz[k] = 0;
1980649b366bSFande Kong       }
1981629c3df2SDmitry Karpeev       /*
1982629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
1983629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
1984629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
1985629c3df2SDmitry Karpeev        */
198683b1a929SMark Adams       ierr = MatGetOwnershipRange(B,&rstart,NULL);CHKERRQ(ierr);
1987629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
1988131c27b5Sprj-         PetscInt       row = bmindices[br], brncols, col;
1989629c3df2SDmitry Karpeev         const PetscInt *brcols;
1990a4b3d3acSMatthew G Knepley         PetscInt       rowrel = 0; /* row's relative index on its owner rank */
1991131c27b5Sprj-         PetscMPIInt    rowowner = 0;
1992629c3df2SDmitry Karpeev         ierr      = PetscLayoutFindOwnerIndex(A->rmap,row,&rowowner,&rowrel);CHKERRQ(ierr);
1993649b366bSFande Kong         /* how many roots  */
1994649b366bSFande Kong         iremote[br].rank = rowowner; iremote[br].index = rowrel;           /* edge from bmdnnz to dnnz */
1995649b366bSFande Kong         /* get nonzero pattern */
199683b1a929SMark Adams         ierr = MatGetRow(B,br+rstart,&brncols,&brcols,NULL);CHKERRQ(ierr);
1997629c3df2SDmitry Karpeev         for (k=0; k<brncols; k++) {
1998629c3df2SDmitry Karpeev           col  = bNindices[brcols[k]];
1999649b366bSFande Kong           if (col>=A->cmap->range[rowowner] && col<A->cmap->range[rowowner+1]) {
2000649b366bSFande Kong             sub_dnnz[br]++;
2001649b366bSFande Kong           } else {
2002649b366bSFande Kong             sub_onnz[br]++;
2003649b366bSFande Kong           }
2004629c3df2SDmitry Karpeev         }
200583b1a929SMark Adams         ierr = MatRestoreRow(B,br+rstart,&brncols,&brcols,NULL);CHKERRQ(ierr);
2006629c3df2SDmitry Karpeev       }
2007629c3df2SDmitry Karpeev       ierr = ISRestoreIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
2008629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
2009649b366bSFande Kong       ierr = PetscSFSetGraph(bmsf,m,bm,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
2010649b366bSFande Kong       ierr = PetscSFReduceBegin(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM);CHKERRQ(ierr);
2011649b366bSFande Kong       ierr = PetscSFReduceEnd(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM);CHKERRQ(ierr);
2012649b366bSFande Kong       ierr = PetscSFReduceBegin(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM);CHKERRQ(ierr);
2013649b366bSFande Kong       ierr = PetscSFReduceEnd(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM);CHKERRQ(ierr);
2014649b366bSFande Kong       ierr = PetscFree(sub_dnnz);CHKERRQ(ierr);
2015649b366bSFande Kong       ierr = PetscFree(sub_onnz);CHKERRQ(ierr);
2016629c3df2SDmitry Karpeev       ierr = PetscSFDestroy(&bmsf);CHKERRQ(ierr);
2017629c3df2SDmitry Karpeev     }
201822d28d08SBarry Smith     ierr = ISRestoreIndices(bNis,&bNindices);CHKERRQ(ierr);
2019629c3df2SDmitry Karpeev     ierr = ISDestroy(&bNis);CHKERRQ(ierr);
202065a4a0a3Sstefano_zampini   }
202165a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
202265a4a0a3Sstefano_zampini   for (i=0;i<m;i++) {
202365a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i],A->cmap->n);
202465a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i],A->cmap->N - A->cmap->n);
2025629c3df2SDmitry Karpeev   }
2026629c3df2SDmitry Karpeev   ierr = MatSeqAIJSetPreallocation(C,0,dnnz);CHKERRQ(ierr);
2027629c3df2SDmitry Karpeev   ierr = MatMPIAIJSetPreallocation(C,0,dnnz,0,onnz);CHKERRQ(ierr);
2028629c3df2SDmitry Karpeev   ierr = PetscFree(dnnz);CHKERRQ(ierr);
2029629c3df2SDmitry Karpeev 
2030629c3df2SDmitry Karpeev   /* Fill by row */
2031629c3df2SDmitry Karpeev   for (j=0; j<nest->nc; ++j) {
2032629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
2033629c3df2SDmitry Karpeev     IS             bNis;
2034629c3df2SDmitry Karpeev     PetscInt       bN;
2035629c3df2SDmitry Karpeev     const PetscInt *bNindices;
2036629c3df2SDmitry Karpeev     ierr = ISAllGather(nest->isglobal.col[j], &bNis);CHKERRQ(ierr);
2037629c3df2SDmitry Karpeev     ierr = ISGetSize(bNis,&bN);CHKERRQ(ierr);
2038629c3df2SDmitry Karpeev     ierr = ISGetIndices(bNis,&bNindices);CHKERRQ(ierr);
2039629c3df2SDmitry Karpeev     for (i=0; i<nest->nr; ++i) {
2040629c3df2SDmitry Karpeev       Mat            B;
2041629c3df2SDmitry Karpeev       PetscInt       bm, br;
2042629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2043629c3df2SDmitry Karpeev       B = nest->m[i][j];
2044629c3df2SDmitry Karpeev       if (!B) continue;
2045629c3df2SDmitry Karpeev       ierr = ISGetLocalSize(nest->isglobal.row[i],&bm);CHKERRQ(ierr);
2046629c3df2SDmitry Karpeev       ierr = ISGetIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
204783b1a929SMark Adams       ierr = MatGetOwnershipRange(B,&rstart,NULL);CHKERRQ(ierr);
2048629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2049629c3df2SDmitry Karpeev         PetscInt          row = bmindices[br], brncols,  *cols;
2050629c3df2SDmitry Karpeev         const PetscInt    *brcols;
2051629c3df2SDmitry Karpeev         const PetscScalar *brcoldata;
205283b1a929SMark Adams         ierr = MatGetRow(B,br+rstart,&brncols,&brcols,&brcoldata);CHKERRQ(ierr);
2053785e854fSJed Brown         ierr = PetscMalloc1(brncols,&cols);CHKERRQ(ierr);
205426fbe8dcSKarl Rupp         for (k=0; k<brncols; k++) cols[k] = bNindices[brcols[k]];
2055629c3df2SDmitry Karpeev         /*
2056629c3df2SDmitry Karpeev           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
2057629c3df2SDmitry Karpeev           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
2058629c3df2SDmitry Karpeev          */
2059a2ea699eSBarry Smith         ierr = MatSetValues(C,1,&row,brncols,cols,brcoldata,ADD_VALUES);CHKERRQ(ierr);
206083b1a929SMark Adams         ierr = MatRestoreRow(B,br+rstart,&brncols,&brcols,&brcoldata);CHKERRQ(ierr);
2061629c3df2SDmitry Karpeev         ierr = PetscFree(cols);CHKERRQ(ierr);
2062629c3df2SDmitry Karpeev       }
2063629c3df2SDmitry Karpeev       ierr = ISRestoreIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
2064629c3df2SDmitry Karpeev     }
2065a2ea699eSBarry Smith     ierr = ISRestoreIndices(bNis,&bNindices);CHKERRQ(ierr);
2066629c3df2SDmitry Karpeev     ierr = ISDestroy(&bNis);CHKERRQ(ierr);
2067629c3df2SDmitry Karpeev   }
2068629c3df2SDmitry Karpeev   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2069629c3df2SDmitry Karpeev   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2070629c3df2SDmitry Karpeev   PetscFunctionReturn(0);
2071629c3df2SDmitry Karpeev }
2072629c3df2SDmitry Karpeev 
20738b7d3b4bSBarry Smith PetscErrorCode MatHasOperation_Nest(Mat mat,MatOperation op,PetscBool *has)
20748b7d3b4bSBarry Smith {
20758b7d3b4bSBarry Smith   Mat_Nest       *bA = (Mat_Nest*)mat->data;
20768b7d3b4bSBarry Smith   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
20778b7d3b4bSBarry Smith   PetscBool      flg;
207852c5f739Sprj-   PetscErrorCode ierr;
207952c5f739Sprj-   PetscFunctionBegin;
20808b7d3b4bSBarry Smith 
208152c5f739Sprj-   *has = PETSC_FALSE;
208252c5f739Sprj-   if (op == MATOP_MULT_TRANSPOSE || op == MATOP_MAT_MULT) {
20838b7d3b4bSBarry Smith     for (j=0; j<nc; j++) {
20848b7d3b4bSBarry Smith       for (i=0; i<nr; i++) {
20858b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
208652c5f739Sprj-         ierr = MatHasOperation(bA->m[i][j],op,&flg);CHKERRQ(ierr);
20878b7d3b4bSBarry Smith         if (!flg) PetscFunctionReturn(0);
20888b7d3b4bSBarry Smith       }
20898b7d3b4bSBarry Smith     }
20908b7d3b4bSBarry Smith   }
209152c5f739Sprj-   if (((void**)mat->ops)[op] || (op == MATOP_MAT_MULT && flg)) *has = PETSC_TRUE;
20928b7d3b4bSBarry Smith   PetscFunctionReturn(0);
20938b7d3b4bSBarry Smith }
20948b7d3b4bSBarry Smith 
2095659c6bb0SJed Brown /*MC
2096659c6bb0SJed Brown   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.
2097659c6bb0SJed Brown 
2098659c6bb0SJed Brown   Level: intermediate
2099659c6bb0SJed Brown 
2100659c6bb0SJed Brown   Notes:
2101659c6bb0SJed Brown   This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices.
2102659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
2103950540a4SJed Brown   It is usually used with DMComposite and DMCreateMatrix()
2104659c6bb0SJed Brown 
21058b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
21068b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
21078b7d3b4bSBarry Smith   than the nest matrix.
21088b7d3b4bSBarry Smith 
210979798668SBarry Smith .seealso: MatCreate(), MatType, MatCreateNest(), MatNestSetSubMat(), MatNestGetSubMat(),
211079798668SBarry Smith           VecCreateNest(), DMCreateMatrix(), DMCOMPOSITE, MatNestSetVecType(), MatNestGetLocalISs(),
211179798668SBarry Smith           MatNestGetISs(), MatNestSetSubMats(), MatNestGetSubMats()
2112659c6bb0SJed Brown M*/
21138cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2114c8883902SJed Brown {
2115c8883902SJed Brown   Mat_Nest       *s;
2116c8883902SJed Brown   PetscErrorCode ierr;
2117c8883902SJed Brown 
2118c8883902SJed Brown   PetscFunctionBegin;
2119b00a9115SJed Brown   ierr    = PetscNewLog(A,&s);CHKERRQ(ierr);
2120c8883902SJed Brown   A->data = (void*)s;
2121e7c19651SJed Brown 
2122e7c19651SJed Brown   s->nr            = -1;
2123e7c19651SJed Brown   s->nc            = -1;
21240298fd71SBarry Smith   s->m             = NULL;
2125e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
2126c8883902SJed Brown 
2127c8883902SJed Brown   ierr = PetscMemzero(A->ops,sizeof(*A->ops));CHKERRQ(ierr);
212826fbe8dcSKarl Rupp 
2129c8883902SJed Brown   A->ops->mult                  = MatMult_Nest;
21309194d70fSJed Brown   A->ops->multadd               = MatMultAdd_Nest;
2131c8883902SJed Brown   A->ops->multtranspose         = MatMultTranspose_Nest;
21329194d70fSJed Brown   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
2133f8170845SAlex Fikl   A->ops->transpose             = MatTranspose_Nest;
2134c8883902SJed Brown   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
2135c8883902SJed Brown   A->ops->assemblyend           = MatAssemblyEnd_Nest;
2136c8883902SJed Brown   A->ops->zeroentries           = MatZeroEntries_Nest;
2137c222c20dSDavid Ham   A->ops->copy                  = MatCopy_Nest;
21386e76ffeaSPierre Jolivet   A->ops->axpy                  = MatAXPY_Nest;
2139c8883902SJed Brown   A->ops->duplicate             = MatDuplicate_Nest;
21407dae84e0SHong Zhang   A->ops->createsubmatrix       = MatCreateSubMatrix_Nest;
2141c8883902SJed Brown   A->ops->destroy               = MatDestroy_Nest;
2142c8883902SJed Brown   A->ops->view                  = MatView_Nest;
2143c8883902SJed Brown   A->ops->getvecs               = 0; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2144c8883902SJed Brown   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
2145c8883902SJed Brown   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
2146429bac76SJed Brown   A->ops->getdiagonal           = MatGetDiagonal_Nest;
2147429bac76SJed Brown   A->ops->diagonalscale         = MatDiagonalScale_Nest;
2148a061e289SJed Brown   A->ops->scale                 = MatScale_Nest;
2149a061e289SJed Brown   A->ops->shift                 = MatShift_Nest;
215013135bc6SAlex Fikl   A->ops->diagonalset           = MatDiagonalSet_Nest;
2151f8170845SAlex Fikl   A->ops->setrandom             = MatSetRandom_Nest;
21528b7d3b4bSBarry Smith   A->ops->hasoperation          = MatHasOperation_Nest;
2153*381b8e50SStefano Zampini   A->ops->missingdiagonal       = MatMissingDiagonal_Nest;
2154c8883902SJed Brown 
2155c8883902SJed Brown   A->spptr        = 0;
2156c8883902SJed Brown   A->assembled    = PETSC_FALSE;
2157c8883902SJed Brown 
2158c8883902SJed Brown   /* expose Nest api's */
2159bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",        MatNestGetSubMat_Nest);CHKERRQ(ierr);
2160bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",        MatNestSetSubMat_Nest);CHKERRQ(ierr);
2161bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",       MatNestGetSubMats_Nest);CHKERRQ(ierr);
2162bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",          MatNestGetSize_Nest);CHKERRQ(ierr);
2163bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",           MatNestGetISs_Nest);CHKERRQ(ierr);
2164bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",      MatNestGetLocalISs_Nest);CHKERRQ(ierr);
2165bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",       MatNestSetVecType_Nest);CHKERRQ(ierr);
2166bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",       MatNestSetSubMats_Nest);CHKERRQ(ierr);
21670899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",  MatConvert_Nest_AIJ);CHKERRQ(ierr);
21680899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",  MatConvert_Nest_AIJ);CHKERRQ(ierr);
216983b1a929SMark Adams   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",     MatConvert_Nest_AIJ);CHKERRQ(ierr);
21705e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",      MatConvert_Nest_IS);CHKERRQ(ierr);
217152c5f739Sprj-   ierr = PetscObjectComposeFunction((PetscObject)A,"MatMatMult_nest_mpidense_C",MatMatMult_Nest_Dense);CHKERRQ(ierr);
217252c5f739Sprj-   ierr = PetscObjectComposeFunction((PetscObject)A,"MatMatMult_nest_seqdense_C",MatMatMult_Nest_Dense);CHKERRQ(ierr);
217352c5f739Sprj-   ierr = PetscObjectComposeFunction((PetscObject)A,"MatMatMult_nest_dense_C",   MatMatMult_Nest_Dense);CHKERRQ(ierr);
2174c8883902SJed Brown 
2175c8883902SJed Brown   ierr = PetscObjectChangeTypeName((PetscObject)A,MATNEST);CHKERRQ(ierr);
2176c8883902SJed Brown   PetscFunctionReturn(0);
2177c8883902SJed Brown }
2178