xref: /petsc/src/mat/impls/nest/matnest.c (revision 7fb60732ccf1806988e9909cd147cdb09c395756)
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 
17d8588912SDave May   PetscFunctionBegin;
188188e55aSJed Brown   *m = *n = *M = *N = 0;
198188e55aSJed Brown   for (i=0; i<bA->nr; i++) {  /* rows */
208188e55aSJed Brown     PetscInt sm,sM;
219566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[i],&sm));
229566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.row[i],&sM));
238188e55aSJed Brown     *m  += sm;
248188e55aSJed Brown     *M  += sM;
25d8588912SDave May   }
268188e55aSJed Brown   for (j=0; j<bA->nc; j++) {  /* cols */
278188e55aSJed Brown     PetscInt sn,sN;
289566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[j],&sn));
299566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[j],&sN));
308188e55aSJed Brown     *n  += sn;
318188e55aSJed Brown     *N  += sN;
32d8588912SDave May   }
33d8588912SDave May   PetscFunctionReturn(0);
34d8588912SDave May }
35d8588912SDave May 
36d8588912SDave May /* operations */
37207556f9SJed Brown static PetscErrorCode MatMult_Nest(Mat A,Vec x,Vec y)
38d8588912SDave May {
39d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
40207556f9SJed Brown   Vec            *bx = bA->right,*by = bA->left;
41207556f9SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
42d8588912SDave May 
43d8588912SDave May   PetscFunctionBegin;
449566063dSJacob Faibussowitsch   for (i=0; i<nr; i++) PetscCall(VecGetSubVector(y,bA->isglobal.row[i],&by[i]));
459566063dSJacob Faibussowitsch   for (i=0; i<nc; i++) PetscCall(VecGetSubVector(x,bA->isglobal.col[i],&bx[i]));
46207556f9SJed Brown   for (i=0; i<nr; i++) {
479566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[i]));
48207556f9SJed Brown     for (j=0; j<nc; j++) {
49207556f9SJed Brown       if (!bA->m[i][j]) continue;
50d8588912SDave May       /* y[i] <- y[i] + A[i][j] * x[j] */
519566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(bA->m[i][j],bx[j],by[i],by[i]));
52d8588912SDave May     }
53d8588912SDave May   }
549566063dSJacob Faibussowitsch   for (i=0; i<nr; i++) PetscCall(VecRestoreSubVector(y,bA->isglobal.row[i],&by[i]));
559566063dSJacob Faibussowitsch   for (i=0; i<nc; i++) PetscCall(VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]));
56d8588912SDave May   PetscFunctionReturn(0);
57d8588912SDave May }
58d8588912SDave May 
599194d70fSJed Brown static PetscErrorCode MatMultAdd_Nest(Mat A,Vec x,Vec y,Vec z)
609194d70fSJed Brown {
619194d70fSJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
629194d70fSJed Brown   Vec            *bx = bA->right,*bz = bA->left;
639194d70fSJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
649194d70fSJed Brown 
659194d70fSJed Brown   PetscFunctionBegin;
669566063dSJacob Faibussowitsch   for (i=0; i<nr; i++) PetscCall(VecGetSubVector(z,bA->isglobal.row[i],&bz[i]));
679566063dSJacob Faibussowitsch   for (i=0; i<nc; i++) PetscCall(VecGetSubVector(x,bA->isglobal.col[i],&bx[i]));
689194d70fSJed Brown   for (i=0; i<nr; i++) {
699194d70fSJed Brown     if (y != z) {
709194d70fSJed Brown       Vec by;
719566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y,bA->isglobal.row[i],&by));
729566063dSJacob Faibussowitsch       PetscCall(VecCopy(by,bz[i]));
739566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y,bA->isglobal.row[i],&by));
749194d70fSJed Brown     }
759194d70fSJed Brown     for (j=0; j<nc; j++) {
769194d70fSJed Brown       if (!bA->m[i][j]) continue;
779194d70fSJed Brown       /* y[i] <- y[i] + A[i][j] * x[j] */
789566063dSJacob Faibussowitsch       PetscCall(MatMultAdd(bA->m[i][j],bx[j],bz[i],bz[i]));
799194d70fSJed Brown     }
809194d70fSJed Brown   }
819566063dSJacob Faibussowitsch   for (i=0; i<nr; i++) PetscCall(VecRestoreSubVector(z,bA->isglobal.row[i],&bz[i]));
829566063dSJacob Faibussowitsch   for (i=0; i<nc; i++) PetscCall(VecRestoreSubVector(x,bA->isglobal.col[i],&bx[i]));
839194d70fSJed Brown   PetscFunctionReturn(0);
849194d70fSJed Brown }
859194d70fSJed Brown 
8652c5f739Sprj- typedef struct {
8752c5f739Sprj-   Mat          *workC;    /* array of Mat with specific containers depending on the underlying MatMatMult implementation */
8852c5f739Sprj-   PetscScalar  *tarray;   /* buffer for storing all temporary products A[i][j] B[j] */
8952c5f739Sprj-   PetscInt     *dm,*dn,k; /* displacements and number of submatrices */
9052c5f739Sprj- } Nest_Dense;
9152c5f739Sprj- 
926718818eSStefano Zampini PETSC_INTERN PetscErrorCode MatProductNumeric_Nest_Dense(Mat C)
9352c5f739Sprj- {
946718818eSStefano Zampini   Mat_Nest          *bA;
9552c5f739Sprj-   Nest_Dense        *contents;
966718818eSStefano Zampini   Mat               viewB,viewC,productB,workC;
9752c5f739Sprj-   const PetscScalar *barray;
9852c5f739Sprj-   PetscScalar       *carray;
996718818eSStefano Zampini   PetscInt          i,j,M,N,nr,nc,ldb,ldc;
1006718818eSStefano Zampini   Mat               A,B;
10152c5f739Sprj- 
10252c5f739Sprj-   PetscFunctionBegin;
1036718818eSStefano Zampini   MatCheckProduct(C,3);
1046718818eSStefano Zampini   A    = C->product->A;
1056718818eSStefano Zampini   B    = C->product->B;
1069566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B,NULL,&N));
1076718818eSStefano Zampini   if (!N) {
1089566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY));
1099566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY));
1106718818eSStefano Zampini     PetscFunctionReturn(0);
1116718818eSStefano Zampini   }
1126718818eSStefano Zampini   contents = (Nest_Dense*)C->product->data;
11328b400f6SJacob Faibussowitsch   PetscCheck(contents,PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data empty");
1146718818eSStefano Zampini   bA   = (Mat_Nest*)A->data;
1156718818eSStefano Zampini   nr   = bA->nr;
1166718818eSStefano Zampini   nc   = bA->nc;
1179566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(B,&ldb));
1189566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(C,&ldc));
1199566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(C));
1209566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(B,&barray));
1219566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArray(C,&carray));
12252c5f739Sprj-   for (i=0; i<nr; i++) {
1239566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.row[i],&M));
1249566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A),contents->dm[i+1]-contents->dm[i],PETSC_DECIDE,M,N,carray+contents->dm[i],&viewC));
1259566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewC,ldc));
12652c5f739Sprj-     for (j=0; j<nc; j++) {
12752c5f739Sprj-       if (!bA->m[i][j]) continue;
1289566063dSJacob Faibussowitsch       PetscCall(ISGetSize(bA->isglobal.col[j],&M));
1299566063dSJacob Faibussowitsch       PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A),contents->dn[j+1]-contents->dn[j],PETSC_DECIDE,M,N,(PetscScalar*)(barray+contents->dn[j]),&viewB));
1309566063dSJacob Faibussowitsch       PetscCall(MatDenseSetLDA(viewB,ldb));
1314222ddf1SHong Zhang 
1324222ddf1SHong Zhang       /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */
1334222ddf1SHong Zhang       workC             = contents->workC[i*nc + j];
1344222ddf1SHong Zhang       productB          = workC->product->B;
1354222ddf1SHong Zhang       workC->product->B = viewB; /* use newly created dense matrix viewB */
1369566063dSJacob Faibussowitsch       PetscCall(MatProductNumeric(workC));
1379566063dSJacob Faibussowitsch       PetscCall(MatDestroy(&viewB));
1384222ddf1SHong Zhang       workC->product->B = productB; /* resume original B */
1394222ddf1SHong Zhang 
14052c5f739Sprj-       /* C[i] <- workC + C[i] */
1419566063dSJacob Faibussowitsch       PetscCall(MatAXPY(viewC,1.0,contents->workC[i*nc + j],SAME_NONZERO_PATTERN));
14252c5f739Sprj-     }
1439566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewC));
14452c5f739Sprj-   }
1459566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArray(C,&carray));
1469566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B,&barray));
1474222ddf1SHong Zhang 
1489566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(C,MAT_FINAL_ASSEMBLY));
1499566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(C,MAT_FINAL_ASSEMBLY));
15052c5f739Sprj-   PetscFunctionReturn(0);
15152c5f739Sprj- }
15252c5f739Sprj- 
15352c5f739Sprj- PetscErrorCode MatNest_DenseDestroy(void *ctx)
15452c5f739Sprj- {
15552c5f739Sprj-   Nest_Dense     *contents = (Nest_Dense*)ctx;
15652c5f739Sprj-   PetscInt       i;
15752c5f739Sprj- 
15852c5f739Sprj-   PetscFunctionBegin;
1599566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents->tarray));
16052c5f739Sprj-   for (i=0; i<contents->k; i++) {
1619566063dSJacob Faibussowitsch     PetscCall(MatDestroy(contents->workC + i));
16252c5f739Sprj-   }
1639566063dSJacob Faibussowitsch   PetscCall(PetscFree3(contents->dm,contents->dn,contents->workC));
1649566063dSJacob Faibussowitsch   PetscCall(PetscFree(contents));
16552c5f739Sprj-   PetscFunctionReturn(0);
16652c5f739Sprj- }
16752c5f739Sprj- 
1686718818eSStefano Zampini PETSC_INTERN PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C)
16952c5f739Sprj- {
1706718818eSStefano Zampini   Mat_Nest          *bA;
1716718818eSStefano Zampini   Mat               viewB,workC;
17252c5f739Sprj-   const PetscScalar *barray;
1736718818eSStefano Zampini   PetscInt          i,j,M,N,m,n,nr,nc,maxm = 0,ldb;
1744222ddf1SHong Zhang   Nest_Dense        *contents=NULL;
1756718818eSStefano Zampini   PetscBool         cisdense;
1766718818eSStefano Zampini   Mat               A,B;
1776718818eSStefano Zampini   PetscReal         fill;
17852c5f739Sprj- 
17952c5f739Sprj-   PetscFunctionBegin;
1806718818eSStefano Zampini   MatCheckProduct(C,4);
18128b400f6SJacob Faibussowitsch   PetscCheck(!C->product->data,PetscObjectComm((PetscObject)C),PETSC_ERR_PLIB,"Product data not empty");
1826718818eSStefano Zampini   A    = C->product->A;
1836718818eSStefano Zampini   B    = C->product->B;
1846718818eSStefano Zampini   fill = C->product->fill;
1856718818eSStefano Zampini   bA   = (Mat_Nest*)A->data;
1866718818eSStefano Zampini   nr   = bA->nr;
1876718818eSStefano Zampini   nc   = bA->nc;
1889566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(C,&m,&n));
1899566063dSJacob Faibussowitsch   PetscCall(MatGetSize(C,&M,&N));
1900572eedcSPierre Jolivet   if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) {
1919566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(B,NULL,&n));
1929566063dSJacob Faibussowitsch     PetscCall(MatGetSize(B,NULL,&N));
1939566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(A,&m,NULL));
1949566063dSJacob Faibussowitsch     PetscCall(MatGetSize(A,&M,NULL));
1959566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C,m,n,M,N));
1960572eedcSPierre Jolivet   }
1979566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompareAny((PetscObject)C,&cisdense,MATSEQDENSE,MATMPIDENSE,MATSEQDENSECUDA,MATMPIDENSECUDA,""));
1986718818eSStefano Zampini   if (!cisdense) {
1999566063dSJacob Faibussowitsch     PetscCall(MatSetType(C,((PetscObject)B)->type_name));
2006718818eSStefano Zampini   }
2019566063dSJacob Faibussowitsch   PetscCall(MatSetUp(C));
2026718818eSStefano Zampini   if (!N) {
2036718818eSStefano Zampini     C->ops->productnumeric = MatProductNumeric_Nest_Dense;
2046718818eSStefano Zampini     PetscFunctionReturn(0);
20552c5f739Sprj-   }
20652c5f739Sprj- 
2079566063dSJacob Faibussowitsch   PetscCall(PetscNew(&contents));
2086718818eSStefano Zampini   C->product->data = contents;
2096718818eSStefano Zampini   C->product->destroy = MatNest_DenseDestroy;
2109566063dSJacob Faibussowitsch   PetscCall(PetscCalloc3(nr+1,&contents->dm,nc+1,&contents->dn,nr*nc,&contents->workC));
21152c5f739Sprj-   contents->k = nr*nc;
21252c5f739Sprj-   for (i=0; i<nr; i++) {
2139566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.row[i],contents->dm + i+1));
21452c5f739Sprj-     maxm = PetscMax(maxm,contents->dm[i+1]);
21552c5f739Sprj-     contents->dm[i+1] += contents->dm[i];
21652c5f739Sprj-   }
21752c5f739Sprj-   for (i=0; i<nc; i++) {
2189566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(bA->isglobal.col[i],contents->dn + i+1));
21952c5f739Sprj-     contents->dn[i+1] += contents->dn[i];
22052c5f739Sprj-   }
2219566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(maxm*N,&contents->tarray));
2229566063dSJacob Faibussowitsch   PetscCall(MatDenseGetLDA(B,&ldb));
2239566063dSJacob Faibussowitsch   PetscCall(MatGetSize(B,NULL,&N));
2249566063dSJacob Faibussowitsch   PetscCall(MatDenseGetArrayRead(B,&barray));
22552c5f739Sprj-   /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */
22652c5f739Sprj-   for (j=0; j<nc; j++) {
2279566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bA->isglobal.col[j],&M));
2289566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A),contents->dn[j+1]-contents->dn[j],PETSC_DECIDE,M,N,(PetscScalar*)(barray+contents->dn[j]),&viewB));
2299566063dSJacob Faibussowitsch     PetscCall(MatDenseSetLDA(viewB,ldb));
23052c5f739Sprj-     for (i=0; i<nr; i++) {
23152c5f739Sprj-       if (!bA->m[i][j]) continue;
23252c5f739Sprj-       /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */
2334222ddf1SHong Zhang 
2349566063dSJacob Faibussowitsch       PetscCall(MatProductCreate(bA->m[i][j],viewB,NULL,&contents->workC[i*nc + j]));
2354222ddf1SHong Zhang       workC = contents->workC[i*nc + j];
2369566063dSJacob Faibussowitsch       PetscCall(MatProductSetType(workC,MATPRODUCT_AB));
2379566063dSJacob Faibussowitsch       PetscCall(MatProductSetAlgorithm(workC,"default"));
2389566063dSJacob Faibussowitsch       PetscCall(MatProductSetFill(workC,fill));
2399566063dSJacob Faibussowitsch       PetscCall(MatProductSetFromOptions(workC));
2409566063dSJacob Faibussowitsch       PetscCall(MatProductSymbolic(workC));
2414222ddf1SHong Zhang 
2426718818eSStefano Zampini       /* since tarray will be shared by all Mat */
2439566063dSJacob Faibussowitsch       PetscCall(MatSeqDenseSetPreallocation(workC,contents->tarray));
2449566063dSJacob Faibussowitsch       PetscCall(MatMPIDenseSetPreallocation(workC,contents->tarray));
24552c5f739Sprj-     }
2469566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&viewB));
24752c5f739Sprj-   }
2489566063dSJacob Faibussowitsch   PetscCall(MatDenseRestoreArrayRead(B,&barray));
24952c5f739Sprj- 
2506718818eSStefano Zampini   C->ops->productnumeric = MatProductNumeric_Nest_Dense;
25152c5f739Sprj-   PetscFunctionReturn(0);
25252c5f739Sprj- }
25352c5f739Sprj- 
2544222ddf1SHong Zhang /* --------------------------------------------------------- */
2554222ddf1SHong Zhang static PetscErrorCode MatProductSetFromOptions_Nest_Dense_AB(Mat C)
2564222ddf1SHong Zhang {
2574222ddf1SHong Zhang   PetscFunctionBegin;
2586718818eSStefano Zampini   C->ops->productsymbolic = MatProductSymbolic_Nest_Dense;
2594222ddf1SHong Zhang   PetscFunctionReturn(0);
2604222ddf1SHong Zhang }
2614222ddf1SHong Zhang 
2624222ddf1SHong Zhang PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C)
26352c5f739Sprj- {
2644222ddf1SHong Zhang   Mat_Product    *product = C->product;
26552c5f739Sprj- 
26652c5f739Sprj-   PetscFunctionBegin;
2674222ddf1SHong Zhang   if (product->type == MATPRODUCT_AB) {
2689566063dSJacob Faibussowitsch     PetscCall(MatProductSetFromOptions_Nest_Dense_AB(C));
2696718818eSStefano Zampini   }
27052c5f739Sprj-   PetscFunctionReturn(0);
27152c5f739Sprj- }
2724222ddf1SHong Zhang /* --------------------------------------------------------- */
27352c5f739Sprj- 
274207556f9SJed Brown static PetscErrorCode MatMultTranspose_Nest(Mat A,Vec x,Vec y)
275d8588912SDave May {
276d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
277207556f9SJed Brown   Vec            *bx = bA->left,*by = bA->right;
278207556f9SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
279d8588912SDave May 
280d8588912SDave May   PetscFunctionBegin;
2819566063dSJacob Faibussowitsch   for (i=0; i<nr; i++) PetscCall(VecGetSubVector(x,bA->isglobal.row[i],&bx[i]));
2829566063dSJacob Faibussowitsch   for (i=0; i<nc; i++) PetscCall(VecGetSubVector(y,bA->isglobal.col[i],&by[i]));
283207556f9SJed Brown   for (j=0; j<nc; j++) {
2849566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(by[j]));
285609e31cbSJed Brown     for (i=0; i<nr; i++) {
2866c75ac25SJed Brown       if (!bA->m[i][j]) continue;
287609e31cbSJed Brown       /* y[j] <- y[j] + (A[i][j])^T * x[i] */
2889566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(bA->m[i][j],bx[i],by[j],by[j]));
289d8588912SDave May     }
290d8588912SDave May   }
2919566063dSJacob Faibussowitsch   for (i=0; i<nr; i++) PetscCall(VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]));
2929566063dSJacob Faibussowitsch   for (i=0; i<nc; i++) PetscCall(VecRestoreSubVector(y,bA->isglobal.col[i],&by[i]));
293d8588912SDave May   PetscFunctionReturn(0);
294d8588912SDave May }
295d8588912SDave May 
2969194d70fSJed Brown static PetscErrorCode MatMultTransposeAdd_Nest(Mat A,Vec x,Vec y,Vec z)
2979194d70fSJed Brown {
2989194d70fSJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
2999194d70fSJed Brown   Vec            *bx = bA->left,*bz = bA->right;
3009194d70fSJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
3019194d70fSJed Brown 
3029194d70fSJed Brown   PetscFunctionBegin;
3039566063dSJacob Faibussowitsch   for (i=0; i<nr; i++) PetscCall(VecGetSubVector(x,bA->isglobal.row[i],&bx[i]));
3049566063dSJacob Faibussowitsch   for (i=0; i<nc; i++) PetscCall(VecGetSubVector(z,bA->isglobal.col[i],&bz[i]));
3059194d70fSJed Brown   for (j=0; j<nc; j++) {
3069194d70fSJed Brown     if (y != z) {
3079194d70fSJed Brown       Vec by;
3089566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(y,bA->isglobal.col[j],&by));
3099566063dSJacob Faibussowitsch       PetscCall(VecCopy(by,bz[j]));
3109566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(y,bA->isglobal.col[j],&by));
3119194d70fSJed Brown     }
3129194d70fSJed Brown     for (i=0; i<nr; i++) {
3136c75ac25SJed Brown       if (!bA->m[i][j]) continue;
3149194d70fSJed Brown       /* z[j] <- y[j] + (A[i][j])^T * x[i] */
3159566063dSJacob Faibussowitsch       PetscCall(MatMultTransposeAdd(bA->m[i][j],bx[i],bz[j],bz[j]));
3169194d70fSJed Brown     }
3179194d70fSJed Brown   }
3189566063dSJacob Faibussowitsch   for (i=0; i<nr; i++) PetscCall(VecRestoreSubVector(x,bA->isglobal.row[i],&bx[i]));
3199566063dSJacob Faibussowitsch   for (i=0; i<nc; i++) PetscCall(VecRestoreSubVector(z,bA->isglobal.col[i],&bz[i]));
3209194d70fSJed Brown   PetscFunctionReturn(0);
3219194d70fSJed Brown }
3229194d70fSJed Brown 
323f8170845SAlex Fikl static PetscErrorCode MatTranspose_Nest(Mat A,MatReuse reuse,Mat *B)
324f8170845SAlex Fikl {
325f8170845SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data, *bC;
326f8170845SAlex Fikl   Mat            C;
327f8170845SAlex Fikl   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
328f8170845SAlex Fikl 
329f8170845SAlex Fikl   PetscFunctionBegin;
330*7fb60732SBarry Smith   if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A,*B));
331aed4548fSBarry Smith   PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_SIZ,"Square nested matrix only for in-place");
332f8170845SAlex Fikl 
333cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) {
334f8170845SAlex Fikl     Mat *subs;
335f8170845SAlex Fikl     IS  *is_row,*is_col;
336f8170845SAlex Fikl 
3379566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(nr * nc,&subs));
3389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nr,&is_row,nc,&is_col));
3399566063dSJacob Faibussowitsch     PetscCall(MatNestGetISs(A,is_row,is_col));
340cf37664fSBarry Smith     if (reuse == MAT_INPLACE_MATRIX) {
341ddeb9bd8SAlex Fikl       for (i=0; i<nr; i++) {
342ddeb9bd8SAlex Fikl         for (j=0; j<nc; j++) {
343ddeb9bd8SAlex Fikl           subs[i + nr * j] = bA->m[i][j];
344ddeb9bd8SAlex Fikl         }
345ddeb9bd8SAlex Fikl       }
346ddeb9bd8SAlex Fikl     }
347ddeb9bd8SAlex Fikl 
3489566063dSJacob Faibussowitsch     PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A),nc,is_col,nr,is_row,subs,&C));
3499566063dSJacob Faibussowitsch     PetscCall(PetscFree(subs));
3509566063dSJacob Faibussowitsch     PetscCall(PetscFree2(is_row,is_col));
351f8170845SAlex Fikl   } else {
352f8170845SAlex Fikl     C = *B;
353f8170845SAlex Fikl   }
354f8170845SAlex Fikl 
355f8170845SAlex Fikl   bC = (Mat_Nest*)C->data;
356f8170845SAlex Fikl   for (i=0; i<nr; i++) {
357f8170845SAlex Fikl     for (j=0; j<nc; j++) {
358f8170845SAlex Fikl       if (bA->m[i][j]) {
3599566063dSJacob Faibussowitsch         PetscCall(MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i])));
360f8170845SAlex Fikl       } else {
361f8170845SAlex Fikl         bC->m[j][i] = NULL;
362f8170845SAlex Fikl       }
363f8170845SAlex Fikl     }
364f8170845SAlex Fikl   }
365f8170845SAlex Fikl 
366cf37664fSBarry Smith   if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) {
367f8170845SAlex Fikl     *B = C;
368f8170845SAlex Fikl   } else {
3699566063dSJacob Faibussowitsch     PetscCall(MatHeaderMerge(A, &C));
370f8170845SAlex Fikl   }
371f8170845SAlex Fikl   PetscFunctionReturn(0);
372f8170845SAlex Fikl }
373f8170845SAlex Fikl 
374e2d7f03fSJed Brown static PetscErrorCode MatNestDestroyISList(PetscInt n,IS **list)
375e2d7f03fSJed Brown {
376e2d7f03fSJed Brown   IS             *lst = *list;
377e2d7f03fSJed Brown   PetscInt       i;
378e2d7f03fSJed Brown 
379e2d7f03fSJed Brown   PetscFunctionBegin;
380e2d7f03fSJed Brown   if (!lst) PetscFunctionReturn(0);
3819566063dSJacob Faibussowitsch   for (i=0; i<n; i++) if (lst[i]) PetscCall(ISDestroy(&lst[i]));
3829566063dSJacob Faibussowitsch   PetscCall(PetscFree(lst));
3830298fd71SBarry Smith   *list = NULL;
384e2d7f03fSJed Brown   PetscFunctionReturn(0);
385e2d7f03fSJed Brown }
386e2d7f03fSJed Brown 
38706a1af2fSStefano Zampini static PetscErrorCode MatReset_Nest(Mat A)
388d8588912SDave May {
389d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
390d8588912SDave May   PetscInt       i,j;
391d8588912SDave May 
392d8588912SDave May   PetscFunctionBegin;
393d8588912SDave May   /* release the matrices and the place holders */
3949566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr,&vs->isglobal.row));
3959566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc,&vs->isglobal.col));
3969566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nr,&vs->islocal.row));
3979566063dSJacob Faibussowitsch   PetscCall(MatNestDestroyISList(vs->nc,&vs->islocal.col));
398d8588912SDave May 
3999566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->row_len));
4009566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->col_len));
4019566063dSJacob Faibussowitsch   PetscCall(PetscFree(vs->nnzstate));
402d8588912SDave May 
4039566063dSJacob Faibussowitsch   PetscCall(PetscFree2(vs->left,vs->right));
404207556f9SJed Brown 
405d8588912SDave May   /* release the matrices and the place holders */
406d8588912SDave May   if (vs->m) {
407d8588912SDave May     for (i=0; i<vs->nr; i++) {
408d8588912SDave May       for (j=0; j<vs->nc; j++) {
4099566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&vs->m[i][j]));
410d8588912SDave May       }
4119566063dSJacob Faibussowitsch       PetscCall(PetscFree(vs->m[i]));
412d8588912SDave May     }
4139566063dSJacob Faibussowitsch     PetscCall(PetscFree(vs->m));
414d8588912SDave May   }
41506a1af2fSStefano Zampini 
41606a1af2fSStefano Zampini   /* restore defaults */
41706a1af2fSStefano Zampini   vs->nr = 0;
41806a1af2fSStefano Zampini   vs->nc = 0;
41906a1af2fSStefano Zampini   vs->splitassembly = PETSC_FALSE;
42006a1af2fSStefano Zampini   PetscFunctionReturn(0);
42106a1af2fSStefano Zampini }
42206a1af2fSStefano Zampini 
42306a1af2fSStefano Zampini static PetscErrorCode MatDestroy_Nest(Mat A)
42406a1af2fSStefano Zampini {
425362febeeSStefano Zampini   PetscFunctionBegin;
4269566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
4279566063dSJacob Faibussowitsch   PetscCall(PetscFree(A->data));
4289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",NULL));
4299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",NULL));
4309566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",NULL));
4319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",NULL));
4329566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",NULL));
4339566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",NULL));
4349566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",NULL));
4359566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",NULL));
4369566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",NULL));
4379566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",NULL));
4389566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",NULL));
4399566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",NULL));
4409566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpidense_C",NULL));
4419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqdense_C",NULL));
4429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_seqdense_C",NULL));
4439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_mpidense_C",NULL));
4449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_dense_C",NULL));
445d8588912SDave May   PetscFunctionReturn(0);
446d8588912SDave May }
447d8588912SDave May 
448381b8e50SStefano Zampini static PetscErrorCode MatMissingDiagonal_Nest(Mat mat,PetscBool *missing,PetscInt *dd)
449381b8e50SStefano Zampini {
450381b8e50SStefano Zampini   Mat_Nest       *vs = (Mat_Nest*)mat->data;
451381b8e50SStefano Zampini   PetscInt       i;
452381b8e50SStefano Zampini 
453381b8e50SStefano Zampini   PetscFunctionBegin;
454381b8e50SStefano Zampini   if (dd) *dd = 0;
455381b8e50SStefano Zampini   if (!vs->nr) {
456381b8e50SStefano Zampini     *missing = PETSC_TRUE;
457381b8e50SStefano Zampini     PetscFunctionReturn(0);
458381b8e50SStefano Zampini   }
459381b8e50SStefano Zampini   *missing = PETSC_FALSE;
460381b8e50SStefano Zampini   for (i = 0; i < vs->nr && !(*missing); i++) {
461381b8e50SStefano Zampini     *missing = PETSC_TRUE;
462381b8e50SStefano Zampini     if (vs->m[i][i]) {
4639566063dSJacob Faibussowitsch       PetscCall(MatMissingDiagonal(vs->m[i][i],missing,NULL));
46408401ef6SPierre Jolivet       PetscCheck(!*missing || !dd,PetscObjectComm((PetscObject)mat),PETSC_ERR_SUP,"First missing entry not yet implemented");
465381b8e50SStefano Zampini     }
466381b8e50SStefano Zampini   }
467381b8e50SStefano Zampini   PetscFunctionReturn(0);
468381b8e50SStefano Zampini }
469381b8e50SStefano Zampini 
470207556f9SJed Brown static PetscErrorCode MatAssemblyBegin_Nest(Mat A,MatAssemblyType type)
471d8588912SDave May {
472d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
473d8588912SDave May   PetscInt       i,j;
47406a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
475d8588912SDave May 
476d8588912SDave May   PetscFunctionBegin;
477d8588912SDave May   for (i=0; i<vs->nr; i++) {
478d8588912SDave May     for (j=0; j<vs->nc; j++) {
47906a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
480e7c19651SJed Brown       if (vs->m[i][j]) {
4819566063dSJacob Faibussowitsch         PetscCall(MatAssemblyBegin(vs->m[i][j],type));
482e7c19651SJed Brown         if (!vs->splitassembly) {
483e7c19651SJed Brown           /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested
484e7c19651SJed 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
485e7c19651SJed Brown            * already performing an assembly, but the result would by more complicated and appears to offer less
486e7c19651SJed Brown            * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an
487e7c19651SJed Brown            * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives".
488e7c19651SJed Brown            */
4899566063dSJacob Faibussowitsch           PetscCall(MatAssemblyEnd(vs->m[i][j],type));
4909566063dSJacob Faibussowitsch           PetscCall(MatGetNonzeroState(vs->m[i][j],&subnnzstate));
491e7c19651SJed Brown         }
492e7c19651SJed Brown       }
49306a1af2fSStefano Zampini       nnzstate = (PetscBool)(nnzstate || vs->nnzstate[i*vs->nc+j] != subnnzstate);
49406a1af2fSStefano Zampini       vs->nnzstate[i*vs->nc+j] = subnnzstate;
495d8588912SDave May     }
496d8588912SDave May   }
49706a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
498d8588912SDave May   PetscFunctionReturn(0);
499d8588912SDave May }
500d8588912SDave May 
501207556f9SJed Brown static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type)
502d8588912SDave May {
503d8588912SDave May   Mat_Nest       *vs = (Mat_Nest*)A->data;
504d8588912SDave May   PetscInt       i,j;
505d8588912SDave May 
506d8588912SDave May   PetscFunctionBegin;
507d8588912SDave May   for (i=0; i<vs->nr; i++) {
508d8588912SDave May     for (j=0; j<vs->nc; j++) {
509e7c19651SJed Brown       if (vs->m[i][j]) {
510e7c19651SJed Brown         if (vs->splitassembly) {
5119566063dSJacob Faibussowitsch           PetscCall(MatAssemblyEnd(vs->m[i][j],type));
512e7c19651SJed Brown         }
513e7c19651SJed Brown       }
514d8588912SDave May     }
515d8588912SDave May   }
516d8588912SDave May   PetscFunctionReturn(0);
517d8588912SDave May }
518d8588912SDave May 
519f349c1fdSJed Brown static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A,PetscInt row,Mat *B)
520d8588912SDave May {
521f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
522f349c1fdSJed Brown   PetscInt       j;
523f349c1fdSJed Brown   Mat            sub;
524d8588912SDave May 
525d8588912SDave May   PetscFunctionBegin;
5260298fd71SBarry Smith   sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */
527f349c1fdSJed Brown   for (j=0; !sub && j<vs->nc; j++) sub = vs->m[row][j];
5289566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub));       /* Ensure that the sizes are available */
529f349c1fdSJed Brown   *B = sub;
530f349c1fdSJed Brown   PetscFunctionReturn(0);
531d8588912SDave May }
532d8588912SDave May 
533f349c1fdSJed Brown static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A,PetscInt col,Mat *B)
534f349c1fdSJed Brown {
535f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
536f349c1fdSJed Brown   PetscInt       i;
537f349c1fdSJed Brown   Mat            sub;
538f349c1fdSJed Brown 
539f349c1fdSJed Brown   PetscFunctionBegin;
5400298fd71SBarry Smith   sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */
541f349c1fdSJed Brown   for (i=0; !sub && i<vs->nr; i++) sub = vs->m[i][col];
5429566063dSJacob Faibussowitsch   if (sub) PetscCall(MatSetUp(sub));       /* Ensure that the sizes are available */
543f349c1fdSJed Brown   *B = sub;
544f349c1fdSJed Brown   PetscFunctionReturn(0);
545d8588912SDave May }
546d8588912SDave May 
54718d228c0SPierre Jolivet static PetscErrorCode MatNestFindISRange(Mat A,PetscInt n,const IS list[],IS is,PetscInt *begin,PetscInt *end)
548f349c1fdSJed Brown {
54918d228c0SPierre Jolivet   PetscInt       i,j,size,m;
550f349c1fdSJed Brown   PetscBool      flg;
55118d228c0SPierre Jolivet   IS             out,concatenate[2];
552f349c1fdSJed Brown 
553f349c1fdSJed Brown   PetscFunctionBegin;
554f349c1fdSJed Brown   PetscValidPointer(list,3);
555f349c1fdSJed Brown   PetscValidHeaderSpecific(is,IS_CLASSID,4);
55618d228c0SPierre Jolivet   if (begin) {
55718d228c0SPierre Jolivet     PetscValidIntPointer(begin,5);
55818d228c0SPierre Jolivet     *begin = -1;
55918d228c0SPierre Jolivet   }
56018d228c0SPierre Jolivet   if (end) {
56118d228c0SPierre Jolivet     PetscValidIntPointer(end,6);
56218d228c0SPierre Jolivet     *end = -1;
56318d228c0SPierre Jolivet   }
564f349c1fdSJed Brown   for (i=0; i<n; i++) {
565207556f9SJed Brown     if (!list[i]) continue;
5669566063dSJacob Faibussowitsch     PetscCall(ISEqualUnsorted(list[i],is,&flg));
567f349c1fdSJed Brown     if (flg) {
56818d228c0SPierre Jolivet       if (begin) *begin = i;
56918d228c0SPierre Jolivet       if (end) *end = i+1;
570f349c1fdSJed Brown       PetscFunctionReturn(0);
571f349c1fdSJed Brown     }
572f349c1fdSJed Brown   }
5739566063dSJacob Faibussowitsch   PetscCall(ISGetSize(is,&size));
57418d228c0SPierre Jolivet   for (i=0; i<n-1; i++) {
57518d228c0SPierre Jolivet     if (!list[i]) continue;
57618d228c0SPierre Jolivet     m = 0;
5779566063dSJacob Faibussowitsch     PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A),2,list+i,&out));
5789566063dSJacob Faibussowitsch     PetscCall(ISGetSize(out,&m));
57918d228c0SPierre Jolivet     for (j=i+2; j<n && m<size; j++) {
58018d228c0SPierre Jolivet       if (list[j]) {
58118d228c0SPierre Jolivet         concatenate[0] = out;
58218d228c0SPierre Jolivet         concatenate[1] = list[j];
5839566063dSJacob Faibussowitsch         PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A),2,concatenate,&out));
5849566063dSJacob Faibussowitsch         PetscCall(ISDestroy(concatenate));
5859566063dSJacob Faibussowitsch         PetscCall(ISGetSize(out,&m));
58618d228c0SPierre Jolivet       }
58718d228c0SPierre Jolivet     }
58818d228c0SPierre Jolivet     if (m == size) {
5899566063dSJacob Faibussowitsch       PetscCall(ISEqualUnsorted(out,is,&flg));
59018d228c0SPierre Jolivet       if (flg) {
59118d228c0SPierre Jolivet         if (begin) *begin = i;
59218d228c0SPierre Jolivet         if (end) *end = j;
5939566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&out));
59418d228c0SPierre Jolivet         PetscFunctionReturn(0);
59518d228c0SPierre Jolivet       }
59618d228c0SPierre Jolivet     }
5979566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&out));
59818d228c0SPierre Jolivet   }
59918d228c0SPierre Jolivet   PetscFunctionReturn(0);
600f349c1fdSJed Brown }
601f349c1fdSJed Brown 
60218d228c0SPierre Jolivet static PetscErrorCode MatNestFillEmptyMat_Private(Mat A,PetscInt i,PetscInt j,Mat *B)
6038188e55aSJed Brown {
6048188e55aSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
60518d228c0SPierre Jolivet   PetscInt       lr,lc;
60618d228c0SPierre Jolivet 
60718d228c0SPierre Jolivet   PetscFunctionBegin;
6089566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)A),B));
6099566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.row[i],&lr));
6109566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(vs->isglobal.col[j],&lc));
6119566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*B,lr,lc,PETSC_DECIDE,PETSC_DECIDE));
6129566063dSJacob Faibussowitsch   PetscCall(MatSetType(*B,MATAIJ));
6139566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(*B,0,NULL));
6149566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(*B,0,NULL,0,NULL));
6159566063dSJacob Faibussowitsch   PetscCall(MatSetUp(*B));
6169566063dSJacob Faibussowitsch   PetscCall(MatSetOption(*B,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE));
6179566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY));
6189566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY));
61918d228c0SPierre Jolivet   PetscFunctionReturn(0);
62018d228c0SPierre Jolivet }
62118d228c0SPierre Jolivet 
62218d228c0SPierre Jolivet static PetscErrorCode MatNestGetBlock_Private(Mat A,PetscInt rbegin,PetscInt rend,PetscInt cbegin,PetscInt cend,Mat *B)
62318d228c0SPierre Jolivet {
62418d228c0SPierre Jolivet   Mat_Nest       *vs = (Mat_Nest*)A->data;
62518d228c0SPierre Jolivet   Mat            *a;
62618d228c0SPierre Jolivet   PetscInt       i,j,k,l,nr=rend-rbegin,nc=cend-cbegin;
6278188e55aSJed Brown   char           keyname[256];
62818d228c0SPierre Jolivet   PetscBool      *b;
62918d228c0SPierre Jolivet   PetscBool      flg;
6308188e55aSJed Brown 
6318188e55aSJed Brown   PetscFunctionBegin;
6320298fd71SBarry Smith   *B   = NULL;
6339566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(keyname,sizeof(keyname),"NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT,rbegin,rend,cbegin,cend));
6349566063dSJacob Faibussowitsch   PetscCall(PetscObjectQuery((PetscObject)A,keyname,(PetscObject*)B));
6358188e55aSJed Brown   if (*B) PetscFunctionReturn(0);
6368188e55aSJed Brown 
6379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nr*nc,&a,nr*nc,&b));
63818d228c0SPierre Jolivet   for (i=0; i<nr; i++) {
63918d228c0SPierre Jolivet     for (j=0; j<nc; j++) {
64018d228c0SPierre Jolivet       a[i*nc + j] = vs->m[rbegin+i][cbegin+j];
64118d228c0SPierre Jolivet       b[i*nc + j] = PETSC_FALSE;
64218d228c0SPierre Jolivet     }
64318d228c0SPierre Jolivet   }
64418d228c0SPierre Jolivet   if (nc!=vs->nc&&nr!=vs->nr) {
64518d228c0SPierre Jolivet     for (i=0; i<nr; i++) {
64618d228c0SPierre Jolivet       for (j=0; j<nc; j++) {
64718d228c0SPierre Jolivet         flg = PETSC_FALSE;
64818d228c0SPierre Jolivet         for (k=0; (k<nr&&!flg); k++) {
64918d228c0SPierre Jolivet           if (a[j + k*nc]) flg = PETSC_TRUE;
65018d228c0SPierre Jolivet         }
65118d228c0SPierre Jolivet         if (flg) {
65218d228c0SPierre Jolivet           flg = PETSC_FALSE;
65318d228c0SPierre Jolivet           for (l=0; (l<nc&&!flg); l++) {
65418d228c0SPierre Jolivet             if (a[i*nc + l]) flg = PETSC_TRUE;
65518d228c0SPierre Jolivet           }
65618d228c0SPierre Jolivet         }
65718d228c0SPierre Jolivet         if (!flg) {
65818d228c0SPierre Jolivet           b[i*nc + j] = PETSC_TRUE;
6599566063dSJacob Faibussowitsch           PetscCall(MatNestFillEmptyMat_Private(A,rbegin+i,cbegin+j,a + i*nc + j));
66018d228c0SPierre Jolivet         }
66118d228c0SPierre Jolivet       }
66218d228c0SPierre Jolivet     }
66318d228c0SPierre Jolivet   }
6649566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A),nr,nr!=vs->nr?NULL:vs->isglobal.row,nc,nc!=vs->nc?NULL:vs->isglobal.col,a,B));
66518d228c0SPierre Jolivet   for (i=0; i<nr; i++) {
66618d228c0SPierre Jolivet     for (j=0; j<nc; j++) {
66718d228c0SPierre Jolivet       if (b[i*nc + j]) {
6689566063dSJacob Faibussowitsch         PetscCall(MatDestroy(a + i*nc + j));
66918d228c0SPierre Jolivet       }
67018d228c0SPierre Jolivet     }
67118d228c0SPierre Jolivet   }
6729566063dSJacob Faibussowitsch   PetscCall(PetscFree2(a,b));
6738188e55aSJed Brown   (*B)->assembled = A->assembled;
6749566063dSJacob Faibussowitsch   PetscCall(PetscObjectCompose((PetscObject)A,keyname,(PetscObject)*B));
6759566063dSJacob Faibussowitsch   PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */
6768188e55aSJed Brown   PetscFunctionReturn(0);
6778188e55aSJed Brown }
6788188e55aSJed Brown 
679f349c1fdSJed Brown static PetscErrorCode MatNestFindSubMat(Mat A,struct MatNestISPair *is,IS isrow,IS iscol,Mat *B)
680f349c1fdSJed Brown {
681f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
68218d228c0SPierre Jolivet   PetscInt       rbegin,rend,cbegin,cend;
683f349c1fdSJed Brown 
684f349c1fdSJed Brown   PetscFunctionBegin;
6859566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A,vs->nr,is->row,isrow,&rbegin,&rend));
6869566063dSJacob Faibussowitsch   PetscCall(MatNestFindISRange(A,vs->nc,is->col,iscol,&cbegin,&cend));
68718d228c0SPierre Jolivet   if (rend == rbegin + 1 && cend == cbegin + 1) {
68818d228c0SPierre Jolivet     if (!vs->m[rbegin][cbegin]) {
6899566063dSJacob Faibussowitsch       PetscCall(MatNestFillEmptyMat_Private(A,rbegin,cbegin,vs->m[rbegin] + cbegin));
69077019fcaSJed Brown     }
69118d228c0SPierre Jolivet     *B = vs->m[rbegin][cbegin];
69218d228c0SPierre Jolivet   } else if (rbegin != -1 && cbegin != -1) {
6939566063dSJacob Faibussowitsch     PetscCall(MatNestGetBlock_Private(A,rbegin,rend,cbegin,cend,B));
69418d228c0SPierre Jolivet   } else SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Could not find index set");
695f349c1fdSJed Brown   PetscFunctionReturn(0);
696f349c1fdSJed Brown }
697f349c1fdSJed Brown 
69806a1af2fSStefano Zampini /*
69906a1af2fSStefano Zampini    TODO: This does not actually returns a submatrix we can modify
70006a1af2fSStefano Zampini */
7017dae84e0SHong Zhang static PetscErrorCode MatCreateSubMatrix_Nest(Mat A,IS isrow,IS iscol,MatReuse reuse,Mat *B)
702f349c1fdSJed Brown {
703f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
704f349c1fdSJed Brown   Mat            sub;
705f349c1fdSJed Brown 
706f349c1fdSJed Brown   PetscFunctionBegin;
7079566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A,&vs->isglobal,isrow,iscol,&sub));
708f349c1fdSJed Brown   switch (reuse) {
709f349c1fdSJed Brown   case MAT_INITIAL_MATRIX:
7109566063dSJacob Faibussowitsch     if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
711f349c1fdSJed Brown     *B = sub;
712f349c1fdSJed Brown     break;
713f349c1fdSJed Brown   case MAT_REUSE_MATRIX:
71408401ef6SPierre Jolivet     PetscCheck(sub == *B,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Submatrix was not used before in this call");
715f349c1fdSJed Brown     break;
716f349c1fdSJed Brown   case MAT_IGNORE_MATRIX:       /* Nothing to do */
717f349c1fdSJed Brown     break;
718511c6705SHong Zhang   case MAT_INPLACE_MATRIX:       /* Nothing to do */
719511c6705SHong Zhang     SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"MAT_INPLACE_MATRIX is not supported yet");
720f349c1fdSJed Brown   }
721f349c1fdSJed Brown   PetscFunctionReturn(0);
722f349c1fdSJed Brown }
723f349c1fdSJed Brown 
724f349c1fdSJed Brown PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
725f349c1fdSJed Brown {
726f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
727f349c1fdSJed Brown   Mat            sub;
728f349c1fdSJed Brown 
729f349c1fdSJed Brown   PetscFunctionBegin;
7309566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub));
731f349c1fdSJed Brown   /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */
7329566063dSJacob Faibussowitsch   if (sub) PetscCall(PetscObjectReference((PetscObject)sub));
733f349c1fdSJed Brown   *B = sub;
734d8588912SDave May   PetscFunctionReturn(0);
735d8588912SDave May }
736d8588912SDave May 
737207556f9SJed Brown static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A,IS isrow,IS iscol,Mat *B)
738d8588912SDave May {
739f349c1fdSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
740f349c1fdSJed Brown   Mat            sub;
741d8588912SDave May 
742d8588912SDave May   PetscFunctionBegin;
7439566063dSJacob Faibussowitsch   PetscCall(MatNestFindSubMat(A,&vs->islocal,isrow,iscol,&sub));
74408401ef6SPierre Jolivet   PetscCheck(*B == sub,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has not been gotten");
745f349c1fdSJed Brown   if (sub) {
746aed4548fSBarry Smith     PetscCheck(((PetscObject)sub)->refct > 1,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Local submatrix has had reference count decremented too many times");
7479566063dSJacob Faibussowitsch     PetscCall(MatDestroy(B));
748d8588912SDave May   }
749d8588912SDave May   PetscFunctionReturn(0);
750d8588912SDave May }
751d8588912SDave May 
7527874fa86SDave May static PetscErrorCode MatGetDiagonal_Nest(Mat A,Vec v)
7537874fa86SDave May {
7547874fa86SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
7557874fa86SDave May   PetscInt       i;
7567874fa86SDave May 
7577874fa86SDave May   PetscFunctionBegin;
7587874fa86SDave May   for (i=0; i<bA->nr; i++) {
759429bac76SJed Brown     Vec bv;
7609566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(v,bA->isglobal.row[i],&bv));
7617874fa86SDave May     if (bA->m[i][i]) {
7629566063dSJacob Faibussowitsch       PetscCall(MatGetDiagonal(bA->m[i][i],bv));
7637874fa86SDave May     } else {
7649566063dSJacob Faibussowitsch       PetscCall(VecSet(bv,0.0));
7657874fa86SDave May     }
7669566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(v,bA->isglobal.row[i],&bv));
7677874fa86SDave May   }
7687874fa86SDave May   PetscFunctionReturn(0);
7697874fa86SDave May }
7707874fa86SDave May 
7717874fa86SDave May static PetscErrorCode MatDiagonalScale_Nest(Mat A,Vec l,Vec r)
7727874fa86SDave May {
7737874fa86SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
774429bac76SJed Brown   Vec            bl,*br;
7757874fa86SDave May   PetscInt       i,j;
7767874fa86SDave May 
7777874fa86SDave May   PetscFunctionBegin;
7789566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(bA->nc,&br));
7792e6472ebSElliott Sales de Andrade   if (r) {
7809566063dSJacob Faibussowitsch     for (j=0; j<bA->nc; j++) PetscCall(VecGetSubVector(r,bA->isglobal.col[j],&br[j]));
7812e6472ebSElliott Sales de Andrade   }
7822e6472ebSElliott Sales de Andrade   bl = NULL;
7837874fa86SDave May   for (i=0; i<bA->nr; i++) {
7842e6472ebSElliott Sales de Andrade     if (l) {
7859566063dSJacob Faibussowitsch       PetscCall(VecGetSubVector(l,bA->isglobal.row[i],&bl));
7862e6472ebSElliott Sales de Andrade     }
7877874fa86SDave May     for (j=0; j<bA->nc; j++) {
7887874fa86SDave May       if (bA->m[i][j]) {
7899566063dSJacob Faibussowitsch         PetscCall(MatDiagonalScale(bA->m[i][j],bl,br[j]));
7907874fa86SDave May       }
7917874fa86SDave May     }
7922e6472ebSElliott Sales de Andrade     if (l) {
7939566063dSJacob Faibussowitsch       PetscCall(VecRestoreSubVector(l,bA->isglobal.row[i],&bl));
7947874fa86SDave May     }
7952e6472ebSElliott Sales de Andrade   }
7962e6472ebSElliott Sales de Andrade   if (r) {
7979566063dSJacob Faibussowitsch     for (j=0; j<bA->nc; j++) PetscCall(VecRestoreSubVector(r,bA->isglobal.col[j],&br[j]));
7982e6472ebSElliott Sales de Andrade   }
7999566063dSJacob Faibussowitsch   PetscCall(PetscFree(br));
8007874fa86SDave May   PetscFunctionReturn(0);
8017874fa86SDave May }
8027874fa86SDave May 
803a061e289SJed Brown static PetscErrorCode MatScale_Nest(Mat A,PetscScalar a)
804a061e289SJed Brown {
805a061e289SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
806a061e289SJed Brown   PetscInt       i,j;
807a061e289SJed Brown 
808a061e289SJed Brown   PetscFunctionBegin;
809a061e289SJed Brown   for (i=0; i<bA->nr; i++) {
810a061e289SJed Brown     for (j=0; j<bA->nc; j++) {
811a061e289SJed Brown       if (bA->m[i][j]) {
8129566063dSJacob Faibussowitsch         PetscCall(MatScale(bA->m[i][j],a));
813a061e289SJed Brown       }
814a061e289SJed Brown     }
815a061e289SJed Brown   }
816a061e289SJed Brown   PetscFunctionReturn(0);
817a061e289SJed Brown }
818a061e289SJed Brown 
819a061e289SJed Brown static PetscErrorCode MatShift_Nest(Mat A,PetscScalar a)
820a061e289SJed Brown {
821a061e289SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
822a061e289SJed Brown   PetscInt       i;
82306a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
824a061e289SJed Brown 
825a061e289SJed Brown   PetscFunctionBegin;
826a061e289SJed Brown   for (i=0; i<bA->nr; i++) {
82706a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
82808401ef6SPierre Jolivet     PetscCheck(bA->m[i][i],PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support for shifting an empty diagonal block, insert a matrix in block (%" PetscInt_FMT ",%" PetscInt_FMT ")",i,i);
8299566063dSJacob Faibussowitsch     PetscCall(MatShift(bA->m[i][i],a));
8309566063dSJacob Faibussowitsch     PetscCall(MatGetNonzeroState(bA->m[i][i],&subnnzstate));
83106a1af2fSStefano Zampini     nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i*bA->nc+i] != subnnzstate);
83206a1af2fSStefano Zampini     bA->nnzstate[i*bA->nc+i] = subnnzstate;
833a061e289SJed Brown   }
83406a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
835a061e289SJed Brown   PetscFunctionReturn(0);
836a061e289SJed Brown }
837a061e289SJed Brown 
83813135bc6SAlex Fikl static PetscErrorCode MatDiagonalSet_Nest(Mat A,Vec D,InsertMode is)
83913135bc6SAlex Fikl {
84013135bc6SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data;
84113135bc6SAlex Fikl   PetscInt       i;
84206a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
84313135bc6SAlex Fikl 
84413135bc6SAlex Fikl   PetscFunctionBegin;
84513135bc6SAlex Fikl   for (i=0; i<bA->nr; i++) {
84606a1af2fSStefano Zampini     PetscObjectState subnnzstate = 0;
84713135bc6SAlex Fikl     Vec              bv;
8489566063dSJacob Faibussowitsch     PetscCall(VecGetSubVector(D,bA->isglobal.row[i],&bv));
84913135bc6SAlex Fikl     if (bA->m[i][i]) {
8509566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(bA->m[i][i],bv,is));
8519566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bA->m[i][i],&subnnzstate));
85213135bc6SAlex Fikl     }
8539566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(D,bA->isglobal.row[i],&bv));
85406a1af2fSStefano Zampini     nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i*bA->nc+i] != subnnzstate);
85506a1af2fSStefano Zampini     bA->nnzstate[i*bA->nc+i] = subnnzstate;
85613135bc6SAlex Fikl   }
85706a1af2fSStefano Zampini   if (nnzstate) A->nonzerostate++;
85813135bc6SAlex Fikl   PetscFunctionReturn(0);
85913135bc6SAlex Fikl }
86013135bc6SAlex Fikl 
861f8170845SAlex Fikl static PetscErrorCode MatSetRandom_Nest(Mat A,PetscRandom rctx)
862f8170845SAlex Fikl {
863f8170845SAlex Fikl   Mat_Nest       *bA = (Mat_Nest*)A->data;
864f8170845SAlex Fikl   PetscInt       i,j;
865f8170845SAlex Fikl 
866f8170845SAlex Fikl   PetscFunctionBegin;
867f8170845SAlex Fikl   for (i=0; i<bA->nr; i++) {
868f8170845SAlex Fikl     for (j=0; j<bA->nc; j++) {
869f8170845SAlex Fikl       if (bA->m[i][j]) {
8709566063dSJacob Faibussowitsch         PetscCall(MatSetRandom(bA->m[i][j],rctx));
871f8170845SAlex Fikl       }
872f8170845SAlex Fikl     }
873f8170845SAlex Fikl   }
874f8170845SAlex Fikl   PetscFunctionReturn(0);
875f8170845SAlex Fikl }
876f8170845SAlex Fikl 
8772a7a6963SBarry Smith static PetscErrorCode MatCreateVecs_Nest(Mat A,Vec *right,Vec *left)
878d8588912SDave May {
879d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
880d8588912SDave May   Vec            *L,*R;
881d8588912SDave May   MPI_Comm       comm;
882d8588912SDave May   PetscInt       i,j;
883d8588912SDave May 
884d8588912SDave May   PetscFunctionBegin;
8859566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)A,&comm));
886d8588912SDave May   if (right) {
887d8588912SDave May     /* allocate R */
8889566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nc, &R));
889d8588912SDave May     /* Create the right vectors */
890d8588912SDave May     for (j=0; j<bA->nc; j++) {
891d8588912SDave May       for (i=0; i<bA->nr; i++) {
892d8588912SDave May         if (bA->m[i][j]) {
8939566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j],&R[j],NULL));
894d8588912SDave May           break;
895d8588912SDave May         }
896d8588912SDave May       }
89708401ef6SPierre Jolivet       PetscCheck(i!=bA->nr,PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column.");
898d8588912SDave May     }
8999566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm,bA->nc,bA->isglobal.col,R,right));
900d8588912SDave May     /* hand back control to the nest vector */
901d8588912SDave May     for (j=0; j<bA->nc; j++) {
9029566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&R[j]));
903d8588912SDave May     }
9049566063dSJacob Faibussowitsch     PetscCall(PetscFree(R));
905d8588912SDave May   }
906d8588912SDave May 
907d8588912SDave May   if (left) {
908d8588912SDave May     /* allocate L */
9099566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(bA->nr, &L));
910d8588912SDave May     /* Create the left vectors */
911d8588912SDave May     for (i=0; i<bA->nr; i++) {
912d8588912SDave May       for (j=0; j<bA->nc; j++) {
913d8588912SDave May         if (bA->m[i][j]) {
9149566063dSJacob Faibussowitsch           PetscCall(MatCreateVecs(bA->m[i][j],NULL,&L[i]));
915d8588912SDave May           break;
916d8588912SDave May         }
917d8588912SDave May       }
91808401ef6SPierre Jolivet       PetscCheck(j!=bA->nc,PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row.");
919d8588912SDave May     }
920d8588912SDave May 
9219566063dSJacob Faibussowitsch     PetscCall(VecCreateNest(comm,bA->nr,bA->isglobal.row,L,left));
922d8588912SDave May     for (i=0; i<bA->nr; i++) {
9239566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&L[i]));
924d8588912SDave May     }
925d8588912SDave May 
9269566063dSJacob Faibussowitsch     PetscCall(PetscFree(L));
927d8588912SDave May   }
928d8588912SDave May   PetscFunctionReturn(0);
929d8588912SDave May }
930d8588912SDave May 
931207556f9SJed Brown static PetscErrorCode MatView_Nest(Mat A,PetscViewer viewer)
932d8588912SDave May {
933d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
93429e60adbSStefano Zampini   PetscBool      isascii,viewSub = PETSC_FALSE;
935d8588912SDave May   PetscInt       i,j;
936d8588912SDave May 
937d8588912SDave May   PetscFunctionBegin;
9389566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
939d8588912SDave May   if (isascii) {
940d8588912SDave May 
9419566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)A)->options,((PetscObject)A)->prefix,"-mat_view_nest_sub",&viewSub,NULL));
9429566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer,"Matrix object: \n"));
9439566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
9449566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT " \n",bA->nr,bA->nc));
945d8588912SDave May 
9469566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer,"MatNest structure: \n"));
947d8588912SDave May     for (i=0; i<bA->nr; i++) {
948d8588912SDave May       for (j=0; j<bA->nc; j++) {
94919fd82e9SBarry Smith         MatType   type;
950270f95d7SJed Brown         char      name[256] = "",prefix[256] = "";
951d8588912SDave May         PetscInt  NR,NC;
952d8588912SDave May         PetscBool isNest = PETSC_FALSE;
953d8588912SDave May 
954d8588912SDave May         if (!bA->m[i][j]) {
9559566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL \n",i,j));
956d8588912SDave May           continue;
957d8588912SDave May         }
9589566063dSJacob Faibussowitsch         PetscCall(MatGetSize(bA->m[i][j],&NR,&NC));
9599566063dSJacob Faibussowitsch         PetscCall(MatGetType(bA->m[i][j], &type));
9609566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name,sizeof(name),"name=\"%s\", ",((PetscObject)bA->m[i][j])->name));
9619566063dSJacob Faibussowitsch         if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix,sizeof(prefix),"prefix=\"%s\", ",((PetscObject)bA->m[i][j])->prefix));
9629566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j],MATNEST,&isNest));
963d8588912SDave May 
9649566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer,"(%" PetscInt_FMT ",%" PetscInt_FMT ") : %s%stype=%s, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT " \n",i,j,name,prefix,type,NR,NC));
965d8588912SDave May 
96629e60adbSStefano Zampini         if (isNest || viewSub) {
9679566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPushTab(viewer));  /* push1 */
9689566063dSJacob Faibussowitsch           PetscCall(MatView(bA->m[i][j],viewer));
9699566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPopTab(viewer));    /* pop1 */
970d8588912SDave May         }
971d8588912SDave May       }
972d8588912SDave May     }
9739566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));    /* pop0 */
974d8588912SDave May   }
975d8588912SDave May   PetscFunctionReturn(0);
976d8588912SDave May }
977d8588912SDave May 
978207556f9SJed Brown static PetscErrorCode MatZeroEntries_Nest(Mat A)
979d8588912SDave May {
980d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
981d8588912SDave May   PetscInt       i,j;
982d8588912SDave May 
983d8588912SDave May   PetscFunctionBegin;
984d8588912SDave May   for (i=0; i<bA->nr; i++) {
985d8588912SDave May     for (j=0; j<bA->nc; j++) {
986d8588912SDave May       if (!bA->m[i][j]) continue;
9879566063dSJacob Faibussowitsch       PetscCall(MatZeroEntries(bA->m[i][j]));
988d8588912SDave May     }
989d8588912SDave May   }
990d8588912SDave May   PetscFunctionReturn(0);
991d8588912SDave May }
992d8588912SDave May 
993c222c20dSDavid Ham static PetscErrorCode MatCopy_Nest(Mat A,Mat B,MatStructure str)
994c222c20dSDavid Ham {
995c222c20dSDavid Ham   Mat_Nest       *bA = (Mat_Nest*)A->data,*bB = (Mat_Nest*)B->data;
996c222c20dSDavid Ham   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
99706a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
998c222c20dSDavid Ham 
999c222c20dSDavid Ham   PetscFunctionBegin;
1000aed4548fSBarry Smith   PetscCheck(nr == bB->nr && nc == bB->nc,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Cannot copy a Mat_Nest of block size (%" PetscInt_FMT ",%" PetscInt_FMT ") to a Mat_Nest of block size (%" PetscInt_FMT ",%" PetscInt_FMT ")",bB->nr,bB->nc,nr,nc);
1001c222c20dSDavid Ham   for (i=0; i<nr; i++) {
1002c222c20dSDavid Ham     for (j=0; j<nc; j++) {
100306a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
100446a2b97cSJed Brown       if (bA->m[i][j] && bB->m[i][j]) {
10059566063dSJacob Faibussowitsch         PetscCall(MatCopy(bA->m[i][j],bB->m[i][j],str));
100608401ef6SPierre Jolivet       } else PetscCheck(!bA->m[i][j] && !bB->m[i][j],PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT,i,j);
10079566063dSJacob Faibussowitsch       PetscCall(MatGetNonzeroState(bB->m[i][j],&subnnzstate));
100806a1af2fSStefano Zampini       nnzstate = (PetscBool)(nnzstate || bB->nnzstate[i*nc+j] != subnnzstate);
100906a1af2fSStefano Zampini       bB->nnzstate[i*nc+j] = subnnzstate;
1010c222c20dSDavid Ham     }
1011c222c20dSDavid Ham   }
101206a1af2fSStefano Zampini   if (nnzstate) B->nonzerostate++;
1013c222c20dSDavid Ham   PetscFunctionReturn(0);
1014c222c20dSDavid Ham }
1015c222c20dSDavid Ham 
10166e76ffeaSPierre Jolivet static PetscErrorCode MatAXPY_Nest(Mat Y,PetscScalar a,Mat X,MatStructure str)
10176e76ffeaSPierre Jolivet {
10186e76ffeaSPierre Jolivet   Mat_Nest       *bY = (Mat_Nest*)Y->data,*bX = (Mat_Nest*)X->data;
10196e76ffeaSPierre Jolivet   PetscInt       i,j,nr = bY->nr,nc = bY->nc;
102006a1af2fSStefano Zampini   PetscBool      nnzstate = PETSC_FALSE;
10216e76ffeaSPierre Jolivet 
10226e76ffeaSPierre Jolivet   PetscFunctionBegin;
1023aed4548fSBarry Smith   PetscCheck(nr == bX->nr && nc == bX->nc,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Cannot AXPY a MatNest of block size (%" PetscInt_FMT ",%" PetscInt_FMT ") with a MatNest of block size (%" PetscInt_FMT ",%" PetscInt_FMT ")",bX->nr,bX->nc,nr,nc);
10246e76ffeaSPierre Jolivet   for (i=0; i<nr; i++) {
10256e76ffeaSPierre Jolivet     for (j=0; j<nc; j++) {
102606a1af2fSStefano Zampini       PetscObjectState subnnzstate = 0;
10276e76ffeaSPierre Jolivet       if (bY->m[i][j] && bX->m[i][j]) {
10289566063dSJacob Faibussowitsch         PetscCall(MatAXPY(bY->m[i][j],a,bX->m[i][j],str));
1029c066aebcSStefano Zampini       } else if (bX->m[i][j]) {
1030c066aebcSStefano Zampini         Mat M;
1031c066aebcSStefano Zampini 
103208401ef6SPierre Jolivet         PetscCheck(str == DIFFERENT_NONZERO_PATTERN,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN",i,j);
10339566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bX->m[i][j],MAT_COPY_VALUES,&M));
10349566063dSJacob Faibussowitsch         PetscCall(MatNestSetSubMat(Y,i,j,M));
10359566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&M));
1036c066aebcSStefano Zampini       }
10379566063dSJacob Faibussowitsch       if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j],&subnnzstate));
103806a1af2fSStefano Zampini       nnzstate = (PetscBool)(nnzstate || bY->nnzstate[i*nc+j] != subnnzstate);
103906a1af2fSStefano Zampini       bY->nnzstate[i*nc+j] = subnnzstate;
10406e76ffeaSPierre Jolivet     }
10416e76ffeaSPierre Jolivet   }
104206a1af2fSStefano Zampini   if (nnzstate) Y->nonzerostate++;
10436e76ffeaSPierre Jolivet   PetscFunctionReturn(0);
10446e76ffeaSPierre Jolivet }
10456e76ffeaSPierre Jolivet 
1046207556f9SJed Brown static PetscErrorCode MatDuplicate_Nest(Mat A,MatDuplicateOption op,Mat *B)
1047d8588912SDave May {
1048d8588912SDave May   Mat_Nest       *bA = (Mat_Nest*)A->data;
1049841e96a3SJed Brown   Mat            *b;
1050841e96a3SJed Brown   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
1051d8588912SDave May 
1052d8588912SDave May   PetscFunctionBegin;
10539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr*nc,&b));
1054841e96a3SJed Brown   for (i=0; i<nr; i++) {
1055841e96a3SJed Brown     for (j=0; j<nc; j++) {
1056841e96a3SJed Brown       if (bA->m[i][j]) {
10579566063dSJacob Faibussowitsch         PetscCall(MatDuplicate(bA->m[i][j],op,&b[i*nc+j]));
1058841e96a3SJed Brown       } else {
10590298fd71SBarry Smith         b[i*nc+j] = NULL;
1060d8588912SDave May       }
1061d8588912SDave May     }
1062d8588912SDave May   }
10639566063dSJacob Faibussowitsch   PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A),nr,bA->isglobal.row,nc,bA->isglobal.col,b,B));
1064841e96a3SJed Brown   /* Give the new MatNest exclusive ownership */
1065841e96a3SJed Brown   for (i=0; i<nr*nc; i++) {
10669566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&b[i]));
1067d8588912SDave May   }
10689566063dSJacob Faibussowitsch   PetscCall(PetscFree(b));
1069d8588912SDave May 
10709566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*B,MAT_FINAL_ASSEMBLY));
10719566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*B,MAT_FINAL_ASSEMBLY));
1072d8588912SDave May   PetscFunctionReturn(0);
1073d8588912SDave May }
1074d8588912SDave May 
1075d8588912SDave May /* nest api */
1076d8588912SDave May PetscErrorCode MatNestGetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat *mat)
1077d8588912SDave May {
1078d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
10795fd66863SKarl Rupp 
1080d8588912SDave May   PetscFunctionBegin;
108108401ef6SPierre Jolivet   PetscCheck(idxm < bA->nr,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT,idxm,bA->nr-1);
108208401ef6SPierre Jolivet   PetscCheck(jdxm < bA->nc,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT,jdxm,bA->nc-1);
1083d8588912SDave May   *mat = bA->m[idxm][jdxm];
1084d8588912SDave May   PetscFunctionReturn(0);
1085d8588912SDave May }
1086d8588912SDave May 
10879ba0d327SJed Brown /*@
1088d8588912SDave May  MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix.
1089d8588912SDave May 
1090d8588912SDave May  Not collective
1091d8588912SDave May 
1092d8588912SDave May  Input Parameters:
1093629881c0SJed Brown +   A  - nest matrix
1094d8588912SDave May .   idxm - index of the matrix within the nest matrix
1095629881c0SJed Brown -   jdxm - index of the matrix within the nest matrix
1096d8588912SDave May 
1097d8588912SDave May  Output Parameter:
1098d8588912SDave May .   sub - matrix at index idxm,jdxm within the nest matrix
1099d8588912SDave May 
1100d8588912SDave May  Level: developer
1101d8588912SDave May 
1102db781477SPatrick Sanan .seealso: `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MATNEST`, `MatNestSetSubMat()`,
1103db781477SPatrick Sanan           `MatNestGetLocalISs()`, `MatNestGetISs()`
1104d8588912SDave May @*/
11057087cfbeSBarry Smith PetscErrorCode  MatNestGetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat *sub)
1106d8588912SDave May {
1107d8588912SDave May   PetscFunctionBegin;
1108cac4c232SBarry Smith   PetscUseMethod(A,"MatNestGetSubMat_C",(Mat,PetscInt,PetscInt,Mat*),(A,idxm,jdxm,sub));
1109d8588912SDave May   PetscFunctionReturn(0);
1110d8588912SDave May }
1111d8588912SDave May 
11120782ca92SJed Brown PetscErrorCode MatNestSetSubMat_Nest(Mat A,PetscInt idxm,PetscInt jdxm,Mat mat)
11130782ca92SJed Brown {
11140782ca92SJed Brown   Mat_Nest       *bA = (Mat_Nest*)A->data;
11150782ca92SJed Brown   PetscInt       m,n,M,N,mi,ni,Mi,Ni;
11160782ca92SJed Brown 
11170782ca92SJed Brown   PetscFunctionBegin;
111808401ef6SPierre Jolivet   PetscCheck(idxm < bA->nr,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT,idxm,bA->nr-1);
111908401ef6SPierre Jolivet   PetscCheck(jdxm < bA->nc,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT,jdxm,bA->nc-1);
11209566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(mat,&m,&n));
11219566063dSJacob Faibussowitsch   PetscCall(MatGetSize(mat,&M,&N));
11229566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.row[idxm],&mi));
11239566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.row[idxm],&Mi));
11249566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm],&ni));
11259566063dSJacob Faibussowitsch   PetscCall(ISGetSize(bA->isglobal.col[jdxm],&Ni));
1126aed4548fSBarry Smith   PetscCheck(M == Mi && N == Ni,PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_INCOMP,"Submatrix dimension (%" PetscInt_FMT ",%" PetscInt_FMT ") incompatible with nest block (%" PetscInt_FMT ",%" PetscInt_FMT ")",M,N,Mi,Ni);
1127aed4548fSBarry Smith   PetscCheck(m == mi && n == ni,PetscObjectComm((PetscObject)mat),PETSC_ERR_ARG_INCOMP,"Submatrix local dimension (%" PetscInt_FMT ",%" PetscInt_FMT ") incompatible with nest block (%" PetscInt_FMT ",%" PetscInt_FMT ")",m,n,mi,ni);
112826fbe8dcSKarl Rupp 
112906a1af2fSStefano Zampini   /* do not increase object state */
113006a1af2fSStefano Zampini   if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(0);
113106a1af2fSStefano Zampini 
11329566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)mat));
11339566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&bA->m[idxm][jdxm]));
11340782ca92SJed Brown   bA->m[idxm][jdxm] = mat;
11359566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
11369566063dSJacob Faibussowitsch   PetscCall(MatGetNonzeroState(mat,&bA->nnzstate[idxm*bA->nc+jdxm]));
113706a1af2fSStefano Zampini   A->nonzerostate++;
11380782ca92SJed Brown   PetscFunctionReturn(0);
11390782ca92SJed Brown }
11400782ca92SJed Brown 
11419ba0d327SJed Brown /*@
11420782ca92SJed Brown  MatNestSetSubMat - Set a single submatrix in the nest matrix.
11430782ca92SJed Brown 
11440782ca92SJed Brown  Logically collective on the submatrix communicator
11450782ca92SJed Brown 
11460782ca92SJed Brown  Input Parameters:
11470782ca92SJed Brown +   A  - nest matrix
11480782ca92SJed Brown .   idxm - index of the matrix within the nest matrix
11490782ca92SJed Brown .   jdxm - index of the matrix within the nest matrix
11500782ca92SJed Brown -   sub - matrix at index idxm,jdxm within the nest matrix
11510782ca92SJed Brown 
11520782ca92SJed Brown  Notes:
11530782ca92SJed Brown  The new submatrix must have the same size and communicator as that block of the nest.
11540782ca92SJed Brown 
11550782ca92SJed Brown  This increments the reference count of the submatrix.
11560782ca92SJed Brown 
11570782ca92SJed Brown  Level: developer
11580782ca92SJed Brown 
1159db781477SPatrick Sanan .seealso: `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MATNEST`, `MatCreateNest()`,
1160db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()`
11610782ca92SJed Brown @*/
11620782ca92SJed Brown PetscErrorCode  MatNestSetSubMat(Mat A,PetscInt idxm,PetscInt jdxm,Mat sub)
11630782ca92SJed Brown {
11640782ca92SJed Brown   PetscFunctionBegin;
1165cac4c232SBarry Smith   PetscUseMethod(A,"MatNestSetSubMat_C",(Mat,PetscInt,PetscInt,Mat),(A,idxm,jdxm,sub));
11660782ca92SJed Brown   PetscFunctionReturn(0);
11670782ca92SJed Brown }
11680782ca92SJed Brown 
1169d8588912SDave May PetscErrorCode MatNestGetSubMats_Nest(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
1170d8588912SDave May {
1171d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
11725fd66863SKarl Rupp 
1173d8588912SDave May   PetscFunctionBegin;
117426fbe8dcSKarl Rupp   if (M)   *M   = bA->nr;
117526fbe8dcSKarl Rupp   if (N)   *N   = bA->nc;
117626fbe8dcSKarl Rupp   if (mat) *mat = bA->m;
1177d8588912SDave May   PetscFunctionReturn(0);
1178d8588912SDave May }
1179d8588912SDave May 
1180d8588912SDave May /*@C
1181d8588912SDave May  MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix.
1182d8588912SDave May 
1183d8588912SDave May  Not collective
1184d8588912SDave May 
1185f899ff85SJose E. Roman  Input Parameter:
1186629881c0SJed Brown .   A  - nest matrix
1187d8588912SDave May 
1188d8d19677SJose E. Roman  Output Parameters:
1189629881c0SJed Brown +   M - number of rows in the nest matrix
1190d8588912SDave May .   N - number of cols in the nest matrix
1191629881c0SJed Brown -   mat - 2d array of matrices
1192d8588912SDave May 
1193d8588912SDave May  Notes:
1194d8588912SDave May 
1195d8588912SDave May  The user should not free the array mat.
1196d8588912SDave May 
1197351962e3SVincent Le Chenadec  In Fortran, this routine has a calling sequence
1198351962e3SVincent Le Chenadec $   call MatNestGetSubMats(A, M, N, mat, ierr)
1199351962e3SVincent Le Chenadec  where the space allocated for the optional argument mat is assumed large enough (if provided).
1200351962e3SVincent Le Chenadec 
1201d8588912SDave May  Level: developer
1202d8588912SDave May 
1203db781477SPatrick Sanan .seealso: `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MATNEST`, `MatCreateNest()`,
1204db781477SPatrick Sanan           `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()`
1205d8588912SDave May @*/
12067087cfbeSBarry Smith PetscErrorCode  MatNestGetSubMats(Mat A,PetscInt *M,PetscInt *N,Mat ***mat)
1207d8588912SDave May {
1208d8588912SDave May   PetscFunctionBegin;
1209cac4c232SBarry Smith   PetscUseMethod(A,"MatNestGetSubMats_C",(Mat,PetscInt*,PetscInt*,Mat***),(A,M,N,mat));
1210d8588912SDave May   PetscFunctionReturn(0);
1211d8588912SDave May }
1212d8588912SDave May 
12137087cfbeSBarry Smith PetscErrorCode  MatNestGetSize_Nest(Mat A,PetscInt *M,PetscInt *N)
1214d8588912SDave May {
1215d8588912SDave May   Mat_Nest *bA = (Mat_Nest*)A->data;
1216d8588912SDave May 
1217d8588912SDave May   PetscFunctionBegin;
121826fbe8dcSKarl Rupp   if (M) *M = bA->nr;
121926fbe8dcSKarl Rupp   if (N) *N = bA->nc;
1220d8588912SDave May   PetscFunctionReturn(0);
1221d8588912SDave May }
1222d8588912SDave May 
12239ba0d327SJed Brown /*@
1224d8588912SDave May  MatNestGetSize - Returns the size of the nest matrix.
1225d8588912SDave May 
1226d8588912SDave May  Not collective
1227d8588912SDave May 
1228f899ff85SJose E. Roman  Input Parameter:
1229d8588912SDave May .   A  - nest matrix
1230d8588912SDave May 
1231d8d19677SJose E. Roman  Output Parameters:
1232629881c0SJed Brown +   M - number of rows in the nested mat
1233629881c0SJed Brown -   N - number of cols in the nested mat
1234d8588912SDave May 
1235d8588912SDave May  Notes:
1236d8588912SDave May 
1237d8588912SDave May  Level: developer
1238d8588912SDave May 
1239db781477SPatrick Sanan .seealso: `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MATNEST`, `MatCreateNest()`, `MatNestGetLocalISs()`,
1240db781477SPatrick Sanan           `MatNestGetISs()`
1241d8588912SDave May @*/
12427087cfbeSBarry Smith PetscErrorCode  MatNestGetSize(Mat A,PetscInt *M,PetscInt *N)
1243d8588912SDave May {
1244d8588912SDave May   PetscFunctionBegin;
1245cac4c232SBarry Smith   PetscUseMethod(A,"MatNestGetSize_C",(Mat,PetscInt*,PetscInt*),(A,M,N));
1246d8588912SDave May   PetscFunctionReturn(0);
1247d8588912SDave May }
1248d8588912SDave May 
1249f7a08781SBarry Smith static PetscErrorCode MatNestGetISs_Nest(Mat A,IS rows[],IS cols[])
1250900e7ff2SJed Brown {
1251900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest*)A->data;
1252900e7ff2SJed Brown   PetscInt i;
1253900e7ff2SJed Brown 
1254900e7ff2SJed Brown   PetscFunctionBegin;
1255900e7ff2SJed Brown   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->isglobal.row[i];
1256900e7ff2SJed Brown   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->isglobal.col[i];
1257900e7ff2SJed Brown   PetscFunctionReturn(0);
1258900e7ff2SJed Brown }
1259900e7ff2SJed Brown 
12603a4d7b9aSSatish Balay /*@C
1261900e7ff2SJed Brown  MatNestGetISs - Returns the index sets partitioning the row and column spaces
1262900e7ff2SJed Brown 
1263900e7ff2SJed Brown  Not collective
1264900e7ff2SJed Brown 
1265f899ff85SJose E. Roman  Input Parameter:
1266900e7ff2SJed Brown .   A  - nest matrix
1267900e7ff2SJed Brown 
1268d8d19677SJose E. Roman  Output Parameters:
1269900e7ff2SJed Brown +   rows - array of row index sets
1270900e7ff2SJed Brown -   cols - array of column index sets
1271900e7ff2SJed Brown 
1272900e7ff2SJed Brown  Level: advanced
1273900e7ff2SJed Brown 
1274900e7ff2SJed Brown  Notes:
1275900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1276900e7ff2SJed Brown 
1277db781477SPatrick Sanan .seealso: `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`, `MATNEST`,
1278db781477SPatrick Sanan           `MatCreateNest()`, `MatNestGetSubMats()`, `MatNestSetSubMats()`
1279900e7ff2SJed Brown @*/
1280900e7ff2SJed Brown PetscErrorCode  MatNestGetISs(Mat A,IS rows[],IS cols[])
1281900e7ff2SJed Brown {
1282900e7ff2SJed Brown   PetscFunctionBegin;
1283900e7ff2SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1284cac4c232SBarry Smith   PetscUseMethod(A,"MatNestGetISs_C",(Mat,IS[],IS[]),(A,rows,cols));
1285900e7ff2SJed Brown   PetscFunctionReturn(0);
1286900e7ff2SJed Brown }
1287900e7ff2SJed Brown 
1288f7a08781SBarry Smith static PetscErrorCode MatNestGetLocalISs_Nest(Mat A,IS rows[],IS cols[])
1289900e7ff2SJed Brown {
1290900e7ff2SJed Brown   Mat_Nest *vs = (Mat_Nest*)A->data;
1291900e7ff2SJed Brown   PetscInt i;
1292900e7ff2SJed Brown 
1293900e7ff2SJed Brown   PetscFunctionBegin;
1294900e7ff2SJed Brown   if (rows) for (i=0; i<vs->nr; i++) rows[i] = vs->islocal.row[i];
1295900e7ff2SJed Brown   if (cols) for (i=0; i<vs->nc; i++) cols[i] = vs->islocal.col[i];
1296900e7ff2SJed Brown   PetscFunctionReturn(0);
1297900e7ff2SJed Brown }
1298900e7ff2SJed Brown 
1299900e7ff2SJed Brown /*@C
1300900e7ff2SJed Brown  MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces
1301900e7ff2SJed Brown 
1302900e7ff2SJed Brown  Not collective
1303900e7ff2SJed Brown 
1304f899ff85SJose E. Roman  Input Parameter:
1305900e7ff2SJed Brown .   A  - nest matrix
1306900e7ff2SJed Brown 
1307d8d19677SJose E. Roman  Output Parameters:
13080298fd71SBarry Smith +   rows - array of row index sets (or NULL to ignore)
13090298fd71SBarry Smith -   cols - array of column index sets (or NULL to ignore)
1310900e7ff2SJed Brown 
1311900e7ff2SJed Brown  Level: advanced
1312900e7ff2SJed Brown 
1313900e7ff2SJed Brown  Notes:
1314900e7ff2SJed Brown  The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs.
1315900e7ff2SJed Brown 
1316db781477SPatrick Sanan .seealso: `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`,
1317db781477SPatrick Sanan           `MATNEST`, `MatNestSetSubMats()`, `MatNestSetSubMat()`
1318900e7ff2SJed Brown @*/
1319900e7ff2SJed Brown PetscErrorCode  MatNestGetLocalISs(Mat A,IS rows[],IS cols[])
1320900e7ff2SJed Brown {
1321900e7ff2SJed Brown   PetscFunctionBegin;
1322900e7ff2SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
1323cac4c232SBarry Smith   PetscUseMethod(A,"MatNestGetLocalISs_C",(Mat,IS[],IS[]),(A,rows,cols));
1324900e7ff2SJed Brown   PetscFunctionReturn(0);
1325900e7ff2SJed Brown }
1326900e7ff2SJed Brown 
132719fd82e9SBarry Smith PetscErrorCode  MatNestSetVecType_Nest(Mat A,VecType vtype)
1328207556f9SJed Brown {
1329207556f9SJed Brown   PetscBool      flg;
1330207556f9SJed Brown 
1331207556f9SJed Brown   PetscFunctionBegin;
13329566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype,VECNEST,&flg));
1333207556f9SJed Brown   /* In reality, this only distinguishes VECNEST and "other" */
13342a7a6963SBarry Smith   if (flg) A->ops->getvecs = MatCreateVecs_Nest;
133512b53f24SSatish Balay   else A->ops->getvecs = (PetscErrorCode (*)(Mat,Vec*,Vec*)) 0;
1336207556f9SJed Brown   PetscFunctionReturn(0);
1337207556f9SJed Brown }
1338207556f9SJed Brown 
1339207556f9SJed Brown /*@C
13402a7a6963SBarry Smith  MatNestSetVecType - Sets the type of Vec returned by MatCreateVecs()
1341207556f9SJed Brown 
1342207556f9SJed Brown  Not collective
1343207556f9SJed Brown 
1344207556f9SJed Brown  Input Parameters:
1345207556f9SJed Brown +  A  - nest matrix
1346207556f9SJed Brown -  vtype - type to use for creating vectors
1347207556f9SJed Brown 
1348207556f9SJed Brown  Notes:
1349207556f9SJed Brown 
1350207556f9SJed Brown  Level: developer
1351207556f9SJed Brown 
1352db781477SPatrick Sanan .seealso: `MatCreateVecs()`, `MATNEST`, `MatCreateNest()`
1353207556f9SJed Brown @*/
135419fd82e9SBarry Smith PetscErrorCode  MatNestSetVecType(Mat A,VecType vtype)
1355207556f9SJed Brown {
1356207556f9SJed Brown   PetscFunctionBegin;
1357cac4c232SBarry Smith   PetscTryMethod(A,"MatNestSetVecType_C",(Mat,VecType),(A,vtype));
1358207556f9SJed Brown   PetscFunctionReturn(0);
1359207556f9SJed Brown }
1360207556f9SJed Brown 
1361c8883902SJed Brown PetscErrorCode MatNestSetSubMats_Nest(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1362d8588912SDave May {
1363c8883902SJed Brown   Mat_Nest       *s = (Mat_Nest*)A->data;
1364c8883902SJed Brown   PetscInt       i,j,m,n,M,N;
136588ffe2e8SJose E. Roman   PetscBool      cong,isstd,sametype=PETSC_FALSE;
136688ffe2e8SJose E. Roman   VecType        vtype,type;
1367d8588912SDave May 
1368d8588912SDave May   PetscFunctionBegin;
13699566063dSJacob Faibussowitsch   PetscCall(MatReset_Nest(A));
137006a1af2fSStefano Zampini 
1371c8883902SJed Brown   s->nr = nr;
1372c8883902SJed Brown   s->nc = nc;
1373d8588912SDave May 
1374c8883902SJed Brown   /* Create space for submatrices */
13759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr,&s->m));
1376c8883902SJed Brown   for (i=0; i<nr; i++) {
13779566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nc,&s->m[i]));
1378d8588912SDave May   }
1379c8883902SJed Brown   for (i=0; i<nr; i++) {
1380c8883902SJed Brown     for (j=0; j<nc; j++) {
1381c8883902SJed Brown       s->m[i][j] = a[i*nc+j];
1382c8883902SJed Brown       if (a[i*nc+j]) {
13839566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)a[i*nc+j]));
1384d8588912SDave May       }
1385d8588912SDave May     }
1386d8588912SDave May   }
13879566063dSJacob Faibussowitsch   PetscCall(MatGetVecType(A,&vtype));
13889566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(vtype,VECSTANDARD,&isstd));
138988ffe2e8SJose E. Roman   if (isstd) {
139088ffe2e8SJose E. Roman     /* check if all blocks have the same vectype */
139188ffe2e8SJose E. Roman     vtype = NULL;
139288ffe2e8SJose E. Roman     for (i=0; i<nr; i++) {
139388ffe2e8SJose E. Roman       for (j=0; j<nc; j++) {
139488ffe2e8SJose E. Roman         if (a[i*nc+j]) {
139588ffe2e8SJose E. Roman           if (!vtype) {  /* first visited block */
13969566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i*nc+j],&vtype));
139788ffe2e8SJose E. Roman             sametype = PETSC_TRUE;
139888ffe2e8SJose E. Roman           } else if (sametype) {
13999566063dSJacob Faibussowitsch             PetscCall(MatGetVecType(a[i*nc+j],&type));
14009566063dSJacob Faibussowitsch             PetscCall(PetscStrcmp(vtype,type,&sametype));
140188ffe2e8SJose E. Roman           }
140288ffe2e8SJose E. Roman         }
140388ffe2e8SJose E. Roman       }
140488ffe2e8SJose E. Roman     }
140588ffe2e8SJose E. Roman     if (sametype) {  /* propagate vectype */
14069566063dSJacob Faibussowitsch       PetscCall(MatSetVecType(A,vtype));
140788ffe2e8SJose E. Roman     }
140888ffe2e8SJose E. Roman   }
1409d8588912SDave May 
14109566063dSJacob Faibussowitsch   PetscCall(MatSetUp_NestIS_Private(A,nr,is_row,nc,is_col));
1411d8588912SDave May 
14129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr,&s->row_len));
14139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc,&s->col_len));
1414c8883902SJed Brown   for (i=0; i<nr; i++) s->row_len[i]=-1;
1415c8883902SJed Brown   for (j=0; j<nc; j++) s->col_len[j]=-1;
1416d8588912SDave May 
14179566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr*nc,&s->nnzstate));
141806a1af2fSStefano Zampini   for (i=0; i<nr; i++) {
141906a1af2fSStefano Zampini     for (j=0; j<nc; j++) {
142006a1af2fSStefano Zampini       if (s->m[i][j]) {
14219566063dSJacob Faibussowitsch         PetscCall(MatGetNonzeroState(s->m[i][j],&s->nnzstate[i*nc+j]));
142206a1af2fSStefano Zampini       }
142306a1af2fSStefano Zampini     }
142406a1af2fSStefano Zampini   }
142506a1af2fSStefano Zampini 
14269566063dSJacob Faibussowitsch   PetscCall(MatNestGetSizes_Private(A,&m,&n,&M,&N));
1427d8588912SDave May 
14289566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->rmap,M));
14299566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->rmap,m));
14309566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetSize(A->cmap,N));
14319566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetLocalSize(A->cmap,n));
1432c8883902SJed Brown 
14339566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->rmap));
14349566063dSJacob Faibussowitsch   PetscCall(PetscLayoutSetUp(A->cmap));
1435c8883902SJed Brown 
143606a1af2fSStefano Zampini   /* disable operations that are not supported for non-square matrices,
143706a1af2fSStefano Zampini      or matrices for which is_row != is_col  */
14389566063dSJacob Faibussowitsch   PetscCall(MatHasCongruentLayouts(A,&cong));
143906a1af2fSStefano Zampini   if (cong && nr != nc) cong = PETSC_FALSE;
144006a1af2fSStefano Zampini   if (cong) {
144106a1af2fSStefano Zampini     for (i = 0; cong && i < nr; i++) {
14429566063dSJacob Faibussowitsch       PetscCall(ISEqualUnsorted(s->isglobal.row[i],s->isglobal.col[i],&cong));
144306a1af2fSStefano Zampini     }
144406a1af2fSStefano Zampini   }
144506a1af2fSStefano Zampini   if (!cong) {
1446381b8e50SStefano Zampini     A->ops->missingdiagonal = NULL;
144706a1af2fSStefano Zampini     A->ops->getdiagonal     = NULL;
144806a1af2fSStefano Zampini     A->ops->shift           = NULL;
144906a1af2fSStefano Zampini     A->ops->diagonalset     = NULL;
145006a1af2fSStefano Zampini   }
145106a1af2fSStefano Zampini 
14529566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nr,&s->left,nc,&s->right));
14539566063dSJacob Faibussowitsch   PetscCall(PetscObjectStateIncrease((PetscObject)A));
145406a1af2fSStefano Zampini   A->nonzerostate++;
1455d8588912SDave May   PetscFunctionReturn(0);
1456d8588912SDave May }
1457d8588912SDave May 
1458c8883902SJed Brown /*@
1459c8883902SJed Brown    MatNestSetSubMats - Sets the nested submatrices
1460c8883902SJed Brown 
1461c8883902SJed Brown    Collective on Mat
1462c8883902SJed Brown 
1463d8d19677SJose E. Roman    Input Parameters:
1464ffd6319bSRichard Tran Mills +  A - nested matrix
1465c8883902SJed Brown .  nr - number of nested row blocks
14660298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1467c8883902SJed Brown .  nc - number of nested column blocks
14680298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
14690298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1470c8883902SJed Brown 
147106a1af2fSStefano Zampini    Notes: this always resets any submatrix information previously set
147206a1af2fSStefano Zampini 
1473c8883902SJed Brown    Level: advanced
1474c8883902SJed Brown 
1475db781477SPatrick Sanan .seealso: `MatCreateNest()`, `MATNEST`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()`
1476c8883902SJed Brown @*/
1477c8883902SJed Brown PetscErrorCode MatNestSetSubMats(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[])
1478c8883902SJed Brown {
147906a1af2fSStefano Zampini   PetscInt       i;
1480c8883902SJed Brown 
1481c8883902SJed Brown   PetscFunctionBegin;
1482c8883902SJed Brown   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
148308401ef6SPierre Jolivet   PetscCheck(nr >= 0,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of rows cannot be negative");
1484c8883902SJed Brown   if (nr && is_row) {
1485c8883902SJed Brown     PetscValidPointer(is_row,3);
1486c8883902SJed Brown     for (i=0; i<nr; i++) PetscValidHeaderSpecific(is_row[i],IS_CLASSID,3);
1487c8883902SJed Brown   }
148808401ef6SPierre Jolivet   PetscCheck(nc >= 0,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_OUTOFRANGE,"Number of columns cannot be negative");
14891664e352SJed Brown   if (nc && is_col) {
1490c8883902SJed Brown     PetscValidPointer(is_col,5);
14919b30a8f6SBarry Smith     for (i=0; i<nc; i++) PetscValidHeaderSpecific(is_col[i],IS_CLASSID,5);
1492c8883902SJed Brown   }
149306a1af2fSStefano Zampini   if (nr*nc > 0) PetscValidPointer(a,6);
1494cac4c232SBarry Smith   PetscUseMethod(A,"MatNestSetSubMats_C",(Mat,PetscInt,const IS[],PetscInt,const IS[],const Mat[]),(A,nr,is_row,nc,is_col,a));
1495c8883902SJed Brown   PetscFunctionReturn(0);
1496c8883902SJed Brown }
1497d8588912SDave May 
149845b6f7e9SBarry Smith static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A,PetscInt n,const IS islocal[],const IS isglobal[],PetscBool colflg,ISLocalToGlobalMapping *ltog)
149977019fcaSJed Brown {
150077019fcaSJed Brown   PetscBool      flg;
150177019fcaSJed Brown   PetscInt       i,j,m,mi,*ix;
150277019fcaSJed Brown 
150377019fcaSJed Brown   PetscFunctionBegin;
1504aea6d515SStefano Zampini   *ltog = NULL;
150577019fcaSJed Brown   for (i=0,m=0,flg=PETSC_FALSE; i<n; i++) {
150677019fcaSJed Brown     if (islocal[i]) {
15079566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i],&mi));
150877019fcaSJed Brown       flg  = PETSC_TRUE;      /* We found a non-trivial entry */
150977019fcaSJed Brown     } else {
15109566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i],&mi));
151177019fcaSJed Brown     }
151277019fcaSJed Brown     m += mi;
151377019fcaSJed Brown   }
1514aea6d515SStefano Zampini   if (!flg) PetscFunctionReturn(0);
1515aea6d515SStefano Zampini 
15169566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(m,&ix));
1517165cd838SBarry Smith   for (i=0,m=0; i<n; i++) {
15180298fd71SBarry Smith     ISLocalToGlobalMapping smap = NULL;
1519e108cb99SStefano Zampini     Mat                    sub = NULL;
1520f6d38dbbSStefano Zampini     PetscSF                sf;
1521f6d38dbbSStefano Zampini     PetscLayout            map;
1522aea6d515SStefano Zampini     const PetscInt         *ix2;
152377019fcaSJed Brown 
1524165cd838SBarry Smith     if (!colflg) {
15259566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A,i,&sub));
152677019fcaSJed Brown     } else {
15279566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A,i,&sub));
152877019fcaSJed Brown     }
1529191fd14bSBarry Smith     if (sub) {
1530191fd14bSBarry Smith       if (!colflg) {
15319566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub,&smap,NULL));
1532191fd14bSBarry Smith       } else {
15339566063dSJacob Faibussowitsch         PetscCall(MatGetLocalToGlobalMapping(sub,NULL,&smap));
1534191fd14bSBarry Smith       }
1535191fd14bSBarry Smith     }
153677019fcaSJed Brown     /*
153777019fcaSJed Brown        Now we need to extract the monolithic global indices that correspond to the given split global indices.
153877019fcaSJed 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.
153977019fcaSJed Brown     */
15409566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isglobal[i],&ix2));
1541aea6d515SStefano Zampini     if (islocal[i]) {
1542aea6d515SStefano Zampini       PetscInt *ilocal,*iremote;
1543aea6d515SStefano Zampini       PetscInt mil,nleaves;
1544aea6d515SStefano Zampini 
15459566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(islocal[i],&mi));
154628b400f6SJacob Faibussowitsch       PetscCheck(smap,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Missing local to global map");
1547aea6d515SStefano Zampini       for (j=0; j<mi; j++) ix[m+j] = j;
15489566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingApply(smap,mi,ix+m,ix+m));
1549aea6d515SStefano Zampini 
1550aea6d515SStefano Zampini       /* PetscSFSetGraphLayout does not like negative indices */
15519566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(mi,&ilocal,mi,&iremote));
1552aea6d515SStefano Zampini       for (j=0, nleaves = 0; j<mi; j++) {
1553aea6d515SStefano Zampini         if (ix[m+j] < 0) continue;
1554aea6d515SStefano Zampini         ilocal[nleaves]  = j;
1555aea6d515SStefano Zampini         iremote[nleaves] = ix[m+j];
1556aea6d515SStefano Zampini         nleaves++;
1557aea6d515SStefano Zampini       }
15589566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i],&mil));
15599566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A),&sf));
15609566063dSJacob Faibussowitsch       PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A),&map));
15619566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetLocalSize(map,mil));
15629566063dSJacob Faibussowitsch       PetscCall(PetscLayoutSetUp(map));
15639566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraphLayout(sf,map,nleaves,ilocal,PETSC_USE_POINTER,iremote));
15649566063dSJacob Faibussowitsch       PetscCall(PetscLayoutDestroy(&map));
15659566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(sf,MPIU_INT,ix2,ix + m,MPI_REPLACE));
15669566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(sf,MPIU_INT,ix2,ix + m,MPI_REPLACE));
15679566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&sf));
15689566063dSJacob Faibussowitsch       PetscCall(PetscFree2(ilocal,iremote));
1569aea6d515SStefano Zampini     } else {
15709566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(isglobal[i],&mi));
1571aea6d515SStefano Zampini       for (j=0; j<mi; j++) ix[m+j] = ix2[i];
1572aea6d515SStefano Zampini     }
15739566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isglobal[i],&ix2));
157477019fcaSJed Brown     m   += mi;
157577019fcaSJed Brown   }
15769566063dSJacob Faibussowitsch   PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A),1,m,ix,PETSC_OWN_POINTER,ltog));
157777019fcaSJed Brown   PetscFunctionReturn(0);
157877019fcaSJed Brown }
157977019fcaSJed Brown 
1580d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */
1581d8588912SDave May /*
1582d8588912SDave May   nprocessors = NP
1583d8588912SDave May   Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1))
1584d8588912SDave May        proc 0: => (g_0,h_0,)
1585d8588912SDave May        proc 1: => (g_1,h_1,)
1586d8588912SDave May        ...
1587d8588912SDave May        proc nprocs-1: => (g_NP-1,h_NP-1,)
1588d8588912SDave May 
1589d8588912SDave May             proc 0:                      proc 1:                    proc nprocs-1:
1590d8588912SDave May     is[0] = (0,1,2,...,nlocal(g_0)-1)  (0,1,...,nlocal(g_1)-1)  (0,1,...,nlocal(g_NP-1))
1591d8588912SDave May 
1592d8588912SDave May             proc 0:
1593d8588912SDave May     is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1)
1594d8588912SDave May             proc 1:
1595d8588912SDave May     is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1)
1596d8588912SDave May 
1597d8588912SDave May             proc NP-1:
1598d8588912SDave May     is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1)
1599d8588912SDave May */
1600841e96a3SJed Brown static PetscErrorCode MatSetUp_NestIS_Private(Mat A,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[])
1601d8588912SDave May {
1602e2d7f03fSJed Brown   Mat_Nest       *vs = (Mat_Nest*)A->data;
16038188e55aSJed Brown   PetscInt       i,j,offset,n,nsum,bs;
16040298fd71SBarry Smith   Mat            sub = NULL;
1605d8588912SDave May 
1606d8588912SDave May   PetscFunctionBegin;
16079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nr,&vs->isglobal.row));
16089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nc,&vs->isglobal.col));
1609d8588912SDave May   if (is_row) { /* valid IS is passed in */
1610a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1611e2d7f03fSJed Brown     for (i=0; i<vs->nr; i++) {
16129566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_row[i]));
161326fbe8dcSKarl Rupp 
1614e2d7f03fSJed Brown       vs->isglobal.row[i] = is_row[i];
1615d8588912SDave May     }
16162ae74bdbSJed Brown   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each row */
16178188e55aSJed Brown     nsum = 0;
16188188e55aSJed Brown     for (i=0; i<vs->nr; i++) {  /* Add up the local sizes to compute the aggregate offset */
16199566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A,i,&sub));
162028b400f6SJacob Faibussowitsch       PetscCheck(sub,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in row %" PetscInt_FMT,i);
16219566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub,&n,NULL));
162208401ef6SPierre Jolivet       PetscCheck(n >= 0,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
16238188e55aSJed Brown       nsum += n;
16248188e55aSJed Brown     }
16259566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A)));
162630bc264bSJed Brown     offset -= nsum;
1627e2d7f03fSJed Brown     for (i=0; i<vs->nr; i++) {
16289566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatRow(A,i,&sub));
16299566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub,&n,NULL));
16309566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub,&bs,NULL));
16319566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.row[i]));
16329566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.row[i],bs));
16332ae74bdbSJed Brown       offset += n;
1634d8588912SDave May     }
1635d8588912SDave May   }
1636d8588912SDave May 
1637d8588912SDave May   if (is_col) { /* valid IS is passed in */
1638a5b23f4aSJose E. Roman     /* refs on is[] are incremented */
1639e2d7f03fSJed Brown     for (j=0; j<vs->nc; j++) {
16409566063dSJacob Faibussowitsch       PetscCall(PetscObjectReference((PetscObject)is_col[j]));
164126fbe8dcSKarl Rupp 
1642e2d7f03fSJed Brown       vs->isglobal.col[j] = is_col[j];
1643d8588912SDave May     }
16442ae74bdbSJed Brown   } else {                      /* Create the ISs by inspecting sizes of a submatrix in each column */
16452ae74bdbSJed Brown     offset = A->cmap->rstart;
16468188e55aSJed Brown     nsum   = 0;
16478188e55aSJed Brown     for (j=0; j<vs->nc; j++) {
16489566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A,j,&sub));
164928b400f6SJacob Faibussowitsch       PetscCheck(sub,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONG,"No nonzero submatrix in column %" PetscInt_FMT,i);
16509566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub,NULL,&n));
165108401ef6SPierre Jolivet       PetscCheck(n >= 0,PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_WRONGSTATE,"Sizes have not yet been set for submatrix");
16528188e55aSJed Brown       nsum += n;
16538188e55aSJed Brown     }
16549566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Scan(&nsum,&offset,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)A)));
165530bc264bSJed Brown     offset -= nsum;
1656e2d7f03fSJed Brown     for (j=0; j<vs->nc; j++) {
16579566063dSJacob Faibussowitsch       PetscCall(MatNestFindNonzeroSubMatCol(A,j,&sub));
16589566063dSJacob Faibussowitsch       PetscCall(MatGetLocalSize(sub,NULL,&n));
16599566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub,NULL,&bs));
16609566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub),n,offset,1,&vs->isglobal.col[j]));
16619566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(vs->isglobal.col[j],bs));
16622ae74bdbSJed Brown       offset += n;
1663d8588912SDave May     }
1664d8588912SDave May   }
1665e2d7f03fSJed Brown 
1666e2d7f03fSJed Brown   /* Set up the local ISs */
16679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nr,&vs->islocal.row));
16689566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(vs->nc,&vs->islocal.col));
1669e2d7f03fSJed Brown   for (i=0,offset=0; i<vs->nr; i++) {
1670e2d7f03fSJed Brown     IS                     isloc;
16710298fd71SBarry Smith     ISLocalToGlobalMapping rmap = NULL;
1672e2d7f03fSJed Brown     PetscInt               nlocal,bs;
16739566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatRow(A,i,&sub));
16749566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub,&rmap,NULL));
1675207556f9SJed Brown     if (rmap) {
16769566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub,&bs,NULL));
16779566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(rmap,&nlocal));
16789566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc));
16799566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc,bs));
1680207556f9SJed Brown     } else {
1681207556f9SJed Brown       nlocal = 0;
16820298fd71SBarry Smith       isloc  = NULL;
1683207556f9SJed Brown     }
1684e2d7f03fSJed Brown     vs->islocal.row[i] = isloc;
1685e2d7f03fSJed Brown     offset            += nlocal;
1686e2d7f03fSJed Brown   }
16878188e55aSJed Brown   for (i=0,offset=0; i<vs->nc; i++) {
1688e2d7f03fSJed Brown     IS                     isloc;
16890298fd71SBarry Smith     ISLocalToGlobalMapping cmap = NULL;
1690e2d7f03fSJed Brown     PetscInt               nlocal,bs;
16919566063dSJacob Faibussowitsch     PetscCall(MatNestFindNonzeroSubMatCol(A,i,&sub));
16929566063dSJacob Faibussowitsch     if (sub) PetscCall(MatGetLocalToGlobalMapping(sub,NULL,&cmap));
1693207556f9SJed Brown     if (cmap) {
16949566063dSJacob Faibussowitsch       PetscCall(MatGetBlockSizes(sub,NULL,&bs));
16959566063dSJacob Faibussowitsch       PetscCall(ISLocalToGlobalMappingGetSize(cmap,&nlocal));
16969566063dSJacob Faibussowitsch       PetscCall(ISCreateStride(PETSC_COMM_SELF,nlocal,offset,1,&isloc));
16979566063dSJacob Faibussowitsch       PetscCall(ISSetBlockSize(isloc,bs));
1698207556f9SJed Brown     } else {
1699207556f9SJed Brown       nlocal = 0;
17000298fd71SBarry Smith       isloc  = NULL;
1701207556f9SJed Brown     }
1702e2d7f03fSJed Brown     vs->islocal.col[i] = isloc;
1703e2d7f03fSJed Brown     offset            += nlocal;
1704e2d7f03fSJed Brown   }
17050189643fSJed Brown 
170677019fcaSJed Brown   /* Set up the aggregate ISLocalToGlobalMapping */
170777019fcaSJed Brown   {
170845b6f7e9SBarry Smith     ISLocalToGlobalMapping rmap,cmap;
17099566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A,vs->nr,vs->islocal.row,vs->isglobal.row,PETSC_FALSE,&rmap));
17109566063dSJacob Faibussowitsch     PetscCall(MatNestCreateAggregateL2G_Private(A,vs->nc,vs->islocal.col,vs->isglobal.col,PETSC_TRUE,&cmap));
17119566063dSJacob Faibussowitsch     if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A,rmap,cmap));
17129566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&rmap));
17139566063dSJacob Faibussowitsch     PetscCall(ISLocalToGlobalMappingDestroy(&cmap));
171477019fcaSJed Brown   }
171577019fcaSJed Brown 
171676bd3646SJed Brown   if (PetscDefined(USE_DEBUG)) {
17170189643fSJed Brown     for (i=0; i<vs->nr; i++) {
17180189643fSJed Brown       for (j=0; j<vs->nc; j++) {
17190189643fSJed Brown         PetscInt m,n,M,N,mi,ni,Mi,Ni;
17200189643fSJed Brown         Mat      B = vs->m[i][j];
17210189643fSJed Brown         if (!B) continue;
17229566063dSJacob Faibussowitsch         PetscCall(MatGetSize(B,&M,&N));
17239566063dSJacob Faibussowitsch         PetscCall(MatGetLocalSize(B,&m,&n));
17249566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.row[i],&Mi));
17259566063dSJacob Faibussowitsch         PetscCall(ISGetSize(vs->isglobal.col[j],&Ni));
17269566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.row[i],&mi));
17279566063dSJacob Faibussowitsch         PetscCall(ISGetLocalSize(vs->isglobal.col[j],&ni));
1728aed4548fSBarry Smith         PetscCheck(M == Mi && N == Ni,PetscObjectComm((PetscObject)sub),PETSC_ERR_ARG_INCOMP,"Global sizes (%" PetscInt_FMT ",%" PetscInt_FMT ") of nested submatrix (%" PetscInt_FMT ",%" PetscInt_FMT ") do not agree with space defined by index sets (%" PetscInt_FMT ",%" PetscInt_FMT ")",M,N,i,j,Mi,Ni);
1729aed4548fSBarry Smith         PetscCheck(m == mi && n == ni,PetscObjectComm((PetscObject)sub),PETSC_ERR_ARG_INCOMP,"Local sizes (%" PetscInt_FMT ",%" PetscInt_FMT ") of nested submatrix (%" PetscInt_FMT ",%" PetscInt_FMT ") do not agree with space defined by index sets (%" PetscInt_FMT ",%" PetscInt_FMT ")",m,n,i,j,mi,ni);
17300189643fSJed Brown       }
17310189643fSJed Brown     }
173276bd3646SJed Brown   }
1733a061e289SJed Brown 
1734a061e289SJed Brown   /* Set A->assembled if all non-null blocks are currently assembled */
1735a061e289SJed Brown   for (i=0; i<vs->nr; i++) {
1736a061e289SJed Brown     for (j=0; j<vs->nc; j++) {
1737a061e289SJed Brown       if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0);
1738a061e289SJed Brown     }
1739a061e289SJed Brown   }
1740a061e289SJed Brown   A->assembled = PETSC_TRUE;
1741d8588912SDave May   PetscFunctionReturn(0);
1742d8588912SDave May }
1743d8588912SDave May 
174445c38901SJed Brown /*@C
1745659c6bb0SJed Brown    MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately
1746659c6bb0SJed Brown 
1747659c6bb0SJed Brown    Collective on Mat
1748659c6bb0SJed Brown 
1749d8d19677SJose E. Roman    Input Parameters:
1750659c6bb0SJed Brown +  comm - Communicator for the new Mat
1751659c6bb0SJed Brown .  nr - number of nested row blocks
17520298fd71SBarry Smith .  is_row - index sets for each nested row block, or NULL to make contiguous
1753659c6bb0SJed Brown .  nc - number of nested column blocks
17540298fd71SBarry Smith .  is_col - index sets for each nested column block, or NULL to make contiguous
17550298fd71SBarry Smith -  a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL
1756659c6bb0SJed Brown 
1757659c6bb0SJed Brown    Output Parameter:
1758659c6bb0SJed Brown .  B - new matrix
1759659c6bb0SJed Brown 
1760659c6bb0SJed Brown    Level: advanced
1761659c6bb0SJed Brown 
1762db781477SPatrick Sanan .seealso: `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MATNEST`, `MatNestSetSubMat()`,
1763db781477SPatrick Sanan           `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`,
1764db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
1765659c6bb0SJed Brown @*/
17667087cfbeSBarry Smith PetscErrorCode MatCreateNest(MPI_Comm comm,PetscInt nr,const IS is_row[],PetscInt nc,const IS is_col[],const Mat a[],Mat *B)
1767d8588912SDave May {
1768d8588912SDave May   Mat            A;
1769d8588912SDave May 
1770d8588912SDave May   PetscFunctionBegin;
1771f4259b30SLisandro Dalcin   *B   = NULL;
17729566063dSJacob Faibussowitsch   PetscCall(MatCreate(comm,&A));
17739566063dSJacob Faibussowitsch   PetscCall(MatSetType(A,MATNEST));
177491a28eb3SBarry Smith   A->preallocated = PETSC_TRUE;
17759566063dSJacob Faibussowitsch   PetscCall(MatNestSetSubMats(A,nr,is_row,nc,is_col,a));
1776d8588912SDave May   *B   = A;
1777d8588912SDave May   PetscFunctionReturn(0);
1778d8588912SDave May }
1779659c6bb0SJed Brown 
1780be705e3aSPierre Jolivet PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
1781b68353e5Sstefano_zampini {
1782b68353e5Sstefano_zampini   Mat_Nest       *nest = (Mat_Nest*)A->data;
178323875855Sstefano_zampini   Mat            *trans;
1784b68353e5Sstefano_zampini   PetscScalar    **avv;
1785b68353e5Sstefano_zampini   PetscScalar    *vv;
1786b68353e5Sstefano_zampini   PetscInt       **aii,**ajj;
1787b68353e5Sstefano_zampini   PetscInt       *ii,*jj,*ci;
1788b68353e5Sstefano_zampini   PetscInt       nr,nc,nnz,i,j;
1789b68353e5Sstefano_zampini   PetscBool      done;
1790b68353e5Sstefano_zampini 
1791b68353e5Sstefano_zampini   PetscFunctionBegin;
17929566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A,&nr,&nc));
1793b68353e5Sstefano_zampini   if (reuse == MAT_REUSE_MATRIX) {
1794b68353e5Sstefano_zampini     PetscInt rnr;
1795b68353e5Sstefano_zampini 
17969566063dSJacob Faibussowitsch     PetscCall(MatGetRowIJ(*newmat,0,PETSC_FALSE,PETSC_FALSE,&rnr,(const PetscInt**)&ii,(const PetscInt**)&jj,&done));
179728b400f6SJacob Faibussowitsch     PetscCheck(done,PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"MatGetRowIJ");
179808401ef6SPierre Jolivet     PetscCheck(rnr == nr,PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of rows");
17999566063dSJacob Faibussowitsch     PetscCall(MatSeqAIJGetArray(*newmat,&vv));
1800b68353e5Sstefano_zampini   }
1801b68353e5Sstefano_zampini   /* extract CSR for nested SeqAIJ matrices */
1802b68353e5Sstefano_zampini   nnz  = 0;
18039566063dSJacob Faibussowitsch   PetscCall(PetscCalloc4(nest->nr*nest->nc,&aii,nest->nr*nest->nc,&ajj,nest->nr*nest->nc,&avv,nest->nr*nest->nc,&trans));
1804b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1805b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1806b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1807b68353e5Sstefano_zampini       if (B) {
1808b68353e5Sstefano_zampini         PetscScalar *naa;
1809b68353e5Sstefano_zampini         PetscInt    *nii,*njj,nnr;
181023875855Sstefano_zampini         PetscBool   istrans;
1811b68353e5Sstefano_zampini 
18129566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans));
181323875855Sstefano_zampini         if (istrans) {
181423875855Sstefano_zampini           Mat Bt;
181523875855Sstefano_zampini 
18169566063dSJacob Faibussowitsch           PetscCall(MatTransposeGetMat(B,&Bt));
18179566063dSJacob Faibussowitsch           PetscCall(MatTranspose(Bt,MAT_INITIAL_MATRIX,&trans[i*nest->nc+j]));
181823875855Sstefano_zampini           B    = trans[i*nest->nc+j];
181923875855Sstefano_zampini         }
18209566063dSJacob Faibussowitsch         PetscCall(MatGetRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&nii,(const PetscInt**)&njj,&done));
182128b400f6SJacob Faibussowitsch         PetscCheck(done,PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatGetRowIJ");
18229566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJGetArray(B,&naa));
1823b68353e5Sstefano_zampini         nnz += nii[nnr];
1824b68353e5Sstefano_zampini 
1825b68353e5Sstefano_zampini         aii[i*nest->nc+j] = nii;
1826b68353e5Sstefano_zampini         ajj[i*nest->nc+j] = njj;
1827b68353e5Sstefano_zampini         avv[i*nest->nc+j] = naa;
1828b68353e5Sstefano_zampini       }
1829b68353e5Sstefano_zampini     }
1830b68353e5Sstefano_zampini   }
1831b68353e5Sstefano_zampini   if (reuse != MAT_REUSE_MATRIX) {
18329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nr+1,&ii));
18339566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz,&jj));
18349566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nnz,&vv));
1835b68353e5Sstefano_zampini   } else {
183608401ef6SPierre Jolivet     PetscCheck(nnz == ii[nr],PetscObjectComm((PetscObject)A),PETSC_ERR_USER,"Cannot reuse matrix, wrong number of nonzeros");
1837b68353e5Sstefano_zampini   }
1838b68353e5Sstefano_zampini 
1839b68353e5Sstefano_zampini   /* new row pointer */
18409566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(ii,nr+1));
1841b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1842b68353e5Sstefano_zampini     PetscInt       ncr,rst;
1843b68353e5Sstefano_zampini 
18449566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL));
18459566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i],&ncr));
1846b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1847b68353e5Sstefano_zampini       if (aii[i*nest->nc+j]) {
1848b68353e5Sstefano_zampini         PetscInt    *nii = aii[i*nest->nc+j];
1849b68353e5Sstefano_zampini         PetscInt    ir;
1850b68353e5Sstefano_zampini 
1851b68353e5Sstefano_zampini         for (ir=rst; ir<ncr+rst; ++ir) {
1852b68353e5Sstefano_zampini           ii[ir+1] += nii[1]-nii[0];
1853b68353e5Sstefano_zampini           nii++;
1854b68353e5Sstefano_zampini         }
1855b68353e5Sstefano_zampini       }
1856b68353e5Sstefano_zampini     }
1857b68353e5Sstefano_zampini   }
1858b68353e5Sstefano_zampini   for (i=0; i<nr; i++) ii[i+1] += ii[i];
1859b68353e5Sstefano_zampini 
1860b68353e5Sstefano_zampini   /* construct CSR for the new matrix */
18619566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(nr,&ci));
1862b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1863b68353e5Sstefano_zampini     PetscInt       ncr,rst;
1864b68353e5Sstefano_zampini 
18659566063dSJacob Faibussowitsch     PetscCall(ISStrideGetInfo(nest->isglobal.row[i],&rst,NULL));
18669566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(nest->isglobal.row[i],&ncr));
1867b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1868b68353e5Sstefano_zampini       if (aii[i*nest->nc+j]) {
1869b68353e5Sstefano_zampini         PetscScalar *nvv = avv[i*nest->nc+j];
1870b68353e5Sstefano_zampini         PetscInt    *nii = aii[i*nest->nc+j];
1871b68353e5Sstefano_zampini         PetscInt    *njj = ajj[i*nest->nc+j];
1872b68353e5Sstefano_zampini         PetscInt    ir,cst;
1873b68353e5Sstefano_zampini 
18749566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[j],&cst,NULL));
1875b68353e5Sstefano_zampini         for (ir=rst; ir<ncr+rst; ++ir) {
1876b68353e5Sstefano_zampini           PetscInt ij,rsize = nii[1]-nii[0],ist = ii[ir]+ci[ir];
1877b68353e5Sstefano_zampini 
1878b68353e5Sstefano_zampini           for (ij=0;ij<rsize;ij++) {
1879b68353e5Sstefano_zampini             jj[ist+ij] = *njj+cst;
1880b68353e5Sstefano_zampini             vv[ist+ij] = *nvv;
1881b68353e5Sstefano_zampini             njj++;
1882b68353e5Sstefano_zampini             nvv++;
1883b68353e5Sstefano_zampini           }
1884b68353e5Sstefano_zampini           ci[ir] += rsize;
1885b68353e5Sstefano_zampini           nii++;
1886b68353e5Sstefano_zampini         }
1887b68353e5Sstefano_zampini       }
1888b68353e5Sstefano_zampini     }
1889b68353e5Sstefano_zampini   }
18909566063dSJacob Faibussowitsch   PetscCall(PetscFree(ci));
1891b68353e5Sstefano_zampini 
1892b68353e5Sstefano_zampini   /* restore info */
1893b68353e5Sstefano_zampini   for (i=0; i<nest->nr; ++i) {
1894b68353e5Sstefano_zampini     for (j=0; j<nest->nc; ++j) {
1895b68353e5Sstefano_zampini       Mat B = nest->m[i][j];
1896b68353e5Sstefano_zampini       if (B) {
1897b68353e5Sstefano_zampini         PetscInt nnr = 0, k = i*nest->nc+j;
189823875855Sstefano_zampini 
189923875855Sstefano_zampini         B    = (trans[k] ? trans[k] : B);
19009566063dSJacob Faibussowitsch         PetscCall(MatRestoreRowIJ(B,0,PETSC_FALSE,PETSC_FALSE,&nnr,(const PetscInt**)&aii[k],(const PetscInt**)&ajj[k],&done));
190128b400f6SJacob Faibussowitsch         PetscCheck(done,PetscObjectComm((PetscObject)B),PETSC_ERR_PLIB,"MatRestoreRowIJ");
19029566063dSJacob Faibussowitsch         PetscCall(MatSeqAIJRestoreArray(B,&avv[k]));
19039566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&trans[k]));
1904b68353e5Sstefano_zampini       }
1905b68353e5Sstefano_zampini     }
1906b68353e5Sstefano_zampini   }
19079566063dSJacob Faibussowitsch   PetscCall(PetscFree4(aii,ajj,avv,trans));
1908b68353e5Sstefano_zampini 
1909b68353e5Sstefano_zampini   /* finalize newmat */
1910b68353e5Sstefano_zampini   if (reuse == MAT_INITIAL_MATRIX) {
19119566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,newmat));
1912b68353e5Sstefano_zampini   } else if (reuse == MAT_INPLACE_MATRIX) {
1913b68353e5Sstefano_zampini     Mat B;
1914b68353e5Sstefano_zampini 
19159566063dSJacob Faibussowitsch     PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A),nr,nc,ii,jj,vv,&B));
19169566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A,&B));
1917b68353e5Sstefano_zampini   }
19189566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(*newmat,MAT_FINAL_ASSEMBLY));
19199566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(*newmat,MAT_FINAL_ASSEMBLY));
1920b68353e5Sstefano_zampini   {
1921b68353e5Sstefano_zampini     Mat_SeqAIJ *a = (Mat_SeqAIJ*)((*newmat)->data);
1922b68353e5Sstefano_zampini     a->free_a     = PETSC_TRUE;
1923b68353e5Sstefano_zampini     a->free_ij    = PETSC_TRUE;
1924b68353e5Sstefano_zampini   }
1925b68353e5Sstefano_zampini   PetscFunctionReturn(0);
1926b68353e5Sstefano_zampini }
1927b68353e5Sstefano_zampini 
1928be705e3aSPierre Jolivet PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y,PetscScalar a,Mat X)
1929be705e3aSPierre Jolivet {
1930be705e3aSPierre Jolivet   Mat_Nest       *nest = (Mat_Nest*)X->data;
1931be705e3aSPierre Jolivet   PetscInt       i,j,k,rstart;
1932be705e3aSPierre Jolivet   PetscBool      flg;
1933be705e3aSPierre Jolivet 
1934be705e3aSPierre Jolivet   PetscFunctionBegin;
1935be705e3aSPierre Jolivet   /* Fill by row */
1936be705e3aSPierre Jolivet   for (j=0; j<nest->nc; ++j) {
1937be705e3aSPierre Jolivet     /* Using global column indices and ISAllGather() is not scalable. */
1938be705e3aSPierre Jolivet     IS             bNis;
1939be705e3aSPierre Jolivet     PetscInt       bN;
1940be705e3aSPierre Jolivet     const PetscInt *bNindices;
19419566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
19429566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis,&bN));
19439566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis,&bNindices));
1944be705e3aSPierre Jolivet     for (i=0; i<nest->nr; ++i) {
1945fd8a7442SPierre Jolivet       Mat            B=nest->m[i][j],D=NULL;
1946be705e3aSPierre Jolivet       PetscInt       bm,br;
1947be705e3aSPierre Jolivet       const PetscInt *bmindices;
1948be705e3aSPierre Jolivet       if (!B) continue;
19499566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&flg));
1950be705e3aSPierre Jolivet       if (flg) {
1951cac4c232SBarry Smith         PetscTryMethod(B,"MatTransposeGetMat_C",(Mat,Mat*),(B,&D));
1952cac4c232SBarry Smith         PetscTryMethod(B,"MatHermitianTransposeGetMat_C",(Mat,Mat*),(B,&D));
19539566063dSJacob Faibussowitsch         PetscCall(MatConvert(B,((PetscObject)D)->type_name,MAT_INITIAL_MATRIX,&D));
1954be705e3aSPierre Jolivet         B = D;
1955be705e3aSPierre Jolivet       }
19569566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompareAny((PetscObject)B,&flg,MATSEQSBAIJ,MATMPISBAIJ,""));
1957be705e3aSPierre Jolivet       if (flg) {
1958fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D,MATBAIJ,MAT_INPLACE_MATRIX,&D));
1959fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B,MATBAIJ,MAT_INITIAL_MATRIX,&D));
1960be705e3aSPierre Jolivet         B = D;
1961be705e3aSPierre Jolivet       }
19629566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i],&bm));
19639566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i],&bmindices));
19649566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B,&rstart,NULL));
1965be705e3aSPierre Jolivet       for (br = 0; br < bm; ++br) {
1966be705e3aSPierre Jolivet         PetscInt          row = bmindices[br], brncols, *cols;
1967be705e3aSPierre Jolivet         const PetscInt    *brcols;
1968be705e3aSPierre Jolivet         const PetscScalar *brcoldata;
1969be705e3aSPierre Jolivet         PetscScalar       *vals = NULL;
19709566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B,br+rstart,&brncols,&brcols,&brcoldata));
19719566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(brncols,&cols));
1972be705e3aSPierre Jolivet         for (k=0; k<brncols; k++) cols[k] = bNindices[brcols[k]];
1973be705e3aSPierre Jolivet         /*
1974be705e3aSPierre Jolivet           Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match.
1975be705e3aSPierre Jolivet           Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES.
1976be705e3aSPierre Jolivet          */
1977be705e3aSPierre Jolivet         if (a != 1.0) {
19789566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(brncols,&vals));
1979be705e3aSPierre Jolivet           for (k=0; k<brncols; k++) vals[k] = a * brcoldata[k];
19809566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y,1,&row,brncols,cols,vals,ADD_VALUES));
19819566063dSJacob Faibussowitsch           PetscCall(PetscFree(vals));
1982be705e3aSPierre Jolivet         } else {
19839566063dSJacob Faibussowitsch           PetscCall(MatSetValues(Y,1,&row,brncols,cols,brcoldata,ADD_VALUES));
1984be705e3aSPierre Jolivet         }
19859566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B,br+rstart,&brncols,&brcols,&brcoldata));
19869566063dSJacob Faibussowitsch         PetscCall(PetscFree(cols));
1987be705e3aSPierre Jolivet       }
1988fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
19899566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i],&bmindices));
1990be705e3aSPierre Jolivet     }
19919566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis,&bNindices));
19929566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
1993be705e3aSPierre Jolivet   }
19949566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(Y,MAT_FINAL_ASSEMBLY));
19959566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(Y,MAT_FINAL_ASSEMBLY));
1996be705e3aSPierre Jolivet   PetscFunctionReturn(0);
1997be705e3aSPierre Jolivet }
1998be705e3aSPierre Jolivet 
1999be705e3aSPierre Jolivet PetscErrorCode MatConvert_Nest_AIJ(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
2000629c3df2SDmitry Karpeev {
2001629c3df2SDmitry Karpeev   Mat_Nest       *nest = (Mat_Nest*)A->data;
2002be705e3aSPierre Jolivet   PetscInt       m,n,M,N,i,j,k,*dnnz,*onnz,rstart,cstart,cend;
2003b68353e5Sstefano_zampini   PetscMPIInt    size;
2004629c3df2SDmitry Karpeev   Mat            C;
2005629c3df2SDmitry Karpeev 
2006629c3df2SDmitry Karpeev   PetscFunctionBegin;
20079566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A),&size));
2008b68353e5Sstefano_zampini   if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */
2009b68353e5Sstefano_zampini     PetscInt  nf;
2010b68353e5Sstefano_zampini     PetscBool fast;
2011b68353e5Sstefano_zampini 
20129566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(newtype,MATAIJ,&fast));
2013b68353e5Sstefano_zampini     if (!fast) {
20149566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(newtype,MATSEQAIJ,&fast));
2015b68353e5Sstefano_zampini     }
2016b68353e5Sstefano_zampini     for (i=0; i<nest->nr && fast; ++i) {
2017b68353e5Sstefano_zampini       for (j=0; j<nest->nc && fast; ++j) {
2018b68353e5Sstefano_zampini         Mat B = nest->m[i][j];
2019b68353e5Sstefano_zampini         if (B) {
20209566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)B,MATSEQAIJ,&fast));
202123875855Sstefano_zampini           if (!fast) {
202223875855Sstefano_zampini             PetscBool istrans;
202323875855Sstefano_zampini 
20249566063dSJacob Faibussowitsch             PetscCall(PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&istrans));
202523875855Sstefano_zampini             if (istrans) {
202623875855Sstefano_zampini               Mat Bt;
202723875855Sstefano_zampini 
20289566063dSJacob Faibussowitsch               PetscCall(MatTransposeGetMat(B,&Bt));
20299566063dSJacob Faibussowitsch               PetscCall(PetscObjectTypeCompare((PetscObject)Bt,MATSEQAIJ,&fast));
203023875855Sstefano_zampini             }
2031b68353e5Sstefano_zampini           }
2032b68353e5Sstefano_zampini         }
2033b68353e5Sstefano_zampini       }
2034b68353e5Sstefano_zampini     }
2035b68353e5Sstefano_zampini     for (i=0, nf=0; i<nest->nr && fast; ++i) {
20369566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i],ISSTRIDE,&fast));
2037b68353e5Sstefano_zampini       if (fast) {
2038b68353e5Sstefano_zampini         PetscInt f,s;
2039b68353e5Sstefano_zampini 
20409566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.row[i],&f,&s));
2041b68353e5Sstefano_zampini         if (f != nf || s != 1) { fast = PETSC_FALSE; }
2042b68353e5Sstefano_zampini         else {
20439566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.row[i],&f));
2044b68353e5Sstefano_zampini           nf  += f;
2045b68353e5Sstefano_zampini         }
2046b68353e5Sstefano_zampini       }
2047b68353e5Sstefano_zampini     }
2048b68353e5Sstefano_zampini     for (i=0, nf=0; i<nest->nc && fast; ++i) {
20499566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i],ISSTRIDE,&fast));
2050b68353e5Sstefano_zampini       if (fast) {
2051b68353e5Sstefano_zampini         PetscInt f,s;
2052b68353e5Sstefano_zampini 
20539566063dSJacob Faibussowitsch         PetscCall(ISStrideGetInfo(nest->isglobal.col[i],&f,&s));
2054b68353e5Sstefano_zampini         if (f != nf || s != 1) { fast = PETSC_FALSE; }
2055b68353e5Sstefano_zampini         else {
20569566063dSJacob Faibussowitsch           PetscCall(ISGetSize(nest->isglobal.col[i],&f));
2057b68353e5Sstefano_zampini           nf  += f;
2058b68353e5Sstefano_zampini         }
2059b68353e5Sstefano_zampini       }
2060b68353e5Sstefano_zampini     }
2061b68353e5Sstefano_zampini     if (fast) {
20629566063dSJacob Faibussowitsch       PetscCall(MatConvert_Nest_SeqAIJ_fast(A,newtype,reuse,newmat));
2063b68353e5Sstefano_zampini       PetscFunctionReturn(0);
2064b68353e5Sstefano_zampini     }
2065b68353e5Sstefano_zampini   }
20669566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A,&M,&N));
20679566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A,&m,&n));
20689566063dSJacob Faibussowitsch   PetscCall(MatGetOwnershipRangeColumn(A,&cstart,&cend));
2069d1487292SPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) C = *newmat;
2070d1487292SPierre Jolivet   else {
20719566063dSJacob Faibussowitsch     PetscCall(MatCreate(PetscObjectComm((PetscObject)A),&C));
20729566063dSJacob Faibussowitsch     PetscCall(MatSetType(C,newtype));
20739566063dSJacob Faibussowitsch     PetscCall(MatSetSizes(C,m,n,M,N));
2074629c3df2SDmitry Karpeev   }
20759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(2*m,&dnnz));
2076629c3df2SDmitry Karpeev   onnz = dnnz + m;
2077629c3df2SDmitry Karpeev   for (k=0; k<m; k++) {
2078629c3df2SDmitry Karpeev     dnnz[k] = 0;
2079629c3df2SDmitry Karpeev     onnz[k] = 0;
2080629c3df2SDmitry Karpeev   }
2081629c3df2SDmitry Karpeev   for (j=0; j<nest->nc; ++j) {
2082629c3df2SDmitry Karpeev     IS             bNis;
2083629c3df2SDmitry Karpeev     PetscInt       bN;
2084629c3df2SDmitry Karpeev     const PetscInt *bNindices;
2085fd8a7442SPierre Jolivet     PetscBool      flg;
2086629c3df2SDmitry Karpeev     /* Using global column indices and ISAllGather() is not scalable. */
20879566063dSJacob Faibussowitsch     PetscCall(ISAllGather(nest->isglobal.col[j], &bNis));
20889566063dSJacob Faibussowitsch     PetscCall(ISGetSize(bNis, &bN));
20899566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(bNis,&bNindices));
2090629c3df2SDmitry Karpeev     for (i=0; i<nest->nr; ++i) {
2091629c3df2SDmitry Karpeev       PetscSF        bmsf;
2092649b366bSFande Kong       PetscSFNode    *iremote;
2093fd8a7442SPierre Jolivet       Mat            B=nest->m[i][j],D=NULL;
2094649b366bSFande Kong       PetscInt       bm,*sub_dnnz,*sub_onnz,br;
2095629c3df2SDmitry Karpeev       const PetscInt *bmindices;
2096629c3df2SDmitry Karpeev       if (!B) continue;
20979566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(nest->isglobal.row[i],&bm));
20989566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(nest->isglobal.row[i],&bmindices));
20999566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf));
21009566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm,&iremote));
21019566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm,&sub_dnnz));
21029566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(bm,&sub_onnz));
2103649b366bSFande Kong       for (k = 0; k < bm; ++k) {
2104649b366bSFande Kong         sub_dnnz[k] = 0;
2105649b366bSFande Kong         sub_onnz[k] = 0;
2106649b366bSFande Kong       }
2107fd8a7442SPierre Jolivet       PetscCall(PetscObjectTypeCompare((PetscObject)B,MATTRANSPOSEMAT,&flg));
2108fd8a7442SPierre Jolivet       if (flg) {
2109fd8a7442SPierre Jolivet         PetscTryMethod(B,"MatTransposeGetMat_C",(Mat,Mat*),(B,&D));
2110fd8a7442SPierre Jolivet         PetscTryMethod(B,"MatHermitianTransposeGetMat_C",(Mat,Mat*),(B,&D));
2111fd8a7442SPierre Jolivet         PetscCall(MatConvert(B,((PetscObject)D)->type_name,MAT_INITIAL_MATRIX,&D));
2112fd8a7442SPierre Jolivet         B = D;
2113fd8a7442SPierre Jolivet       }
2114fd8a7442SPierre Jolivet       PetscCall(PetscObjectTypeCompareAny((PetscObject)B,&flg,MATSEQSBAIJ,MATMPISBAIJ,""));
2115fd8a7442SPierre Jolivet       if (flg) {
2116fd8a7442SPierre Jolivet         if (D) PetscCall(MatConvert(D,MATBAIJ,MAT_INPLACE_MATRIX,&D));
2117fd8a7442SPierre Jolivet         else PetscCall(MatConvert(B,MATBAIJ,MAT_INITIAL_MATRIX,&D));
2118fd8a7442SPierre Jolivet         B = D;
2119fd8a7442SPierre Jolivet       }
2120629c3df2SDmitry Karpeev       /*
2121629c3df2SDmitry Karpeev        Locate the owners for all of the locally-owned global row indices for this row block.
2122629c3df2SDmitry Karpeev        These determine the roots of PetscSF used to communicate preallocation data to row owners.
2123629c3df2SDmitry Karpeev        The roots correspond to the dnnz and onnz entries; thus, there are two roots per row.
2124629c3df2SDmitry Karpeev        */
21259566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(B,&rstart,NULL));
2126629c3df2SDmitry Karpeev       for (br = 0; br < bm; ++br) {
2127131c27b5Sprj-         PetscInt       row = bmindices[br], brncols, col;
2128629c3df2SDmitry Karpeev         const PetscInt *brcols;
2129a4b3d3acSMatthew G Knepley         PetscInt       rowrel = 0; /* row's relative index on its owner rank */
2130131c27b5Sprj-         PetscMPIInt    rowowner = 0;
21319566063dSJacob Faibussowitsch         PetscCall(PetscLayoutFindOwnerIndex(A->rmap,row,&rowowner,&rowrel));
2132649b366bSFande Kong         /* how many roots  */
2133649b366bSFande Kong         iremote[br].rank = rowowner; iremote[br].index = rowrel;           /* edge from bmdnnz to dnnz */
2134649b366bSFande Kong         /* get nonzero pattern */
21359566063dSJacob Faibussowitsch         PetscCall(MatGetRow(B,br+rstart,&brncols,&brcols,NULL));
2136629c3df2SDmitry Karpeev         for (k=0; k<brncols; k++) {
2137629c3df2SDmitry Karpeev           col  = bNindices[brcols[k]];
2138649b366bSFande Kong           if (col>=A->cmap->range[rowowner] && col<A->cmap->range[rowowner+1]) {
2139649b366bSFande Kong             sub_dnnz[br]++;
2140649b366bSFande Kong           } else {
2141649b366bSFande Kong             sub_onnz[br]++;
2142649b366bSFande Kong           }
2143629c3df2SDmitry Karpeev         }
21449566063dSJacob Faibussowitsch         PetscCall(MatRestoreRow(B,br+rstart,&brncols,&brcols,NULL));
2145629c3df2SDmitry Karpeev       }
2146fd8a7442SPierre Jolivet       if (D) PetscCall(MatDestroy(&D));
21479566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(nest->isglobal.row[i],&bmindices));
2148629c3df2SDmitry Karpeev       /* bsf will have to take care of disposing of bedges. */
21499566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(bmsf,m,bm,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER));
21509566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM));
21519566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf,MPIU_INT,sub_dnnz,dnnz,MPI_SUM));
21529566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM));
21539566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(bmsf,MPIU_INT,sub_onnz,onnz,MPI_SUM));
21549566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_dnnz));
21559566063dSJacob Faibussowitsch       PetscCall(PetscFree(sub_onnz));
21569566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&bmsf));
2157629c3df2SDmitry Karpeev     }
21589566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(bNis,&bNindices));
21599566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&bNis));
216065a4a0a3Sstefano_zampini   }
216165a4a0a3Sstefano_zampini   /* Resize preallocation if overestimated */
216265a4a0a3Sstefano_zampini   for (i=0;i<m;i++) {
216365a4a0a3Sstefano_zampini     dnnz[i] = PetscMin(dnnz[i],A->cmap->n);
216465a4a0a3Sstefano_zampini     onnz[i] = PetscMin(onnz[i],A->cmap->N - A->cmap->n);
2165629c3df2SDmitry Karpeev   }
21669566063dSJacob Faibussowitsch   PetscCall(MatSeqAIJSetPreallocation(C,0,dnnz));
21679566063dSJacob Faibussowitsch   PetscCall(MatMPIAIJSetPreallocation(C,0,dnnz,0,onnz));
21689566063dSJacob Faibussowitsch   PetscCall(PetscFree(dnnz));
21699566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(C,1.0,A));
2170d1487292SPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21719566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A,&C));
2172d1487292SPierre Jolivet   } else *newmat = C;
2173be705e3aSPierre Jolivet   PetscFunctionReturn(0);
2174be705e3aSPierre Jolivet }
2175629c3df2SDmitry Karpeev 
2176be705e3aSPierre Jolivet PetscErrorCode MatConvert_Nest_Dense(Mat A,MatType newtype,MatReuse reuse,Mat *newmat)
2177be705e3aSPierre Jolivet {
2178629c3df2SDmitry Karpeev   Mat            B;
2179be705e3aSPierre Jolivet   PetscInt       m,n,M,N;
2180be705e3aSPierre Jolivet 
2181be705e3aSPierre Jolivet   PetscFunctionBegin;
21829566063dSJacob Faibussowitsch   PetscCall(MatGetSize(A,&M,&N));
21839566063dSJacob Faibussowitsch   PetscCall(MatGetLocalSize(A,&m,&n));
2184be705e3aSPierre Jolivet   if (reuse == MAT_REUSE_MATRIX) {
2185be705e3aSPierre Jolivet     B = *newmat;
21869566063dSJacob Faibussowitsch     PetscCall(MatZeroEntries(B));
2187be705e3aSPierre Jolivet   } else {
21889566063dSJacob Faibussowitsch     PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A),m,PETSC_DECIDE,M,N,NULL,&B));
2189629c3df2SDmitry Karpeev   }
21909566063dSJacob Faibussowitsch   PetscCall(MatAXPY_Dense_Nest(B,1.0,A));
2191be705e3aSPierre Jolivet   if (reuse == MAT_INPLACE_MATRIX) {
21929566063dSJacob Faibussowitsch     PetscCall(MatHeaderReplace(A,&B));
2193be705e3aSPierre Jolivet   } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B;
2194629c3df2SDmitry Karpeev   PetscFunctionReturn(0);
2195629c3df2SDmitry Karpeev }
2196629c3df2SDmitry Karpeev 
21978b7d3b4bSBarry Smith PetscErrorCode MatHasOperation_Nest(Mat mat,MatOperation op,PetscBool *has)
21988b7d3b4bSBarry Smith {
21998b7d3b4bSBarry Smith   Mat_Nest       *bA = (Mat_Nest*)mat->data;
22003c6db4c4SPierre Jolivet   MatOperation   opAdd;
22018b7d3b4bSBarry Smith   PetscInt       i,j,nr = bA->nr,nc = bA->nc;
22028b7d3b4bSBarry Smith   PetscBool      flg;
220352c5f739Sprj-   PetscFunctionBegin;
22048b7d3b4bSBarry Smith 
220552c5f739Sprj-   *has = PETSC_FALSE;
22063c6db4c4SPierre Jolivet   if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) {
22073c6db4c4SPierre Jolivet     opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD);
22088b7d3b4bSBarry Smith     for (j=0; j<nc; j++) {
22098b7d3b4bSBarry Smith       for (i=0; i<nr; i++) {
22108b7d3b4bSBarry Smith         if (!bA->m[i][j]) continue;
22119566063dSJacob Faibussowitsch         PetscCall(MatHasOperation(bA->m[i][j],opAdd,&flg));
22128b7d3b4bSBarry Smith         if (!flg) PetscFunctionReturn(0);
22138b7d3b4bSBarry Smith       }
22148b7d3b4bSBarry Smith     }
22158b7d3b4bSBarry Smith   }
22163c6db4c4SPierre Jolivet   if (((void**)mat->ops)[op]) *has = PETSC_TRUE;
22178b7d3b4bSBarry Smith   PetscFunctionReturn(0);
22188b7d3b4bSBarry Smith }
22198b7d3b4bSBarry Smith 
2220659c6bb0SJed Brown /*MC
2221659c6bb0SJed Brown   MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately.
2222659c6bb0SJed Brown 
2223659c6bb0SJed Brown   Level: intermediate
2224659c6bb0SJed Brown 
2225659c6bb0SJed Brown   Notes:
2226659c6bb0SJed Brown   This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices.
2227659c6bb0SJed Brown   It allows the use of symmetric and block formats for parts of multi-physics simulations.
2228950540a4SJed Brown   It is usually used with DMComposite and DMCreateMatrix()
2229659c6bb0SJed Brown 
22308b7d3b4bSBarry Smith   Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero
22318b7d3b4bSBarry Smith   rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes
22328b7d3b4bSBarry Smith   than the nest matrix.
22338b7d3b4bSBarry Smith 
2234db781477SPatrick Sanan .seealso: `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`,
2235db781477SPatrick Sanan           `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`,
2236db781477SPatrick Sanan           `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()`
2237659c6bb0SJed Brown M*/
22388cc058d9SJed Brown PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A)
2239c8883902SJed Brown {
2240c8883902SJed Brown   Mat_Nest       *s;
2241c8883902SJed Brown 
2242c8883902SJed Brown   PetscFunctionBegin;
22439566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(A,&s));
2244c8883902SJed Brown   A->data = (void*)s;
2245e7c19651SJed Brown 
2246e7c19651SJed Brown   s->nr            = -1;
2247e7c19651SJed Brown   s->nc            = -1;
22480298fd71SBarry Smith   s->m             = NULL;
2249e7c19651SJed Brown   s->splitassembly = PETSC_FALSE;
2250c8883902SJed Brown 
22519566063dSJacob Faibussowitsch   PetscCall(PetscMemzero(A->ops,sizeof(*A->ops)));
225226fbe8dcSKarl Rupp 
2253c8883902SJed Brown   A->ops->mult                  = MatMult_Nest;
22549194d70fSJed Brown   A->ops->multadd               = MatMultAdd_Nest;
2255c8883902SJed Brown   A->ops->multtranspose         = MatMultTranspose_Nest;
22569194d70fSJed Brown   A->ops->multtransposeadd      = MatMultTransposeAdd_Nest;
2257f8170845SAlex Fikl   A->ops->transpose             = MatTranspose_Nest;
2258c8883902SJed Brown   A->ops->assemblybegin         = MatAssemblyBegin_Nest;
2259c8883902SJed Brown   A->ops->assemblyend           = MatAssemblyEnd_Nest;
2260c8883902SJed Brown   A->ops->zeroentries           = MatZeroEntries_Nest;
2261c222c20dSDavid Ham   A->ops->copy                  = MatCopy_Nest;
22626e76ffeaSPierre Jolivet   A->ops->axpy                  = MatAXPY_Nest;
2263c8883902SJed Brown   A->ops->duplicate             = MatDuplicate_Nest;
22647dae84e0SHong Zhang   A->ops->createsubmatrix       = MatCreateSubMatrix_Nest;
2265c8883902SJed Brown   A->ops->destroy               = MatDestroy_Nest;
2266c8883902SJed Brown   A->ops->view                  = MatView_Nest;
2267f4259b30SLisandro Dalcin   A->ops->getvecs               = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */
2268c8883902SJed Brown   A->ops->getlocalsubmatrix     = MatGetLocalSubMatrix_Nest;
2269c8883902SJed Brown   A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest;
2270429bac76SJed Brown   A->ops->getdiagonal           = MatGetDiagonal_Nest;
2271429bac76SJed Brown   A->ops->diagonalscale         = MatDiagonalScale_Nest;
2272a061e289SJed Brown   A->ops->scale                 = MatScale_Nest;
2273a061e289SJed Brown   A->ops->shift                 = MatShift_Nest;
227413135bc6SAlex Fikl   A->ops->diagonalset           = MatDiagonalSet_Nest;
2275f8170845SAlex Fikl   A->ops->setrandom             = MatSetRandom_Nest;
22768b7d3b4bSBarry Smith   A->ops->hasoperation          = MatHasOperation_Nest;
2277381b8e50SStefano Zampini   A->ops->missingdiagonal       = MatMissingDiagonal_Nest;
2278c8883902SJed Brown 
2279f4259b30SLisandro Dalcin   A->spptr        = NULL;
2280c8883902SJed Brown   A->assembled    = PETSC_FALSE;
2281c8883902SJed Brown 
2282c8883902SJed Brown   /* expose Nest api's */
22839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMat_C",        MatNestGetSubMat_Nest));
22849566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMat_C",        MatNestSetSubMat_Nest));
22859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetSubMats_C",       MatNestGetSubMats_Nest));
22869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetSize_C",          MatNestGetSize_Nest));
22879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetISs_C",           MatNestGetISs_Nest));
22889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestGetLocalISs_C",      MatNestGetLocalISs_Nest));
22899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestSetVecType_C",       MatNestSetVecType_Nest));
22909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatNestSetSubMats_C",       MatNestSetSubMats_Nest));
22919566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpiaij_C",  MatConvert_Nest_AIJ));
22929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqaij_C",  MatConvert_Nest_AIJ));
22939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_aij_C",     MatConvert_Nest_AIJ));
22949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_is_C",      MatConvert_Nest_IS));
22959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_mpidense_C",MatConvert_Nest_Dense));
22969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatConvert_nest_seqdense_C",MatConvert_Nest_Dense));
22979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_seqdense_C",MatProductSetFromOptions_Nest_Dense));
22989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_mpidense_C",MatProductSetFromOptions_Nest_Dense));
22999566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_nest_dense_C",MatProductSetFromOptions_Nest_Dense));
2300c8883902SJed Brown 
23019566063dSJacob Faibussowitsch   PetscCall(PetscObjectChangeTypeName((PetscObject)A,MATNEST));
2302c8883902SJed Brown   PetscFunctionReturn(0);
2303c8883902SJed Brown }
2304