xref: /petsc/src/mat/impls/nest/matnest.c (revision 18d228c0a586965c0880d3bfa9550cc6cda09270)
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- 
956718818eSStefano Zampini PETSC_INTERN PetscErrorCode MatProductNumeric_Nest_Dense(Mat C)
9652c5f739Sprj- {
976718818eSStefano Zampini   Mat_Nest          *bA;
9852c5f739Sprj-   Nest_Dense        *contents;
996718818eSStefano Zampini   Mat               viewB,viewC,productB,workC;
10052c5f739Sprj-   const PetscScalar *barray;
10152c5f739Sprj-   PetscScalar       *carray;
1026718818eSStefano Zampini   PetscInt          i,j,M,N,nr,nc,ldb,ldc;
10352c5f739Sprj-   PetscErrorCode    ierr;
1046718818eSStefano Zampini   Mat               A,B;
10552c5f739Sprj- 
10652c5f739Sprj-   PetscFunctionBegin;
1076718818eSStefano Zampini   MatCheckProduct(C,3);
1086718818eSStefano Zampini   A    = C->product->A;
1096718818eSStefano Zampini   B    = C->product->B;
1106718818eSStefano Zampini   ierr = MatGetSize(B,NULL,&N);CHKERRQ(ierr);
1116718818eSStefano Zampini   if (!N) {
1126718818eSStefano Zampini     ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1136718818eSStefano Zampini     ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1146718818eSStefano Zampini     PetscFunctionReturn(0);
1156718818eSStefano Zampini   }
1166718818eSStefano Zampini   contents = (Nest_Dense*)C->product->data;
1176718818eSStefano Zampini   if (!contents) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data empty");
1186718818eSStefano Zampini   bA   = (Mat_Nest*)A->data;
1196718818eSStefano Zampini   nr   = bA->nr;
1206718818eSStefano Zampini   nc   = bA->nc;
12152c5f739Sprj-   ierr = MatDenseGetLDA(B,&ldb);CHKERRQ(ierr);
12252c5f739Sprj-   ierr = MatDenseGetLDA(C,&ldc);CHKERRQ(ierr);
12352c5f739Sprj-   ierr = MatZeroEntries(C);CHKERRQ(ierr);
12452c5f739Sprj-   ierr = MatDenseGetArrayRead(B,&barray);CHKERRQ(ierr);
1256718818eSStefano Zampini   ierr = MatDenseGetArrayWrite(C,&carray);CHKERRQ(ierr);
12652c5f739Sprj-   for (i=0; i<nr; i++) {
12752c5f739Sprj-     ierr = ISGetSize(bA->isglobal.row[i],&M);CHKERRQ(ierr);
12852c5f739Sprj-     ierr = MatCreateDense(PetscObjectComm((PetscObject)A),contents->dm[i+1]-contents->dm[i],PETSC_DECIDE,M,N,carray+contents->dm[i],&viewC);CHKERRQ(ierr);
1296718818eSStefano Zampini     ierr = MatDenseSetLDA(viewC,ldc);CHKERRQ(ierr);
13052c5f739Sprj-     for (j=0; j<nc; j++) {
13152c5f739Sprj-       if (!bA->m[i][j]) continue;
13252c5f739Sprj-       ierr = ISGetSize(bA->isglobal.col[j],&M);CHKERRQ(ierr);
13352c5f739Sprj-       ierr = MatCreateDense(PetscObjectComm((PetscObject)A),contents->dn[j+1]-contents->dn[j],PETSC_DECIDE,M,N,(PetscScalar*)(barray+contents->dn[j]),&viewB);CHKERRQ(ierr);
1346718818eSStefano Zampini       ierr = MatDenseSetLDA(viewB,ldb);CHKERRQ(ierr);
1354222ddf1SHong Zhang 
1364222ddf1SHong Zhang       /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */
1374222ddf1SHong Zhang       workC             = contents->workC[i*nc + j];
1384222ddf1SHong Zhang       productB          = workC->product->B;
1394222ddf1SHong Zhang       workC->product->B = viewB; /* use newly created dense matrix viewB */
1406718818eSStefano Zampini       ierr = MatProductNumeric(workC);CHKERRQ(ierr);
14152c5f739Sprj-       ierr = MatDestroy(&viewB);CHKERRQ(ierr);
1424222ddf1SHong Zhang       workC->product->B = productB; /* resume original B */
1434222ddf1SHong Zhang 
14452c5f739Sprj-       /* C[i] <- workC + C[i] */
14552c5f739Sprj-       ierr = MatAXPY(viewC,1.0,contents->workC[i*nc + j],SAME_NONZERO_PATTERN);CHKERRQ(ierr);
14652c5f739Sprj-     }
14752c5f739Sprj-     ierr = MatDestroy(&viewC);CHKERRQ(ierr);
14852c5f739Sprj-   }
1496718818eSStefano Zampini   ierr = MatDenseRestoreArrayWrite(C,&carray);CHKERRQ(ierr);
15052c5f739Sprj-   ierr = MatDenseRestoreArrayRead(B,&barray);CHKERRQ(ierr);
1514222ddf1SHong Zhang 
1524222ddf1SHong Zhang   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1534222ddf1SHong Zhang   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
15452c5f739Sprj-   PetscFunctionReturn(0);
15552c5f739Sprj- }
15652c5f739Sprj- 
15752c5f739Sprj- PetscErrorCode MatNest_DenseDestroy(void *ctx)
15852c5f739Sprj- {
15952c5f739Sprj-   Nest_Dense     *contents = (Nest_Dense*)ctx;
16052c5f739Sprj-   PetscInt       i;
16152c5f739Sprj-   PetscErrorCode ierr;
16252c5f739Sprj- 
16352c5f739Sprj-   PetscFunctionBegin;
16452c5f739Sprj-   ierr = PetscFree(contents->tarray);CHKERRQ(ierr);
16552c5f739Sprj-   for (i=0; i<contents->k; i++) {
16652c5f739Sprj-     ierr = MatDestroy(contents->workC + i);CHKERRQ(ierr);
16752c5f739Sprj-   }
16852c5f739Sprj-   ierr = PetscFree3(contents->dm,contents->dn,contents->workC);CHKERRQ(ierr);
16952c5f739Sprj-   ierr = PetscFree(contents);CHKERRQ(ierr);
17052c5f739Sprj-   PetscFunctionReturn(0);
17152c5f739Sprj- }
17252c5f739Sprj- 
1736718818eSStefano Zampini PETSC_INTERN PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C)
17452c5f739Sprj- {
1756718818eSStefano Zampini   Mat_Nest          *bA;
1766718818eSStefano Zampini   Mat               viewB,workC;
17752c5f739Sprj-   const PetscScalar *barray;
1786718818eSStefano Zampini   PetscInt          i,j,M,N,m,n,nr,nc,maxm = 0,ldb;
1794222ddf1SHong Zhang   Nest_Dense        *contents=NULL;
1806718818eSStefano Zampini   PetscBool         cisdense;
18152c5f739Sprj-   PetscErrorCode    ierr;
1826718818eSStefano Zampini   Mat               A,B;
1836718818eSStefano Zampini   PetscReal         fill;
18452c5f739Sprj- 
18552c5f739Sprj-   PetscFunctionBegin;
1866718818eSStefano Zampini   MatCheckProduct(C,4);
1876718818eSStefano Zampini   if (C->product->data) SETERRQ(PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data not empty");
1886718818eSStefano Zampini   A    = C->product->A;
1896718818eSStefano Zampini   B    = C->product->B;
1906718818eSStefano Zampini   fill = C->product->fill;
1916718818eSStefano Zampini   bA   = (Mat_Nest*)A->data;
1926718818eSStefano Zampini   nr   = bA->nr;
1936718818eSStefano Zampini   nc   = bA->nc;
1946718818eSStefano Zampini   ierr = MatGetLocalSize(B,NULL,&n);CHKERRQ(ierr);
19552c5f739Sprj-   ierr = MatGetSize(B,NULL,&N);CHKERRQ(ierr);
19652c5f739Sprj-   ierr = MatGetLocalSize(A,&m,NULL);CHKERRQ(ierr);
19752c5f739Sprj-   ierr = MatGetSize(A,&M,NULL);CHKERRQ(ierr);
1986718818eSStefano Zampini   ierr = MatSetSizes(C,m,n,M,N);CHKERRQ(ierr);
1996718818eSStefano Zampini   ierr = PetscObjectTypeCompareAny((PetscObject)C,&cisdense,MATSEQDENSE,MATMPIDENSE,MATSEQDENSECUDA,MATMPIDENSECUDA,"");CHKERRQ(ierr);
2006718818eSStefano Zampini   if (!cisdense) {
2016718818eSStefano Zampini     ierr = MatSetType(C,((PetscObject)B)->type_name);CHKERRQ(ierr);
2026718818eSStefano Zampini   }
20318992e5dSStefano Zampini   ierr = MatSetUp(C);CHKERRQ(ierr);
2046718818eSStefano Zampini   if (!N) {
2056718818eSStefano Zampini     C->ops->productnumeric = MatProductNumeric_Nest_Dense;
2066718818eSStefano Zampini     PetscFunctionReturn(0);
20752c5f739Sprj-   }
20852c5f739Sprj- 
20952c5f739Sprj-   ierr = PetscNew(&contents);CHKERRQ(ierr);
2106718818eSStefano Zampini   C->product->data = contents;
2116718818eSStefano Zampini   C->product->destroy = MatNest_DenseDestroy;
21252c5f739Sprj-   ierr = PetscCalloc3(nr+1,&contents->dm,nc+1,&contents->dn,nr*nc,&contents->workC);CHKERRQ(ierr);
21352c5f739Sprj-   contents->k = nr*nc;
21452c5f739Sprj-   for (i=0; i<nr; i++) {
21552c5f739Sprj-     ierr = ISGetLocalSize(bA->isglobal.row[i],contents->dm + i+1);CHKERRQ(ierr);
21652c5f739Sprj-     maxm = PetscMax(maxm,contents->dm[i+1]);
21752c5f739Sprj-     contents->dm[i+1] += contents->dm[i];
21852c5f739Sprj-   }
21952c5f739Sprj-   for (i=0; i<nc; i++) {
22052c5f739Sprj-     ierr = ISGetLocalSize(bA->isglobal.col[i],contents->dn + i+1);CHKERRQ(ierr);
22152c5f739Sprj-     contents->dn[i+1] += contents->dn[i];
22252c5f739Sprj-   }
22352c5f739Sprj-   ierr = PetscMalloc1(maxm*N,&contents->tarray);CHKERRQ(ierr);
22452c5f739Sprj-   ierr = MatDenseGetLDA(B,&ldb);CHKERRQ(ierr);
22552c5f739Sprj-   ierr = MatGetSize(B,NULL,&N);CHKERRQ(ierr);
22652c5f739Sprj-   ierr = MatDenseGetArrayRead(B,&barray);CHKERRQ(ierr);
22752c5f739Sprj-   /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */
22852c5f739Sprj-   for (j=0; j<nc; j++) {
22952c5f739Sprj-     ierr = ISGetSize(bA->isglobal.col[j],&M);CHKERRQ(ierr);
23052c5f739Sprj-     ierr = MatCreateDense(PetscObjectComm((PetscObject)A),contents->dn[j+1]-contents->dn[j],PETSC_DECIDE,M,N,(PetscScalar*)(barray+contents->dn[j]),&viewB);CHKERRQ(ierr);
2316718818eSStefano Zampini     ierr = MatDenseSetLDA(viewB,ldb);CHKERRQ(ierr);
23252c5f739Sprj-     for (i=0; i<nr; i++) {
23352c5f739Sprj-       if (!bA->m[i][j]) continue;
23452c5f739Sprj-       /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */
2354222ddf1SHong Zhang 
2364222ddf1SHong Zhang       ierr = MatProductCreate(bA->m[i][j],viewB,NULL,&contents->workC[i*nc + j]);CHKERRQ(ierr);
2374222ddf1SHong Zhang       workC = contents->workC[i*nc + j];
2384222ddf1SHong Zhang       ierr = MatProductSetType(workC,MATPRODUCT_AB);CHKERRQ(ierr);
2394222ddf1SHong Zhang       ierr = MatProductSetAlgorithm(workC,"default");CHKERRQ(ierr);
2404222ddf1SHong Zhang       ierr = MatProductSetFill(workC,fill);CHKERRQ(ierr);
2414222ddf1SHong Zhang       ierr = MatProductSetFromOptions(workC);CHKERRQ(ierr);
2424222ddf1SHong Zhang       ierr = MatProductSymbolic(workC);CHKERRQ(ierr);
2434222ddf1SHong Zhang 
2446718818eSStefano Zampini       /* since tarray will be shared by all Mat */
2456718818eSStefano Zampini       ierr = MatSeqDenseSetPreallocation(workC,contents->tarray);CHKERRQ(ierr);
2466718818eSStefano Zampini       ierr = MatMPIDenseSetPreallocation(workC,contents->tarray);CHKERRQ(ierr);
24752c5f739Sprj-     }
24852c5f739Sprj-     ierr = MatDestroy(&viewB);CHKERRQ(ierr);
24952c5f739Sprj-   }
25052c5f739Sprj-   ierr = MatDenseRestoreArrayRead(B,&barray);CHKERRQ(ierr);
25152c5f739Sprj- 
2526718818eSStefano Zampini   C->ops->productnumeric = MatProductNumeric_Nest_Dense;
25352c5f739Sprj-   PetscFunctionReturn(0);
25452c5f739Sprj- }
25552c5f739Sprj- 
2564222ddf1SHong Zhang /* --------------------------------------------------------- */
2574222ddf1SHong Zhang static PetscErrorCode MatProductSetFromOptions_Nest_Dense_AB(Mat C)
2584222ddf1SHong Zhang {
2594222ddf1SHong Zhang   PetscFunctionBegin;
2606718818eSStefano Zampini   C->ops->productsymbolic = MatProductSymbolic_Nest_Dense;
2614222ddf1SHong Zhang   PetscFunctionReturn(0);
2624222ddf1SHong Zhang }
2634222ddf1SHong Zhang 
2644222ddf1SHong Zhang PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C)
26552c5f739Sprj- {
26652c5f739Sprj-   PetscErrorCode ierr;
2674222ddf1SHong Zhang   Mat_Product    *product = C->product;
26852c5f739Sprj- 
26952c5f739Sprj-   PetscFunctionBegin;
2704222ddf1SHong Zhang   if (product->type == MATPRODUCT_AB) {
2714222ddf1SHong Zhang     ierr = MatProductSetFromOptions_Nest_Dense_AB(C);CHKERRQ(ierr);
2726718818eSStefano Zampini   }
27352c5f739Sprj-   PetscFunctionReturn(0);
27452c5f739Sprj- }
2754222ddf1SHong Zhang /* --------------------------------------------------------- */
27652c5f739Sprj- 
277207556f9SJed Brown static PetscErrorCode MatMultTranspose_Nest(Mat A,Vec x,Vec y)
278d8588912SDave May {
279d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
280207556f9SJed Brown   Vec            *bx = bA->left,*by = bA->right;
281207556f9SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
282d8588912SDave May   PetscErrorCode ierr;
283d8588912SDave May 
284d8588912SDave May   PetscFunctionBegin;
285609e31cbSJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
286609e31cbSJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(y,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);}
287207556f9SJed Brown   for (j=0; j<nc; j++) {
288609e31cbSJed Brown     ierr = VecZeroEntries(by[j]);CHKERRQ(ierr);
289609e31cbSJed Brown     for (i=0; i<nr; i++) {
2906c75ac25SJed Brown       if (!bA->m[i][j]) continue;
291609e31cbSJed Brown       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
292609e31cbSJed Brown       ierr = MatMultTransposeAdd(bA->m[i][j],bx[i],by[j],by[j]);CHKERRQ(ierr);
293d8588912SDave May     }
294d8588912SDave May   }
295609e31cbSJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
296609e31cbSJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(y,bA->isglobal.col[i],&by[i]);CHKERRQ(ierr);}
297d8588912SDave May   PetscFunctionReturn(0);
298d8588912SDave May }
299d8588912SDave May 
3009194d70fSJed Brown static PetscErrorCode MatMultTransposeAdd_Nest(Mat A,Vec x,Vec y,Vec z)
3019194d70fSJed Brown {
3029194d70fSJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
3039194d70fSJed Brown   Vec            *bx = bA->left,*bz = bA->right;
3049194d70fSJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
3059194d70fSJed Brown   PetscErrorCode ierr;
3069194d70fSJed Brown 
3079194d70fSJed Brown   PetscFunctionBegin;
3089194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecGetSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
3099194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecGetSubVector(z,bA->isglobal.col[i],&bz[i]);CHKERRQ(ierr);}
3109194d70fSJed Brown   for (j=0; j<nc; j++) {
3119194d70fSJed Brown     if (y != z) {
3129194d70fSJed Brown       Vec by;
3139194d70fSJed Brown       ierr = VecGetSubVector(y,bA->isglobal.col[j],&by);CHKERRQ(ierr);
3149194d70fSJed Brown       ierr = VecCopy(by,bz[j]);CHKERRQ(ierr);
3159194d70fSJed Brown       ierr = VecRestoreSubVector(y,bA->isglobal.col[j],&by);CHKERRQ(ierr);
3169194d70fSJed Brown     }
3179194d70fSJed Brown     for (i=0; i<nr; i++) {
3186c75ac25SJed Brown       if (!bA->m[i][j]) continue;
3199194d70fSJed Brown       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
3209194d70fSJed Brown       ierr = MatMultTransposeAdd(bA->m[i][j],bx[i],bz[j],bz[j]);CHKERRQ(ierr);
3219194d70fSJed Brown     }
3229194d70fSJed Brown   }
3239194d70fSJed Brown   for (i=0; i<nr; i++) {ierr = VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]);CHKERRQ(ierr);}
3249194d70fSJed Brown   for (i=0; i<nc; i++) {ierr = VecRestoreSubVector(z,bA->isglobal.col[i],&bz[i]);CHKERRQ(ierr);}
3259194d70fSJed Brown   PetscFunctionReturn(0);
3269194d70fSJed Brown }
3279194d70fSJed Brown 
328f8170845SAlex Fikl static PetscErrorCode MatTranspose_Nest(Mat A,MatReuse reuse,Mat *B)
329f8170845SAlex Fikl {
330f8170845SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data, *bC;
331f8170845SAlex Fikl   Mat            C;
332f8170845SAlex Fikl   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
333f8170845SAlex Fikl   PetscErrorCode ierr;
334f8170845SAlex Fikl 
335f8170845SAlex Fikl   PetscFunctionBegin;
336cf37664fSBarry Smith   if (reuse == MAT_INPLACE_MATRIX && nr != nc) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Square nested matrix only for in-place");
337f8170845SAlex Fikl 
338cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
339f8170845SAlex Fikl     Mat *subs;
340f8170845SAlex Fikl     IS  *is_row,*is_col;
341f8170845SAlex Fikl 
342f8170845SAlex Fikl     ierr = PetscCalloc1(nr * nc,&subs);CHKERRQ(ierr);
343f8170845SAlex Fikl     ierr = PetscMalloc2(nr,&is_row,nc,&is_col);CHKERRQ(ierr);
344f8170845SAlex Fikl     ierr = MatNestGetISs(A,is_row,is_col);CHKERRQ(ierr);
345cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
346ddeb9bd8SAlex Fikl       for (i=0; i<nr; i++) {
347ddeb9bd8SAlex Fikl         for (j=0; j<nc; j++) {
348ddeb9bd8SAlex Fikl           subs[i + nr * j] = bA->m[i][j];
349ddeb9bd8SAlex Fikl         }
350ddeb9bd8SAlex Fikl       }
351ddeb9bd8SAlex Fikl     }
352ddeb9bd8SAlex Fikl 
353f8170845SAlex Fikl     ierr = MatCreateNest(PetscObjectComm((PetscObject)A),nc,is_col,nr,is_row,subs,&C);CHKERRQ(ierr);
354f8170845SAlex Fikl     ierr = PetscFree(subs);CHKERRQ(ierr);
3553d994f23SBarry Smith     ierr = PetscFree2(is_row,is_col);CHKERRQ(ierr);
356f8170845SAlex Fikl   } else {
357f8170845SAlex Fikl     C = *B;
358f8170845SAlex Fikl   }
359f8170845SAlex Fikl 
360f8170845SAlex Fikl   bC = (Mat_Nest*)C->data;
361f8170845SAlex Fikl   for (i=0; i<nr; i++) {
362f8170845SAlex Fikl     for (j=0; j<nc; j++) {
363f8170845SAlex Fikl       if (bA->m[i][j]) {
364f8170845SAlex Fikl         ierr = MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i]));CHKERRQ(ierr);
365f8170845SAlex Fikl       } else {
366f8170845SAlex Fikl         bC->m[j][i] = NULL;
367f8170845SAlex Fikl       }
368f8170845SAlex Fikl     }
369f8170845SAlex Fikl   }
370f8170845SAlex Fikl 
371cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
372f8170845SAlex Fikl     *B = C;
373f8170845SAlex Fikl   } else {
374f8170845SAlex Fikl     ierr = MatHeaderMerge(A, &C);CHKERRQ(ierr);
375f8170845SAlex Fikl   }
376f8170845SAlex Fikl   PetscFunctionReturn(0);
377f8170845SAlex Fikl }
378f8170845SAlex Fikl 
379e2d7f03fSJed Brown static PetscErrorCode MatNestDestroyISList(PetscInt n,IS **list)
380e2d7f03fSJed Brown {
381e2d7f03fSJed Brown   PetscErrorCode ierr;
382e2d7f03fSJed Brown   IS             *lst = *list;
383e2d7f03fSJed Brown   PetscInt       i;
384e2d7f03fSJed Brown 
385e2d7f03fSJed Brown   PetscFunctionBegin;
386e2d7f03fSJed Brown   if (!lst) PetscFunctionReturn(0);
3876bf464f9SBarry Smith   for (i=0; i<n; i++) if (lst[i]) {ierr = ISDestroy(&lst[i]);CHKERRQ(ierr);}
388e2d7f03fSJed Brown   ierr  = PetscFree(lst);CHKERRQ(ierr);
3890298fd71SBarry Smith   *list = NULL;
390e2d7f03fSJed Brown   PetscFunctionReturn(0);
391e2d7f03fSJed Brown }
392e2d7f03fSJed Brown 
39306a1af2fSStefano Zampini static PetscErrorCode MatReset_Nest(Mat A)
394d8588912SDave May {
395d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
396d8588912SDave May   PetscInt       i,j;
397d8588912SDave May   PetscErrorCode ierr;
398d8588912SDave May 
399d8588912SDave May   PetscFunctionBegin;
400d8588912SDave May   /* release the matrices and the place holders */
401e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nr,&vs->isglobal.row);CHKERRQ(ierr);
402e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nc,&vs->isglobal.col);CHKERRQ(ierr);
403e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nr,&vs->islocal.row);CHKERRQ(ierr);
404e2d7f03fSJed Brown   ierr = MatNestDestroyISList(vs->nc,&vs->islocal.col);CHKERRQ(ierr);
405d8588912SDave May 
406d8588912SDave May   ierr = PetscFree(vs->row_len);CHKERRQ(ierr);
407d8588912SDave May   ierr = PetscFree(vs->col_len);CHKERRQ(ierr);
40806a1af2fSStefano Zampini   ierr = PetscFree(vs->nnzstate);CHKERRQ(ierr);
409d8588912SDave May 
410207556f9SJed Brown   ierr = PetscFree2(vs->left,vs->right);CHKERRQ(ierr);
411207556f9SJed Brown 
412d8588912SDave May   /* release the matrices and the place holders */
413d8588912SDave May   if (vs->m) {
414d8588912SDave May     for (i=0; i<vs->nr; i++) {
415d8588912SDave May       for (j=0; j<vs->nc; j++) {
4166bf464f9SBarry Smith         ierr = MatDestroy(&vs->m[i][j]);CHKERRQ(ierr);
417d8588912SDave May       }
418d8588912SDave May       ierr = PetscFree(vs->m[i]);CHKERRQ(ierr);
419d8588912SDave May     }
420d8588912SDave May     ierr = PetscFree(vs->m);CHKERRQ(ierr);
421d8588912SDave May   }
42206a1af2fSStefano Zampini 
42306a1af2fSStefano Zampini   /* restore defaults */
42406a1af2fSStefano Zampini   vs->nr = 0;
42506a1af2fSStefano Zampini   vs->nc = 0;
42606a1af2fSStefano Zampini   vs->splitassembly = PETSC_FALSE;
42706a1af2fSStefano Zampini   PetscFunctionReturn(0);
42806a1af2fSStefano Zampini }
42906a1af2fSStefano Zampini 
43006a1af2fSStefano Zampini static PetscErrorCode MatDestroy_Nest(Mat A)
43106a1af2fSStefano Zampini {
43206a1af2fSStefano Zampini   PetscErrorCode ierr;
43306a1af2fSStefano Zampini 
43406a1af2fSStefano Zampini   ierr = MatReset_Nest(A);CHKERRQ(ierr);
435bf0cc555SLisandro Dalcin   ierr = PetscFree(A->data);CHKERRQ(ierr);
436d8588912SDave May 
437bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",0);CHKERRQ(ierr);
438bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",0);CHKERRQ(ierr);
439bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",0);CHKERRQ(ierr);
440bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",0);CHKERRQ(ierr);
441bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",0);CHKERRQ(ierr);
442bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",0);CHKERRQ(ierr);
443bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",0);CHKERRQ(ierr);
444bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",0);CHKERRQ(ierr);
4450899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",0);CHKERRQ(ierr);
4460899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",0);CHKERRQ(ierr);
4475e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",0);CHKERRQ(ierr);
4485e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",0);CHKERRQ(ierr);
4494222ddf1SHong Zhang   ierr = PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_seqdense_C",NULL);CHKERRQ(ierr);
4504222ddf1SHong Zhang   ierr = PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_mpidense_C",NULL);CHKERRQ(ierr);
4514222ddf1SHong Zhang   ierr = PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_dense_C",NULL);CHKERRQ(ierr);
452d8588912SDave May   PetscFunctionReturn(0);
453d8588912SDave May }
454d8588912SDave May 
455381b8e50SStefano Zampini static PetscErrorCode MatMissingDiagonal_Nest(Mat mat,PetscBool *missing,PetscInt *dd)
456381b8e50SStefano Zampini {
457381b8e50SStefano Zampini   Mat_Nest       *vs = (Mat_Nest*)mat->data;
458381b8e50SStefano Zampini   PetscInt       i;
459381b8e50SStefano Zampini   PetscErrorCode ierr;
460381b8e50SStefano Zampini 
461381b8e50SStefano Zampini   PetscFunctionBegin;
462381b8e50SStefano Zampini   if (dd) *dd = 0;
463381b8e50SStefano Zampini   if (!vs->nr) {
464381b8e50SStefano Zampini     *missing = PETSC_TRUE;
465381b8e50SStefano Zampini     PetscFunctionReturn(0);
466381b8e50SStefano Zampini   }
467381b8e50SStefano Zampini   *missing = PETSC_FALSE;
468381b8e50SStefano Zampini   for (i = 0; i < vs->nr && !(*missing); i++) {
469381b8e50SStefano Zampini     *missing = PETSC_TRUE;
470381b8e50SStefano Zampini     if (vs->m[i][i]) {
471381b8e50SStefano Zampini       ierr = MatMissingDiagonal(vs->m[i][i],missing,NULL);CHKERRQ(ierr);
472381b8e50SStefano Zampini       if (*missing && dd) SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"First missing entry not yet implemented");
473381b8e50SStefano Zampini     }
474381b8e50SStefano Zampini   }
475381b8e50SStefano Zampini   PetscFunctionReturn(0);
476381b8e50SStefano Zampini }
477381b8e50SStefano Zampini 
478207556f9SJed Brown static PetscErrorCode MatAssemblyBegin_Nest(Mat A,MatAssemblyType type)
479d8588912SDave May {
480d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
481d8588912SDave May   PetscInt       i,j;
482d8588912SDave May   PetscErrorCode ierr;
48306a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
484d8588912SDave May 
485d8588912SDave May   PetscFunctionBegin;
486d8588912SDave May   for (i=0; i<vs->nr; i++) {
487d8588912SDave May     for (j=0; j<vs->nc; j++) {
48806a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
489e7c19651SJed Brown       if (vs->m[i][j]) {
490e7c19651SJed Brown         ierr = MatAssemblyBegin(vs->m[i][j],type);CHKERRQ(ierr);
491e7c19651SJed Brown         if (!vs->splitassembly) {
492e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
493e7c19651SJed 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
494e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
495e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
496e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
497e7c19651SJed Brown            */
498e7c19651SJed Brown           ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr);
49906a1af2fSStefano Zampini           ierr = MatGetNonzeroState(vs->m[i][j],&subnnzstate);CHKERRQ(ierr);
500e7c19651SJed Brown         }
501e7c19651SJed Brown       }
50206a1af2fSStefano Zampini       nnzstate = (PetscBool)(nnzstate || vs->nnzstate[i*vs->nc+j] != subnnzstate);
50306a1af2fSStefano Zampini       vs->nnzstate[i*vs->nc+j] = subnnzstate;
504d8588912SDave May     }
505d8588912SDave May   }
50606a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
507d8588912SDave May   PetscFunctionReturn(0);
508d8588912SDave May }
509d8588912SDave May 
510207556f9SJed Brown static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
511d8588912SDave May {
512d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
513d8588912SDave May   PetscInt       i,j;
514d8588912SDave May   PetscErrorCode ierr;
515d8588912SDave May 
516d8588912SDave May   PetscFunctionBegin;
517d8588912SDave May   for (i=0; i<vs->nr; i++) {
518d8588912SDave May     for (j=0; j<vs->nc; j++) {
519e7c19651SJed Brown       if (vs->m[i][j]) {
520e7c19651SJed Brown         if (vs->splitassembly) {
521e7c19651SJed Brown           ierr = MatAssemblyEnd(vs->m[i][j],type);CHKERRQ(ierr);
522e7c19651SJed Brown         }
523e7c19651SJed Brown       }
524d8588912SDave May     }
525d8588912SDave May   }
526d8588912SDave May   PetscFunctionReturn(0);
527d8588912SDave May }
528d8588912SDave May 
529f349c1fdSJed Brown static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat *B)
530d8588912SDave May {
531207556f9SJed Brown   PetscErrorCode ierr;
532f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
533f349c1fdSJed Brown   PetscInt       j;
534f349c1fdSJed Brown   Mat            sub;
535d8588912SDave May 
536d8588912SDave May   PetscFunctionBegin;
5370298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
538f349c1fdSJed Brown   for (j=0; !sub && j<vs->nc; j++) sub = vs->m[row][j];
5394994cf47SJed Brown   if (sub) {ierr = MatSetUp(sub);CHKERRQ(ierr);}       /* Ensure that the sizes are available */
540f349c1fdSJed Brown   *B = sub;
541f349c1fdSJed Brown   PetscFunctionReturn(0);
542d8588912SDave May }
543d8588912SDave May 
544f349c1fdSJed Brown static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat *B)
545f349c1fdSJed Brown {
546207556f9SJed Brown   PetscErrorCode ierr;
547f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
548f349c1fdSJed Brown   PetscInt       i;
549f349c1fdSJed Brown   Mat            sub;
550f349c1fdSJed Brown 
551f349c1fdSJed Brown   PetscFunctionBegin;
5520298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
553f349c1fdSJed Brown   for (i=0; !sub && i<vs->nr; i++) sub = vs->m[i][col];
5544994cf47SJed Brown   if (sub) {ierr = MatSetUp(sub);CHKERRQ(ierr);}       /* Ensure that the sizes are available */
555f349c1fdSJed Brown   *B = sub;
556f349c1fdSJed Brown   PetscFunctionReturn(0);
557d8588912SDave May }
558d8588912SDave May 
559*18d228c0SPierre Jolivet static PetscErrorCode MatNestFindISRange(Mat A,PetscInt n,const IS list[],IS is,PetscInt *begin,PetscInt *end)
560f349c1fdSJed Brown {
561*18d228c0SPierre Jolivet   PetscInt       i,j,size,m;
562f349c1fdSJed Brown   PetscBool      flg;
563*18d228c0SPierre Jolivet   IS             out,concatenate[2];
564*18d228c0SPierre Jolivet   PetscErrorCode ierr;
565f349c1fdSJed Brown 
566f349c1fdSJed Brown   PetscFunctionBegin;
567f349c1fdSJed Brown   PetscValidPointer(list,3);
568f349c1fdSJed Brown   PetscValidHeaderSpecific(is,IS_CLASSID,4);
569*18d228c0SPierre Jolivet   if (begin) {
570*18d228c0SPierre Jolivet     PetscValidIntPointer(begin,5);
571*18d228c0SPierre Jolivet     *begin = -1;
572*18d228c0SPierre Jolivet   }
573*18d228c0SPierre Jolivet   if (end) {
574*18d228c0SPierre Jolivet     PetscValidIntPointer(end,6);
575*18d228c0SPierre Jolivet     *end = -1;
576*18d228c0SPierre Jolivet   }
577f349c1fdSJed Brown   for (i=0; i<n; i++) {
578207556f9SJed Brown     if (!list[i]) continue;
579320466b0SStefano Zampini     ierr = ISEqualUnsorted(list[i],is,&flg);CHKERRQ(ierr);
580f349c1fdSJed Brown     if (flg) {
581*18d228c0SPierre Jolivet       if (begin) *begin = i;
582*18d228c0SPierre Jolivet       if (end) *end = i+1;
583f349c1fdSJed Brown       PetscFunctionReturn(0);
584f349c1fdSJed Brown     }
585f349c1fdSJed Brown   }
586*18d228c0SPierre Jolivet   ierr = ISGetSize(is,&size);CHKERRQ(ierr);
587*18d228c0SPierre Jolivet   for (i=0; i<n-1; i++) {
588*18d228c0SPierre Jolivet     if (!list[i]) continue;
589*18d228c0SPierre Jolivet     m = 0;
590*18d228c0SPierre Jolivet     ierr = ISConcatenate(PetscObjectComm((PetscObject)A),2,list+i,&out);CHKERRQ(ierr);
591*18d228c0SPierre Jolivet     ierr = ISGetSize(out,&m);CHKERRQ(ierr);
592*18d228c0SPierre Jolivet     for (j=i+2; j<n && m<size; j++) {
593*18d228c0SPierre Jolivet       if (list[j]) {
594*18d228c0SPierre Jolivet         concatenate[0] = out;
595*18d228c0SPierre Jolivet         concatenate[1] = list[j];
596*18d228c0SPierre Jolivet         ierr = ISConcatenate(PetscObjectComm((PetscObject)A),2,concatenate,&out);CHKERRQ(ierr);
597*18d228c0SPierre Jolivet         ierr = ISDestroy(concatenate);CHKERRQ(ierr);
598*18d228c0SPierre Jolivet         ierr = ISGetSize(out,&m);CHKERRQ(ierr);
599*18d228c0SPierre Jolivet       }
600*18d228c0SPierre Jolivet     }
601*18d228c0SPierre Jolivet     if (m == size) {
602*18d228c0SPierre Jolivet       ierr = ISEqualUnsorted(out,is,&flg);CHKERRQ(ierr);
603*18d228c0SPierre Jolivet       if (flg) {
604*18d228c0SPierre Jolivet         if (begin) *begin = i;
605*18d228c0SPierre Jolivet         if (end) *end = j;
606*18d228c0SPierre Jolivet         ierr = ISDestroy(&out);CHKERRQ(ierr);
607*18d228c0SPierre Jolivet         PetscFunctionReturn(0);
608*18d228c0SPierre Jolivet       }
609*18d228c0SPierre Jolivet     }
610*18d228c0SPierre Jolivet     ierr = ISDestroy(&out);CHKERRQ(ierr);
611*18d228c0SPierre Jolivet   }
612*18d228c0SPierre Jolivet   PetscFunctionReturn(0);
613f349c1fdSJed Brown }
614f349c1fdSJed Brown 
615*18d228c0SPierre Jolivet 
616*18d228c0SPierre Jolivet static PetscErrorCode MatNestFillEmptyMat_Private(Mat A,PetscInt i,PetscInt j,Mat *B)
6178188e55aSJed Brown {
6188188e55aSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
619*18d228c0SPierre Jolivet   PetscInt       lr,lc;
620*18d228c0SPierre Jolivet   PetscErrorCode ierr;
621*18d228c0SPierre Jolivet 
622*18d228c0SPierre Jolivet   PetscFunctionBegin;
623*18d228c0SPierre Jolivet   ierr = MatCreate(PetscObjectComm((PetscObject)A),B);CHKERRQ(ierr);
624*18d228c0SPierre Jolivet   ierr = ISGetLocalSize(vs->isglobal.row[i],&lr);CHKERRQ(ierr);
625*18d228c0SPierre Jolivet   ierr = ISGetLocalSize(vs->isglobal.col[j],&lc);CHKERRQ(ierr);
626*18d228c0SPierre Jolivet   ierr = MatSetSizes(*B,lr,lc,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
627*18d228c0SPierre Jolivet   ierr = MatSetType(*B,MATAIJ);CHKERRQ(ierr);
628*18d228c0SPierre Jolivet   ierr = MatSeqAIJSetPreallocation(*B,0,NULL);CHKERRQ(ierr);
629*18d228c0SPierre Jolivet   ierr = MatMPIAIJSetPreallocation(*B,0,NULL,0,NULL);CHKERRQ(ierr);
630*18d228c0SPierre Jolivet   ierr = MatSetUp(*B);CHKERRQ(ierr);
631*18d228c0SPierre Jolivet   ierr = MatSetOption(*B,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE);CHKERRQ(ierr);
632*18d228c0SPierre Jolivet   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
633*18d228c0SPierre Jolivet   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
634*18d228c0SPierre Jolivet   PetscFunctionReturn(0);
635*18d228c0SPierre Jolivet }
636*18d228c0SPierre Jolivet 
637*18d228c0SPierre Jolivet static PetscErrorCode MatNestGetBlock_Private(Mat A,PetscInt rbegin,PetscInt rend,PetscInt cbegin,PetscInt cend,Mat *B)
638*18d228c0SPierre Jolivet {
639*18d228c0SPierre Jolivet   Mat_Nest       *vs = (Mat_Nest*)A->data;
640*18d228c0SPierre Jolivet   Mat            *a;
641*18d228c0SPierre Jolivet   PetscInt       i,j,k,l,nr=rend-rbegin,nc=cend-cbegin;
6428188e55aSJed Brown   char           keyname[256];
643*18d228c0SPierre Jolivet   PetscBool      *b;
644*18d228c0SPierre Jolivet   PetscBool      flg;
6458188e55aSJed Brown   PetscErrorCode ierr;
6468188e55aSJed Brown 
6478188e55aSJed Brown   PetscFunctionBegin;
6480298fd71SBarry Smith   *B   = NULL;
649*18d228c0SPierre Jolivet   ierr = PetscSNPrintf(keyname,sizeof(keyname),"NestBlock_%D-%Dx%D-%D",rbegin,rend,cbegin,cend);CHKERRQ(ierr);
6508188e55aSJed Brown   ierr = PetscObjectQuery((PetscObject)A,keyname,(PetscObject*)B);CHKERRQ(ierr);
6518188e55aSJed Brown   if (*B) PetscFunctionReturn(0);
6528188e55aSJed Brown 
653*18d228c0SPierre Jolivet   ierr = PetscMalloc2(nr*nc,&a,nr*nc,&b);CHKERRQ(ierr);
654*18d228c0SPierre Jolivet   for (i=0; i<nr; i++) {
655*18d228c0SPierre Jolivet     for (j=0; j<nc; j++) {
656*18d228c0SPierre Jolivet       a[i*nc + j] = vs->m[rbegin+i][cbegin+j];
657*18d228c0SPierre Jolivet       b[i*nc + j] = PETSC_FALSE;
658*18d228c0SPierre Jolivet     }
659*18d228c0SPierre Jolivet   }
660*18d228c0SPierre Jolivet   if (nc!=vs->nc&&nr!=vs->nr) {
661*18d228c0SPierre Jolivet     for (i=0; i<nr; i++) {
662*18d228c0SPierre Jolivet       for (j=0; j<nc; j++) {
663*18d228c0SPierre Jolivet         flg = PETSC_FALSE;
664*18d228c0SPierre Jolivet         for (k=0; (k<nr&&!flg); k++) {
665*18d228c0SPierre Jolivet           if (a[j + k*nc]) flg = PETSC_TRUE;
666*18d228c0SPierre Jolivet         }
667*18d228c0SPierre Jolivet         if (flg) {
668*18d228c0SPierre Jolivet           flg = PETSC_FALSE;
669*18d228c0SPierre Jolivet           for (l=0; (l<nc&&!flg); l++) {
670*18d228c0SPierre Jolivet             if (a[i*nc + l]) flg = PETSC_TRUE;
671*18d228c0SPierre Jolivet           }
672*18d228c0SPierre Jolivet         }
673*18d228c0SPierre Jolivet         if (!flg) {
674*18d228c0SPierre Jolivet           b[i*nc + j] = PETSC_TRUE;
675*18d228c0SPierre Jolivet           ierr = MatNestFillEmptyMat_Private(A,rbegin+i,cbegin+j,a + i*nc + j);CHKERRQ(ierr);
676*18d228c0SPierre Jolivet         }
677*18d228c0SPierre Jolivet       }
678*18d228c0SPierre Jolivet     }
679*18d228c0SPierre Jolivet   }
680*18d228c0SPierre Jolivet   ierr = MatCreateNest(PetscObjectComm((PetscObject)A),nr,nr!=vs->nr?NULL:vs->isglobal.row,nc,nc!=vs->nc?NULL:vs->isglobal.col,a,B);CHKERRQ(ierr);
681*18d228c0SPierre Jolivet   for (i=0; i<nr; i++) {
682*18d228c0SPierre Jolivet     for (j=0; j<nc; j++) {
683*18d228c0SPierre Jolivet       if (b[i*nc + j]) {
684*18d228c0SPierre Jolivet         ierr = MatDestroy(a + i*nc + j);CHKERRQ(ierr);
685*18d228c0SPierre Jolivet       }
686*18d228c0SPierre Jolivet     }
687*18d228c0SPierre Jolivet   }
688*18d228c0SPierre Jolivet   ierr = PetscFree2(a,b);CHKERRQ(ierr);
6898188e55aSJed Brown   (*B)->assembled = A->assembled;
6908188e55aSJed Brown   ierr = PetscObjectCompose((PetscObject)A,keyname,(PetscObject)*B);CHKERRQ(ierr);
6918188e55aSJed Brown   ierr = PetscObjectDereference((PetscObject)*B);CHKERRQ(ierr); /* Leave the only remaining reference in the composition */
6928188e55aSJed Brown   PetscFunctionReturn(0);
6938188e55aSJed Brown }
6948188e55aSJed Brown 
695f349c1fdSJed Brown static PetscErrorCode MatNestFindSubMat(Mat A,struct MatNestISPair *is,IS isrow,IS iscol,Mat *B)
696f349c1fdSJed Brown {
697f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
698*18d228c0SPierre Jolivet   PetscInt       rbegin,rend,cbegin,cend;
6998188e55aSJed Brown   PetscErrorCode ierr;
700f349c1fdSJed Brown 
701f349c1fdSJed Brown   PetscFunctionBegin;
702*18d228c0SPierre Jolivet   ierr = MatNestFindISRange(A,vs->nr,is->row,isrow,&rbegin,&rend);CHKERRQ(ierr);
703*18d228c0SPierre Jolivet   ierr = MatNestFindISRange(A,vs->nc,is->col,iscol,&cbegin,&cend);CHKERRQ(ierr);
704*18d228c0SPierre Jolivet   if (rend == rbegin + 1 && cend == cbegin + 1) {
705*18d228c0SPierre Jolivet     if (!vs->m[rbegin][cbegin]) {
706*18d228c0SPierre Jolivet       ierr = MatNestFillEmptyMat_Private(A,rbegin,cbegin,vs->m[rbegin] + cbegin);CHKERRQ(ierr);
70777019fcaSJed Brown     }
708*18d228c0SPierre Jolivet     *B = vs->m[rbegin][cbegin];
709*18d228c0SPierre Jolivet   } else if (rbegin != -1 && cbegin != -1) {
710*18d228c0SPierre Jolivet     ierr = MatNestGetBlock_Private(A,rbegin,rend,cbegin,cend,B);CHKERRQ(ierr);
711*18d228c0SPierre Jolivet   } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Could not find index set");
712f349c1fdSJed Brown   PetscFunctionReturn(0);
713f349c1fdSJed Brown }
714f349c1fdSJed Brown 
71506a1af2fSStefano Zampini /*
71606a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
71706a1af2fSStefano Zampini */
7187dae84e0SHong Zhang static PetscErrorCode MatCreateSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat *B)
719f349c1fdSJed Brown {
720f349c1fdSJed Brown   PetscErrorCode ierr;
721f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
722f349c1fdSJed Brown   Mat            sub;
723f349c1fdSJed Brown 
724f349c1fdSJed Brown   PetscFunctionBegin;
725f349c1fdSJed Brown   ierr = MatNestFindSubMat(A,&vs->isglobal,isrow,iscol,&sub);CHKERRQ(ierr);
726f349c1fdSJed Brown   switch (reuse) {
727f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
7287874fa86SDave May     if (sub) { ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr); }
729f349c1fdSJed Brown     *B = sub;
730f349c1fdSJed Brown     break;
731f349c1fdSJed Brown   case MAT_REUSE_MATRIX:
732ce94432eSBarry Smith     if (sub != *B) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Submatrix was not used before in this call");
733f349c1fdSJed Brown     break;
734f349c1fdSJed Brown   case MAT_IGNORE_MATRIX:       /* Nothing to do */
735f349c1fdSJed Brown     break;
736511c6705SHong Zhang   case MAT_INPLACE_MATRIX:       /* Nothing to do */
737511c6705SHong Zhang     SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MAT_INPLACE_MATRIX is not supported yet");
738f349c1fdSJed Brown   }
739f349c1fdSJed Brown   PetscFunctionReturn(0);
740f349c1fdSJed Brown }
741f349c1fdSJed Brown 
742f349c1fdSJed Brown PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
743f349c1fdSJed Brown {
744f349c1fdSJed Brown   PetscErrorCode ierr;
745f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
746f349c1fdSJed Brown   Mat            sub;
747f349c1fdSJed Brown 
748f349c1fdSJed Brown   PetscFunctionBegin;
749f349c1fdSJed Brown   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
750f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
751f349c1fdSJed Brown   if (sub) {ierr = PetscObjectReference((PetscObject)sub);CHKERRQ(ierr);}
752f349c1fdSJed Brown   *B = sub;
753d8588912SDave May   PetscFunctionReturn(0);
754d8588912SDave May }
755d8588912SDave May 
756207556f9SJed Brown static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
757d8588912SDave May {
758d8588912SDave May   PetscErrorCode ierr;
759f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
760f349c1fdSJed Brown   Mat            sub;
761d8588912SDave May 
762d8588912SDave May   PetscFunctionBegin;
763f349c1fdSJed Brown   ierr = MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub);CHKERRQ(ierr);
764ce94432eSBarry Smith   if (*B != sub) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has not been gotten");
765f349c1fdSJed Brown   if (sub) {
766ce94432eSBarry Smith     if (((PetscObject)sub)->refct <= 1) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has had reference count decremented too many times");
7676bf464f9SBarry Smith     ierr = MatDestroy(B);CHKERRQ(ierr);
768d8588912SDave May   }
769d8588912SDave May   PetscFunctionReturn(0);
770d8588912SDave May }
771d8588912SDave May 
7727874fa86SDave May static PetscErrorCode MatGetDiagonal_Nest(Mat A,Vec v)
7737874fa86SDave May {
7747874fa86SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
7757874fa86SDave May   PetscInt       i;
7767874fa86SDave May   PetscErrorCode ierr;
7777874fa86SDave May 
7787874fa86SDave May   PetscFunctionBegin;
7797874fa86SDave May   for (i=0; i<bA->nr; i++) {
780429bac76SJed Brown     Vec bv;
781429bac76SJed Brown     ierr = VecGetSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
7827874fa86SDave May     if (bA->m[i][i]) {
783429bac76SJed Brown       ierr = MatGetDiagonal(bA->m[i][i],bv);CHKERRQ(ierr);
7847874fa86SDave May     } else {
7855159a857SMatthew G. Knepley       ierr = VecSet(bv,0.0);CHKERRQ(ierr);
7867874fa86SDave May     }
787429bac76SJed Brown     ierr = VecRestoreSubVector(v,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
7887874fa86SDave May   }
7897874fa86SDave May   PetscFunctionReturn(0);
7907874fa86SDave May }
7917874fa86SDave May 
7927874fa86SDave May static PetscErrorCode MatDiagonalScale_Nest(Mat A,Vec l,Vec r)
7937874fa86SDave May {
7947874fa86SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
795429bac76SJed Brown   Vec            bl,*br;
7967874fa86SDave May   PetscInt       i,j;
7977874fa86SDave May   PetscErrorCode ierr;
7987874fa86SDave May 
7997874fa86SDave May   PetscFunctionBegin;
8003f800ebeSJed Brown   ierr = PetscCalloc1(bA->nc,&br);CHKERRQ(ierr);
8012e6472ebSElliott Sales de Andrade   if (r) {
802429bac76SJed Brown     for (j=0; j<bA->nc; j++) {ierr = VecGetSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);}
8032e6472ebSElliott Sales de Andrade   }
8042e6472ebSElliott Sales de Andrade   bl = NULL;
8057874fa86SDave May   for (i=0; i<bA->nr; i++) {
8062e6472ebSElliott Sales de Andrade     if (l) {
807429bac76SJed Brown       ierr = VecGetSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr);
8082e6472ebSElliott Sales de Andrade     }
8097874fa86SDave May     for (j=0; j<bA->nc; j++) {
8107874fa86SDave May       if (bA->m[i][j]) {
811429bac76SJed Brown         ierr = MatDiagonalScale(bA->m[i][j],bl,br[j]);CHKERRQ(ierr);
8127874fa86SDave May       }
8137874fa86SDave May     }
8142e6472ebSElliott Sales de Andrade     if (l) {
815a061e289SJed Brown       ierr = VecRestoreSubVector(l,bA->isglobal.row[i],&bl);CHKERRQ(ierr);
8167874fa86SDave May     }
8172e6472ebSElliott Sales de Andrade   }
8182e6472ebSElliott Sales de Andrade   if (r) {
819429bac76SJed Brown     for (j=0; j<bA->nc; j++) {ierr = VecRestoreSubVector(r,bA->isglobal.col[j],&br[j]);CHKERRQ(ierr);}
8202e6472ebSElliott Sales de Andrade   }
821429bac76SJed Brown   ierr = PetscFree(br);CHKERRQ(ierr);
8227874fa86SDave May   PetscFunctionReturn(0);
8237874fa86SDave May }
8247874fa86SDave May 
825a061e289SJed Brown static PetscErrorCode MatScale_Nest(Mat A,PetscScalar a)
826a061e289SJed Brown {
827a061e289SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
828a061e289SJed Brown   PetscInt       i,j;
829a061e289SJed Brown   PetscErrorCode ierr;
830a061e289SJed Brown 
831a061e289SJed Brown   PetscFunctionBegin;
832a061e289SJed Brown   for (i=0; i<bA->nr; i++) {
833a061e289SJed Brown     for (j=0; j<bA->nc; j++) {
834a061e289SJed Brown       if (bA->m[i][j]) {
835a061e289SJed Brown         ierr = MatScale(bA->m[i][j],a);CHKERRQ(ierr);
836a061e289SJed Brown       }
837a061e289SJed Brown     }
838a061e289SJed Brown   }
839a061e289SJed Brown   PetscFunctionReturn(0);
840a061e289SJed Brown }
841a061e289SJed Brown 
842a061e289SJed Brown static PetscErrorCode MatShift_Nest(Mat A,PetscScalar a)
843a061e289SJed Brown {
844a061e289SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
845a061e289SJed Brown   PetscInt       i;
846a061e289SJed Brown   PetscErrorCode ierr;
84706a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
848a061e289SJed Brown 
849a061e289SJed Brown   PetscFunctionBegin;
850a061e289SJed Brown   for (i=0; i<bA->nr; i++) {
85106a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
852ce94432eSBarry 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);
853a061e289SJed Brown     ierr = MatShift(bA->m[i][i],a);CHKERRQ(ierr);
85406a1af2fSStefano Zampini     ierr = MatGetNonzeroState(bA->m[i][i],&subnnzstate);CHKERRQ(ierr);
85506a1af2fSStefano Zampini     nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i*bA->nc+i] != subnnzstate);
85606a1af2fSStefano Zampini     bA->nnzstate[i*bA->nc+i] = subnnzstate;
857a061e289SJed Brown   }
85806a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
859a061e289SJed Brown   PetscFunctionReturn(0);
860a061e289SJed Brown }
861a061e289SJed Brown 
86213135bc6SAlex Fikl static PetscErrorCode MatDiagonalSet_Nest(Mat A,Vec D,InsertMode is)
86313135bc6SAlex Fikl {
86413135bc6SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data;
86513135bc6SAlex Fikl   PetscInt       i;
86613135bc6SAlex Fikl   PetscErrorCode ierr;
86706a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
86813135bc6SAlex Fikl 
86913135bc6SAlex Fikl   PetscFunctionBegin;
87013135bc6SAlex Fikl   for (i=0; i<bA->nr; i++) {
87106a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
87213135bc6SAlex Fikl     Vec              bv;
87313135bc6SAlex Fikl     ierr = VecGetSubVector(D,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
87413135bc6SAlex Fikl     if (bA->m[i][i]) {
87513135bc6SAlex Fikl       ierr = MatDiagonalSet(bA->m[i][i],bv,is);CHKERRQ(ierr);
87606a1af2fSStefano Zampini       ierr = MatGetNonzeroState(bA->m[i][i],&subnnzstate);CHKERRQ(ierr);
87713135bc6SAlex Fikl     }
87813135bc6SAlex Fikl     ierr = VecRestoreSubVector(D,bA->isglobal.row[i],&bv);CHKERRQ(ierr);
87906a1af2fSStefano Zampini     nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i*bA->nc+i] != subnnzstate);
88006a1af2fSStefano Zampini     bA->nnzstate[i*bA->nc+i] = subnnzstate;
88113135bc6SAlex Fikl   }
88206a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
88313135bc6SAlex Fikl   PetscFunctionReturn(0);
88413135bc6SAlex Fikl }
88513135bc6SAlex Fikl 
886f8170845SAlex Fikl static PetscErrorCode MatSetRandom_Nest(Mat A,PetscRandom rctx)
887f8170845SAlex Fikl {
888f8170845SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data;
889f8170845SAlex Fikl   PetscInt       i,j;
890f8170845SAlex Fikl   PetscErrorCode ierr;
891f8170845SAlex Fikl 
892f8170845SAlex Fikl   PetscFunctionBegin;
893f8170845SAlex Fikl   for (i=0; i<bA->nr; i++) {
894f8170845SAlex Fikl     for (j=0; j<bA->nc; j++) {
895f8170845SAlex Fikl       if (bA->m[i][j]) {
896f8170845SAlex Fikl         ierr = MatSetRandom(bA->m[i][j],rctx);CHKERRQ(ierr);
897f8170845SAlex Fikl       }
898f8170845SAlex Fikl     }
899f8170845SAlex Fikl   }
900f8170845SAlex Fikl   PetscFunctionReturn(0);
901f8170845SAlex Fikl }
902f8170845SAlex Fikl 
9032a7a6963SBarry Smith static PetscErrorCode MatCreateVecs_Nest(Mat A,Vec *right,Vec *left)
904d8588912SDave May {
905d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
906d8588912SDave May   Vec            *L,*R;
907d8588912SDave May   MPI_Comm       comm;
908d8588912SDave May   PetscInt       i,j;
909d8588912SDave May   PetscErrorCode ierr;
910d8588912SDave May 
911d8588912SDave May   PetscFunctionBegin;
912ce94432eSBarry Smith   ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr);
913d8588912SDave May   if (right) {
914d8588912SDave May     /* allocate R */
915854ce69bSBarry Smith     ierr = PetscMalloc1(bA->nc, &R);CHKERRQ(ierr);
916d8588912SDave May     /* Create the right vectors */
917d8588912SDave May     for (j=0; j<bA->nc; j++) {
918d8588912SDave May       for (i=0; i<bA->nr; i++) {
919d8588912SDave May         if (bA->m[i][j]) {
9202a7a6963SBarry Smith           ierr = MatCreateVecs(bA->m[i][j],&R[j],NULL);CHKERRQ(ierr);
921d8588912SDave May           break;
922d8588912SDave May         }
923d8588912SDave May       }
9246c4ed002SBarry Smith       if (i==bA->nr) SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
925d8588912SDave May     }
926f349c1fdSJed Brown     ierr = VecCreateNest(comm,bA->nc,bA->isglobal.col,R,right);CHKERRQ(ierr);
927d8588912SDave May     /* hand back control to the nest vector */
928d8588912SDave May     for (j=0; j<bA->nc; j++) {
9296bf464f9SBarry Smith       ierr = VecDestroy(&R[j]);CHKERRQ(ierr);
930d8588912SDave May     }
931d8588912SDave May     ierr = PetscFree(R);CHKERRQ(ierr);
932d8588912SDave May   }
933d8588912SDave May 
934d8588912SDave May   if (left) {
935d8588912SDave May     /* allocate L */
936854ce69bSBarry Smith     ierr = PetscMalloc1(bA->nr, &L);CHKERRQ(ierr);
937d8588912SDave May     /* Create the left vectors */
938d8588912SDave May     for (i=0; i<bA->nr; i++) {
939d8588912SDave May       for (j=0; j<bA->nc; j++) {
940d8588912SDave May         if (bA->m[i][j]) {
9412a7a6963SBarry Smith           ierr = MatCreateVecs(bA->m[i][j],NULL,&L[i]);CHKERRQ(ierr);
942d8588912SDave May           break;
943d8588912SDave May         }
944d8588912SDave May       }
9456c4ed002SBarry Smith       if (j==bA->nc) SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
946d8588912SDave May     }
947d8588912SDave May 
948f349c1fdSJed Brown     ierr = VecCreateNest(comm,bA->nr,bA->isglobal.row,L,left);CHKERRQ(ierr);
949d8588912SDave May     for (i=0; i<bA->nr; i++) {
9506bf464f9SBarry Smith       ierr = VecDestroy(&L[i]);CHKERRQ(ierr);
951d8588912SDave May     }
952d8588912SDave May 
953d8588912SDave May     ierr = PetscFree(L);CHKERRQ(ierr);
954d8588912SDave May   }
955d8588912SDave May   PetscFunctionReturn(0);
956d8588912SDave May }
957d8588912SDave May 
958207556f9SJed Brown static PetscErrorCode MatView_Nest(Mat A,PetscViewer viewer)
959d8588912SDave May {
960d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
96129e60adbSStefano Zampini   PetscBool      isascii,viewSub = PETSC_FALSE;
962d8588912SDave May   PetscInt       i,j;
963d8588912SDave May   PetscErrorCode ierr;
964d8588912SDave May 
965d8588912SDave May   PetscFunctionBegin;
966251f4c67SDmitry Karpeev   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
967d8588912SDave May   if (isascii) {
968d8588912SDave May 
96929e60adbSStefano Zampini     ierr = PetscOptionsGetBool(((PetscObject)A)->options,((PetscObject)A)->prefix,"-mat_view_nest_sub",&viewSub,NULL);CHKERRQ(ierr);
970d86155a6SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"Matrix object: \n");CHKERRQ(ierr);
971d86155a6SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
972d86155a6SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer, "type=nest, rows=%D, cols=%D \n",bA->nr,bA->nc);CHKERRQ(ierr);
973d8588912SDave May 
974d86155a6SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"MatNest structure: \n");CHKERRQ(ierr);
975d8588912SDave May     for (i=0; i<bA->nr; i++) {
976d8588912SDave May       for (j=0; j<bA->nc; j++) {
97719fd82e9SBarry Smith         MatType   type;
978270f95d7SJed Brown         char      name[256] = "",prefix[256] = "";
979d8588912SDave May         PetscInt  NR,NC;
980d8588912SDave May         PetscBool isNest = PETSC_FALSE;
981d8588912SDave May 
982d8588912SDave May         if (!bA->m[i][j]) {
98385019af4SBarry Smith           ierr = PetscViewerASCIIPrintf(viewer, "(%D,%D) : NULL \n",i,j);CHKERRQ(ierr);
984d8588912SDave May           continue;
985d8588912SDave May         }
986d8588912SDave May         ierr = MatGetSize(bA->m[i][j],&NR,&NC);CHKERRQ(ierr);
987d8588912SDave May         ierr = MatGetType(bA->m[i][j], &type);CHKERRQ(ierr);
9888caf3d72SBarry Smith         if (((PetscObject)bA->m[i][j])->name) {ierr = PetscSNPrintf(name,sizeof(name),"name=\"%s\", ",((PetscObject)bA->m[i][j])->name);CHKERRQ(ierr);}
9898caf3d72SBarry Smith         if (((PetscObject)bA->m[i][j])->prefix) {ierr = PetscSNPrintf(prefix,sizeof(prefix),"prefix=\"%s\", ",((PetscObject)bA->m[i][j])->prefix);CHKERRQ(ierr);}
990251f4c67SDmitry Karpeev         ierr = PetscObjectTypeCompare((PetscObject)bA->m[i][j],MATNEST,&isNest);CHKERRQ(ierr);
991d8588912SDave May 
992270f95d7SJed Brown         ierr = PetscViewerASCIIPrintf(viewer,"(%D,%D) : %s%stype=%s, rows=%D, cols=%D \n",i,j,name,prefix,type,NR,NC);CHKERRQ(ierr);
993d8588912SDave May 
99429e60adbSStefano Zampini         if (isNest || viewSub) {
995270f95d7SJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);  /* push1 */
996d8588912SDave May           ierr = MatView(bA->m[i][j],viewer);CHKERRQ(ierr);
997270f95d7SJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);    /* pop1 */
998d8588912SDave May         }
999d8588912SDave May       }
1000d8588912SDave May     }
1001d86155a6SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);    /* pop0 */
1002d8588912SDave May   }
1003d8588912SDave May   PetscFunctionReturn(0);
1004d8588912SDave May }
1005d8588912SDave May 
1006207556f9SJed Brown static PetscErrorCode MatZeroEntries_Nest(Mat A)
1007d8588912SDave May {
1008d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
1009d8588912SDave May   PetscInt       i,j;
1010d8588912SDave May   PetscErrorCode ierr;
1011d8588912SDave May 
1012d8588912SDave May   PetscFunctionBegin;
1013d8588912SDave May   for (i=0; i<bA->nr; i++) {
1014d8588912SDave May     for (j=0; j<bA->nc; j++) {
1015d8588912SDave May       if (!bA->m[i][j]) continue;
1016d8588912SDave May       ierr = MatZeroEntries(bA->m[i][j]);CHKERRQ(ierr);
1017d8588912SDave May     }
1018d8588912SDave May   }
1019d8588912SDave May   PetscFunctionReturn(0);
1020d8588912SDave May }
1021d8588912SDave May 
1022c222c20dSDavid Ham static PetscErrorCode MatCopy_Nest(Mat A,Mat B,MatStructure str)
1023c222c20dSDavid Ham {
1024c222c20dSDavid Ham   Mat_Nest       *bA = (Mat_Nest*)A->data,*bB = (Mat_Nest*)B->data;
1025c222c20dSDavid Ham   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
1026c222c20dSDavid Ham   PetscErrorCode ierr;
102706a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
1028c222c20dSDavid Ham 
1029c222c20dSDavid Ham   PetscFunctionBegin;
1030c222c20dSDavid 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);
1031c222c20dSDavid Ham   for (i=0; i<nr; i++) {
1032c222c20dSDavid Ham     for (j=0; j<nc; j++) {
103306a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
103446a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
1035c222c20dSDavid Ham         ierr = MatCopy(bA->m[i][j],bB->m[i][j],str);CHKERRQ(ierr);
103646a2b97cSJed 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);
103706a1af2fSStefano Zampini       ierr = MatGetNonzeroState(bB->m[i][j],&subnnzstate);CHKERRQ(ierr);
103806a1af2fSStefano Zampini       nnzstate = (PetscBool)(nnzstate || bB->nnzstate[i*nc+j] != subnnzstate);
103906a1af2fSStefano Zampini       bB->nnzstate[i*nc+j] = subnnzstate;
1040c222c20dSDavid Ham     }
1041c222c20dSDavid Ham   }
104206a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
1043c222c20dSDavid Ham   PetscFunctionReturn(0);
1044c222c20dSDavid Ham }
1045c222c20dSDavid Ham 
10466e76ffeaSPierre Jolivet static PetscErrorCode MatAXPY_Nest(Mat Y,PetscScalar a,Mat X,MatStructure str)
10476e76ffeaSPierre Jolivet {
10486e76ffeaSPierre Jolivet   Mat_Nest       *bY = (Mat_Nest*)Y->data,*bX = (Mat_Nest*)X->data;
10496e76ffeaSPierre Jolivet   PetscInt       i,j,nr = bY->nr,nc = bY->nc;
10506e76ffeaSPierre Jolivet   PetscErrorCode ierr;
105106a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
10526e76ffeaSPierre Jolivet 
10536e76ffeaSPierre Jolivet   PetscFunctionBegin;
10546e76ffeaSPierre 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);
10556e76ffeaSPierre Jolivet   for (i=0; i<nr; i++) {
10566e76ffeaSPierre Jolivet     for (j=0; j<nc; j++) {
105706a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
10586e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
10596e76ffeaSPierre Jolivet         ierr = MatAXPY(bY->m[i][j],a,bX->m[i][j],str);CHKERRQ(ierr);
1060c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
1061c066aebcSStefano Zampini         Mat M;
1062c066aebcSStefano Zampini 
1063060bfc19SStefano 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);
1064c066aebcSStefano Zampini         ierr = MatDuplicate(bX->m[i][j],MAT_COPY_VALUES,&M);CHKERRQ(ierr);
1065c066aebcSStefano Zampini         ierr = MatNestSetSubMat(Y,i,j,M);CHKERRQ(ierr);
1066c066aebcSStefano Zampini         ierr = MatDestroy(&M);CHKERRQ(ierr);
1067c066aebcSStefano Zampini       }
1068060bfc19SStefano Zampini       if (bY->m[i][j]) { ierr = MatGetNonzeroState(bY->m[i][j],&subnnzstate);CHKERRQ(ierr); }
106906a1af2fSStefano Zampini       nnzstate = (PetscBool)(nnzstate || bY->nnzstate[i*nc+j] != subnnzstate);
107006a1af2fSStefano Zampini       bY->nnzstate[i*nc+j] = subnnzstate;
10716e76ffeaSPierre Jolivet     }
10726e76ffeaSPierre Jolivet   }
107306a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
10746e76ffeaSPierre Jolivet   PetscFunctionReturn(0);
10756e76ffeaSPierre Jolivet }
10766e76ffeaSPierre Jolivet 
1077207556f9SJed Brown static PetscErrorCode MatDuplicate_Nest(Mat A,MatDuplicateOption op,Mat *B)
1078d8588912SDave May {
1079d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
1080841e96a3SJed Brown   Mat            *b;
1081841e96a3SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
1082d8588912SDave May   PetscErrorCode ierr;
1083d8588912SDave May 
1084d8588912SDave May   PetscFunctionBegin;
1085785e854fSJed Brown   ierr = PetscMalloc1(nr*nc,&b);CHKERRQ(ierr);
1086841e96a3SJed Brown   for (i=0; i<nr; i++) {
1087841e96a3SJed Brown     for (j=0; j<nc; j++) {
1088841e96a3SJed Brown       if (bA->m[i][j]) {
1089841e96a3SJed Brown         ierr = MatDuplicate(bA->m[i][j],op,&b[i*nc+j]);CHKERRQ(ierr);
1090841e96a3SJed Brown       } else {
10910298fd71SBarry Smith         b[i*nc+j] = NULL;
1092d8588912SDave May       }
1093d8588912SDave May     }
1094d8588912SDave May   }
1095ce94432eSBarry Smith   ierr = MatCreateNest(PetscObjectComm((PetscObject)A),nr,bA->isglobal.row,nc,bA->isglobal.col,b,B);CHKERRQ(ierr);
1096841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
1097841e96a3SJed Brown   for (i=0; i<nr*nc; i++) {
10986bf464f9SBarry Smith     ierr = MatDestroy(&b[i]);CHKERRQ(ierr);
1099d8588912SDave May   }
1100d8588912SDave May   ierr = PetscFree(b);CHKERRQ(ierr);
1101d8588912SDave May 
1102841e96a3SJed Brown   ierr = MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1103841e96a3SJed Brown   ierr = MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1104d8588912SDave May   PetscFunctionReturn(0);
1105d8588912SDave May }
1106d8588912SDave May 
1107d8588912SDave May /* nest api */
1108d8588912SDave May PetscErrorCode MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat *mat)
1109d8588912SDave May {
1110d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
11115fd66863SKarl Rupp 
1112d8588912SDave May   PetscFunctionBegin;
1113ce94432eSBarry Smith   if (idxm >= bA->nr) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
1114ce94432eSBarry Smith   if (jdxm >= bA->nc) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
1115d8588912SDave May   *mat = bA->m[idxm][jdxm];
1116d8588912SDave May   PetscFunctionReturn(0);
1117d8588912SDave May }
1118d8588912SDave May 
11199ba0d327SJed Brown /*@
1120d8588912SDave May  MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix.
1121d8588912SDave May 
1122d8588912SDave May  Not collective
1123d8588912SDave May 
1124d8588912SDave May  Input Parameters:
1125629881c0SJed Brown +   A  - nest matrix
1126d8588912SDave May .   idxm - index of the matrix within the nest matrix
1127629881c0SJed Brown -   jdxm - index of the matrix within the nest matrix
1128d8588912SDave May 
1129d8588912SDave May  Output Parameter:
1130d8588912SDave May .   sub - matrix at index idxm,jdxm within the nest matrix
1131d8588912SDave May 
1132d8588912SDave May  Level: developer
1133d8588912SDave May 
1134bb97c47cSPierre Jolivet .seealso: MatNestGetSize(), MatNestGetSubMats(), MatCreateNest(), MATNEST, MatNestSetSubMat(),
113579798668SBarry Smith           MatNestGetLocalISs(), MatNestGetISs()
1136d8588912SDave May @*/
11377087cfbeSBarry Smith PetscErrorCode  MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat *sub)
1138d8588912SDave May {
1139699a902aSJed Brown   PetscErrorCode ierr;
1140d8588912SDave May 
1141d8588912SDave May   PetscFunctionBegin;
1142699a902aSJed Brown   ierr = PetscUseMethod(A,"MatNestGetSubMat_C",(Mat,PetscInt,PetscInt,Mat*),(A,idxm,jdxm,sub));CHKERRQ(ierr);
1143d8588912SDave May   PetscFunctionReturn(0);
1144d8588912SDave May }
1145d8588912SDave May 
11460782ca92SJed Brown PetscErrorCode MatNestSetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat mat)
11470782ca92SJed Brown {
11480782ca92SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
11490782ca92SJed Brown   PetscInt       m,n,M,N,mi,ni,Mi,Ni;
11500782ca92SJed Brown   PetscErrorCode ierr;
11510782ca92SJed Brown 
11520782ca92SJed Brown   PetscFunctionBegin;
1153ce94432eSBarry Smith   if (idxm >= bA->nr) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %D max %D",idxm,bA->nr-1);
1154ce94432eSBarry Smith   if (jdxm >= bA->nc) SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %D max %D",jdxm,bA->nc-1);
11550782ca92SJed Brown   ierr = MatGetLocalSize(mat,&m,&n);CHKERRQ(ierr);
11560782ca92SJed Brown   ierr = MatGetSize(mat,&M,&N);CHKERRQ(ierr);
11570782ca92SJed Brown   ierr = ISGetLocalSize(bA->isglobal.row[idxm],&mi);CHKERRQ(ierr);
11580782ca92SJed Brown   ierr = ISGetSize(bA->isglobal.row[idxm],&Mi);CHKERRQ(ierr);
11590782ca92SJed Brown   ierr = ISGetLocalSize(bA->isglobal.col[jdxm],&ni);CHKERRQ(ierr);
11600782ca92SJed Brown   ierr = ISGetSize(bA->isglobal.col[jdxm],&Ni);CHKERRQ(ierr);
1161ce94432eSBarry 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);
1162ce94432eSBarry 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);
116326fbe8dcSKarl Rupp 
116406a1af2fSStefano Zampini   /* do not increase object state */
116506a1af2fSStefano Zampini   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(0);
116606a1af2fSStefano Zampini 
11670782ca92SJed Brown   ierr = PetscObjectReference((PetscObject)mat);CHKERRQ(ierr);
11680782ca92SJed Brown   ierr = MatDestroy(&bA->m[idxm][jdxm]);CHKERRQ(ierr);
11690782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
117006a1af2fSStefano Zampini   ierr = PetscObjectStateIncrease((PetscObject)A);CHKERRQ(ierr);
117106a1af2fSStefano Zampini   ierr = MatGetNonzeroState(mat,&bA->nnzstate[idxm*bA->nc+jdxm]);CHKERRQ(ierr);
117206a1af2fSStefano Zampini   A->nonzerostate++;
11730782ca92SJed Brown   PetscFunctionReturn(0);
11740782ca92SJed Brown }
11750782ca92SJed Brown 
11769ba0d327SJed Brown /*@
11770782ca92SJed Brown  MatNestSetSubMat - Set a single submatrix in the nest matrix.
11780782ca92SJed Brown 
11790782ca92SJed Brown  Logically collective on the submatrix communicator
11800782ca92SJed Brown 
11810782ca92SJed Brown  Input Parameters:
11820782ca92SJed Brown +   A  - nest matrix
11830782ca92SJed Brown .   idxm - index of the matrix within the nest matrix
11840782ca92SJed Brown .   jdxm - index of the matrix within the nest matrix
11850782ca92SJed Brown -   sub - matrix at index idxm,jdxm within the nest matrix
11860782ca92SJed Brown 
11870782ca92SJed Brown  Notes:
11880782ca92SJed Brown  The new submatrix must have the same size and communicator as that block of the nest.
11890782ca92SJed Brown 
11900782ca92SJed Brown  This increments the reference count of the submatrix.
11910782ca92SJed Brown 
11920782ca92SJed Brown  Level: developer
11930782ca92SJed Brown 
1194bb97c47cSPierre Jolivet .seealso: MatNestSetSubMats(), MatNestGetSubMats(), MatNestGetLocalISs(), MATNEST, MatCreateNest(),
119579798668SBarry Smith           MatNestGetSubMat(), MatNestGetISs(), MatNestGetSize()
11960782ca92SJed Brown @*/
11970782ca92SJed Brown PetscErrorCode  MatNestSetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat sub)
11980782ca92SJed Brown {
11990782ca92SJed Brown   PetscErrorCode ierr;
12000782ca92SJed Brown 
12010782ca92SJed Brown   PetscFunctionBegin;
12020782ca92SJed Brown   ierr = PetscUseMethod(A,"MatNestSetSubMat_C",(Mat,PetscInt,PetscInt,Mat),(A,idxm,jdxm,sub));CHKERRQ(ierr);
12030782ca92SJed Brown   PetscFunctionReturn(0);
12040782ca92SJed Brown }
12050782ca92SJed Brown 
1206d8588912SDave May PetscErrorCode MatNestGetSubMats_Nest(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
1207d8588912SDave May {
1208d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
12095fd66863SKarl Rupp 
1210d8588912SDave May   PetscFunctionBegin;
121126fbe8dcSKarl Rupp   if (M)   *M   = bA->nr;
121226fbe8dcSKarl Rupp   if (N)   *N   = bA->nc;
121326fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
1214d8588912SDave May   PetscFunctionReturn(0);
1215d8588912SDave May }
1216d8588912SDave May 
1217d8588912SDave May /*@C
1218d8588912SDave May  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix.
1219d8588912SDave May 
1220d8588912SDave May  Not collective
1221d8588912SDave May 
1222d8588912SDave May  Input Parameters:
1223629881c0SJed Brown .   A  - nest matrix
1224d8588912SDave May 
1225d8588912SDave May  Output Parameter:
1226629881c0SJed Brown +   M - number of rows in the nest matrix
1227d8588912SDave May .   N - number of cols in the nest matrix
1228629881c0SJed Brown -   mat - 2d array of matrices
1229d8588912SDave May 
1230d8588912SDave May  Notes:
1231d8588912SDave May 
1232d8588912SDave May  The user should not free the array mat.
1233d8588912SDave May 
1234351962e3SVincent Le Chenadec  In Fortran, this routine has a calling sequence
1235351962e3SVincent Le Chenadec $   call MatNestGetSubMats(A, M, N, mat, ierr)
1236351962e3SVincent Le Chenadec  where the space allocated for the optional argument mat is assumed large enough (if provided).
1237351962e3SVincent Le Chenadec 
1238d8588912SDave May  Level: developer
1239d8588912SDave May 
1240bb97c47cSPierre Jolivet .seealso: MatNestGetSize(), MatNestGetSubMat(), MatNestGetLocalISs(), MATNEST, MatCreateNest(),
124179798668SBarry Smith           MatNestSetSubMats(), MatNestGetISs(), MatNestSetSubMat()
1242d8588912SDave May @*/
12437087cfbeSBarry Smith PetscErrorCode  MatNestGetSubMats(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
1244d8588912SDave May {
1245699a902aSJed Brown   PetscErrorCode ierr;
1246d8588912SDave May 
1247d8588912SDave May   PetscFunctionBegin;
1248699a902aSJed Brown   ierr = PetscUseMethod(A,"MatNestGetSubMats_C",(Mat,PetscInt*,PetscInt*,Mat***),(A,M,N,mat));CHKERRQ(ierr);
1249d8588912SDave May   PetscFunctionReturn(0);
1250d8588912SDave May }
1251d8588912SDave May 
12527087cfbeSBarry Smith PetscErrorCode  MatNestGetSize_Nest(Mat A,PetscInt *M,PetscInt *N)
1253d8588912SDave May {
1254d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
1255d8588912SDave May 
1256d8588912SDave May   PetscFunctionBegin;
125726fbe8dcSKarl Rupp   if (M) *M = bA->nr;
125826fbe8dcSKarl Rupp   if (N) *N = bA->nc;
1259d8588912SDave May   PetscFunctionReturn(0);
1260d8588912SDave May }
1261d8588912SDave May 
12629ba0d327SJed Brown /*@
1263d8588912SDave May  MatNestGetSize - Returns the size of the nest matrix.
1264d8588912SDave May 
1265d8588912SDave May  Not collective
1266d8588912SDave May 
1267d8588912SDave May  Input Parameters:
1268d8588912SDave May .   A  - nest matrix
1269d8588912SDave May 
1270d8588912SDave May  Output Parameter:
1271629881c0SJed Brown +   M - number of rows in the nested mat
1272629881c0SJed Brown -   N - number of cols in the nested mat
1273d8588912SDave May 
1274d8588912SDave May  Notes:
1275d8588912SDave May 
1276d8588912SDave May  Level: developer
1277d8588912SDave May 
1278bb97c47cSPierre Jolivet .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MATNEST, MatCreateNest(), MatNestGetLocalISs(),
127979798668SBarry Smith           MatNestGetISs()
1280d8588912SDave May @*/
12817087cfbeSBarry Smith PetscErrorCode  MatNestGetSize(Mat A,PetscInt *M,PetscInt *N)
1282d8588912SDave May {
1283699a902aSJed Brown   PetscErrorCode ierr;
1284d8588912SDave May 
1285d8588912SDave May   PetscFunctionBegin;
1286699a902aSJed Brown   ierr = PetscUseMethod(A,"MatNestGetSize_C",(Mat,PetscInt*,PetscInt*),(A,M,N));CHKERRQ(ierr);
1287d8588912SDave May   PetscFunctionReturn(0);
1288d8588912SDave May }
1289d8588912SDave May 
1290f7a08781SBarry Smith static PetscErrorCode MatNestGetISs_Nest(Mat A,IS rows[],IS cols[])
1291900e7ff2SJed Brown {
1292900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest*)A->data;
1293900e7ff2SJed Brown   PetscInt i;
1294900e7ff2SJed Brown 
1295900e7ff2SJed Brown   PetscFunctionBegin;
1296900e7ff2SJed Brown   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->isglobal.row[i];
1297900e7ff2SJed Brown   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->isglobal.col[i];
1298900e7ff2SJed Brown   PetscFunctionReturn(0);
1299900e7ff2SJed Brown }
1300900e7ff2SJed Brown 
13013a4d7b9aSSatish Balay /*@C
1302900e7ff2SJed Brown  MatNestGetISs - Returns the index sets partitioning the row and column spaces
1303900e7ff2SJed Brown 
1304900e7ff2SJed Brown  Not collective
1305900e7ff2SJed Brown 
1306900e7ff2SJed Brown  Input Parameters:
1307900e7ff2SJed Brown .   A  - nest matrix
1308900e7ff2SJed Brown 
1309900e7ff2SJed Brown  Output Parameter:
1310900e7ff2SJed Brown +   rows - array of row index sets
1311900e7ff2SJed Brown -   cols - array of column index sets
1312900e7ff2SJed Brown 
1313900e7ff2SJed Brown  Level: advanced
1314900e7ff2SJed Brown 
1315900e7ff2SJed Brown  Notes:
1316900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1317900e7ff2SJed Brown 
131879798668SBarry Smith .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetLocalISs(), MATNEST,
1319bb97c47cSPierre Jolivet           MatCreateNest(), MatNestGetSubMats(), MatNestSetSubMats()
1320900e7ff2SJed Brown @*/
1321900e7ff2SJed Brown PetscErrorCode  MatNestGetISs(Mat A,IS rows[],IS cols[])
1322900e7ff2SJed Brown {
1323900e7ff2SJed Brown   PetscErrorCode ierr;
1324900e7ff2SJed Brown 
1325900e7ff2SJed Brown   PetscFunctionBegin;
1326900e7ff2SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1327900e7ff2SJed Brown   ierr = PetscUseMethod(A,"MatNestGetISs_C",(Mat,IS[],IS[]),(A,rows,cols));CHKERRQ(ierr);
1328900e7ff2SJed Brown   PetscFunctionReturn(0);
1329900e7ff2SJed Brown }
1330900e7ff2SJed Brown 
1331f7a08781SBarry Smith static PetscErrorCode MatNestGetLocalISs_Nest(Mat A,IS rows[],IS cols[])
1332900e7ff2SJed Brown {
1333900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest*)A->data;
1334900e7ff2SJed Brown   PetscInt i;
1335900e7ff2SJed Brown 
1336900e7ff2SJed Brown   PetscFunctionBegin;
1337900e7ff2SJed Brown   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->islocal.row[i];
1338900e7ff2SJed Brown   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->islocal.col[i];
1339900e7ff2SJed Brown   PetscFunctionReturn(0);
1340900e7ff2SJed Brown }
1341900e7ff2SJed Brown 
1342900e7ff2SJed Brown /*@C
1343900e7ff2SJed Brown  MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces
1344900e7ff2SJed Brown 
1345900e7ff2SJed Brown  Not collective
1346900e7ff2SJed Brown 
1347900e7ff2SJed Brown  Input Parameters:
1348900e7ff2SJed Brown .   A  - nest matrix
1349900e7ff2SJed Brown 
1350900e7ff2SJed Brown  Output Parameter:
13510298fd71SBarry Smith +   rows - array of row index sets (or NULL to ignore)
13520298fd71SBarry Smith -   cols - array of column index sets (or NULL to ignore)
1353900e7ff2SJed Brown 
1354900e7ff2SJed Brown  Level: advanced
1355900e7ff2SJed Brown 
1356900e7ff2SJed Brown  Notes:
1357900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1358900e7ff2SJed Brown 
1359bb97c47cSPierre Jolivet .seealso: MatNestGetSubMat(), MatNestGetSubMats(), MatNestGetSize(), MatNestGetISs(), MatCreateNest(),
136079798668SBarry Smith           MATNEST, MatNestSetSubMats(), MatNestSetSubMat()
1361900e7ff2SJed Brown @*/
1362900e7ff2SJed Brown PetscErrorCode  MatNestGetLocalISs(Mat A,IS rows[],IS cols[])
1363900e7ff2SJed Brown {
1364900e7ff2SJed Brown   PetscErrorCode ierr;
1365900e7ff2SJed Brown 
1366900e7ff2SJed Brown   PetscFunctionBegin;
1367900e7ff2SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1368900e7ff2SJed Brown   ierr = PetscUseMethod(A,"MatNestGetLocalISs_C",(Mat,IS[],IS[]),(A,rows,cols));CHKERRQ(ierr);
1369900e7ff2SJed Brown   PetscFunctionReturn(0);
1370900e7ff2SJed Brown }
1371900e7ff2SJed Brown 
137219fd82e9SBarry Smith PetscErrorCode  MatNestSetVecType_Nest(Mat A,VecType vtype)
1373207556f9SJed Brown {
1374207556f9SJed Brown   PetscErrorCode ierr;
1375207556f9SJed Brown   PetscBool      flg;
1376207556f9SJed Brown 
1377207556f9SJed Brown   PetscFunctionBegin;
1378207556f9SJed Brown   ierr = PetscStrcmp(vtype,VECNEST,&flg);CHKERRQ(ierr);
1379207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
13802a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
138112b53f24SSatish Balay   else A->ops->getvecs = (PetscErrorCode (*)(Mat,Vec*,Vec*)) 0;
1382207556f9SJed Brown   PetscFunctionReturn(0);
1383207556f9SJed Brown }
1384207556f9SJed Brown 
1385207556f9SJed Brown /*@C
13862a7a6963SBarry Smith  MatNestSetVecType - Sets the type of Vec returned by MatCreateVecs()
1387207556f9SJed Brown 
1388207556f9SJed Brown  Not collective
1389207556f9SJed Brown 
1390207556f9SJed Brown  Input Parameters:
1391207556f9SJed Brown +  A  - nest matrix
1392207556f9SJed Brown -  vtype - type to use for creating vectors
1393207556f9SJed Brown 
1394207556f9SJed Brown  Notes:
1395207556f9SJed Brown 
1396207556f9SJed Brown  Level: developer
1397207556f9SJed Brown 
1398bb97c47cSPierre Jolivet .seealso: MatCreateVecs(), MATNEST, MatCreateNest()
1399207556f9SJed Brown @*/
140019fd82e9SBarry Smith PetscErrorCode  MatNestSetVecType(Mat A,VecType vtype)
1401207556f9SJed Brown {
1402207556f9SJed Brown   PetscErrorCode ierr;
1403207556f9SJed Brown 
1404207556f9SJed Brown   PetscFunctionBegin;
140519fd82e9SBarry Smith   ierr = PetscTryMethod(A,"MatNestSetVecType_C",(Mat,VecType),(A,vtype));CHKERRQ(ierr);
1406207556f9SJed Brown   PetscFunctionReturn(0);
1407207556f9SJed Brown }
1408207556f9SJed Brown 
1409c8883902SJed Brown PetscErrorCode MatNestSetSubMats_Nest(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1410d8588912SDave May {
1411c8883902SJed Brown   Mat_Nest       *s = (Mat_Nest*)A->data;
1412c8883902SJed Brown   PetscInt       i,j,m,n,M,N;
1413d8588912SDave May   PetscErrorCode ierr;
141406a1af2fSStefano Zampini   PetscBool      cong;
1415d8588912SDave May 
1416d8588912SDave May   PetscFunctionBegin;
141706a1af2fSStefano Zampini   ierr = MatReset_Nest(A);CHKERRQ(ierr);
141806a1af2fSStefano Zampini 
1419c8883902SJed Brown   s->nr = nr;
1420c8883902SJed Brown   s->nc = nc;
1421d8588912SDave May 
1422c8883902SJed Brown   /* Create space for submatrices */
1423854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&s->m);CHKERRQ(ierr);
1424c8883902SJed Brown   for (i=0; i<nr; i++) {
1425854ce69bSBarry Smith     ierr = PetscMalloc1(nc,&s->m[i]);CHKERRQ(ierr);
1426d8588912SDave May   }
1427c8883902SJed Brown   for (i=0; i<nr; i++) {
1428c8883902SJed Brown     for (j=0; j<nc; j++) {
1429c8883902SJed Brown       s->m[i][j] = a[i*nc+j];
1430c8883902SJed Brown       if (a[i*nc+j]) {
1431c8883902SJed Brown         ierr = PetscObjectReference((PetscObject)a[i*nc+j]);CHKERRQ(ierr);
1432d8588912SDave May       }
1433d8588912SDave May     }
1434d8588912SDave May   }
1435d8588912SDave May 
14368188e55aSJed Brown   ierr = MatSetUp_NestIS_Private(A,nr,is_row,nc,is_col);CHKERRQ(ierr);
1437d8588912SDave May 
1438854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&s->row_len);CHKERRQ(ierr);
1439854ce69bSBarry Smith   ierr = PetscMalloc1(nc,&s->col_len);CHKERRQ(ierr);
1440c8883902SJed Brown   for (i=0; i<nr; i++) s->row_len[i]=-1;
1441c8883902SJed Brown   for (j=0; j<nc; j++) s->col_len[j]=-1;
1442d8588912SDave May 
144306a1af2fSStefano Zampini   ierr = PetscCalloc1(nr*nc,&s->nnzstate);CHKERRQ(ierr);
144406a1af2fSStefano Zampini   for (i=0; i<nr; i++) {
144506a1af2fSStefano Zampini     for (j=0; j<nc; j++) {
144606a1af2fSStefano Zampini       if (s->m[i][j]) {
144706a1af2fSStefano Zampini         ierr = MatGetNonzeroState(s->m[i][j],&s->nnzstate[i*nc+j]);CHKERRQ(ierr);
144806a1af2fSStefano Zampini       }
144906a1af2fSStefano Zampini     }
145006a1af2fSStefano Zampini   }
145106a1af2fSStefano Zampini 
14528188e55aSJed Brown   ierr = MatNestGetSizes_Private(A,&m,&n,&M,&N);CHKERRQ(ierr);
1453d8588912SDave May 
1454c8883902SJed Brown   ierr = PetscLayoutSetSize(A->rmap,M);CHKERRQ(ierr);
1455c8883902SJed Brown   ierr = PetscLayoutSetLocalSize(A->rmap,m);CHKERRQ(ierr);
1456c8883902SJed Brown   ierr = PetscLayoutSetSize(A->cmap,N);CHKERRQ(ierr);
1457c8883902SJed Brown   ierr = PetscLayoutSetLocalSize(A->cmap,n);CHKERRQ(ierr);
1458c8883902SJed Brown 
1459c8883902SJed Brown   ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr);
1460c8883902SJed Brown   ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr);
1461c8883902SJed Brown 
146206a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
146306a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
146406a1af2fSStefano Zampini   ierr = MatHasCongruentLayouts(A,&cong);CHKERRQ(ierr);
146506a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
146606a1af2fSStefano Zampini   if (cong) {
146706a1af2fSStefano Zampini     for (i = 0; cong && i < nr; i++) {
1468320466b0SStefano Zampini       ierr = ISEqualUnsorted(s->isglobal.row[i],s->isglobal.col[i],&cong);CHKERRQ(ierr);
146906a1af2fSStefano Zampini     }
147006a1af2fSStefano Zampini   }
147106a1af2fSStefano Zampini   if (!cong) {
1472381b8e50SStefano Zampini     A->ops->missingdiagonal = NULL;
147306a1af2fSStefano Zampini     A->ops->getdiagonal     = NULL;
147406a1af2fSStefano Zampini     A->ops->shift           = NULL;
147506a1af2fSStefano Zampini     A->ops->diagonalset     = NULL;
147606a1af2fSStefano Zampini   }
147706a1af2fSStefano Zampini 
14781795a4d1SJed Brown   ierr = PetscCalloc2(nr,&s->left,nc,&s->right);CHKERRQ(ierr);
147906a1af2fSStefano Zampini   ierr = PetscObjectStateIncrease((PetscObject)A);CHKERRQ(ierr);
148006a1af2fSStefano Zampini   A->nonzerostate++;
1481d8588912SDave May   PetscFunctionReturn(0);
1482d8588912SDave May }
1483d8588912SDave May 
1484c8883902SJed Brown /*@
1485c8883902SJed Brown    MatNestSetSubMats - Sets the nested submatrices
1486c8883902SJed Brown 
1487c8883902SJed Brown    Collective on Mat
1488c8883902SJed Brown 
1489c8883902SJed Brown    Input Parameter:
1490ffd6319bSRichard Tran Mills +  A - nested matrix
1491c8883902SJed Brown .  nr - number of nested row blocks
14920298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1493c8883902SJed Brown .  nc - number of nested column blocks
14940298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
14950298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1496c8883902SJed Brown 
149706a1af2fSStefano Zampini    Notes: this always resets any submatrix information previously set
149806a1af2fSStefano Zampini 
1499c8883902SJed Brown    Level: advanced
1500c8883902SJed Brown 
150179798668SBarry Smith .seealso: MatCreateNest(), MATNEST, MatNestSetSubMat(), MatNestGetSubMat(), MatNestGetSubMats()
1502c8883902SJed Brown @*/
1503c8883902SJed Brown PetscErrorCode MatNestSetSubMats(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1504c8883902SJed Brown {
1505c8883902SJed Brown   PetscErrorCode ierr;
150606a1af2fSStefano Zampini   PetscInt       i;
1507c8883902SJed Brown 
1508c8883902SJed Brown   PetscFunctionBegin;
1509c8883902SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1510ce94432eSBarry Smith   if (nr < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of rows cannot be negative");
1511c8883902SJed Brown   if (nr && is_row) {
1512c8883902SJed Brown     PetscValidPointer(is_row,3);
1513c8883902SJed Brown     for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_row[i],IS_CLASSID,3);
1514c8883902SJed Brown   }
1515ce94432eSBarry Smith   if (nc < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of columns cannot be negative");
15161664e352SJed Brown   if (nc && is_col) {
1517c8883902SJed Brown     PetscValidPointer(is_col,5);
15189b30a8f6SBarry Smith     for (i=0; i<nc; i++) PetscValidHeaderSpecific(is_col[i],IS_CLASSID,5);
1519c8883902SJed Brown   }
152006a1af2fSStefano Zampini   if (nr*nc > 0) PetscValidPointer(a,6);
1521c8883902SJed 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);
1522c8883902SJed Brown   PetscFunctionReturn(0);
1523c8883902SJed Brown }
1524d8588912SDave May 
152545b6f7e9SBarry Smith static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A,PetscInt n,const IS islocal[],const IS isglobal[],PetscBool colflg,ISLocalToGlobalMapping *ltog)
152677019fcaSJed Brown {
152777019fcaSJed Brown   PetscErrorCode ierr;
152877019fcaSJed Brown   PetscBool      flg;
152977019fcaSJed Brown   PetscInt       i,j,m,mi,*ix;
153077019fcaSJed Brown 
153177019fcaSJed Brown   PetscFunctionBegin;
1532aea6d515SStefano Zampini   *ltog = NULL;
153377019fcaSJed Brown   for (i=0,m=0,flg=PETSC_FALSE; i<n; i++) {
153477019fcaSJed Brown     if (islocal[i]) {
1535aea6d515SStefano Zampini       ierr = ISGetLocalSize(islocal[i],&mi);CHKERRQ(ierr);
153677019fcaSJed Brown       flg  = PETSC_TRUE;      /* We found a non-trivial entry */
153777019fcaSJed Brown     } else {
1538aea6d515SStefano Zampini       ierr = ISGetLocalSize(isglobal[i],&mi);CHKERRQ(ierr);
153977019fcaSJed Brown     }
154077019fcaSJed Brown     m += mi;
154177019fcaSJed Brown   }
1542aea6d515SStefano Zampini   if (!flg) PetscFunctionReturn(0);
1543aea6d515SStefano Zampini 
1544785e854fSJed Brown   ierr = PetscMalloc1(m,&ix);CHKERRQ(ierr);
1545165cd838SBarry Smith   for (i=0,m=0; i<n; i++) {
15460298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1547e108cb99SStefano Zampini     Mat                    sub = NULL;
1548f6d38dbbSStefano Zampini     PetscSF                sf;
1549f6d38dbbSStefano Zampini     PetscLayout            map;
1550aea6d515SStefano Zampini     const PetscInt         *ix2;
155177019fcaSJed Brown 
1552165cd838SBarry Smith     if (!colflg) {
155377019fcaSJed Brown       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
155477019fcaSJed Brown     } else {
155577019fcaSJed Brown       ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
155677019fcaSJed Brown     }
1557191fd14bSBarry Smith     if (sub) {
1558191fd14bSBarry Smith       if (!colflg) {
1559191fd14bSBarry Smith         ierr = MatGetLocalToGlobalMapping(sub,&smap,NULL);CHKERRQ(ierr);
1560191fd14bSBarry Smith       } else {
1561191fd14bSBarry Smith         ierr = MatGetLocalToGlobalMapping(sub,NULL,&smap);CHKERRQ(ierr);
1562191fd14bSBarry Smith       }
1563191fd14bSBarry Smith     }
156477019fcaSJed Brown     /*
156577019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
156677019fcaSJed 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.
156777019fcaSJed Brown     */
1568aea6d515SStefano Zampini     ierr = ISGetIndices(isglobal[i],&ix2);CHKERRQ(ierr);
1569aea6d515SStefano Zampini     if (islocal[i]) {
1570aea6d515SStefano Zampini       PetscInt *ilocal,*iremote;
1571aea6d515SStefano Zampini       PetscInt mil,nleaves;
1572aea6d515SStefano Zampini 
1573aea6d515SStefano Zampini       ierr = ISGetLocalSize(islocal[i],&mi);CHKERRQ(ierr);
1574aea6d515SStefano Zampini       if (!smap) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing local to global map");
1575aea6d515SStefano Zampini       for (j=0; j<mi; j++) ix[m+j] = j;
1576aea6d515SStefano Zampini       ierr = ISLocalToGlobalMappingApply(smap,mi,ix+m,ix+m);CHKERRQ(ierr);
1577aea6d515SStefano Zampini 
1578aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
1579aea6d515SStefano Zampini       ierr = PetscMalloc2(mi,&ilocal,mi,&iremote);CHKERRQ(ierr);
1580aea6d515SStefano Zampini       for (j=0, nleaves = 0; j<mi; j++) {
1581aea6d515SStefano Zampini         if (ix[m+j] < 0) continue;
1582aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1583aea6d515SStefano Zampini         iremote[nleaves] = ix[m+j];
1584aea6d515SStefano Zampini         nleaves++;
1585aea6d515SStefano Zampini       }
1586aea6d515SStefano Zampini       ierr = ISGetLocalSize(isglobal[i],&mil);CHKERRQ(ierr);
1587aea6d515SStefano Zampini       ierr = PetscSFCreate(PetscObjectComm((PetscObject)A),&sf);CHKERRQ(ierr);
1588aea6d515SStefano Zampini       ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A),&map);CHKERRQ(ierr);
1589aea6d515SStefano Zampini       ierr = PetscLayoutSetLocalSize(map,mil);CHKERRQ(ierr);
1590f6d38dbbSStefano Zampini       ierr = PetscLayoutSetUp(map);CHKERRQ(ierr);
1591aea6d515SStefano Zampini       ierr = PetscSFSetGraphLayout(sf,map,nleaves,ilocal,PETSC_USE_POINTER,iremote);CHKERRQ(ierr);
1592f6d38dbbSStefano Zampini       ierr = PetscLayoutDestroy(&map);CHKERRQ(ierr);
1593f6d38dbbSStefano Zampini       ierr = PetscSFBcastBegin(sf,MPIU_INT,ix2,ix + m);CHKERRQ(ierr);
1594f6d38dbbSStefano Zampini       ierr = PetscSFBcastEnd(sf,MPIU_INT,ix2,ix + m);CHKERRQ(ierr);
1595f6d38dbbSStefano Zampini       ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
1596aea6d515SStefano Zampini       ierr = PetscFree2(ilocal,iremote);CHKERRQ(ierr);
1597aea6d515SStefano Zampini     } else {
1598aea6d515SStefano Zampini       ierr = ISGetLocalSize(isglobal[i],&mi);CHKERRQ(ierr);
1599aea6d515SStefano Zampini       for (j=0; j<mi; j++) ix[m+j] = ix2[i];
1600aea6d515SStefano Zampini     }
1601aea6d515SStefano Zampini     ierr = ISRestoreIndices(isglobal[i],&ix2);CHKERRQ(ierr);
160277019fcaSJed Brown     m   += mi;
160377019fcaSJed Brown   }
1604f0413b6fSBarry Smith   ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,m,ix,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
160577019fcaSJed Brown   PetscFunctionReturn(0);
160677019fcaSJed Brown }
160777019fcaSJed Brown 
160877019fcaSJed Brown 
1609d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1610d8588912SDave May /*
1611d8588912SDave May   nprocessors = NP
1612d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1613d8588912SDave May        proc 0: => (g_0,h_0,)
1614d8588912SDave May        proc 1: => (g_1,h_1,)
1615d8588912SDave May        ...
1616d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1617d8588912SDave May 
1618d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1619d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1620d8588912SDave May 
1621d8588912SDave May             proc 0:
1622d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1623d8588912SDave May             proc 1:
1624d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1625d8588912SDave May 
1626d8588912SDave May             proc NP-1:
1627d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1628d8588912SDave May */
1629841e96a3SJed Brown static PetscErrorCode MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[])
1630d8588912SDave May {
1631e2d7f03fSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
16328188e55aSJed Brown   PetscInt       i,j,offset,n,nsum,bs;
1633d8588912SDave May   PetscErrorCode ierr;
16340298fd71SBarry Smith   Mat            sub = NULL;
1635d8588912SDave May 
1636d8588912SDave May   PetscFunctionBegin;
1637854ce69bSBarry Smith   ierr = PetscMalloc1(nr,&vs->isglobal.row);CHKERRQ(ierr);
1638854ce69bSBarry Smith   ierr = PetscMalloc1(nc,&vs->isglobal.col);CHKERRQ(ierr);
1639d8588912SDave May   if (is_row) { /* valid IS is passed in */
1640d8588912SDave May     /* refs on is[] are incremeneted */
1641e2d7f03fSJed Brown     for (i=0; i<vs->nr; i++) {
1642d8588912SDave May       ierr = PetscObjectReference((PetscObject)is_row[i]);CHKERRQ(ierr);
164326fbe8dcSKarl Rupp 
1644e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1645d8588912SDave May     }
16462ae74bdbSJed Brown   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each row */
16478188e55aSJed Brown     nsum = 0;
16488188e55aSJed Brown     for (i=0; i<vs->nr; i++) {  /* Add up the local sizes to compute the aggregate offset */
16498188e55aSJed Brown       ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
1650ce94432eSBarry Smith       if (!sub) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %D",i);
16510298fd71SBarry Smith       ierr = MatGetLocalSize(sub,&n,NULL);CHKERRQ(ierr);
1652ce94432eSBarry Smith       if (n < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
16538188e55aSJed Brown       nsum += n;
16548188e55aSJed Brown     }
165555b25c41SPierre Jolivet     ierr    = MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A));CHKERRMPI(ierr);
165630bc264bSJed Brown     offset -= nsum;
1657e2d7f03fSJed Brown     for (i=0; i<vs->nr; i++) {
1658f349c1fdSJed Brown       ierr    = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
16590298fd71SBarry Smith       ierr    = MatGetLocalSize(sub,&n,NULL);CHKERRQ(ierr);
166073b6653fSLawrence Mitchell       ierr    = MatGetBlockSizes(sub,&bs,NULL);CHKERRQ(ierr);
1661ce94432eSBarry Smith       ierr    = ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.row[i]);CHKERRQ(ierr);
1662e2d7f03fSJed Brown       ierr    = ISSetBlockSize(vs->isglobal.row[i],bs);CHKERRQ(ierr);
16632ae74bdbSJed Brown       offset += n;
1664d8588912SDave May     }
1665d8588912SDave May   }
1666d8588912SDave May 
1667d8588912SDave May   if (is_col) { /* valid IS is passed in */
1668d8588912SDave May     /* refs on is[] are incremeneted */
1669e2d7f03fSJed Brown     for (j=0; j<vs->nc; j++) {
1670d8588912SDave May       ierr = PetscObjectReference((PetscObject)is_col[j]);CHKERRQ(ierr);
167126fbe8dcSKarl Rupp 
1672e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1673d8588912SDave May     }
16742ae74bdbSJed Brown   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each column */
16752ae74bdbSJed Brown     offset = A->cmap->rstart;
16768188e55aSJed Brown     nsum   = 0;
16778188e55aSJed Brown     for (j=0; j<vs->nc; j++) {
16788188e55aSJed Brown       ierr = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
1679ce94432eSBarry Smith       if (!sub) SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %D",i);
16800298fd71SBarry Smith       ierr = MatGetLocalSize(sub,NULL,&n);CHKERRQ(ierr);
1681ce94432eSBarry Smith       if (n < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
16828188e55aSJed Brown       nsum += n;
16838188e55aSJed Brown     }
168455b25c41SPierre Jolivet     ierr    = MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A));CHKERRMPI(ierr);
168530bc264bSJed Brown     offset -= nsum;
1686e2d7f03fSJed Brown     for (j=0; j<vs->nc; j++) {
1687f349c1fdSJed Brown       ierr    = MatNestFindNonzeroSubMatCol(A,j,&sub);CHKERRQ(ierr);
16880298fd71SBarry Smith       ierr    = MatGetLocalSize(sub,NULL,&n);CHKERRQ(ierr);
168973b6653fSLawrence Mitchell       ierr    = MatGetBlockSizes(sub,NULL,&bs);CHKERRQ(ierr);
1690ce94432eSBarry Smith       ierr    = ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.col[j]);CHKERRQ(ierr);
1691e2d7f03fSJed Brown       ierr    = ISSetBlockSize(vs->isglobal.col[j],bs);CHKERRQ(ierr);
16922ae74bdbSJed Brown       offset += n;
1693d8588912SDave May     }
1694d8588912SDave May   }
1695e2d7f03fSJed Brown 
1696e2d7f03fSJed Brown   /* Set up the local ISs */
1697785e854fSJed Brown   ierr = PetscMalloc1(vs->nr,&vs->islocal.row);CHKERRQ(ierr);
1698785e854fSJed Brown   ierr = PetscMalloc1(vs->nc,&vs->islocal.col);CHKERRQ(ierr);
1699e2d7f03fSJed Brown   for (i=0,offset=0; i<vs->nr; i++) {
1700e2d7f03fSJed Brown     IS                     isloc;
17010298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1702e2d7f03fSJed Brown     PetscInt               nlocal,bs;
1703e2d7f03fSJed Brown     ierr = MatNestFindNonzeroSubMatRow(A,i,&sub);CHKERRQ(ierr);
17040298fd71SBarry Smith     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,&rmap,NULL);CHKERRQ(ierr);}
1705207556f9SJed Brown     if (rmap) {
170673b6653fSLawrence Mitchell       ierr = MatGetBlockSizes(sub,&bs,NULL);CHKERRQ(ierr);
1707e2d7f03fSJed Brown       ierr = ISLocalToGlobalMappingGetSize(rmap,&nlocal);CHKERRQ(ierr);
1708e2d7f03fSJed Brown       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1709e2d7f03fSJed Brown       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1710207556f9SJed Brown     } else {
1711207556f9SJed Brown       nlocal = 0;
17120298fd71SBarry Smith       isloc  = NULL;
1713207556f9SJed Brown     }
1714e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1715e2d7f03fSJed Brown     offset            += nlocal;
1716e2d7f03fSJed Brown   }
17178188e55aSJed Brown   for (i=0,offset=0; i<vs->nc; i++) {
1718e2d7f03fSJed Brown     IS                     isloc;
17190298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1720e2d7f03fSJed Brown     PetscInt               nlocal,bs;
1721e2d7f03fSJed Brown     ierr = MatNestFindNonzeroSubMatCol(A,i,&sub);CHKERRQ(ierr);
17220298fd71SBarry Smith     if (sub) {ierr = MatGetLocalToGlobalMapping(sub,NULL,&cmap);CHKERRQ(ierr);}
1723207556f9SJed Brown     if (cmap) {
172473b6653fSLawrence Mitchell       ierr = MatGetBlockSizes(sub,NULL,&bs);CHKERRQ(ierr);
1725e2d7f03fSJed Brown       ierr = ISLocalToGlobalMappingGetSize(cmap,&nlocal);CHKERRQ(ierr);
1726e2d7f03fSJed Brown       ierr = ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc);CHKERRQ(ierr);
1727e2d7f03fSJed Brown       ierr = ISSetBlockSize(isloc,bs);CHKERRQ(ierr);
1728207556f9SJed Brown     } else {
1729207556f9SJed Brown       nlocal = 0;
17300298fd71SBarry Smith       isloc  = NULL;
1731207556f9SJed Brown     }
1732e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1733e2d7f03fSJed Brown     offset            += nlocal;
1734e2d7f03fSJed Brown   }
17350189643fSJed Brown 
173677019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
173777019fcaSJed Brown   {
173845b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap,cmap;
173945b6f7e9SBarry Smith     ierr = MatNestCreateAggregateL2G_Private(A,vs->nr,vs->islocal.row,vs->isglobal.row,PETSC_FALSE,&rmap);CHKERRQ(ierr);
174045b6f7e9SBarry Smith     ierr = MatNestCreateAggregateL2G_Private(A,vs->nc,vs->islocal.col,vs->isglobal.col,PETSC_TRUE,&cmap);CHKERRQ(ierr);
174177019fcaSJed Brown     if (rmap && cmap) {ierr = MatSetLocalToGlobalMapping(A,rmap,cmap);CHKERRQ(ierr);}
174277019fcaSJed Brown     ierr = ISLocalToGlobalMappingDestroy(&rmap);CHKERRQ(ierr);
174377019fcaSJed Brown     ierr = ISLocalToGlobalMappingDestroy(&cmap);CHKERRQ(ierr);
174477019fcaSJed Brown   }
174577019fcaSJed Brown 
174676bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
17470189643fSJed Brown     for (i=0; i<vs->nr; i++) {
17480189643fSJed Brown       for (j=0; j<vs->nc; j++) {
17490189643fSJed Brown         PetscInt m,n,M,N,mi,ni,Mi,Ni;
17500189643fSJed Brown         Mat      B = vs->m[i][j];
17510189643fSJed Brown         if (!B) continue;
17520189643fSJed Brown         ierr = MatGetSize(B,&M,&N);CHKERRQ(ierr);
17530189643fSJed Brown         ierr = MatGetLocalSize(B,&m,&n);CHKERRQ(ierr);
17540189643fSJed Brown         ierr = ISGetSize(vs->isglobal.row[i],&Mi);CHKERRQ(ierr);
17550189643fSJed Brown         ierr = ISGetSize(vs->isglobal.col[j],&Ni);CHKERRQ(ierr);
17560189643fSJed Brown         ierr = ISGetLocalSize(vs->isglobal.row[i],&mi);CHKERRQ(ierr);
17570189643fSJed Brown         ierr = ISGetLocalSize(vs->isglobal.col[j],&ni);CHKERRQ(ierr);
1758ce94432eSBarry 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);
1759ce94432eSBarry 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);
17600189643fSJed Brown       }
17610189643fSJed Brown     }
176276bd3646SJed Brown   }
1763a061e289SJed Brown 
1764a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1765a061e289SJed Brown   for (i=0; i<vs->nr; i++) {
1766a061e289SJed Brown     for (j=0; j<vs->nc; j++) {
1767a061e289SJed Brown       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0);
1768a061e289SJed Brown     }
1769a061e289SJed Brown   }
1770a061e289SJed Brown   A->assembled = PETSC_TRUE;
1771d8588912SDave May   PetscFunctionReturn(0);
1772d8588912SDave May }
1773d8588912SDave May 
177445c38901SJed Brown /*@C
1775659c6bb0SJed Brown    MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately
1776659c6bb0SJed Brown 
1777659c6bb0SJed Brown    Collective on Mat
1778659c6bb0SJed Brown 
1779659c6bb0SJed Brown    Input Parameter:
1780659c6bb0SJed Brown +  comm - Communicator for the new Mat
1781659c6bb0SJed Brown .  nr - number of nested row blocks
17820298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1783659c6bb0SJed Brown .  nc - number of nested column blocks
17840298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
17850298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1786659c6bb0SJed Brown 
1787659c6bb0SJed Brown    Output Parameter:
1788659c6bb0SJed Brown .  B - new matrix
1789659c6bb0SJed Brown 
1790659c6bb0SJed Brown    Level: advanced
1791659c6bb0SJed Brown 
179279798668SBarry Smith .seealso: MatCreate(), VecCreateNest(), DMCreateMatrix(), MATNEST, MatNestSetSubMat(),
179379798668SBarry Smith           MatNestGetSubMat(), MatNestGetLocalISs(), MatNestGetSize(),
179479798668SBarry Smith           MatNestGetISs(), MatNestSetSubMats(), MatNestGetSubMats()
1795659c6bb0SJed Brown @*/
17967087cfbeSBarry Smith PetscErrorCode MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat *B)
1797d8588912SDave May {
1798d8588912SDave May   Mat            A;
1799d8588912SDave May   PetscErrorCode ierr;
1800d8588912SDave May 
1801d8588912SDave May   PetscFunctionBegin;
1802f4259b30SLisandro Dalcin   *B   = NULL;
1803d8588912SDave May   ierr = MatCreate(comm,&A);CHKERRQ(ierr);
1804c8883902SJed Brown   ierr = MatSetType(A,MATNEST);CHKERRQ(ierr);
180591a28eb3SBarry Smith   A->preallocated = PETSC_TRUE;
1806c8883902SJed Brown   ierr = MatNestSetSubMats(A,nr,is_row,nc,is_col,a);CHKERRQ(ierr);
1807d8588912SDave May   *B   = A;
1808d8588912SDave May   PetscFunctionReturn(0);
1809d8588912SDave May }
1810659c6bb0SJed Brown 
1811b68353e5Sstefano_zampini static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
1812b68353e5Sstefano_zampini {
1813b68353e5Sstefano_zampini   Mat_Nest       *nest = (Mat_Nest*)A->data;
181423875855Sstefano_zampini   Mat            *trans;
1815b68353e5Sstefano_zampini   PetscScalar    **avv;
1816b68353e5Sstefano_zampini   PetscScalar    *vv;
1817b68353e5Sstefano_zampini   PetscInt       **aii,**ajj;
1818b68353e5Sstefano_zampini   PetscInt       *ii,*jj,*ci;
1819b68353e5Sstefano_zampini   PetscInt       nr,nc,nnz,i,j;
1820b68353e5Sstefano_zampini   PetscBool      done;
1821b68353e5Sstefano_zampini   PetscErrorCode ierr;
1822b68353e5Sstefano_zampini 
1823b68353e5Sstefano_zampini   PetscFunctionBegin;
1824b68353e5Sstefano_zampini   ierr = MatGetSize(A,&nr,&nc);CHKERRQ(ierr);
1825b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1826b68353e5Sstefano_zampini     PetscInt rnr;
1827b68353e5Sstefano_zampini 
1828b68353e5Sstefano_zampini     ierr = MatGetRowIJ(*newmat,0,PETSC_FALSE,PETSC_FALSE,&rnr,(const PetscInt**)&ii,(const PetscInt**)&jj,&done);CHKERRQ(ierr);
1829b68353e5Sstefano_zampini     if (!done) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"MatGetRowIJ");
1830b68353e5Sstefano_zampini     if (rnr != nr) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of rows");
1831b68353e5Sstefano_zampini     ierr = MatSeqAIJGetArray(*newmat,&vv);CHKERRQ(ierr);
1832b68353e5Sstefano_zampini   }
1833b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1834b68353e5Sstefano_zampini   nnz  = 0;
183523875855Sstefano_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);
1836b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1837b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1838b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1839b68353e5Sstefano_zampini       if (B) {
1840b68353e5Sstefano_zampini         PetscScalar *naa;
1841b68353e5Sstefano_zampini         PetscInt    *nii,*njj,nnr;
184223875855Sstefano_zampini         PetscBool   istrans;
1843b68353e5Sstefano_zampini 
184423875855Sstefano_zampini         ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
184523875855Sstefano_zampini         if (istrans) {
184623875855Sstefano_zampini           Mat Bt;
184723875855Sstefano_zampini 
184823875855Sstefano_zampini           ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
184923875855Sstefano_zampini           ierr = MatTranspose(Bt,MAT_INITIAL_MATRIX,&trans[i*nest->nc+j]);CHKERRQ(ierr);
185023875855Sstefano_zampini           B    = trans[i*nest->nc+j];
185123875855Sstefano_zampini         }
1852b68353e5Sstefano_zampini         ierr = MatGetRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&nii,(const PetscInt**)&njj,&done);CHKERRQ(ierr);
1853b68353e5Sstefano_zampini         if (!done) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatGetRowIJ");
1854b68353e5Sstefano_zampini         ierr = MatSeqAIJGetArray(B,&naa);CHKERRQ(ierr);
1855b68353e5Sstefano_zampini         nnz += nii[nnr];
1856b68353e5Sstefano_zampini 
1857b68353e5Sstefano_zampini         aii[i*nest->nc+j] = nii;
1858b68353e5Sstefano_zampini         ajj[i*nest->nc+j] = njj;
1859b68353e5Sstefano_zampini         avv[i*nest->nc+j] = naa;
1860b68353e5Sstefano_zampini       }
1861b68353e5Sstefano_zampini     }
1862b68353e5Sstefano_zampini   }
1863b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
1864b68353e5Sstefano_zampini     ierr = PetscMalloc1(nr+1,&ii);CHKERRQ(ierr);
1865b68353e5Sstefano_zampini     ierr = PetscMalloc1(nnz,&jj);CHKERRQ(ierr);
1866b68353e5Sstefano_zampini     ierr = PetscMalloc1(nnz,&vv);CHKERRQ(ierr);
1867b68353e5Sstefano_zampini   } else {
1868b68353e5Sstefano_zampini     if (nnz != ii[nr]) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of nonzeros");
1869b68353e5Sstefano_zampini   }
1870b68353e5Sstefano_zampini 
1871b68353e5Sstefano_zampini   /* new row pointer */
1872580bdb30SBarry Smith   ierr = PetscArrayzero(ii,nr+1);CHKERRQ(ierr);
1873b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1874b68353e5Sstefano_zampini     PetscInt       ncr,rst;
1875b68353e5Sstefano_zampini 
1876b68353e5Sstefano_zampini     ierr = ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL);CHKERRQ(ierr);
1877b68353e5Sstefano_zampini     ierr = ISGetLocalSize(nest->isglobal.row[i],&ncr);CHKERRQ(ierr);
1878b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1879b68353e5Sstefano_zampini       if (aii[i*nest->nc+j]) {
1880b68353e5Sstefano_zampini         PetscInt    *nii = aii[i*nest->nc+j];
1881b68353e5Sstefano_zampini         PetscInt    ir;
1882b68353e5Sstefano_zampini 
1883b68353e5Sstefano_zampini         for (ir=rst; ir<ncr+rst; ++ir) {
1884b68353e5Sstefano_zampini           ii[ir+1] += nii[1]-nii[0];
1885b68353e5Sstefano_zampini           nii++;
1886b68353e5Sstefano_zampini         }
1887b68353e5Sstefano_zampini       }
1888b68353e5Sstefano_zampini     }
1889b68353e5Sstefano_zampini   }
1890b68353e5Sstefano_zampini   for (i=0; i<nr; i++) ii[i+1] += ii[i];
1891b68353e5Sstefano_zampini 
1892b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
1893b68353e5Sstefano_zampini   ierr = PetscCalloc1(nr,&ci);CHKERRQ(ierr);
1894b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1895b68353e5Sstefano_zampini     PetscInt       ncr,rst;
1896b68353e5Sstefano_zampini 
1897b68353e5Sstefano_zampini     ierr = ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL);CHKERRQ(ierr);
1898b68353e5Sstefano_zampini     ierr = ISGetLocalSize(nest->isglobal.row[i],&ncr);CHKERRQ(ierr);
1899b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1900b68353e5Sstefano_zampini       if (aii[i*nest->nc+j]) {
1901b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i*nest->nc+j];
1902b68353e5Sstefano_zampini         PetscInt    *nii = aii[i*nest->nc+j];
1903b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i*nest->nc+j];
1904b68353e5Sstefano_zampini         PetscInt    ir,cst;
1905b68353e5Sstefano_zampini 
1906b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.col[j],&cst,NULL);CHKERRQ(ierr);
1907b68353e5Sstefano_zampini         for (ir=rst; ir<ncr+rst; ++ir) {
1908b68353e5Sstefano_zampini           PetscInt ij,rsize = nii[1]-nii[0],ist = ii[ir]+ci[ir];
1909b68353e5Sstefano_zampini 
1910b68353e5Sstefano_zampini           for (ij=0;ij<rsize;ij++) {
1911b68353e5Sstefano_zampini             jj[ist+ij] = *njj+cst;
1912b68353e5Sstefano_zampini             vv[ist+ij] = *nvv;
1913b68353e5Sstefano_zampini             njj++;
1914b68353e5Sstefano_zampini             nvv++;
1915b68353e5Sstefano_zampini           }
1916b68353e5Sstefano_zampini           ci[ir] += rsize;
1917b68353e5Sstefano_zampini           nii++;
1918b68353e5Sstefano_zampini         }
1919b68353e5Sstefano_zampini       }
1920b68353e5Sstefano_zampini     }
1921b68353e5Sstefano_zampini   }
1922b68353e5Sstefano_zampini   ierr = PetscFree(ci);CHKERRQ(ierr);
1923b68353e5Sstefano_zampini 
1924b68353e5Sstefano_zampini   /* restore info */
1925b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1926b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1927b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1928b68353e5Sstefano_zampini       if (B) {
1929b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i*nest->nc+j;
193023875855Sstefano_zampini 
193123875855Sstefano_zampini         B    = (trans[k] ? trans[k] : B);
1932b68353e5Sstefano_zampini         ierr = MatRestoreRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&aii[k],(const PetscInt**)&ajj[k],&done);CHKERRQ(ierr);
1933b68353e5Sstefano_zampini         if (!done) SETERRQ(PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatRestoreRowIJ");
1934b68353e5Sstefano_zampini         ierr = MatSeqAIJRestoreArray(B,&avv[k]);CHKERRQ(ierr);
193523875855Sstefano_zampini         ierr = MatDestroy(&trans[k]);CHKERRQ(ierr);
1936b68353e5Sstefano_zampini       }
1937b68353e5Sstefano_zampini     }
1938b68353e5Sstefano_zampini   }
193923875855Sstefano_zampini   ierr = PetscFree4(aii,ajj,avv,trans);CHKERRQ(ierr);
1940b68353e5Sstefano_zampini 
1941b68353e5Sstefano_zampini   /* finalize newmat */
1942b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
1943b68353e5Sstefano_zampini     ierr = MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,newmat);CHKERRQ(ierr);
1944b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1945b68353e5Sstefano_zampini     Mat B;
1946b68353e5Sstefano_zampini 
1947b68353e5Sstefano_zampini     ierr = MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,&B);CHKERRQ(ierr);
1948b68353e5Sstefano_zampini     ierr = MatHeaderReplace(A,&B);CHKERRQ(ierr);
1949b68353e5Sstefano_zampini   }
1950b68353e5Sstefano_zampini   ierr = MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1951b68353e5Sstefano_zampini   ierr = MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1952b68353e5Sstefano_zampini   {
1953b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ*)((*newmat)->data);
1954b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1955b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1956b68353e5Sstefano_zampini   }
1957b68353e5Sstefano_zampini   PetscFunctionReturn(0);
1958b68353e5Sstefano_zampini }
1959b68353e5Sstefano_zampini 
1960cc2e6a90SBarry Smith PETSC_INTERN PetscErrorCode MatConvert_Nest_AIJ(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
1961629c3df2SDmitry Karpeev {
1962629c3df2SDmitry Karpeev   PetscErrorCode ierr;
1963629c3df2SDmitry Karpeev   Mat_Nest       *nest = (Mat_Nest*)A->data;
196483b1a929SMark Adams   PetscInt       m,n,M,N,i,j,k,*dnnz,*onnz,rstart;
1965649b366bSFande Kong   PetscInt       cstart,cend;
1966b68353e5Sstefano_zampini   PetscMPIInt    size;
1967629c3df2SDmitry Karpeev   Mat            C;
1968629c3df2SDmitry Karpeev 
1969629c3df2SDmitry Karpeev   PetscFunctionBegin;
1970ffc4695bSBarry Smith   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)A),&size);CHKERRMPI(ierr);
1971b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
1972b68353e5Sstefano_zampini     PetscInt  nf;
1973b68353e5Sstefano_zampini     PetscBool fast;
1974b68353e5Sstefano_zampini 
1975b68353e5Sstefano_zampini     ierr = PetscStrcmp(newtype,MATAIJ,&fast);CHKERRQ(ierr);
1976b68353e5Sstefano_zampini     if (!fast) {
1977b68353e5Sstefano_zampini       ierr = PetscStrcmp(newtype,MATSEQAIJ,&fast);CHKERRQ(ierr);
1978b68353e5Sstefano_zampini     }
1979b68353e5Sstefano_zampini     for (i=0; i<nest->nr && fast; ++i) {
1980b68353e5Sstefano_zampini       for (j=0; j<nest->nc && fast; ++j) {
1981b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
1982b68353e5Sstefano_zampini         if (B) {
1983b68353e5Sstefano_zampini           ierr = PetscObjectTypeCompare((PetscObject)B,MATSEQAIJ,&fast);CHKERRQ(ierr);
198423875855Sstefano_zampini           if (!fast) {
198523875855Sstefano_zampini             PetscBool istrans;
198623875855Sstefano_zampini 
198723875855Sstefano_zampini             ierr = PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans);CHKERRQ(ierr);
198823875855Sstefano_zampini             if (istrans) {
198923875855Sstefano_zampini               Mat Bt;
199023875855Sstefano_zampini 
199123875855Sstefano_zampini               ierr = MatTransposeGetMat(B,&Bt);CHKERRQ(ierr);
199223875855Sstefano_zampini               ierr = PetscObjectTypeCompare((PetscObject)Bt,MATSEQAIJ,&fast);CHKERRQ(ierr);
199323875855Sstefano_zampini             }
1994b68353e5Sstefano_zampini           }
1995b68353e5Sstefano_zampini         }
1996b68353e5Sstefano_zampini       }
1997b68353e5Sstefano_zampini     }
1998b68353e5Sstefano_zampini     for (i=0, nf=0; i<nest->nr && fast; ++i) {
1999b68353e5Sstefano_zampini       ierr = PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i],ISSTRIDE,&fast);CHKERRQ(ierr);
2000b68353e5Sstefano_zampini       if (fast) {
2001b68353e5Sstefano_zampini         PetscInt f,s;
2002b68353e5Sstefano_zampini 
2003b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.row[i],&f,&s);CHKERRQ(ierr);
2004b68353e5Sstefano_zampini         if (f != nf || s != 1) { fast = PETSC_FALSE; }
2005b68353e5Sstefano_zampini         else {
2006b68353e5Sstefano_zampini           ierr = ISGetSize(nest->isglobal.row[i],&f);CHKERRQ(ierr);
2007b68353e5Sstefano_zampini           nf  += f;
2008b68353e5Sstefano_zampini         }
2009b68353e5Sstefano_zampini       }
2010b68353e5Sstefano_zampini     }
2011b68353e5Sstefano_zampini     for (i=0, nf=0; i<nest->nc && fast; ++i) {
2012b68353e5Sstefano_zampini       ierr = PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i],ISSTRIDE,&fast);CHKERRQ(ierr);
2013b68353e5Sstefano_zampini       if (fast) {
2014b68353e5Sstefano_zampini         PetscInt f,s;
2015b68353e5Sstefano_zampini 
2016b68353e5Sstefano_zampini         ierr = ISStrideGetInfo(nest->isglobal.col[i],&f,&s);CHKERRQ(ierr);
2017b68353e5Sstefano_zampini         if (f != nf || s != 1) { fast = PETSC_FALSE; }
2018b68353e5Sstefano_zampini         else {
2019b68353e5Sstefano_zampini           ierr = ISGetSize(nest->isglobal.col[i],&f);CHKERRQ(ierr);
2020b68353e5Sstefano_zampini           nf  += f;
2021b68353e5Sstefano_zampini         }
2022b68353e5Sstefano_zampini       }
2023b68353e5Sstefano_zampini     }
2024b68353e5Sstefano_zampini     if (fast) {
2025b68353e5Sstefano_zampini       ierr = MatConvert_Nest_SeqAIJ_fast(A,newtype,reuse,newmat);CHKERRQ(ierr);
2026b68353e5Sstefano_zampini       PetscFunctionReturn(0);
2027b68353e5Sstefano_zampini     }
2028b68353e5Sstefano_zampini   }
2029629c3df2SDmitry Karpeev   ierr = MatGetSize(A,&M,&N);CHKERRQ(ierr);
2030629c3df2SDmitry Karpeev   ierr = MatGetLocalSize(A,&m,&n);CHKERRQ(ierr);
2031649b366bSFande Kong   ierr = MatGetOwnershipRangeColumn(A,&cstart,&cend);CHKERRQ(ierr);
2032629c3df2SDmitry Karpeev   switch (reuse) {
2033629c3df2SDmitry Karpeev   case MAT_INITIAL_MATRIX:
2034ce94432eSBarry Smith     ierr    = MatCreate(PetscObjectComm((PetscObject)A),&C);CHKERRQ(ierr);
2035629c3df2SDmitry Karpeev     ierr    = MatSetType(C,newtype);CHKERRQ(ierr);
2036629c3df2SDmitry Karpeev     ierr    = MatSetSizes(C,m,n,M,N);CHKERRQ(ierr);
2037629c3df2SDmitry Karpeev     *newmat = C;
2038629c3df2SDmitry Karpeev     break;
2039629c3df2SDmitry Karpeev   case MAT_REUSE_MATRIX:
2040629c3df2SDmitry Karpeev     C = *newmat;
2041629c3df2SDmitry Karpeev     break;
2042ce94432eSBarry Smith   default: SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MatReuse");
2043629c3df2SDmitry Karpeev   }
2044785e854fSJed Brown   ierr = PetscMalloc1(2*m,&dnnz);CHKERRQ(ierr);
2045629c3df2SDmitry Karpeev   onnz = dnnz + m;
2046629c3df2SDmitry Karpeev   for (k=0; k<m; k++) {
2047629c3df2SDmitry Karpeev     dnnz[k] = 0;
2048629c3df2SDmitry Karpeev     onnz[k] = 0;
2049629c3df2SDmitry Karpeev   }
2050629c3df2SDmitry Karpeev   for (j=0; j<nest->nc; ++j) {
2051629c3df2SDmitry Karpeev     IS             bNis;
2052629c3df2SDmitry Karpeev     PetscInt       bN;
2053629c3df2SDmitry Karpeev     const PetscInt *bNindices;
2054629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
2055629c3df2SDmitry Karpeev     ierr = ISAllGather(nest->isglobal.col[j], &bNis);CHKERRQ(ierr);
2056629c3df2SDmitry Karpeev     ierr = ISGetSize(bNis, &bN);CHKERRQ(ierr);
2057629c3df2SDmitry Karpeev     ierr = ISGetIndices(bNis,&bNindices);CHKERRQ(ierr);
2058629c3df2SDmitry Karpeev     for (i=0; i<nest->nr; ++i) {
2059629c3df2SDmitry Karpeev       PetscSF        bmsf;
2060649b366bSFande Kong       PetscSFNode    *iremote;
2061629c3df2SDmitry Karpeev       Mat            B;
2062649b366bSFande Kong       PetscInt       bm, *sub_dnnz,*sub_onnz, br;
2063629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2064629c3df2SDmitry Karpeev       B = nest->m[i][j];
2065629c3df2SDmitry Karpeev       if (!B) continue;
2066629c3df2SDmitry Karpeev       ierr = ISGetLocalSize(nest->isglobal.row[i],&bm);CHKERRQ(ierr);
2067629c3df2SDmitry Karpeev       ierr = ISGetIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
2068ce94432eSBarry Smith       ierr = PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf);CHKERRQ(ierr);
2069649b366bSFande Kong       ierr = PetscMalloc1(bm,&iremote);CHKERRQ(ierr);
2070649b366bSFande Kong       ierr = PetscMalloc1(bm,&sub_dnnz);CHKERRQ(ierr);
2071649b366bSFande Kong       ierr = PetscMalloc1(bm,&sub_onnz);CHKERRQ(ierr);
2072649b366bSFande Kong       for (k = 0; k < bm; ++k){
2073649b366bSFande Kong         sub_dnnz[k] = 0;
2074649b366bSFande Kong         sub_onnz[k] = 0;
2075649b366bSFande Kong       }
2076629c3df2SDmitry Karpeev       /*
2077629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
2078629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2079629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2080629c3df2SDmitry Karpeev        */
208183b1a929SMark Adams       ierr = MatGetOwnershipRange(B,&rstart,NULL);CHKERRQ(ierr);
2082629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2083131c27b5Sprj-         PetscInt       row = bmindices[br], brncols, col;
2084629c3df2SDmitry Karpeev         const PetscInt *brcols;
2085a4b3d3acSMatthew G Knepley         PetscInt       rowrel = 0; /* row's relative index on its owner rank */
2086131c27b5Sprj-         PetscMPIInt    rowowner = 0;
2087629c3df2SDmitry Karpeev         ierr      = PetscLayoutFindOwnerIndex(A->rmap,row,&rowowner,&rowrel);CHKERRQ(ierr);
2088649b366bSFande Kong         /* how many roots  */
2089649b366bSFande Kong         iremote[br].rank = rowowner; iremote[br].index = rowrel;           /* edge from bmdnnz to dnnz */
2090649b366bSFande Kong         /* get nonzero pattern */
209183b1a929SMark Adams         ierr = MatGetRow(B,br+rstart,&brncols,&brcols,NULL);CHKERRQ(ierr);
2092629c3df2SDmitry Karpeev         for (k=0; k<brncols; k++) {
2093629c3df2SDmitry Karpeev           col  = bNindices[brcols[k]];
2094649b366bSFande Kong           if (col>=A->cmap->range[rowowner] && col<A->cmap->range[rowowner+1]) {
2095649b366bSFande Kong             sub_dnnz[br]++;
2096649b366bSFande Kong           } else {
2097649b366bSFande Kong             sub_onnz[br]++;
2098649b366bSFande Kong           }
2099629c3df2SDmitry Karpeev         }
210083b1a929SMark Adams         ierr = MatRestoreRow(B,br+rstart,&brncols,&brcols,NULL);CHKERRQ(ierr);
2101629c3df2SDmitry Karpeev       }
2102629c3df2SDmitry Karpeev       ierr = ISRestoreIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
2103629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
2104649b366bSFande Kong       ierr = PetscSFSetGraph(bmsf,m,bm,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
2105649b366bSFande Kong       ierr = PetscSFReduceBegin(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM);CHKERRQ(ierr);
2106649b366bSFande Kong       ierr = PetscSFReduceEnd(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM);CHKERRQ(ierr);
2107649b366bSFande Kong       ierr = PetscSFReduceBegin(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM);CHKERRQ(ierr);
2108649b366bSFande Kong       ierr = PetscSFReduceEnd(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM);CHKERRQ(ierr);
2109649b366bSFande Kong       ierr = PetscFree(sub_dnnz);CHKERRQ(ierr);
2110649b366bSFande Kong       ierr = PetscFree(sub_onnz);CHKERRQ(ierr);
2111629c3df2SDmitry Karpeev       ierr = PetscSFDestroy(&bmsf);CHKERRQ(ierr);
2112629c3df2SDmitry Karpeev     }
211322d28d08SBarry Smith     ierr = ISRestoreIndices(bNis,&bNindices);CHKERRQ(ierr);
2114629c3df2SDmitry Karpeev     ierr = ISDestroy(&bNis);CHKERRQ(ierr);
211565a4a0a3Sstefano_zampini   }
211665a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
211765a4a0a3Sstefano_zampini   for (i=0;i<m;i++) {
211865a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i],A->cmap->n);
211965a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i],A->cmap->N - A->cmap->n);
2120629c3df2SDmitry Karpeev   }
2121629c3df2SDmitry Karpeev   ierr = MatSeqAIJSetPreallocation(C,0,dnnz);CHKERRQ(ierr);
2122629c3df2SDmitry Karpeev   ierr = MatMPIAIJSetPreallocation(C,0,dnnz,0,onnz);CHKERRQ(ierr);
2123629c3df2SDmitry Karpeev   ierr = PetscFree(dnnz);CHKERRQ(ierr);
2124629c3df2SDmitry Karpeev 
2125629c3df2SDmitry Karpeev   /* Fill by row */
2126629c3df2SDmitry Karpeev   for (j=0; j<nest->nc; ++j) {
2127629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
2128629c3df2SDmitry Karpeev     IS             bNis;
2129629c3df2SDmitry Karpeev     PetscInt       bN;
2130629c3df2SDmitry Karpeev     const PetscInt *bNindices;
2131629c3df2SDmitry Karpeev     ierr = ISAllGather(nest->isglobal.col[j], &bNis);CHKERRQ(ierr);
2132629c3df2SDmitry Karpeev     ierr = ISGetSize(bNis,&bN);CHKERRQ(ierr);
2133629c3df2SDmitry Karpeev     ierr = ISGetIndices(bNis,&bNindices);CHKERRQ(ierr);
2134629c3df2SDmitry Karpeev     for (i=0; i<nest->nr; ++i) {
2135629c3df2SDmitry Karpeev       Mat            B;
2136629c3df2SDmitry Karpeev       PetscInt       bm, br;
2137629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2138629c3df2SDmitry Karpeev       B = nest->m[i][j];
2139629c3df2SDmitry Karpeev       if (!B) continue;
2140629c3df2SDmitry Karpeev       ierr = ISGetLocalSize(nest->isglobal.row[i],&bm);CHKERRQ(ierr);
2141629c3df2SDmitry Karpeev       ierr = ISGetIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
214283b1a929SMark Adams       ierr = MatGetOwnershipRange(B,&rstart,NULL);CHKERRQ(ierr);
2143629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2144629c3df2SDmitry Karpeev         PetscInt          row = bmindices[br], brncols,  *cols;
2145629c3df2SDmitry Karpeev         const PetscInt    *brcols;
2146629c3df2SDmitry Karpeev         const PetscScalar *brcoldata;
214783b1a929SMark Adams         ierr = MatGetRow(B,br+rstart,&brncols,&brcols,&brcoldata);CHKERRQ(ierr);
2148785e854fSJed Brown         ierr = PetscMalloc1(brncols,&cols);CHKERRQ(ierr);
214926fbe8dcSKarl Rupp         for (k=0; k<brncols; k++) cols[k] = bNindices[brcols[k]];
2150629c3df2SDmitry Karpeev         /*
2151629c3df2SDmitry Karpeev           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
2152629c3df2SDmitry Karpeev           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
2153629c3df2SDmitry Karpeev          */
2154a2ea699eSBarry Smith         ierr = MatSetValues(C,1,&row,brncols,cols,brcoldata,ADD_VALUES);CHKERRQ(ierr);
215583b1a929SMark Adams         ierr = MatRestoreRow(B,br+rstart,&brncols,&brcols,&brcoldata);CHKERRQ(ierr);
2156629c3df2SDmitry Karpeev         ierr = PetscFree(cols);CHKERRQ(ierr);
2157629c3df2SDmitry Karpeev       }
2158629c3df2SDmitry Karpeev       ierr = ISRestoreIndices(nest->isglobal.row[i],&bmindices);CHKERRQ(ierr);
2159629c3df2SDmitry Karpeev     }
2160a2ea699eSBarry Smith     ierr = ISRestoreIndices(bNis,&bNindices);CHKERRQ(ierr);
2161629c3df2SDmitry Karpeev     ierr = ISDestroy(&bNis);CHKERRQ(ierr);
2162629c3df2SDmitry Karpeev   }
2163629c3df2SDmitry Karpeev   ierr = MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2164629c3df2SDmitry Karpeev   ierr = MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
2165629c3df2SDmitry Karpeev   PetscFunctionReturn(0);
2166629c3df2SDmitry Karpeev }
2167629c3df2SDmitry Karpeev 
21688b7d3b4bSBarry Smith PetscErrorCode MatHasOperation_Nest(Mat mat,MatOperation op,PetscBool *has)
21698b7d3b4bSBarry Smith {
21708b7d3b4bSBarry Smith   Mat_Nest       *bA = (Mat_Nest*)mat->data;
21713c6db4c4SPierre Jolivet   MatOperation   opAdd;
21728b7d3b4bSBarry Smith   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
21738b7d3b4bSBarry Smith   PetscBool      flg;
217452c5f739Sprj-   PetscErrorCode ierr;
217552c5f739Sprj-   PetscFunctionBegin;
21768b7d3b4bSBarry Smith 
217752c5f739Sprj-   *has = PETSC_FALSE;
21783c6db4c4SPierre Jolivet   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
21793c6db4c4SPierre Jolivet     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
21808b7d3b4bSBarry Smith     for (j=0; j<nc; j++) {
21818b7d3b4bSBarry Smith       for (i=0; i<nr; i++) {
21828b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
21833c6db4c4SPierre Jolivet         ierr = MatHasOperation(bA->m[i][j],opAdd,&flg);CHKERRQ(ierr);
21848b7d3b4bSBarry Smith         if (!flg) PetscFunctionReturn(0);
21858b7d3b4bSBarry Smith       }
21868b7d3b4bSBarry Smith     }
21878b7d3b4bSBarry Smith   }
21883c6db4c4SPierre Jolivet   if (((void**)mat->ops)[op]) *has = PETSC_TRUE;
21898b7d3b4bSBarry Smith   PetscFunctionReturn(0);
21908b7d3b4bSBarry Smith }
21918b7d3b4bSBarry Smith 
2192659c6bb0SJed Brown /*MC
2193659c6bb0SJed Brown   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.
2194659c6bb0SJed Brown 
2195659c6bb0SJed Brown   Level: intermediate
2196659c6bb0SJed Brown 
2197659c6bb0SJed Brown   Notes:
2198659c6bb0SJed Brown   This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices.
2199659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
2200950540a4SJed Brown   It is usually used with DMComposite and DMCreateMatrix()
2201659c6bb0SJed Brown 
22028b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
22038b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
22048b7d3b4bSBarry Smith   than the nest matrix.
22058b7d3b4bSBarry Smith 
220679798668SBarry Smith .seealso: MatCreate(), MatType, MatCreateNest(), MatNestSetSubMat(), MatNestGetSubMat(),
220779798668SBarry Smith           VecCreateNest(), DMCreateMatrix(), DMCOMPOSITE, MatNestSetVecType(), MatNestGetLocalISs(),
220879798668SBarry Smith           MatNestGetISs(), MatNestSetSubMats(), MatNestGetSubMats()
2209659c6bb0SJed Brown M*/
22108cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2211c8883902SJed Brown {
2212c8883902SJed Brown   Mat_Nest       *s;
2213c8883902SJed Brown   PetscErrorCode ierr;
2214c8883902SJed Brown 
2215c8883902SJed Brown   PetscFunctionBegin;
2216b00a9115SJed Brown   ierr    = PetscNewLog(A,&s);CHKERRQ(ierr);
2217c8883902SJed Brown   A->data = (void*)s;
2218e7c19651SJed Brown 
2219e7c19651SJed Brown   s->nr            = -1;
2220e7c19651SJed Brown   s->nc            = -1;
22210298fd71SBarry Smith   s->m             = NULL;
2222e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
2223c8883902SJed Brown 
2224c8883902SJed Brown   ierr = PetscMemzero(A->ops,sizeof(*A->ops));CHKERRQ(ierr);
222526fbe8dcSKarl Rupp 
2226c8883902SJed Brown   A->ops->mult                  = MatMult_Nest;
22279194d70fSJed Brown   A->ops->multadd               = MatMultAdd_Nest;
2228c8883902SJed Brown   A->ops->multtranspose         = MatMultTranspose_Nest;
22299194d70fSJed Brown   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
2230f8170845SAlex Fikl   A->ops->transpose             = MatTranspose_Nest;
2231c8883902SJed Brown   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
2232c8883902SJed Brown   A->ops->assemblyend           = MatAssemblyEnd_Nest;
2233c8883902SJed Brown   A->ops->zeroentries           = MatZeroEntries_Nest;
2234c222c20dSDavid Ham   A->ops->copy                  = MatCopy_Nest;
22356e76ffeaSPierre Jolivet   A->ops->axpy                  = MatAXPY_Nest;
2236c8883902SJed Brown   A->ops->duplicate             = MatDuplicate_Nest;
22377dae84e0SHong Zhang   A->ops->createsubmatrix       = MatCreateSubMatrix_Nest;
2238c8883902SJed Brown   A->ops->destroy               = MatDestroy_Nest;
2239c8883902SJed Brown   A->ops->view                  = MatView_Nest;
2240f4259b30SLisandro Dalcin   A->ops->getvecs               = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2241c8883902SJed Brown   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
2242c8883902SJed Brown   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
2243429bac76SJed Brown   A->ops->getdiagonal           = MatGetDiagonal_Nest;
2244429bac76SJed Brown   A->ops->diagonalscale         = MatDiagonalScale_Nest;
2245a061e289SJed Brown   A->ops->scale                 = MatScale_Nest;
2246a061e289SJed Brown   A->ops->shift                 = MatShift_Nest;
224713135bc6SAlex Fikl   A->ops->diagonalset           = MatDiagonalSet_Nest;
2248f8170845SAlex Fikl   A->ops->setrandom             = MatSetRandom_Nest;
22498b7d3b4bSBarry Smith   A->ops->hasoperation          = MatHasOperation_Nest;
2250381b8e50SStefano Zampini   A->ops->missingdiagonal       = MatMissingDiagonal_Nest;
2251c8883902SJed Brown 
2252f4259b30SLisandro Dalcin   A->spptr        = NULL;
2253c8883902SJed Brown   A->assembled    = PETSC_FALSE;
2254c8883902SJed Brown 
2255c8883902SJed Brown   /* expose Nest api's */
2256bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",        MatNestGetSubMat_Nest);CHKERRQ(ierr);
2257bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",        MatNestSetSubMat_Nest);CHKERRQ(ierr);
2258bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",       MatNestGetSubMats_Nest);CHKERRQ(ierr);
2259bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",          MatNestGetSize_Nest);CHKERRQ(ierr);
2260bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",           MatNestGetISs_Nest);CHKERRQ(ierr);
2261bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",      MatNestGetLocalISs_Nest);CHKERRQ(ierr);
2262bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",       MatNestSetVecType_Nest);CHKERRQ(ierr);
2263bdf89e91SBarry Smith   ierr = PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",       MatNestSetSubMats_Nest);CHKERRQ(ierr);
22640899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",  MatConvert_Nest_AIJ);CHKERRQ(ierr);
22650899c546SStefano Zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",  MatConvert_Nest_AIJ);CHKERRQ(ierr);
226683b1a929SMark Adams   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",     MatConvert_Nest_AIJ);CHKERRQ(ierr);
22675e3038f0Sstefano_zampini   ierr = PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",      MatConvert_Nest_IS);CHKERRQ(ierr);
22684222ddf1SHong Zhang   ierr = PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_seqdense_C",MatProductSetFromOptions_Nest_Dense);CHKERRQ(ierr);
22694222ddf1SHong Zhang   ierr = PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_mpidense_C",MatProductSetFromOptions_Nest_Dense);CHKERRQ(ierr);
22704222ddf1SHong Zhang   ierr = PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_dense_C",MatProductSetFromOptions_Nest_Dense);CHKERRQ(ierr);
2271c8883902SJed Brown 
2272c8883902SJed Brown   ierr = PetscObjectChangeTypeName((PetscObject)A,MATNEST);CHKERRQ(ierr);
2273c8883902SJed Brown   PetscFunctionReturn(0);
2274c8883902SJed Brown }
2275