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 */ 12d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetSizes_Private(Mat A, PetscInt *m, PetscInt *n, PetscInt *M, PetscInt *N) 13d71ae5a4SJacob Faibussowitsch { 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 } 333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 34d8588912SDave May } 35d8588912SDave May 36d8588912SDave May /* operations */ 37d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_Nest(Mat A, Vec x, Vec y) 38d71ae5a4SJacob Faibussowitsch { 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])); 563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 57d8588912SDave May } 58d8588912SDave May 59d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Nest(Mat A, Vec x, Vec y, Vec z) 60d71ae5a4SJacob Faibussowitsch { 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])); 833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 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- 92a678f235SPierre Jolivet static PetscErrorCode MatProductNumeric_Nest_Dense(Mat C) 93d71ae5a4SJacob Faibussowitsch { 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; 1030d6f747bSJacob Faibussowitsch MatCheckProduct(C, 1); 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)); 1103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 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)); 1503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15152c5f739Sprj- } 15252c5f739Sprj- 15366976f2fSJacob Faibussowitsch static PetscErrorCode MatNest_DenseDestroy(void *ctx) 154d71ae5a4SJacob Faibussowitsch { 15552c5f739Sprj- Nest_Dense *contents = (Nest_Dense *)ctx; 15652c5f739Sprj- PetscInt i; 15752c5f739Sprj- 15852c5f739Sprj- PetscFunctionBegin; 1599566063dSJacob Faibussowitsch PetscCall(PetscFree(contents->tarray)); 16048a46eb9SPierre Jolivet for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i)); 1619566063dSJacob Faibussowitsch PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC)); 1629566063dSJacob Faibussowitsch PetscCall(PetscFree(contents)); 1633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16452c5f739Sprj- } 16552c5f739Sprj- 166a678f235SPierre Jolivet static PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C) 167d71ae5a4SJacob Faibussowitsch { 1686718818eSStefano Zampini Mat_Nest *bA; 1696718818eSStefano Zampini Mat viewB, workC; 17052c5f739Sprj- const PetscScalar *barray; 1716718818eSStefano Zampini PetscInt i, j, M, N, m, n, nr, nc, maxm = 0, ldb; 1724222ddf1SHong Zhang Nest_Dense *contents = NULL; 1736718818eSStefano Zampini PetscBool cisdense; 1746718818eSStefano Zampini Mat A, B; 1756718818eSStefano Zampini PetscReal fill; 17652c5f739Sprj- 17752c5f739Sprj- PetscFunctionBegin; 1780d6f747bSJacob Faibussowitsch MatCheckProduct(C, 1); 17928b400f6SJacob Faibussowitsch PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty"); 1806718818eSStefano Zampini A = C->product->A; 1816718818eSStefano Zampini B = C->product->B; 1826718818eSStefano Zampini fill = C->product->fill; 1836718818eSStefano Zampini bA = (Mat_Nest *)A->data; 1846718818eSStefano Zampini nr = bA->nr; 1856718818eSStefano Zampini nc = bA->nc; 1869566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(C, &m, &n)); 1879566063dSJacob Faibussowitsch PetscCall(MatGetSize(C, &M, &N)); 1880572eedcSPierre Jolivet if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) { 1899566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(B, NULL, &n)); 1909566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 1919566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, NULL)); 1929566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, NULL)); 1939566063dSJacob Faibussowitsch PetscCall(MatSetSizes(C, m, n, M, N)); 1940572eedcSPierre Jolivet } 1959566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, "")); 19648a46eb9SPierre Jolivet if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name)); 1979566063dSJacob Faibussowitsch PetscCall(MatSetUp(C)); 1986718818eSStefano Zampini if (!N) { 1996718818eSStefano Zampini C->ops->productnumeric = MatProductNumeric_Nest_Dense; 2003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 20152c5f739Sprj- } 20252c5f739Sprj- 2039566063dSJacob Faibussowitsch PetscCall(PetscNew(&contents)); 2046718818eSStefano Zampini C->product->data = contents; 2056718818eSStefano Zampini C->product->destroy = MatNest_DenseDestroy; 2069566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC)); 20752c5f739Sprj- contents->k = nr * nc; 20852c5f739Sprj- for (i = 0; i < nr; i++) { 2099566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1)); 21052c5f739Sprj- maxm = PetscMax(maxm, contents->dm[i + 1]); 21152c5f739Sprj- contents->dm[i + 1] += contents->dm[i]; 21252c5f739Sprj- } 21352c5f739Sprj- for (i = 0; i < nc; i++) { 2149566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1)); 21552c5f739Sprj- contents->dn[i + 1] += contents->dn[i]; 21652c5f739Sprj- } 2179566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(maxm * N, &contents->tarray)); 2189566063dSJacob Faibussowitsch PetscCall(MatDenseGetLDA(B, &ldb)); 2199566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 2209566063dSJacob Faibussowitsch PetscCall(MatDenseGetArrayRead(B, &barray)); 22152c5f739Sprj- /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */ 22252c5f739Sprj- for (j = 0; j < nc; j++) { 2239566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[j], &M)); 2249566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, (PetscScalar *)(barray + contents->dn[j]), &viewB)); 2259566063dSJacob Faibussowitsch PetscCall(MatDenseSetLDA(viewB, ldb)); 22652c5f739Sprj- for (i = 0; i < nr; i++) { 22752c5f739Sprj- if (!bA->m[i][j]) continue; 22852c5f739Sprj- /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */ 2294222ddf1SHong Zhang 2309566063dSJacob Faibussowitsch PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j])); 2314222ddf1SHong Zhang workC = contents->workC[i * nc + j]; 2329566063dSJacob Faibussowitsch PetscCall(MatProductSetType(workC, MATPRODUCT_AB)); 2339566063dSJacob Faibussowitsch PetscCall(MatProductSetAlgorithm(workC, "default")); 2349566063dSJacob Faibussowitsch PetscCall(MatProductSetFill(workC, fill)); 2359566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(workC)); 2369566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(workC)); 2374222ddf1SHong Zhang 2386718818eSStefano Zampini /* since tarray will be shared by all Mat */ 2399566063dSJacob Faibussowitsch PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray)); 2409566063dSJacob Faibussowitsch PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray)); 24152c5f739Sprj- } 2429566063dSJacob Faibussowitsch PetscCall(MatDestroy(&viewB)); 24352c5f739Sprj- } 2449566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArrayRead(B, &barray)); 24552c5f739Sprj- 2466718818eSStefano Zampini C->ops->productnumeric = MatProductNumeric_Nest_Dense; 2473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 24852c5f739Sprj- } 24952c5f739Sprj- 250a678f235SPierre Jolivet static PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C) 251d71ae5a4SJacob Faibussowitsch { 2524222ddf1SHong Zhang Mat_Product *product = C->product; 25352c5f739Sprj- 25452c5f739Sprj- PetscFunctionBegin; 255*c57d7d18SPierre Jolivet if (product->type == MATPRODUCT_AB) C->ops->productsymbolic = MatProductSymbolic_Nest_Dense; 2563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 25752c5f739Sprj- } 25852c5f739Sprj- 259d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y) 260d71ae5a4SJacob Faibussowitsch { 261d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 262207556f9SJed Brown Vec *bx = bA->left, *by = bA->right; 263207556f9SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 264d8588912SDave May 265d8588912SDave May PetscFunctionBegin; 2669566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 2679566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i])); 268207556f9SJed Brown for (j = 0; j < nc; j++) { 2699566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(by[j])); 270609e31cbSJed Brown for (i = 0; i < nr; i++) { 2716c75ac25SJed Brown if (!bA->m[i][j]) continue; 272609e31cbSJed Brown /* y[j] <- y[j] + (A[i][j])^T * x[i] */ 2739566063dSJacob Faibussowitsch PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j])); 274d8588912SDave May } 275d8588912SDave May } 2769566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 2779566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i])); 2783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 279d8588912SDave May } 280d8588912SDave May 281d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z) 282d71ae5a4SJacob Faibussowitsch { 2839194d70fSJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 2849194d70fSJed Brown Vec *bx = bA->left, *bz = bA->right; 2859194d70fSJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 2869194d70fSJed Brown 2879194d70fSJed Brown PetscFunctionBegin; 2889566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 2899566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i])); 2909194d70fSJed Brown for (j = 0; j < nc; j++) { 2919194d70fSJed Brown if (y != z) { 2929194d70fSJed Brown Vec by; 2939566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by)); 2949566063dSJacob Faibussowitsch PetscCall(VecCopy(by, bz[j])); 2959566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by)); 2969194d70fSJed Brown } 2979194d70fSJed Brown for (i = 0; i < nr; i++) { 2986c75ac25SJed Brown if (!bA->m[i][j]) continue; 2999194d70fSJed Brown /* z[j] <- y[j] + (A[i][j])^T * x[i] */ 3009566063dSJacob Faibussowitsch PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j])); 3019194d70fSJed Brown } 3029194d70fSJed Brown } 3039566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 3049566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i])); 3053ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3069194d70fSJed Brown } 3079194d70fSJed Brown 308d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B) 309d71ae5a4SJacob Faibussowitsch { 310f8170845SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data, *bC; 311f8170845SAlex Fikl Mat C; 312f8170845SAlex Fikl PetscInt i, j, nr = bA->nr, nc = bA->nc; 313f8170845SAlex Fikl 314f8170845SAlex Fikl PetscFunctionBegin; 3157fb60732SBarry Smith if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B)); 316aed4548fSBarry Smith PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place"); 317f8170845SAlex Fikl 318cf37664fSBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) { 319f8170845SAlex Fikl Mat *subs; 320f8170845SAlex Fikl IS *is_row, *is_col; 321f8170845SAlex Fikl 3229566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr * nc, &subs)); 3239566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col)); 3249566063dSJacob Faibussowitsch PetscCall(MatNestGetISs(A, is_row, is_col)); 325cf37664fSBarry Smith if (reuse == MAT_INPLACE_MATRIX) { 326ddeb9bd8SAlex Fikl for (i = 0; i < nr; i++) { 327ad540459SPierre Jolivet for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j]; 328ddeb9bd8SAlex Fikl } 329ddeb9bd8SAlex Fikl } 330ddeb9bd8SAlex Fikl 3319566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C)); 3329566063dSJacob Faibussowitsch PetscCall(PetscFree(subs)); 3339566063dSJacob Faibussowitsch PetscCall(PetscFree2(is_row, is_col)); 334f8170845SAlex Fikl } else { 335f8170845SAlex Fikl C = *B; 336f8170845SAlex Fikl } 337f8170845SAlex Fikl 338f8170845SAlex Fikl bC = (Mat_Nest *)C->data; 339f8170845SAlex Fikl for (i = 0; i < nr; i++) { 340f8170845SAlex Fikl for (j = 0; j < nc; j++) { 341f8170845SAlex Fikl if (bA->m[i][j]) { 3429566063dSJacob Faibussowitsch PetscCall(MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i]))); 343f8170845SAlex Fikl } else { 344f8170845SAlex Fikl bC->m[j][i] = NULL; 345f8170845SAlex Fikl } 346f8170845SAlex Fikl } 347f8170845SAlex Fikl } 348f8170845SAlex Fikl 349cf37664fSBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) { 350f8170845SAlex Fikl *B = C; 351f8170845SAlex Fikl } else { 3529566063dSJacob Faibussowitsch PetscCall(MatHeaderMerge(A, &C)); 353f8170845SAlex Fikl } 3543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 355f8170845SAlex Fikl } 356f8170845SAlex Fikl 357d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list) 358d71ae5a4SJacob Faibussowitsch { 359e2d7f03fSJed Brown IS *lst = *list; 360e2d7f03fSJed Brown PetscInt i; 361e2d7f03fSJed Brown 362e2d7f03fSJed Brown PetscFunctionBegin; 3633ba16761SJacob Faibussowitsch if (!lst) PetscFunctionReturn(PETSC_SUCCESS); 3649371c9d4SSatish Balay for (i = 0; i < n; i++) 3659371c9d4SSatish Balay if (lst[i]) PetscCall(ISDestroy(&lst[i])); 3669566063dSJacob Faibussowitsch PetscCall(PetscFree(lst)); 3670298fd71SBarry Smith *list = NULL; 3683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 369e2d7f03fSJed Brown } 370e2d7f03fSJed Brown 371d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatReset_Nest(Mat A) 372d71ae5a4SJacob Faibussowitsch { 373d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 374d8588912SDave May PetscInt i, j; 375d8588912SDave May 376d8588912SDave May PetscFunctionBegin; 377d8588912SDave May /* release the matrices and the place holders */ 3789566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row)); 3799566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col)); 3809566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row)); 3819566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col)); 382d8588912SDave May 3839566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->row_len)); 3849566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->col_len)); 3859566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->nnzstate)); 386d8588912SDave May 3879566063dSJacob Faibussowitsch PetscCall(PetscFree2(vs->left, vs->right)); 388207556f9SJed Brown 389d8588912SDave May /* release the matrices and the place holders */ 390d8588912SDave May if (vs->m) { 391d8588912SDave May for (i = 0; i < vs->nr; i++) { 39248a46eb9SPierre Jolivet for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j])); 3939566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->m[i])); 394d8588912SDave May } 3959566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->m)); 396d8588912SDave May } 39706a1af2fSStefano Zampini 39806a1af2fSStefano Zampini /* restore defaults */ 39906a1af2fSStefano Zampini vs->nr = 0; 40006a1af2fSStefano Zampini vs->nc = 0; 40106a1af2fSStefano Zampini vs->splitassembly = PETSC_FALSE; 4023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 40306a1af2fSStefano Zampini } 40406a1af2fSStefano Zampini 405d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Nest(Mat A) 406d71ae5a4SJacob Faibussowitsch { 407362febeeSStefano Zampini PetscFunctionBegin; 4089566063dSJacob Faibussowitsch PetscCall(MatReset_Nest(A)); 4099566063dSJacob Faibussowitsch PetscCall(PetscFree(A->data)); 4109566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL)); 4119566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL)); 4129566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL)); 4139566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL)); 4149566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL)); 4159566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL)); 4169566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL)); 4179566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL)); 4189566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL)); 4199566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL)); 4209566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL)); 4219566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL)); 4229566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL)); 4239566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL)); 4249566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL)); 4259566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL)); 4263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 427d8588912SDave May } 428d8588912SDave May 429d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd) 430d71ae5a4SJacob Faibussowitsch { 431381b8e50SStefano Zampini Mat_Nest *vs = (Mat_Nest *)mat->data; 432381b8e50SStefano Zampini PetscInt i; 433381b8e50SStefano Zampini 434381b8e50SStefano Zampini PetscFunctionBegin; 435381b8e50SStefano Zampini if (dd) *dd = 0; 436381b8e50SStefano Zampini if (!vs->nr) { 437381b8e50SStefano Zampini *missing = PETSC_TRUE; 4383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 439381b8e50SStefano Zampini } 440381b8e50SStefano Zampini *missing = PETSC_FALSE; 441381b8e50SStefano Zampini for (i = 0; i < vs->nr && !(*missing); i++) { 442381b8e50SStefano Zampini *missing = PETSC_TRUE; 443381b8e50SStefano Zampini if (vs->m[i][i]) { 4449566063dSJacob Faibussowitsch PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL)); 44508401ef6SPierre Jolivet PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented"); 446381b8e50SStefano Zampini } 447381b8e50SStefano Zampini } 4483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 449381b8e50SStefano Zampini } 450381b8e50SStefano Zampini 451d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type) 452d71ae5a4SJacob Faibussowitsch { 453d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 454d8588912SDave May PetscInt i, j; 45506a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 456d8588912SDave May 457d8588912SDave May PetscFunctionBegin; 458d8588912SDave May for (i = 0; i < vs->nr; i++) { 459d8588912SDave May for (j = 0; j < vs->nc; j++) { 46006a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 461e7c19651SJed Brown if (vs->m[i][j]) { 4629566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(vs->m[i][j], type)); 463e7c19651SJed Brown if (!vs->splitassembly) { 464e7c19651SJed Brown /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested 465e7c19651SJed 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 466e7c19651SJed Brown * already performing an assembly, but the result would by more complicated and appears to offer less 467e7c19651SJed Brown * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an 468e7c19651SJed Brown * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives". 469e7c19651SJed Brown */ 4709566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 4719566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate)); 472e7c19651SJed Brown } 473e7c19651SJed Brown } 47406a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate); 47506a1af2fSStefano Zampini vs->nnzstate[i * vs->nc + j] = subnnzstate; 476d8588912SDave May } 477d8588912SDave May } 47806a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 4793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 480d8588912SDave May } 481d8588912SDave May 482d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type) 483d71ae5a4SJacob Faibussowitsch { 484d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 485d8588912SDave May PetscInt i, j; 486d8588912SDave May 487d8588912SDave May PetscFunctionBegin; 488d8588912SDave May for (i = 0; i < vs->nr; i++) { 489d8588912SDave May for (j = 0; j < vs->nc; j++) { 490e7c19651SJed Brown if (vs->m[i][j]) { 49148a46eb9SPierre Jolivet if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 492e7c19651SJed Brown } 493d8588912SDave May } 494d8588912SDave May } 4953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 496d8588912SDave May } 497d8588912SDave May 498d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B) 499d71ae5a4SJacob Faibussowitsch { 500f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 501f349c1fdSJed Brown PetscInt j; 502f349c1fdSJed Brown Mat sub; 503d8588912SDave May 504d8588912SDave May PetscFunctionBegin; 5050298fd71SBarry Smith sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */ 506f349c1fdSJed Brown for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j]; 5079566063dSJacob Faibussowitsch if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 508f349c1fdSJed Brown *B = sub; 5093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 510d8588912SDave May } 511d8588912SDave May 512d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B) 513d71ae5a4SJacob Faibussowitsch { 514f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 515f349c1fdSJed Brown PetscInt i; 516f349c1fdSJed Brown Mat sub; 517f349c1fdSJed Brown 518f349c1fdSJed Brown PetscFunctionBegin; 5190298fd71SBarry Smith sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */ 520f349c1fdSJed Brown for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col]; 5219566063dSJacob Faibussowitsch if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 522f349c1fdSJed Brown *B = sub; 5233ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 524d8588912SDave May } 525d8588912SDave May 526d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end) 527d71ae5a4SJacob Faibussowitsch { 52818d228c0SPierre Jolivet PetscInt i, j, size, m; 529f349c1fdSJed Brown PetscBool flg; 53018d228c0SPierre Jolivet IS out, concatenate[2]; 531f349c1fdSJed Brown 532f349c1fdSJed Brown PetscFunctionBegin; 5334f572ea9SToby Isaac PetscAssertPointer(list, 3); 534f349c1fdSJed Brown PetscValidHeaderSpecific(is, IS_CLASSID, 4); 53518d228c0SPierre Jolivet if (begin) { 5364f572ea9SToby Isaac PetscAssertPointer(begin, 5); 53718d228c0SPierre Jolivet *begin = -1; 53818d228c0SPierre Jolivet } 53918d228c0SPierre Jolivet if (end) { 5404f572ea9SToby Isaac PetscAssertPointer(end, 6); 54118d228c0SPierre Jolivet *end = -1; 54218d228c0SPierre Jolivet } 543f349c1fdSJed Brown for (i = 0; i < n; i++) { 544207556f9SJed Brown if (!list[i]) continue; 5459566063dSJacob Faibussowitsch PetscCall(ISEqualUnsorted(list[i], is, &flg)); 546f349c1fdSJed Brown if (flg) { 54718d228c0SPierre Jolivet if (begin) *begin = i; 54818d228c0SPierre Jolivet if (end) *end = i + 1; 5493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 550f349c1fdSJed Brown } 551f349c1fdSJed Brown } 5529566063dSJacob Faibussowitsch PetscCall(ISGetSize(is, &size)); 55318d228c0SPierre Jolivet for (i = 0; i < n - 1; i++) { 55418d228c0SPierre Jolivet if (!list[i]) continue; 55518d228c0SPierre Jolivet m = 0; 5569566063dSJacob Faibussowitsch PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out)); 5579566063dSJacob Faibussowitsch PetscCall(ISGetSize(out, &m)); 55818d228c0SPierre Jolivet for (j = i + 2; j < n && m < size; j++) { 55918d228c0SPierre Jolivet if (list[j]) { 56018d228c0SPierre Jolivet concatenate[0] = out; 56118d228c0SPierre Jolivet concatenate[1] = list[j]; 5629566063dSJacob Faibussowitsch PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out)); 5639566063dSJacob Faibussowitsch PetscCall(ISDestroy(concatenate)); 5649566063dSJacob Faibussowitsch PetscCall(ISGetSize(out, &m)); 56518d228c0SPierre Jolivet } 56618d228c0SPierre Jolivet } 56718d228c0SPierre Jolivet if (m == size) { 5689566063dSJacob Faibussowitsch PetscCall(ISEqualUnsorted(out, is, &flg)); 56918d228c0SPierre Jolivet if (flg) { 57018d228c0SPierre Jolivet if (begin) *begin = i; 57118d228c0SPierre Jolivet if (end) *end = j; 5729566063dSJacob Faibussowitsch PetscCall(ISDestroy(&out)); 5733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 57418d228c0SPierre Jolivet } 57518d228c0SPierre Jolivet } 5769566063dSJacob Faibussowitsch PetscCall(ISDestroy(&out)); 57718d228c0SPierre Jolivet } 5783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 579f349c1fdSJed Brown } 580f349c1fdSJed Brown 581d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B) 582d71ae5a4SJacob Faibussowitsch { 5838188e55aSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 58418d228c0SPierre Jolivet PetscInt lr, lc; 58518d228c0SPierre Jolivet 58618d228c0SPierre Jolivet PetscFunctionBegin; 5879566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 5889566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr)); 5899566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc)); 5909566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE)); 5919566063dSJacob Faibussowitsch PetscCall(MatSetType(*B, MATAIJ)); 5929566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL)); 5939566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL)); 5949566063dSJacob Faibussowitsch PetscCall(MatSetUp(*B)); 5959566063dSJacob Faibussowitsch PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 5969566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 5979566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 5983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 59918d228c0SPierre Jolivet } 60018d228c0SPierre Jolivet 601d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B) 602d71ae5a4SJacob Faibussowitsch { 60318d228c0SPierre Jolivet Mat_Nest *vs = (Mat_Nest *)A->data; 60418d228c0SPierre Jolivet Mat *a; 60518d228c0SPierre Jolivet PetscInt i, j, k, l, nr = rend - rbegin, nc = cend - cbegin; 6068188e55aSJed Brown char keyname[256]; 60718d228c0SPierre Jolivet PetscBool *b; 60818d228c0SPierre Jolivet PetscBool flg; 6098188e55aSJed Brown 6108188e55aSJed Brown PetscFunctionBegin; 6110298fd71SBarry Smith *B = NULL; 6129566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend)); 6139566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B)); 6143ba16761SJacob Faibussowitsch if (*B) PetscFunctionReturn(PETSC_SUCCESS); 6158188e55aSJed Brown 6169566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b)); 61718d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 61818d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 61918d228c0SPierre Jolivet a[i * nc + j] = vs->m[rbegin + i][cbegin + j]; 62018d228c0SPierre Jolivet b[i * nc + j] = PETSC_FALSE; 62118d228c0SPierre Jolivet } 62218d228c0SPierre Jolivet } 62318d228c0SPierre Jolivet if (nc != vs->nc && nr != vs->nr) { 62418d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 62518d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 62618d228c0SPierre Jolivet flg = PETSC_FALSE; 62718d228c0SPierre Jolivet for (k = 0; (k < nr && !flg); k++) { 62818d228c0SPierre Jolivet if (a[j + k * nc]) flg = PETSC_TRUE; 62918d228c0SPierre Jolivet } 63018d228c0SPierre Jolivet if (flg) { 63118d228c0SPierre Jolivet flg = PETSC_FALSE; 63218d228c0SPierre Jolivet for (l = 0; (l < nc && !flg); l++) { 63318d228c0SPierre Jolivet if (a[i * nc + l]) flg = PETSC_TRUE; 63418d228c0SPierre Jolivet } 63518d228c0SPierre Jolivet } 63618d228c0SPierre Jolivet if (!flg) { 63718d228c0SPierre Jolivet b[i * nc + j] = PETSC_TRUE; 6389566063dSJacob Faibussowitsch PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j)); 63918d228c0SPierre Jolivet } 64018d228c0SPierre Jolivet } 64118d228c0SPierre Jolivet } 64218d228c0SPierre Jolivet } 6439566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B)); 64418d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 64518d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 64648a46eb9SPierre Jolivet if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j)); 64718d228c0SPierre Jolivet } 64818d228c0SPierre Jolivet } 6499566063dSJacob Faibussowitsch PetscCall(PetscFree2(a, b)); 6508188e55aSJed Brown (*B)->assembled = A->assembled; 6519566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B)); 6529566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */ 6533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6548188e55aSJed Brown } 6558188e55aSJed Brown 656d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B) 657d71ae5a4SJacob Faibussowitsch { 658f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 65918d228c0SPierre Jolivet PetscInt rbegin, rend, cbegin, cend; 660f349c1fdSJed Brown 661f349c1fdSJed Brown PetscFunctionBegin; 6629566063dSJacob Faibussowitsch PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend)); 6639566063dSJacob Faibussowitsch PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend)); 66418d228c0SPierre Jolivet if (rend == rbegin + 1 && cend == cbegin + 1) { 66548a46eb9SPierre Jolivet if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin)); 66618d228c0SPierre Jolivet *B = vs->m[rbegin][cbegin]; 66718d228c0SPierre Jolivet } else if (rbegin != -1 && cbegin != -1) { 6689566063dSJacob Faibussowitsch PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B)); 66918d228c0SPierre Jolivet } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set"); 6703ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 671f349c1fdSJed Brown } 672f349c1fdSJed Brown 67306a1af2fSStefano Zampini /* 67406a1af2fSStefano Zampini TODO: This does not actually returns a submatrix we can modify 67506a1af2fSStefano Zampini */ 676d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B) 677d71ae5a4SJacob Faibussowitsch { 678f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 679f349c1fdSJed Brown Mat sub; 680f349c1fdSJed Brown 681f349c1fdSJed Brown PetscFunctionBegin; 6829566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub)); 683f349c1fdSJed Brown switch (reuse) { 684f349c1fdSJed Brown case MAT_INITIAL_MATRIX: 6859566063dSJacob Faibussowitsch if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 686f349c1fdSJed Brown *B = sub; 687f349c1fdSJed Brown break; 688d71ae5a4SJacob Faibussowitsch case MAT_REUSE_MATRIX: 689d71ae5a4SJacob Faibussowitsch PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call"); 690d71ae5a4SJacob Faibussowitsch break; 691d71ae5a4SJacob Faibussowitsch case MAT_IGNORE_MATRIX: /* Nothing to do */ 692d71ae5a4SJacob Faibussowitsch break; 693d71ae5a4SJacob Faibussowitsch case MAT_INPLACE_MATRIX: /* Nothing to do */ 694d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet"); 695f349c1fdSJed Brown } 6963ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 697f349c1fdSJed Brown } 698f349c1fdSJed Brown 69966976f2fSJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) 700d71ae5a4SJacob Faibussowitsch { 701f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 702f349c1fdSJed Brown Mat sub; 703f349c1fdSJed Brown 704f349c1fdSJed Brown PetscFunctionBegin; 7059566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 706f349c1fdSJed Brown /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */ 7079566063dSJacob Faibussowitsch if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 708f349c1fdSJed Brown *B = sub; 7093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 710d8588912SDave May } 711d8588912SDave May 712d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) 713d71ae5a4SJacob Faibussowitsch { 714f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 715f349c1fdSJed Brown Mat sub; 716d8588912SDave May 717d8588912SDave May PetscFunctionBegin; 7189566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 71908401ef6SPierre Jolivet PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten"); 720f349c1fdSJed Brown if (sub) { 721aed4548fSBarry Smith PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times"); 7229566063dSJacob Faibussowitsch PetscCall(MatDestroy(B)); 723d8588912SDave May } 7243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 725d8588912SDave May } 726d8588912SDave May 727d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v) 728d71ae5a4SJacob Faibussowitsch { 7297874fa86SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 7307874fa86SDave May PetscInt i; 7317874fa86SDave May 7327874fa86SDave May PetscFunctionBegin; 7337874fa86SDave May for (i = 0; i < bA->nr; i++) { 734429bac76SJed Brown Vec bv; 7359566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv)); 7367874fa86SDave May if (bA->m[i][i]) { 7379566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(bA->m[i][i], bv)); 7387874fa86SDave May } else { 7399566063dSJacob Faibussowitsch PetscCall(VecSet(bv, 0.0)); 7407874fa86SDave May } 7419566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv)); 7427874fa86SDave May } 7433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 7447874fa86SDave May } 7457874fa86SDave May 746d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r) 747d71ae5a4SJacob Faibussowitsch { 7487874fa86SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 749429bac76SJed Brown Vec bl, *br; 7507874fa86SDave May PetscInt i, j; 7517874fa86SDave May 7527874fa86SDave May PetscFunctionBegin; 7539566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(bA->nc, &br)); 7542e6472ebSElliott Sales de Andrade if (r) { 7559566063dSJacob Faibussowitsch for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j])); 7562e6472ebSElliott Sales de Andrade } 7572e6472ebSElliott Sales de Andrade bl = NULL; 7587874fa86SDave May for (i = 0; i < bA->nr; i++) { 75948a46eb9SPierre Jolivet if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl)); 7607874fa86SDave May for (j = 0; j < bA->nc; j++) { 76148a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j])); 7627874fa86SDave May } 76348a46eb9SPierre Jolivet if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl)); 7642e6472ebSElliott Sales de Andrade } 7652e6472ebSElliott Sales de Andrade if (r) { 7669566063dSJacob Faibussowitsch for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j])); 7672e6472ebSElliott Sales de Andrade } 7689566063dSJacob Faibussowitsch PetscCall(PetscFree(br)); 7693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 7707874fa86SDave May } 7717874fa86SDave May 772d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a) 773d71ae5a4SJacob Faibussowitsch { 774a061e289SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 775a061e289SJed Brown PetscInt i, j; 776a061e289SJed Brown 777a061e289SJed Brown PetscFunctionBegin; 778a061e289SJed Brown for (i = 0; i < bA->nr; i++) { 779a061e289SJed Brown for (j = 0; j < bA->nc; j++) { 78048a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a)); 781a061e289SJed Brown } 782a061e289SJed Brown } 7833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 784a061e289SJed Brown } 785a061e289SJed Brown 786d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a) 787d71ae5a4SJacob Faibussowitsch { 788a061e289SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 789a061e289SJed Brown PetscInt i; 79006a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 791a061e289SJed Brown 792a061e289SJed Brown PetscFunctionBegin; 793a061e289SJed Brown for (i = 0; i < bA->nr; i++) { 79406a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 79508401ef6SPierre 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); 7969566063dSJacob Faibussowitsch PetscCall(MatShift(bA->m[i][i], a)); 7979566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 79806a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 79906a1af2fSStefano Zampini bA->nnzstate[i * bA->nc + i] = subnnzstate; 800a061e289SJed Brown } 80106a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 8023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 803a061e289SJed Brown } 804a061e289SJed Brown 805d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is) 806d71ae5a4SJacob Faibussowitsch { 80713135bc6SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data; 80813135bc6SAlex Fikl PetscInt i; 80906a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 81013135bc6SAlex Fikl 81113135bc6SAlex Fikl PetscFunctionBegin; 81213135bc6SAlex Fikl for (i = 0; i < bA->nr; i++) { 81306a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 81413135bc6SAlex Fikl Vec bv; 8159566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv)); 81613135bc6SAlex Fikl if (bA->m[i][i]) { 8179566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet(bA->m[i][i], bv, is)); 8189566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 81913135bc6SAlex Fikl } 8209566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv)); 82106a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 82206a1af2fSStefano Zampini bA->nnzstate[i * bA->nc + i] = subnnzstate; 82313135bc6SAlex Fikl } 82406a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 8253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 82613135bc6SAlex Fikl } 82713135bc6SAlex Fikl 828d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx) 829d71ae5a4SJacob Faibussowitsch { 830f8170845SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data; 831f8170845SAlex Fikl PetscInt i, j; 832f8170845SAlex Fikl 833f8170845SAlex Fikl PetscFunctionBegin; 834f8170845SAlex Fikl for (i = 0; i < bA->nr; i++) { 835f8170845SAlex Fikl for (j = 0; j < bA->nc; j++) { 83648a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx)); 837f8170845SAlex Fikl } 838f8170845SAlex Fikl } 8393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 840f8170845SAlex Fikl } 841f8170845SAlex Fikl 842d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left) 843d71ae5a4SJacob Faibussowitsch { 844d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 845d8588912SDave May Vec *L, *R; 846d8588912SDave May MPI_Comm comm; 847d8588912SDave May PetscInt i, j; 848d8588912SDave May 849d8588912SDave May PetscFunctionBegin; 8509566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)A, &comm)); 851d8588912SDave May if (right) { 852d8588912SDave May /* allocate R */ 8539566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bA->nc, &R)); 854d8588912SDave May /* Create the right vectors */ 855d8588912SDave May for (j = 0; j < bA->nc; j++) { 856d8588912SDave May for (i = 0; i < bA->nr; i++) { 857d8588912SDave May if (bA->m[i][j]) { 8589566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL)); 859d8588912SDave May break; 860d8588912SDave May } 861d8588912SDave May } 86208401ef6SPierre Jolivet PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column."); 863d8588912SDave May } 8649566063dSJacob Faibussowitsch PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right)); 865d8588912SDave May /* hand back control to the nest vector */ 86648a46eb9SPierre Jolivet for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j])); 8679566063dSJacob Faibussowitsch PetscCall(PetscFree(R)); 868d8588912SDave May } 869d8588912SDave May 870d8588912SDave May if (left) { 871d8588912SDave May /* allocate L */ 8729566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bA->nr, &L)); 873d8588912SDave May /* Create the left vectors */ 874d8588912SDave May for (i = 0; i < bA->nr; i++) { 875d8588912SDave May for (j = 0; j < bA->nc; j++) { 876d8588912SDave May if (bA->m[i][j]) { 8779566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i])); 878d8588912SDave May break; 879d8588912SDave May } 880d8588912SDave May } 88108401ef6SPierre Jolivet PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row."); 882d8588912SDave May } 883d8588912SDave May 8849566063dSJacob Faibussowitsch PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left)); 88548a46eb9SPierre Jolivet for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i])); 886d8588912SDave May 8879566063dSJacob Faibussowitsch PetscCall(PetscFree(L)); 888d8588912SDave May } 8893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 890d8588912SDave May } 891d8588912SDave May 892d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer) 893d71ae5a4SJacob Faibussowitsch { 894d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 89529e60adbSStefano Zampini PetscBool isascii, viewSub = PETSC_FALSE; 896d8588912SDave May PetscInt i, j; 897d8588912SDave May 898d8588912SDave May PetscFunctionBegin; 8999566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 900d8588912SDave May if (isascii) { 9019566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL)); 9029566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object:\n")); 9039566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 9049566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", bA->nr, bA->nc)); 905d8588912SDave May 9069566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure:\n")); 907d8588912SDave May for (i = 0; i < bA->nr; i++) { 908d8588912SDave May for (j = 0; j < bA->nc; j++) { 90919fd82e9SBarry Smith MatType type; 910270f95d7SJed Brown char name[256] = "", prefix[256] = ""; 911d8588912SDave May PetscInt NR, NC; 912d8588912SDave May PetscBool isNest = PETSC_FALSE; 913d8588912SDave May 914d8588912SDave May if (!bA->m[i][j]) { 9159566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j)); 916d8588912SDave May continue; 917d8588912SDave May } 9189566063dSJacob Faibussowitsch PetscCall(MatGetSize(bA->m[i][j], &NR, &NC)); 9199566063dSJacob Faibussowitsch PetscCall(MatGetType(bA->m[i][j], &type)); 9209566063dSJacob Faibussowitsch if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name)); 9219566063dSJacob Faibussowitsch if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix)); 9229566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest)); 923d8588912SDave May 9249566063dSJacob 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)); 925d8588912SDave May 92629e60adbSStefano Zampini if (isNest || viewSub) { 9279566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */ 9289566063dSJacob Faibussowitsch PetscCall(MatView(bA->m[i][j], viewer)); 9299566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */ 930d8588912SDave May } 931d8588912SDave May } 932d8588912SDave May } 9339566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */ 934d8588912SDave May } 9353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 936d8588912SDave May } 937d8588912SDave May 938d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A) 939d71ae5a4SJacob Faibussowitsch { 940d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 941d8588912SDave May PetscInt i, j; 942d8588912SDave May 943d8588912SDave May PetscFunctionBegin; 944d8588912SDave May for (i = 0; i < bA->nr; i++) { 945d8588912SDave May for (j = 0; j < bA->nc; j++) { 946d8588912SDave May if (!bA->m[i][j]) continue; 9479566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(bA->m[i][j])); 948d8588912SDave May } 949d8588912SDave May } 9503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 951d8588912SDave May } 952d8588912SDave May 953d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str) 954d71ae5a4SJacob Faibussowitsch { 955c222c20dSDavid Ham Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data; 956c222c20dSDavid Ham PetscInt i, j, nr = bA->nr, nc = bA->nc; 95706a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 958c222c20dSDavid Ham 959c222c20dSDavid Ham PetscFunctionBegin; 960aed4548fSBarry 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); 961c222c20dSDavid Ham for (i = 0; i < nr; i++) { 962c222c20dSDavid Ham for (j = 0; j < nc; j++) { 96306a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 96446a2b97cSJed Brown if (bA->m[i][j] && bB->m[i][j]) { 9659566063dSJacob Faibussowitsch PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str)); 96608401ef6SPierre 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); 9679566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate)); 96806a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate); 96906a1af2fSStefano Zampini bB->nnzstate[i * nc + j] = subnnzstate; 970c222c20dSDavid Ham } 971c222c20dSDavid Ham } 97206a1af2fSStefano Zampini if (nnzstate) B->nonzerostate++; 9733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 974c222c20dSDavid Ham } 975c222c20dSDavid Ham 976d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str) 977d71ae5a4SJacob Faibussowitsch { 9786e76ffeaSPierre Jolivet Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data; 9796e76ffeaSPierre Jolivet PetscInt i, j, nr = bY->nr, nc = bY->nc; 98006a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 9816e76ffeaSPierre Jolivet 9826e76ffeaSPierre Jolivet PetscFunctionBegin; 983aed4548fSBarry 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); 9846e76ffeaSPierre Jolivet for (i = 0; i < nr; i++) { 9856e76ffeaSPierre Jolivet for (j = 0; j < nc; j++) { 98606a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 9876e76ffeaSPierre Jolivet if (bY->m[i][j] && bX->m[i][j]) { 9889566063dSJacob Faibussowitsch PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str)); 989c066aebcSStefano Zampini } else if (bX->m[i][j]) { 990c066aebcSStefano Zampini Mat M; 991c066aebcSStefano Zampini 992e75569e9SPierre Jolivet PetscCheck(str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN or UNKNOWN_NONZERO_PATTERN", i, j); 9939566063dSJacob Faibussowitsch PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M)); 9949566063dSJacob Faibussowitsch PetscCall(MatNestSetSubMat(Y, i, j, M)); 9959566063dSJacob Faibussowitsch PetscCall(MatDestroy(&M)); 996c066aebcSStefano Zampini } 9979566063dSJacob Faibussowitsch if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate)); 99806a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate); 99906a1af2fSStefano Zampini bY->nnzstate[i * nc + j] = subnnzstate; 10006e76ffeaSPierre Jolivet } 10016e76ffeaSPierre Jolivet } 100206a1af2fSStefano Zampini if (nnzstate) Y->nonzerostate++; 10033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10046e76ffeaSPierre Jolivet } 10056e76ffeaSPierre Jolivet 1006d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B) 1007d71ae5a4SJacob Faibussowitsch { 1008d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 1009841e96a3SJed Brown Mat *b; 1010841e96a3SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 1011d8588912SDave May 1012d8588912SDave May PetscFunctionBegin; 10139566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr * nc, &b)); 1014841e96a3SJed Brown for (i = 0; i < nr; i++) { 1015841e96a3SJed Brown for (j = 0; j < nc; j++) { 1016841e96a3SJed Brown if (bA->m[i][j]) { 10179566063dSJacob Faibussowitsch PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j])); 1018841e96a3SJed Brown } else { 10190298fd71SBarry Smith b[i * nc + j] = NULL; 1020d8588912SDave May } 1021d8588912SDave May } 1022d8588912SDave May } 10239566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B)); 1024841e96a3SJed Brown /* Give the new MatNest exclusive ownership */ 102548a46eb9SPierre Jolivet for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i])); 10269566063dSJacob Faibussowitsch PetscCall(PetscFree(b)); 1027d8588912SDave May 10289566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 10299566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 10303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1031d8588912SDave May } 1032d8588912SDave May 1033d8588912SDave May /* nest api */ 103466976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat) 1035d71ae5a4SJacob Faibussowitsch { 1036d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 10375fd66863SKarl Rupp 1038d8588912SDave May PetscFunctionBegin; 103908401ef6SPierre 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); 104008401ef6SPierre 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); 1041d8588912SDave May *mat = bA->m[idxm][jdxm]; 10423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1043d8588912SDave May } 1044d8588912SDave May 10459ba0d327SJed Brown /*@ 104611a5261eSBarry Smith MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST` 1047d8588912SDave May 10482ef1f0ffSBarry Smith Not Collective 1049d8588912SDave May 1050d8588912SDave May Input Parameters: 105111a5261eSBarry Smith + A - `MATNEST` matrix 1052d8588912SDave May . idxm - index of the matrix within the nest matrix 1053629881c0SJed Brown - jdxm - index of the matrix within the nest matrix 1054d8588912SDave May 1055d8588912SDave May Output Parameter: 10562ef1f0ffSBarry Smith . sub - matrix at index `idxm`, `jdxm` within the nest matrix 1057d8588912SDave May 1058d8588912SDave May Level: developer 1059d8588912SDave May 1060fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`, 1061db781477SPatrick Sanan `MatNestGetLocalISs()`, `MatNestGetISs()` 1062d8588912SDave May @*/ 1063d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub) 1064d71ae5a4SJacob Faibussowitsch { 1065d8588912SDave May PetscFunctionBegin; 1066cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub)); 10673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1068d8588912SDave May } 1069d8588912SDave May 107066976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat) 1071d71ae5a4SJacob Faibussowitsch { 10720782ca92SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 10730782ca92SJed Brown PetscInt m, n, M, N, mi, ni, Mi, Ni; 10740782ca92SJed Brown 10750782ca92SJed Brown PetscFunctionBegin; 107608401ef6SPierre 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); 107708401ef6SPierre 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); 10789566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 10799566063dSJacob Faibussowitsch PetscCall(MatGetSize(mat, &M, &N)); 10809566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi)); 10819566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi)); 10829566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni)); 10839566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni)); 1084aed4548fSBarry 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); 1085aed4548fSBarry 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); 108626fbe8dcSKarl Rupp 108706a1af2fSStefano Zampini /* do not increase object state */ 10883ba16761SJacob Faibussowitsch if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS); 108906a1af2fSStefano Zampini 10909566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat)); 10919566063dSJacob Faibussowitsch PetscCall(MatDestroy(&bA->m[idxm][jdxm])); 10920782ca92SJed Brown bA->m[idxm][jdxm] = mat; 10939566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)A)); 10949566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm])); 109506a1af2fSStefano Zampini A->nonzerostate++; 10963ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10970782ca92SJed Brown } 10980782ca92SJed Brown 10999ba0d327SJed Brown /*@ 110011a5261eSBarry Smith MatNestSetSubMat - Set a single submatrix in the `MATNEST` 11010782ca92SJed Brown 11022ef1f0ffSBarry Smith Logically Collective 11030782ca92SJed Brown 11040782ca92SJed Brown Input Parameters: 110511a5261eSBarry Smith + A - `MATNEST` matrix 11060782ca92SJed Brown . idxm - index of the matrix within the nest matrix 11070782ca92SJed Brown . jdxm - index of the matrix within the nest matrix 11082ef1f0ffSBarry Smith - sub - matrix at index `idxm`, `jdxm` within the nest matrix 11092ef1f0ffSBarry Smith 11102ef1f0ffSBarry Smith Level: developer 11110782ca92SJed Brown 11120782ca92SJed Brown Notes: 11130782ca92SJed Brown The new submatrix must have the same size and communicator as that block of the nest. 11140782ca92SJed Brown 11150782ca92SJed Brown This increments the reference count of the submatrix. 11160782ca92SJed Brown 1117fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`, 1118db781477SPatrick Sanan `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()` 11190782ca92SJed Brown @*/ 1120d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub) 1121d71ae5a4SJacob Faibussowitsch { 11220782ca92SJed Brown PetscFunctionBegin; 1123cac4c232SBarry Smith PetscUseMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub)); 11243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11250782ca92SJed Brown } 11260782ca92SJed Brown 112766976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) 1128d71ae5a4SJacob Faibussowitsch { 1129d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 11305fd66863SKarl Rupp 1131d8588912SDave May PetscFunctionBegin; 113226fbe8dcSKarl Rupp if (M) *M = bA->nr; 113326fbe8dcSKarl Rupp if (N) *N = bA->nc; 113426fbe8dcSKarl Rupp if (mat) *mat = bA->m; 11353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1136d8588912SDave May } 1137d8588912SDave May 1138d8588912SDave May /*@C 113911a5261eSBarry Smith MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix. 1140d8588912SDave May 11412ef1f0ffSBarry Smith Not Collective 1142d8588912SDave May 1143f899ff85SJose E. Roman Input Parameter: 1144629881c0SJed Brown . A - nest matrix 1145d8588912SDave May 1146d8d19677SJose E. Roman Output Parameters: 1147629881c0SJed Brown + M - number of rows in the nest matrix 1148d8588912SDave May . N - number of cols in the nest matrix 1149e9d3347aSJose E. Roman - mat - array of matrices 1150d8588912SDave May 11512ef1f0ffSBarry Smith Level: developer 11522ef1f0ffSBarry Smith 115311a5261eSBarry Smith Note: 11542ef1f0ffSBarry Smith The user should not free the array `mat`. 1155d8588912SDave May 1156fe59aa6dSJacob Faibussowitsch Fortran Notes: 115711a5261eSBarry Smith This routine has a calling sequence 1158351962e3SVincent Le Chenadec $ call MatNestGetSubMats(A, M, N, mat, ierr) 115920f4b53cSBarry Smith where the space allocated for the optional argument `mat` is assumed large enough (if provided). 1160e9d3347aSJose E. Roman Matrices in `mat` are returned in row-major order, see `MatCreateNest()` for an example. 1161351962e3SVincent Le Chenadec 1162fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`, 1163db781477SPatrick Sanan `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()` 1164d8588912SDave May @*/ 1165d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) 1166d71ae5a4SJacob Faibussowitsch { 1167d8588912SDave May PetscFunctionBegin; 1168cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat)); 11693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1170d8588912SDave May } 1171d8588912SDave May 117266976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N) 1173d71ae5a4SJacob Faibussowitsch { 1174d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 1175d8588912SDave May 1176d8588912SDave May PetscFunctionBegin; 117726fbe8dcSKarl Rupp if (M) *M = bA->nr; 117826fbe8dcSKarl Rupp if (N) *N = bA->nc; 11793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1180d8588912SDave May } 1181d8588912SDave May 11829ba0d327SJed Brown /*@ 118311a5261eSBarry Smith MatNestGetSize - Returns the size of the `MATNEST` matrix. 1184d8588912SDave May 11852ef1f0ffSBarry Smith Not Collective 1186d8588912SDave May 1187f899ff85SJose E. Roman Input Parameter: 118811a5261eSBarry Smith . A - `MATNEST` matrix 1189d8588912SDave May 1190d8d19677SJose E. Roman Output Parameters: 1191629881c0SJed Brown + M - number of rows in the nested mat 1192629881c0SJed Brown - N - number of cols in the nested mat 1193d8588912SDave May 1194d8588912SDave May Level: developer 1195d8588912SDave May 1196fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`, 1197db781477SPatrick Sanan `MatNestGetISs()` 1198d8588912SDave May @*/ 1199d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N) 1200d71ae5a4SJacob Faibussowitsch { 1201d8588912SDave May PetscFunctionBegin; 1202cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N)); 12033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1204d8588912SDave May } 1205d8588912SDave May 1206d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[]) 1207d71ae5a4SJacob Faibussowitsch { 1208900e7ff2SJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 1209900e7ff2SJed Brown PetscInt i; 1210900e7ff2SJed Brown 1211900e7ff2SJed Brown PetscFunctionBegin; 12129371c9d4SSatish Balay if (rows) 12139371c9d4SSatish Balay for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i]; 12149371c9d4SSatish Balay if (cols) 12159371c9d4SSatish Balay for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i]; 12163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1217900e7ff2SJed Brown } 1218900e7ff2SJed Brown 12193a4d7b9aSSatish Balay /*@C 122011a5261eSBarry Smith MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST` 1221900e7ff2SJed Brown 12222ef1f0ffSBarry Smith Not Collective 1223900e7ff2SJed Brown 1224f899ff85SJose E. Roman Input Parameter: 122511a5261eSBarry Smith . A - `MATNEST` matrix 1226900e7ff2SJed Brown 1227d8d19677SJose E. Roman Output Parameters: 1228900e7ff2SJed Brown + rows - array of row index sets 1229900e7ff2SJed Brown - cols - array of column index sets 1230900e7ff2SJed Brown 1231900e7ff2SJed Brown Level: advanced 1232900e7ff2SJed Brown 123311a5261eSBarry Smith Note: 12342ef1f0ffSBarry Smith The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s. 1235900e7ff2SJed Brown 1236fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`, 1237fe59aa6dSJacob Faibussowitsch `MatCreateNest()`, `MatNestSetSubMats()` 1238900e7ff2SJed Brown @*/ 1239d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[]) 1240d71ae5a4SJacob Faibussowitsch { 1241900e7ff2SJed Brown PetscFunctionBegin; 1242900e7ff2SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1243cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 12443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1245900e7ff2SJed Brown } 1246900e7ff2SJed Brown 1247d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[]) 1248d71ae5a4SJacob Faibussowitsch { 1249900e7ff2SJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 1250900e7ff2SJed Brown PetscInt i; 1251900e7ff2SJed Brown 1252900e7ff2SJed Brown PetscFunctionBegin; 12539371c9d4SSatish Balay if (rows) 12549371c9d4SSatish Balay for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i]; 12559371c9d4SSatish Balay if (cols) 12569371c9d4SSatish Balay for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i]; 12573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1258900e7ff2SJed Brown } 1259900e7ff2SJed Brown 1260900e7ff2SJed Brown /*@C 126111a5261eSBarry Smith MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST` 1262900e7ff2SJed Brown 12632ef1f0ffSBarry Smith Not Collective 1264900e7ff2SJed Brown 1265f899ff85SJose E. Roman Input Parameter: 126611a5261eSBarry Smith . A - `MATNEST` matrix 1267900e7ff2SJed Brown 1268d8d19677SJose E. Roman Output Parameters: 12692ef1f0ffSBarry Smith + rows - array of row index sets (or `NULL` to ignore) 12702ef1f0ffSBarry Smith - cols - array of column index sets (or `NULL` to ignore) 1271900e7ff2SJed Brown 1272900e7ff2SJed Brown Level: advanced 1273900e7ff2SJed Brown 127411a5261eSBarry Smith Note: 12752ef1f0ffSBarry Smith The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s. 1276900e7ff2SJed Brown 12771cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`, 1278fe59aa6dSJacob Faibussowitsch `MatNestSetSubMats()`, `MatNestSetSubMat()` 1279900e7ff2SJed Brown @*/ 1280d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[]) 1281d71ae5a4SJacob Faibussowitsch { 1282900e7ff2SJed Brown PetscFunctionBegin; 1283900e7ff2SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1284cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 12853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1286900e7ff2SJed Brown } 1287900e7ff2SJed Brown 128866976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype) 1289d71ae5a4SJacob Faibussowitsch { 1290207556f9SJed Brown PetscBool flg; 1291207556f9SJed Brown 1292207556f9SJed Brown PetscFunctionBegin; 12939566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, VECNEST, &flg)); 1294207556f9SJed Brown /* In reality, this only distinguishes VECNEST and "other" */ 12952a7a6963SBarry Smith if (flg) A->ops->getvecs = MatCreateVecs_Nest; 129612b53f24SSatish Balay else A->ops->getvecs = (PetscErrorCode(*)(Mat, Vec *, Vec *))0; 12973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1298207556f9SJed Brown } 1299207556f9SJed Brown 1300207556f9SJed Brown /*@C 130111a5261eSBarry Smith MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()` 1302207556f9SJed Brown 13032ef1f0ffSBarry Smith Not Collective 1304207556f9SJed Brown 1305207556f9SJed Brown Input Parameters: 130611a5261eSBarry Smith + A - `MATNEST` matrix 130711a5261eSBarry Smith - vtype - `VecType` to use for creating vectors 1308207556f9SJed Brown 1309207556f9SJed Brown Level: developer 1310207556f9SJed Brown 1311fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType` 1312207556f9SJed Brown @*/ 1313d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype) 1314d71ae5a4SJacob Faibussowitsch { 1315207556f9SJed Brown PetscFunctionBegin; 1316cac4c232SBarry Smith PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype)); 13173ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1318207556f9SJed Brown } 1319207556f9SJed Brown 132066976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) 1321d71ae5a4SJacob Faibussowitsch { 1322c8883902SJed Brown Mat_Nest *s = (Mat_Nest *)A->data; 1323c8883902SJed Brown PetscInt i, j, m, n, M, N; 132488ffe2e8SJose E. Roman PetscBool cong, isstd, sametype = PETSC_FALSE; 132588ffe2e8SJose E. Roman VecType vtype, type; 1326d8588912SDave May 1327d8588912SDave May PetscFunctionBegin; 13289566063dSJacob Faibussowitsch PetscCall(MatReset_Nest(A)); 132906a1af2fSStefano Zampini 1330c8883902SJed Brown s->nr = nr; 1331c8883902SJed Brown s->nc = nc; 1332d8588912SDave May 1333c8883902SJed Brown /* Create space for submatrices */ 13349566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &s->m)); 133548a46eb9SPierre Jolivet for (i = 0; i < nr; i++) PetscCall(PetscMalloc1(nc, &s->m[i])); 1336c8883902SJed Brown for (i = 0; i < nr; i++) { 1337c8883902SJed Brown for (j = 0; j < nc; j++) { 1338c8883902SJed Brown s->m[i][j] = a[i * nc + j]; 133948a46eb9SPierre Jolivet if (a[i * nc + j]) PetscCall(PetscObjectReference((PetscObject)a[i * nc + j])); 1340d8588912SDave May } 1341d8588912SDave May } 13429566063dSJacob Faibussowitsch PetscCall(MatGetVecType(A, &vtype)); 13439566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd)); 134488ffe2e8SJose E. Roman if (isstd) { 134588ffe2e8SJose E. Roman /* check if all blocks have the same vectype */ 134688ffe2e8SJose E. Roman vtype = NULL; 134788ffe2e8SJose E. Roman for (i = 0; i < nr; i++) { 134888ffe2e8SJose E. Roman for (j = 0; j < nc; j++) { 134988ffe2e8SJose E. Roman if (a[i * nc + j]) { 135088ffe2e8SJose E. Roman if (!vtype) { /* first visited block */ 13519566063dSJacob Faibussowitsch PetscCall(MatGetVecType(a[i * nc + j], &vtype)); 135288ffe2e8SJose E. Roman sametype = PETSC_TRUE; 135388ffe2e8SJose E. Roman } else if (sametype) { 13549566063dSJacob Faibussowitsch PetscCall(MatGetVecType(a[i * nc + j], &type)); 13559566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, type, &sametype)); 135688ffe2e8SJose E. Roman } 135788ffe2e8SJose E. Roman } 135888ffe2e8SJose E. Roman } 135988ffe2e8SJose E. Roman } 136088ffe2e8SJose E. Roman if (sametype) { /* propagate vectype */ 13619566063dSJacob Faibussowitsch PetscCall(MatSetVecType(A, vtype)); 136288ffe2e8SJose E. Roman } 136388ffe2e8SJose E. Roman } 1364d8588912SDave May 13659566063dSJacob Faibussowitsch PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col)); 1366d8588912SDave May 13679566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &s->row_len)); 13689566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &s->col_len)); 1369c8883902SJed Brown for (i = 0; i < nr; i++) s->row_len[i] = -1; 1370c8883902SJed Brown for (j = 0; j < nc; j++) s->col_len[j] = -1; 1371d8588912SDave May 13729566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr * nc, &s->nnzstate)); 137306a1af2fSStefano Zampini for (i = 0; i < nr; i++) { 137406a1af2fSStefano Zampini for (j = 0; j < nc; j++) { 137548a46eb9SPierre Jolivet if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j])); 137606a1af2fSStefano Zampini } 137706a1af2fSStefano Zampini } 137806a1af2fSStefano Zampini 13799566063dSJacob Faibussowitsch PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N)); 1380d8588912SDave May 13819566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(A->rmap, M)); 13829566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(A->rmap, m)); 13839566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(A->cmap, N)); 13849566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(A->cmap, n)); 1385c8883902SJed Brown 13869566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->rmap)); 13879566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->cmap)); 1388c8883902SJed Brown 138906a1af2fSStefano Zampini /* disable operations that are not supported for non-square matrices, 139006a1af2fSStefano Zampini or matrices for which is_row != is_col */ 13919566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(A, &cong)); 139206a1af2fSStefano Zampini if (cong && nr != nc) cong = PETSC_FALSE; 139306a1af2fSStefano Zampini if (cong) { 139448a46eb9SPierre Jolivet for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong)); 139506a1af2fSStefano Zampini } 139606a1af2fSStefano Zampini if (!cong) { 1397381b8e50SStefano Zampini A->ops->missingdiagonal = NULL; 139806a1af2fSStefano Zampini A->ops->getdiagonal = NULL; 139906a1af2fSStefano Zampini A->ops->shift = NULL; 140006a1af2fSStefano Zampini A->ops->diagonalset = NULL; 140106a1af2fSStefano Zampini } 140206a1af2fSStefano Zampini 14039566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right)); 14049566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)A)); 140506a1af2fSStefano Zampini A->nonzerostate++; 14063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1407d8588912SDave May } 1408d8588912SDave May 1409c8883902SJed Brown /*@ 141011a5261eSBarry Smith MatNestSetSubMats - Sets the nested submatrices in a `MATNEST` 1411c8883902SJed Brown 1412c3339decSBarry Smith Collective 1413c8883902SJed Brown 1414d8d19677SJose E. Roman Input Parameters: 141511a5261eSBarry Smith + A - `MATNEST` matrix 1416c8883902SJed Brown . nr - number of nested row blocks 14172ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous 1418c8883902SJed Brown . nc - number of nested column blocks 14192ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous 1420e9d3347aSJose E. Roman - a - array of nr*nc submatrices, empty submatrices can be passed using `NULL` 14212ef1f0ffSBarry Smith 14222ef1f0ffSBarry Smith Level: advanced 1423c8883902SJed Brown 1424e9d3347aSJose E. Roman Notes: 142511a5261eSBarry Smith This always resets any submatrix information previously set 142606a1af2fSStefano Zampini 1427e9d3347aSJose E. Roman In both C and Fortran, `a` must be a row-major order array containing the matrices. See 1428e9d3347aSJose E. Roman `MatCreateNest()` for an example. 1429e9d3347aSJose E. Roman 14301cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()` 1431c8883902SJed Brown @*/ 1432d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) 1433d71ae5a4SJacob Faibussowitsch { 143406a1af2fSStefano Zampini PetscInt i; 1435c8883902SJed Brown 1436c8883902SJed Brown PetscFunctionBegin; 1437c8883902SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 143808401ef6SPierre Jolivet PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative"); 1439c8883902SJed Brown if (nr && is_row) { 14404f572ea9SToby Isaac PetscAssertPointer(is_row, 3); 1441c8883902SJed Brown for (i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3); 1442c8883902SJed Brown } 144308401ef6SPierre Jolivet PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative"); 14441664e352SJed Brown if (nc && is_col) { 14454f572ea9SToby Isaac PetscAssertPointer(is_col, 5); 14469b30a8f6SBarry Smith for (i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5); 1447c8883902SJed Brown } 14484f572ea9SToby Isaac if (nr * nc > 0) PetscAssertPointer(a, 6); 1449cac4c232SBarry Smith PetscUseMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a)); 14503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1451c8883902SJed Brown } 1452d8588912SDave May 1453d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog) 1454d71ae5a4SJacob Faibussowitsch { 145577019fcaSJed Brown PetscBool flg; 145677019fcaSJed Brown PetscInt i, j, m, mi, *ix; 145777019fcaSJed Brown 145877019fcaSJed Brown PetscFunctionBegin; 1459aea6d515SStefano Zampini *ltog = NULL; 146077019fcaSJed Brown for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) { 146177019fcaSJed Brown if (islocal[i]) { 14629566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(islocal[i], &mi)); 146377019fcaSJed Brown flg = PETSC_TRUE; /* We found a non-trivial entry */ 146477019fcaSJed Brown } else { 14659566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mi)); 146677019fcaSJed Brown } 146777019fcaSJed Brown m += mi; 146877019fcaSJed Brown } 14693ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 1470aea6d515SStefano Zampini 14719566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &ix)); 1472165cd838SBarry Smith for (i = 0, m = 0; i < n; i++) { 14730298fd71SBarry Smith ISLocalToGlobalMapping smap = NULL; 1474e108cb99SStefano Zampini Mat sub = NULL; 1475f6d38dbbSStefano Zampini PetscSF sf; 1476f6d38dbbSStefano Zampini PetscLayout map; 1477aea6d515SStefano Zampini const PetscInt *ix2; 147877019fcaSJed Brown 1479165cd838SBarry Smith if (!colflg) { 14809566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 148177019fcaSJed Brown } else { 14829566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 148377019fcaSJed Brown } 1484191fd14bSBarry Smith if (sub) { 1485191fd14bSBarry Smith if (!colflg) { 14869566063dSJacob Faibussowitsch PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL)); 1487191fd14bSBarry Smith } else { 14889566063dSJacob Faibussowitsch PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap)); 1489191fd14bSBarry Smith } 1490191fd14bSBarry Smith } 149177019fcaSJed Brown /* 149277019fcaSJed Brown Now we need to extract the monolithic global indices that correspond to the given split global indices. 149377019fcaSJed 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. 149477019fcaSJed Brown */ 14959566063dSJacob Faibussowitsch PetscCall(ISGetIndices(isglobal[i], &ix2)); 1496aea6d515SStefano Zampini if (islocal[i]) { 1497aea6d515SStefano Zampini PetscInt *ilocal, *iremote; 1498aea6d515SStefano Zampini PetscInt mil, nleaves; 1499aea6d515SStefano Zampini 15009566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(islocal[i], &mi)); 150128b400f6SJacob Faibussowitsch PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map"); 1502aea6d515SStefano Zampini for (j = 0; j < mi; j++) ix[m + j] = j; 15039566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m)); 1504aea6d515SStefano Zampini 1505aea6d515SStefano Zampini /* PetscSFSetGraphLayout does not like negative indices */ 15069566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote)); 1507aea6d515SStefano Zampini for (j = 0, nleaves = 0; j < mi; j++) { 1508aea6d515SStefano Zampini if (ix[m + j] < 0) continue; 1509aea6d515SStefano Zampini ilocal[nleaves] = j; 1510aea6d515SStefano Zampini iremote[nleaves] = ix[m + j]; 1511aea6d515SStefano Zampini nleaves++; 1512aea6d515SStefano Zampini } 15139566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mil)); 15149566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf)); 15159566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map)); 15169566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(map, mil)); 15179566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(map)); 15189566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote)); 15199566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&map)); 15209566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 15219566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 15229566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&sf)); 15239566063dSJacob Faibussowitsch PetscCall(PetscFree2(ilocal, iremote)); 1524aea6d515SStefano Zampini } else { 15259566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mi)); 1526aea6d515SStefano Zampini for (j = 0; j < mi; j++) ix[m + j] = ix2[i]; 1527aea6d515SStefano Zampini } 15289566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(isglobal[i], &ix2)); 152977019fcaSJed Brown m += mi; 153077019fcaSJed Brown } 15319566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog)); 15323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 153377019fcaSJed Brown } 153477019fcaSJed Brown 1535d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */ 1536d8588912SDave May /* 1537d8588912SDave May nprocessors = NP 1538d8588912SDave May Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1)) 1539d8588912SDave May proc 0: => (g_0,h_0,) 1540d8588912SDave May proc 1: => (g_1,h_1,) 1541d8588912SDave May ... 1542d8588912SDave May proc nprocs-1: => (g_NP-1,h_NP-1,) 1543d8588912SDave May 1544d8588912SDave May proc 0: proc 1: proc nprocs-1: 1545d8588912SDave May is[0] = (0,1,2,...,nlocal(g_0)-1) (0,1,...,nlocal(g_1)-1) (0,1,...,nlocal(g_NP-1)) 1546d8588912SDave May 1547d8588912SDave May proc 0: 1548d8588912SDave May is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1) 1549d8588912SDave May proc 1: 1550d8588912SDave May is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1) 1551d8588912SDave May 1552d8588912SDave May proc NP-1: 1553d8588912SDave May is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1) 1554d8588912SDave May */ 1555d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[]) 1556d71ae5a4SJacob Faibussowitsch { 1557e2d7f03fSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 15588188e55aSJed Brown PetscInt i, j, offset, n, nsum, bs; 15590298fd71SBarry Smith Mat sub = NULL; 1560d8588912SDave May 1561d8588912SDave May PetscFunctionBegin; 15629566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &vs->isglobal.row)); 15639566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &vs->isglobal.col)); 1564d8588912SDave May if (is_row) { /* valid IS is passed in */ 1565a5b23f4aSJose E. Roman /* refs on is[] are incremented */ 1566e2d7f03fSJed Brown for (i = 0; i < vs->nr; i++) { 15679566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is_row[i])); 156826fbe8dcSKarl Rupp 1569e2d7f03fSJed Brown vs->isglobal.row[i] = is_row[i]; 1570d8588912SDave May } 15712ae74bdbSJed Brown } else { /* Create the ISs by inspecting sizes of a submatrix in each row */ 15728188e55aSJed Brown nsum = 0; 15738188e55aSJed Brown for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */ 15749566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 157528b400f6SJacob Faibussowitsch PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i); 15769566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, &n, NULL)); 157708401ef6SPierre Jolivet PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 15788188e55aSJed Brown nsum += n; 15798188e55aSJed Brown } 15809566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 158130bc264bSJed Brown offset -= nsum; 1582e2d7f03fSJed Brown for (i = 0; i < vs->nr; i++) { 15839566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 15849566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, &n, NULL)); 15859566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 15869566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i])); 15879566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs)); 15882ae74bdbSJed Brown offset += n; 1589d8588912SDave May } 1590d8588912SDave May } 1591d8588912SDave May 1592d8588912SDave May if (is_col) { /* valid IS is passed in */ 1593a5b23f4aSJose E. Roman /* refs on is[] are incremented */ 1594e2d7f03fSJed Brown for (j = 0; j < vs->nc; j++) { 15959566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is_col[j])); 159626fbe8dcSKarl Rupp 1597e2d7f03fSJed Brown vs->isglobal.col[j] = is_col[j]; 1598d8588912SDave May } 15992ae74bdbSJed Brown } else { /* Create the ISs by inspecting sizes of a submatrix in each column */ 16002ae74bdbSJed Brown offset = A->cmap->rstart; 16018188e55aSJed Brown nsum = 0; 16028188e55aSJed Brown for (j = 0; j < vs->nc; j++) { 16039566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 160428b400f6SJacob Faibussowitsch PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i); 16059566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, NULL, &n)); 160608401ef6SPierre Jolivet PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 16078188e55aSJed Brown nsum += n; 16088188e55aSJed Brown } 16099566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 161030bc264bSJed Brown offset -= nsum; 1611e2d7f03fSJed Brown for (j = 0; j < vs->nc; j++) { 16129566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 16139566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, NULL, &n)); 16149566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 16159566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j])); 16169566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs)); 16172ae74bdbSJed Brown offset += n; 1618d8588912SDave May } 1619d8588912SDave May } 1620e2d7f03fSJed Brown 1621e2d7f03fSJed Brown /* Set up the local ISs */ 16229566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row)); 16239566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col)); 1624e2d7f03fSJed Brown for (i = 0, offset = 0; i < vs->nr; i++) { 1625e2d7f03fSJed Brown IS isloc; 16260298fd71SBarry Smith ISLocalToGlobalMapping rmap = NULL; 1627e2d7f03fSJed Brown PetscInt nlocal, bs; 16289566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 16299566063dSJacob Faibussowitsch if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL)); 1630207556f9SJed Brown if (rmap) { 16319566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 16329566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal)); 16339566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 16349566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(isloc, bs)); 1635207556f9SJed Brown } else { 1636207556f9SJed Brown nlocal = 0; 16370298fd71SBarry Smith isloc = NULL; 1638207556f9SJed Brown } 1639e2d7f03fSJed Brown vs->islocal.row[i] = isloc; 1640e2d7f03fSJed Brown offset += nlocal; 1641e2d7f03fSJed Brown } 16428188e55aSJed Brown for (i = 0, offset = 0; i < vs->nc; i++) { 1643e2d7f03fSJed Brown IS isloc; 16440298fd71SBarry Smith ISLocalToGlobalMapping cmap = NULL; 1645e2d7f03fSJed Brown PetscInt nlocal, bs; 16469566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 16479566063dSJacob Faibussowitsch if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap)); 1648207556f9SJed Brown if (cmap) { 16499566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 16509566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal)); 16519566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 16529566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(isloc, bs)); 1653207556f9SJed Brown } else { 1654207556f9SJed Brown nlocal = 0; 16550298fd71SBarry Smith isloc = NULL; 1656207556f9SJed Brown } 1657e2d7f03fSJed Brown vs->islocal.col[i] = isloc; 1658e2d7f03fSJed Brown offset += nlocal; 1659e2d7f03fSJed Brown } 16600189643fSJed Brown 166177019fcaSJed Brown /* Set up the aggregate ISLocalToGlobalMapping */ 166277019fcaSJed Brown { 166345b6f7e9SBarry Smith ISLocalToGlobalMapping rmap, cmap; 16649566063dSJacob Faibussowitsch PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap)); 16659566063dSJacob Faibussowitsch PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap)); 16669566063dSJacob Faibussowitsch if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap)); 16679566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingDestroy(&rmap)); 16689566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingDestroy(&cmap)); 166977019fcaSJed Brown } 167077019fcaSJed Brown 167176bd3646SJed Brown if (PetscDefined(USE_DEBUG)) { 16720189643fSJed Brown for (i = 0; i < vs->nr; i++) { 16730189643fSJed Brown for (j = 0; j < vs->nc; j++) { 16740189643fSJed Brown PetscInt m, n, M, N, mi, ni, Mi, Ni; 16750189643fSJed Brown Mat B = vs->m[i][j]; 16760189643fSJed Brown if (!B) continue; 16779566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, &M, &N)); 16789566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(B, &m, &n)); 16799566063dSJacob Faibussowitsch PetscCall(ISGetSize(vs->isglobal.row[i], &Mi)); 16809566063dSJacob Faibussowitsch PetscCall(ISGetSize(vs->isglobal.col[j], &Ni)); 16819566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi)); 16829566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni)); 1683aed4548fSBarry 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); 1684aed4548fSBarry 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); 16850189643fSJed Brown } 16860189643fSJed Brown } 168776bd3646SJed Brown } 1688a061e289SJed Brown 1689a061e289SJed Brown /* Set A->assembled if all non-null blocks are currently assembled */ 1690a061e289SJed Brown for (i = 0; i < vs->nr; i++) { 1691a061e289SJed Brown for (j = 0; j < vs->nc; j++) { 16923ba16761SJacob Faibussowitsch if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS); 1693a061e289SJed Brown } 1694a061e289SJed Brown } 1695a061e289SJed Brown A->assembled = PETSC_TRUE; 16963ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1697d8588912SDave May } 1698d8588912SDave May 169945c38901SJed Brown /*@C 170011a5261eSBarry Smith MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately 1701659c6bb0SJed Brown 170211a5261eSBarry Smith Collective 1703659c6bb0SJed Brown 1704d8d19677SJose E. Roman Input Parameters: 170511a5261eSBarry Smith + comm - Communicator for the new `MATNEST` 1706659c6bb0SJed Brown . nr - number of nested row blocks 17072ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous 1708659c6bb0SJed Brown . nc - number of nested column blocks 17092ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous 1710e9d3347aSJose E. Roman - a - array of nr*nc submatrices, empty submatrices can be passed using `NULL` 1711659c6bb0SJed Brown 1712659c6bb0SJed Brown Output Parameter: 1713659c6bb0SJed Brown . B - new matrix 1714659c6bb0SJed Brown 1715e9d3347aSJose E. Roman Note: 1716e9d3347aSJose E. Roman In both C and Fortran, `a` must be a row-major order array holding references to the matrices. 1717e9d3347aSJose E. Roman For instance, to represent the matrix 1718e9d3347aSJose E. Roman $\begin{bmatrix} A_{11} & A_{12} \\ A_{21} & A_{22}\end{bmatrix}$ 1719e9d3347aSJose E. Roman one should use `Mat a[4]={A11,A12,A21,A22}`. 1720e9d3347aSJose E. Roman 1721659c6bb0SJed Brown Level: advanced 1722659c6bb0SJed Brown 17231cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`, 1724db781477SPatrick Sanan `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`, 1725db781477SPatrick Sanan `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 1726659c6bb0SJed Brown @*/ 1727d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B) 1728d71ae5a4SJacob Faibussowitsch { 1729d8588912SDave May Mat A; 1730d8588912SDave May 1731d8588912SDave May PetscFunctionBegin; 1732f4259b30SLisandro Dalcin *B = NULL; 17339566063dSJacob Faibussowitsch PetscCall(MatCreate(comm, &A)); 17349566063dSJacob Faibussowitsch PetscCall(MatSetType(A, MATNEST)); 173591a28eb3SBarry Smith A->preallocated = PETSC_TRUE; 17369566063dSJacob Faibussowitsch PetscCall(MatNestSetSubMats(A, nr, is_row, nc, is_col, a)); 1737d8588912SDave May *B = A; 17383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1739d8588912SDave May } 1740659c6bb0SJed Brown 174166976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 1742d71ae5a4SJacob Faibussowitsch { 1743b68353e5Sstefano_zampini Mat_Nest *nest = (Mat_Nest *)A->data; 174423875855Sstefano_zampini Mat *trans; 1745b68353e5Sstefano_zampini PetscScalar **avv; 1746b68353e5Sstefano_zampini PetscScalar *vv; 1747b68353e5Sstefano_zampini PetscInt **aii, **ajj; 1748b68353e5Sstefano_zampini PetscInt *ii, *jj, *ci; 1749b68353e5Sstefano_zampini PetscInt nr, nc, nnz, i, j; 1750b68353e5Sstefano_zampini PetscBool done; 1751b68353e5Sstefano_zampini 1752b68353e5Sstefano_zampini PetscFunctionBegin; 17539566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &nr, &nc)); 1754b68353e5Sstefano_zampini if (reuse == MAT_REUSE_MATRIX) { 1755b68353e5Sstefano_zampini PetscInt rnr; 1756b68353e5Sstefano_zampini 17579566063dSJacob Faibussowitsch PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done)); 175828b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ"); 175908401ef6SPierre Jolivet PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows"); 17609566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArray(*newmat, &vv)); 1761b68353e5Sstefano_zampini } 1762b68353e5Sstefano_zampini /* extract CSR for nested SeqAIJ matrices */ 1763b68353e5Sstefano_zampini nnz = 0; 17649566063dSJacob Faibussowitsch PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans)); 1765b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1766b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1767b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1768b68353e5Sstefano_zampini if (B) { 1769b68353e5Sstefano_zampini PetscScalar *naa; 1770b68353e5Sstefano_zampini PetscInt *nii, *njj, nnr; 177123875855Sstefano_zampini PetscBool istrans; 1772b68353e5Sstefano_zampini 1773013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans)); 177423875855Sstefano_zampini if (istrans) { 177523875855Sstefano_zampini Mat Bt; 177623875855Sstefano_zampini 17779566063dSJacob Faibussowitsch PetscCall(MatTransposeGetMat(B, &Bt)); 17789566063dSJacob Faibussowitsch PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 177923875855Sstefano_zampini B = trans[i * nest->nc + j]; 1780013e2dc7SBarry Smith } else { 1781013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans)); 1782013e2dc7SBarry Smith if (istrans) { 1783013e2dc7SBarry Smith Mat Bt; 1784013e2dc7SBarry Smith 1785013e2dc7SBarry Smith PetscCall(MatHermitianTransposeGetMat(B, &Bt)); 1786013e2dc7SBarry Smith PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 1787013e2dc7SBarry Smith B = trans[i * nest->nc + j]; 1788013e2dc7SBarry Smith } 178923875855Sstefano_zampini } 17909566063dSJacob Faibussowitsch PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done)); 179128b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ"); 17929566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArray(B, &naa)); 1793b68353e5Sstefano_zampini nnz += nii[nnr]; 1794b68353e5Sstefano_zampini 1795b68353e5Sstefano_zampini aii[i * nest->nc + j] = nii; 1796b68353e5Sstefano_zampini ajj[i * nest->nc + j] = njj; 1797b68353e5Sstefano_zampini avv[i * nest->nc + j] = naa; 1798b68353e5Sstefano_zampini } 1799b68353e5Sstefano_zampini } 1800b68353e5Sstefano_zampini } 1801b68353e5Sstefano_zampini if (reuse != MAT_REUSE_MATRIX) { 18029566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr + 1, &ii)); 18039566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &jj)); 18049566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &vv)); 1805b68353e5Sstefano_zampini } else { 180608401ef6SPierre Jolivet PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros"); 1807b68353e5Sstefano_zampini } 1808b68353e5Sstefano_zampini 1809b68353e5Sstefano_zampini /* new row pointer */ 18109566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(ii, nr + 1)); 1811b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1812b68353e5Sstefano_zampini PetscInt ncr, rst; 1813b68353e5Sstefano_zampini 18149566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 18159566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1816b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1817b68353e5Sstefano_zampini if (aii[i * nest->nc + j]) { 1818b68353e5Sstefano_zampini PetscInt *nii = aii[i * nest->nc + j]; 1819b68353e5Sstefano_zampini PetscInt ir; 1820b68353e5Sstefano_zampini 1821b68353e5Sstefano_zampini for (ir = rst; ir < ncr + rst; ++ir) { 1822b68353e5Sstefano_zampini ii[ir + 1] += nii[1] - nii[0]; 1823b68353e5Sstefano_zampini nii++; 1824b68353e5Sstefano_zampini } 1825b68353e5Sstefano_zampini } 1826b68353e5Sstefano_zampini } 1827b68353e5Sstefano_zampini } 1828b68353e5Sstefano_zampini for (i = 0; i < nr; i++) ii[i + 1] += ii[i]; 1829b68353e5Sstefano_zampini 1830b68353e5Sstefano_zampini /* construct CSR for the new matrix */ 18319566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr, &ci)); 1832b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1833b68353e5Sstefano_zampini PetscInt ncr, rst; 1834b68353e5Sstefano_zampini 18359566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 18369566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1837b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1838b68353e5Sstefano_zampini if (aii[i * nest->nc + j]) { 1839b68353e5Sstefano_zampini PetscScalar *nvv = avv[i * nest->nc + j]; 1840b68353e5Sstefano_zampini PetscInt *nii = aii[i * nest->nc + j]; 1841b68353e5Sstefano_zampini PetscInt *njj = ajj[i * nest->nc + j]; 1842b68353e5Sstefano_zampini PetscInt ir, cst; 1843b68353e5Sstefano_zampini 18449566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL)); 1845b68353e5Sstefano_zampini for (ir = rst; ir < ncr + rst; ++ir) { 1846b68353e5Sstefano_zampini PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir]; 1847b68353e5Sstefano_zampini 1848b68353e5Sstefano_zampini for (ij = 0; ij < rsize; ij++) { 1849b68353e5Sstefano_zampini jj[ist + ij] = *njj + cst; 1850b68353e5Sstefano_zampini vv[ist + ij] = *nvv; 1851b68353e5Sstefano_zampini njj++; 1852b68353e5Sstefano_zampini nvv++; 1853b68353e5Sstefano_zampini } 1854b68353e5Sstefano_zampini ci[ir] += rsize; 1855b68353e5Sstefano_zampini nii++; 1856b68353e5Sstefano_zampini } 1857b68353e5Sstefano_zampini } 1858b68353e5Sstefano_zampini } 1859b68353e5Sstefano_zampini } 18609566063dSJacob Faibussowitsch PetscCall(PetscFree(ci)); 1861b68353e5Sstefano_zampini 1862b68353e5Sstefano_zampini /* restore info */ 1863b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1864b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1865b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1866b68353e5Sstefano_zampini if (B) { 1867b68353e5Sstefano_zampini PetscInt nnr = 0, k = i * nest->nc + j; 186823875855Sstefano_zampini 186923875855Sstefano_zampini B = (trans[k] ? trans[k] : B); 18709566063dSJacob Faibussowitsch PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done)); 187128b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ"); 18729566063dSJacob Faibussowitsch PetscCall(MatSeqAIJRestoreArray(B, &avv[k])); 18739566063dSJacob Faibussowitsch PetscCall(MatDestroy(&trans[k])); 1874b68353e5Sstefano_zampini } 1875b68353e5Sstefano_zampini } 1876b68353e5Sstefano_zampini } 18779566063dSJacob Faibussowitsch PetscCall(PetscFree4(aii, ajj, avv, trans)); 1878b68353e5Sstefano_zampini 1879b68353e5Sstefano_zampini /* finalize newmat */ 1880b68353e5Sstefano_zampini if (reuse == MAT_INITIAL_MATRIX) { 18819566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat)); 1882b68353e5Sstefano_zampini } else if (reuse == MAT_INPLACE_MATRIX) { 1883b68353e5Sstefano_zampini Mat B; 1884b68353e5Sstefano_zampini 18859566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B)); 18869566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &B)); 1887b68353e5Sstefano_zampini } 18889566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY)); 18899566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY)); 1890b68353e5Sstefano_zampini { 1891b68353e5Sstefano_zampini Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data); 1892b68353e5Sstefano_zampini a->free_a = PETSC_TRUE; 1893b68353e5Sstefano_zampini a->free_ij = PETSC_TRUE; 1894b68353e5Sstefano_zampini } 18953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1896b68353e5Sstefano_zampini } 1897b68353e5Sstefano_zampini 1898d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X) 1899d71ae5a4SJacob Faibussowitsch { 1900be705e3aSPierre Jolivet Mat_Nest *nest = (Mat_Nest *)X->data; 1901be705e3aSPierre Jolivet PetscInt i, j, k, rstart; 1902be705e3aSPierre Jolivet PetscBool flg; 1903be705e3aSPierre Jolivet 1904be705e3aSPierre Jolivet PetscFunctionBegin; 1905be705e3aSPierre Jolivet /* Fill by row */ 1906be705e3aSPierre Jolivet for (j = 0; j < nest->nc; ++j) { 1907be705e3aSPierre Jolivet /* Using global column indices and ISAllGather() is not scalable. */ 1908be705e3aSPierre Jolivet IS bNis; 1909be705e3aSPierre Jolivet PetscInt bN; 1910be705e3aSPierre Jolivet const PetscInt *bNindices; 19119566063dSJacob Faibussowitsch PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 19129566063dSJacob Faibussowitsch PetscCall(ISGetSize(bNis, &bN)); 19139566063dSJacob Faibussowitsch PetscCall(ISGetIndices(bNis, &bNindices)); 1914be705e3aSPierre Jolivet for (i = 0; i < nest->nr; ++i) { 1915fd8a7442SPierre Jolivet Mat B = nest->m[i][j], D = NULL; 1916be705e3aSPierre Jolivet PetscInt bm, br; 1917be705e3aSPierre Jolivet const PetscInt *bmindices; 1918be705e3aSPierre Jolivet if (!B) continue; 1919013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 1920be705e3aSPierre Jolivet if (flg) { 1921cac4c232SBarry Smith PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 1922cac4c232SBarry Smith PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 19239566063dSJacob Faibussowitsch PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 1924be705e3aSPierre Jolivet B = D; 1925be705e3aSPierre Jolivet } 19269566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 1927be705e3aSPierre Jolivet if (flg) { 1928fd8a7442SPierre Jolivet if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 1929fd8a7442SPierre Jolivet else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 1930be705e3aSPierre Jolivet B = D; 1931be705e3aSPierre Jolivet } 19329566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 19339566063dSJacob Faibussowitsch PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 19349566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 1935be705e3aSPierre Jolivet for (br = 0; br < bm; ++br) { 1936be705e3aSPierre Jolivet PetscInt row = bmindices[br], brncols, *cols; 1937be705e3aSPierre Jolivet const PetscInt *brcols; 1938be705e3aSPierre Jolivet const PetscScalar *brcoldata; 1939be705e3aSPierre Jolivet PetscScalar *vals = NULL; 19409566063dSJacob Faibussowitsch PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 19419566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(brncols, &cols)); 1942be705e3aSPierre Jolivet for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]]; 1943be705e3aSPierre Jolivet /* 1944be705e3aSPierre Jolivet Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match. 1945be705e3aSPierre Jolivet Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES. 1946be705e3aSPierre Jolivet */ 1947be705e3aSPierre Jolivet if (a != 1.0) { 19489566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(brncols, &vals)); 1949be705e3aSPierre Jolivet for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k]; 19509566063dSJacob Faibussowitsch PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES)); 19519566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 1952be705e3aSPierre Jolivet } else { 19539566063dSJacob Faibussowitsch PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES)); 1954be705e3aSPierre Jolivet } 19559566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 19569566063dSJacob Faibussowitsch PetscCall(PetscFree(cols)); 1957be705e3aSPierre Jolivet } 1958fd8a7442SPierre Jolivet if (D) PetscCall(MatDestroy(&D)); 19599566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 1960be705e3aSPierre Jolivet } 19619566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(bNis, &bNindices)); 19629566063dSJacob Faibussowitsch PetscCall(ISDestroy(&bNis)); 1963be705e3aSPierre Jolivet } 19649566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY)); 19659566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY)); 19663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1967be705e3aSPierre Jolivet } 1968be705e3aSPierre Jolivet 196966976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 1970d71ae5a4SJacob Faibussowitsch { 1971629c3df2SDmitry Karpeev Mat_Nest *nest = (Mat_Nest *)A->data; 1972e30678d3SPierre Jolivet PetscInt m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend; 1973b68353e5Sstefano_zampini PetscMPIInt size; 1974629c3df2SDmitry Karpeev Mat C; 1975629c3df2SDmitry Karpeev 1976629c3df2SDmitry Karpeev PetscFunctionBegin; 19779566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 1978b68353e5Sstefano_zampini if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */ 1979b68353e5Sstefano_zampini PetscInt nf; 1980b68353e5Sstefano_zampini PetscBool fast; 1981b68353e5Sstefano_zampini 19829566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(newtype, MATAIJ, &fast)); 198348a46eb9SPierre Jolivet if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast)); 1984b68353e5Sstefano_zampini for (i = 0; i < nest->nr && fast; ++i) { 1985b68353e5Sstefano_zampini for (j = 0; j < nest->nc && fast; ++j) { 1986b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1987b68353e5Sstefano_zampini if (B) { 19889566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast)); 198923875855Sstefano_zampini if (!fast) { 199023875855Sstefano_zampini PetscBool istrans; 199123875855Sstefano_zampini 1992013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans)); 199323875855Sstefano_zampini if (istrans) { 199423875855Sstefano_zampini Mat Bt; 199523875855Sstefano_zampini 19969566063dSJacob Faibussowitsch PetscCall(MatTransposeGetMat(B, &Bt)); 19979566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 1998013e2dc7SBarry Smith } else { 1999013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans)); 2000013e2dc7SBarry Smith if (istrans) { 2001013e2dc7SBarry Smith Mat Bt; 2002013e2dc7SBarry Smith 2003013e2dc7SBarry Smith PetscCall(MatHermitianTransposeGetMat(B, &Bt)); 2004013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 2005013e2dc7SBarry Smith } 200623875855Sstefano_zampini } 2007b68353e5Sstefano_zampini } 2008b68353e5Sstefano_zampini } 2009b68353e5Sstefano_zampini } 2010b68353e5Sstefano_zampini } 2011b68353e5Sstefano_zampini for (i = 0, nf = 0; i < nest->nr && fast; ++i) { 20129566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast)); 2013b68353e5Sstefano_zampini if (fast) { 2014b68353e5Sstefano_zampini PetscInt f, s; 2015b68353e5Sstefano_zampini 20169566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s)); 20179371c9d4SSatish Balay if (f != nf || s != 1) { 20189371c9d4SSatish Balay fast = PETSC_FALSE; 20199371c9d4SSatish Balay } else { 20209566063dSJacob Faibussowitsch PetscCall(ISGetSize(nest->isglobal.row[i], &f)); 2021b68353e5Sstefano_zampini nf += f; 2022b68353e5Sstefano_zampini } 2023b68353e5Sstefano_zampini } 2024b68353e5Sstefano_zampini } 2025b68353e5Sstefano_zampini for (i = 0, nf = 0; i < nest->nc && fast; ++i) { 20269566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast)); 2027b68353e5Sstefano_zampini if (fast) { 2028b68353e5Sstefano_zampini PetscInt f, s; 2029b68353e5Sstefano_zampini 20309566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s)); 20319371c9d4SSatish Balay if (f != nf || s != 1) { 20329371c9d4SSatish Balay fast = PETSC_FALSE; 20339371c9d4SSatish Balay } else { 20349566063dSJacob Faibussowitsch PetscCall(ISGetSize(nest->isglobal.col[i], &f)); 2035b68353e5Sstefano_zampini nf += f; 2036b68353e5Sstefano_zampini } 2037b68353e5Sstefano_zampini } 2038b68353e5Sstefano_zampini } 2039b68353e5Sstefano_zampini if (fast) { 20409566063dSJacob Faibussowitsch PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat)); 20413ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2042b68353e5Sstefano_zampini } 2043b68353e5Sstefano_zampini } 20449566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, &N)); 20459566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, &n)); 20469566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend)); 2047d1487292SPierre Jolivet if (reuse == MAT_REUSE_MATRIX) C = *newmat; 2048d1487292SPierre Jolivet else { 20499566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C)); 20509566063dSJacob Faibussowitsch PetscCall(MatSetType(C, newtype)); 20519566063dSJacob Faibussowitsch PetscCall(MatSetSizes(C, m, n, M, N)); 2052629c3df2SDmitry Karpeev } 20539566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(2 * m, &dnnz)); 2054e30678d3SPierre Jolivet if (m) { 2055629c3df2SDmitry Karpeev onnz = dnnz + m; 2056629c3df2SDmitry Karpeev for (k = 0; k < m; k++) { 2057629c3df2SDmitry Karpeev dnnz[k] = 0; 2058629c3df2SDmitry Karpeev onnz[k] = 0; 2059629c3df2SDmitry Karpeev } 2060e30678d3SPierre Jolivet } 2061629c3df2SDmitry Karpeev for (j = 0; j < nest->nc; ++j) { 2062629c3df2SDmitry Karpeev IS bNis; 2063629c3df2SDmitry Karpeev PetscInt bN; 2064629c3df2SDmitry Karpeev const PetscInt *bNindices; 2065fd8a7442SPierre Jolivet PetscBool flg; 2066629c3df2SDmitry Karpeev /* Using global column indices and ISAllGather() is not scalable. */ 20679566063dSJacob Faibussowitsch PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 20689566063dSJacob Faibussowitsch PetscCall(ISGetSize(bNis, &bN)); 20699566063dSJacob Faibussowitsch PetscCall(ISGetIndices(bNis, &bNindices)); 2070629c3df2SDmitry Karpeev for (i = 0; i < nest->nr; ++i) { 2071629c3df2SDmitry Karpeev PetscSF bmsf; 2072649b366bSFande Kong PetscSFNode *iremote; 2073fd8a7442SPierre Jolivet Mat B = nest->m[i][j], D = NULL; 2074649b366bSFande Kong PetscInt bm, *sub_dnnz, *sub_onnz, br; 2075629c3df2SDmitry Karpeev const PetscInt *bmindices; 2076629c3df2SDmitry Karpeev if (!B) continue; 20779566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 20789566063dSJacob Faibussowitsch PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 20799566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf)); 20809566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &iremote)); 20819566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &sub_dnnz)); 20829566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &sub_onnz)); 2083649b366bSFande Kong for (k = 0; k < bm; ++k) { 2084649b366bSFande Kong sub_dnnz[k] = 0; 2085649b366bSFande Kong sub_onnz[k] = 0; 2086649b366bSFande Kong } 2087dead4d76SPierre Jolivet PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 2088fd8a7442SPierre Jolivet if (flg) { 2089fd8a7442SPierre Jolivet PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2090fd8a7442SPierre Jolivet PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2091fd8a7442SPierre Jolivet PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 2092fd8a7442SPierre Jolivet B = D; 2093fd8a7442SPierre Jolivet } 2094fd8a7442SPierre Jolivet PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 2095fd8a7442SPierre Jolivet if (flg) { 2096fd8a7442SPierre Jolivet if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 2097fd8a7442SPierre Jolivet else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 2098fd8a7442SPierre Jolivet B = D; 2099fd8a7442SPierre Jolivet } 2100629c3df2SDmitry Karpeev /* 2101629c3df2SDmitry Karpeev Locate the owners for all of the locally-owned global row indices for this row block. 2102629c3df2SDmitry Karpeev These determine the roots of PetscSF used to communicate preallocation data to row owners. 2103629c3df2SDmitry Karpeev The roots correspond to the dnnz and onnz entries; thus, there are two roots per row. 2104629c3df2SDmitry Karpeev */ 21059566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 2106629c3df2SDmitry Karpeev for (br = 0; br < bm; ++br) { 2107131c27b5Sprj- PetscInt row = bmindices[br], brncols, col; 2108629c3df2SDmitry Karpeev const PetscInt *brcols; 2109a4b3d3acSMatthew G Knepley PetscInt rowrel = 0; /* row's relative index on its owner rank */ 2110131c27b5Sprj- PetscMPIInt rowowner = 0; 21119566063dSJacob Faibussowitsch PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel)); 2112649b366bSFande Kong /* how many roots */ 21139371c9d4SSatish Balay iremote[br].rank = rowowner; 21149371c9d4SSatish Balay iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */ 2115649b366bSFande Kong /* get nonzero pattern */ 21169566063dSJacob Faibussowitsch PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL)); 2117629c3df2SDmitry Karpeev for (k = 0; k < brncols; k++) { 2118629c3df2SDmitry Karpeev col = bNindices[brcols[k]]; 2119649b366bSFande Kong if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) { 2120649b366bSFande Kong sub_dnnz[br]++; 2121649b366bSFande Kong } else { 2122649b366bSFande Kong sub_onnz[br]++; 2123649b366bSFande Kong } 2124629c3df2SDmitry Karpeev } 21259566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL)); 2126629c3df2SDmitry Karpeev } 2127fd8a7442SPierre Jolivet if (D) PetscCall(MatDestroy(&D)); 21289566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 2129629c3df2SDmitry Karpeev /* bsf will have to take care of disposing of bedges. */ 21309566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 21319566063dSJacob Faibussowitsch PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 21329566063dSJacob Faibussowitsch PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 21339566063dSJacob Faibussowitsch PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 21349566063dSJacob Faibussowitsch PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 21359566063dSJacob Faibussowitsch PetscCall(PetscFree(sub_dnnz)); 21369566063dSJacob Faibussowitsch PetscCall(PetscFree(sub_onnz)); 21379566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&bmsf)); 2138629c3df2SDmitry Karpeev } 21399566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(bNis, &bNindices)); 21409566063dSJacob Faibussowitsch PetscCall(ISDestroy(&bNis)); 214165a4a0a3Sstefano_zampini } 214265a4a0a3Sstefano_zampini /* Resize preallocation if overestimated */ 214365a4a0a3Sstefano_zampini for (i = 0; i < m; i++) { 214465a4a0a3Sstefano_zampini dnnz[i] = PetscMin(dnnz[i], A->cmap->n); 214565a4a0a3Sstefano_zampini onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n); 2146629c3df2SDmitry Karpeev } 21479566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz)); 21489566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz)); 21499566063dSJacob Faibussowitsch PetscCall(PetscFree(dnnz)); 21509566063dSJacob Faibussowitsch PetscCall(MatAXPY_Dense_Nest(C, 1.0, A)); 2151d1487292SPierre Jolivet if (reuse == MAT_INPLACE_MATRIX) { 21529566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &C)); 2153d1487292SPierre Jolivet } else *newmat = C; 21543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2155be705e3aSPierre Jolivet } 2156629c3df2SDmitry Karpeev 215766976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 2158d71ae5a4SJacob Faibussowitsch { 2159629c3df2SDmitry Karpeev Mat B; 2160be705e3aSPierre Jolivet PetscInt m, n, M, N; 2161be705e3aSPierre Jolivet 2162be705e3aSPierre Jolivet PetscFunctionBegin; 21639566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, &N)); 21649566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, &n)); 2165be705e3aSPierre Jolivet if (reuse == MAT_REUSE_MATRIX) { 2166be705e3aSPierre Jolivet B = *newmat; 21679566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(B)); 2168be705e3aSPierre Jolivet } else { 21699566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B)); 2170629c3df2SDmitry Karpeev } 21719566063dSJacob Faibussowitsch PetscCall(MatAXPY_Dense_Nest(B, 1.0, A)); 2172be705e3aSPierre Jolivet if (reuse == MAT_INPLACE_MATRIX) { 21739566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &B)); 2174be705e3aSPierre Jolivet } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B; 21753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2176629c3df2SDmitry Karpeev } 2177629c3df2SDmitry Karpeev 217866976f2fSJacob Faibussowitsch static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has) 2179d71ae5a4SJacob Faibussowitsch { 21808b7d3b4bSBarry Smith Mat_Nest *bA = (Mat_Nest *)mat->data; 21813c6db4c4SPierre Jolivet MatOperation opAdd; 21828b7d3b4bSBarry Smith PetscInt i, j, nr = bA->nr, nc = bA->nc; 21838b7d3b4bSBarry Smith PetscBool flg; 218452c5f739Sprj- PetscFunctionBegin; 21858b7d3b4bSBarry Smith 218652c5f739Sprj- *has = PETSC_FALSE; 21873c6db4c4SPierre Jolivet if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) { 21883c6db4c4SPierre Jolivet opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD); 21898b7d3b4bSBarry Smith for (j = 0; j < nc; j++) { 21908b7d3b4bSBarry Smith for (i = 0; i < nr; i++) { 21918b7d3b4bSBarry Smith if (!bA->m[i][j]) continue; 21929566063dSJacob Faibussowitsch PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg)); 21933ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 21948b7d3b4bSBarry Smith } 21958b7d3b4bSBarry Smith } 21968b7d3b4bSBarry Smith } 21973c6db4c4SPierre Jolivet if (((void **)mat->ops)[op]) *has = PETSC_TRUE; 21983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 21998b7d3b4bSBarry Smith } 22008b7d3b4bSBarry Smith 2201659c6bb0SJed Brown /*MC 22022ef1f0ffSBarry Smith MATNEST - "nest" - Matrix type consisting of nested submatrices, each stored separately. 2203659c6bb0SJed Brown 2204659c6bb0SJed Brown Level: intermediate 2205659c6bb0SJed Brown 2206659c6bb0SJed Brown Notes: 220711a5261eSBarry Smith This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices. 2208659c6bb0SJed Brown It allows the use of symmetric and block formats for parts of multi-physics simulations. 220911a5261eSBarry Smith It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()` 2210659c6bb0SJed Brown 22118b7d3b4bSBarry Smith Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero 22128b7d3b4bSBarry Smith rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes 22138b7d3b4bSBarry Smith than the nest matrix. 22148b7d3b4bSBarry Smith 22151cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, 2216db781477SPatrick Sanan `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`, 2217db781477SPatrick Sanan `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 2218659c6bb0SJed Brown M*/ 2219d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A) 2220d71ae5a4SJacob Faibussowitsch { 2221c8883902SJed Brown Mat_Nest *s; 2222c8883902SJed Brown 2223c8883902SJed Brown PetscFunctionBegin; 22244dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&s)); 2225c8883902SJed Brown A->data = (void *)s; 2226e7c19651SJed Brown 2227e7c19651SJed Brown s->nr = -1; 2228e7c19651SJed Brown s->nc = -1; 22290298fd71SBarry Smith s->m = NULL; 2230e7c19651SJed Brown s->splitassembly = PETSC_FALSE; 2231c8883902SJed Brown 22329566063dSJacob Faibussowitsch PetscCall(PetscMemzero(A->ops, sizeof(*A->ops))); 223326fbe8dcSKarl Rupp 2234c8883902SJed Brown A->ops->mult = MatMult_Nest; 22359194d70fSJed Brown A->ops->multadd = MatMultAdd_Nest; 2236c8883902SJed Brown A->ops->multtranspose = MatMultTranspose_Nest; 22379194d70fSJed Brown A->ops->multtransposeadd = MatMultTransposeAdd_Nest; 2238f8170845SAlex Fikl A->ops->transpose = MatTranspose_Nest; 2239c8883902SJed Brown A->ops->assemblybegin = MatAssemblyBegin_Nest; 2240c8883902SJed Brown A->ops->assemblyend = MatAssemblyEnd_Nest; 2241c8883902SJed Brown A->ops->zeroentries = MatZeroEntries_Nest; 2242c222c20dSDavid Ham A->ops->copy = MatCopy_Nest; 22436e76ffeaSPierre Jolivet A->ops->axpy = MatAXPY_Nest; 2244c8883902SJed Brown A->ops->duplicate = MatDuplicate_Nest; 22457dae84e0SHong Zhang A->ops->createsubmatrix = MatCreateSubMatrix_Nest; 2246c8883902SJed Brown A->ops->destroy = MatDestroy_Nest; 2247c8883902SJed Brown A->ops->view = MatView_Nest; 2248f4259b30SLisandro Dalcin A->ops->getvecs = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */ 2249c8883902SJed Brown A->ops->getlocalsubmatrix = MatGetLocalSubMatrix_Nest; 2250c8883902SJed Brown A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest; 2251429bac76SJed Brown A->ops->getdiagonal = MatGetDiagonal_Nest; 2252429bac76SJed Brown A->ops->diagonalscale = MatDiagonalScale_Nest; 2253a061e289SJed Brown A->ops->scale = MatScale_Nest; 2254a061e289SJed Brown A->ops->shift = MatShift_Nest; 225513135bc6SAlex Fikl A->ops->diagonalset = MatDiagonalSet_Nest; 2256f8170845SAlex Fikl A->ops->setrandom = MatSetRandom_Nest; 22578b7d3b4bSBarry Smith A->ops->hasoperation = MatHasOperation_Nest; 2258381b8e50SStefano Zampini A->ops->missingdiagonal = MatMissingDiagonal_Nest; 2259c8883902SJed Brown 2260f4259b30SLisandro Dalcin A->spptr = NULL; 2261c8883902SJed Brown A->assembled = PETSC_FALSE; 2262c8883902SJed Brown 2263c8883902SJed Brown /* expose Nest api's */ 22649566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest)); 22659566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest)); 22669566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest)); 22679566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest)); 22689566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest)); 22699566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest)); 22709566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest)); 22719566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest)); 22729566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ)); 22739566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ)); 22749566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ)); 22759566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS)); 22769566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense)); 22779566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense)); 22789566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense)); 22799566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense)); 2280c8883902SJed Brown 22819566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST)); 22823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2283c8883902SJed Brown } 2284