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)); 1248e3a54c0SPierre Jolivet PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dm[i + 1] - contents->dm[i], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset(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)); 1298e3a54c0SPierre Jolivet PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((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 14867af85e8SPierre Jolivet PetscCall(MatSetOption(C, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 1499566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 1509566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 1513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15252c5f739Sprj- } 15352c5f739Sprj- 15466976f2fSJacob Faibussowitsch static PetscErrorCode MatNest_DenseDestroy(void *ctx) 155d71ae5a4SJacob Faibussowitsch { 15652c5f739Sprj- Nest_Dense *contents = (Nest_Dense *)ctx; 15752c5f739Sprj- PetscInt i; 15852c5f739Sprj- 15952c5f739Sprj- PetscFunctionBegin; 1609566063dSJacob Faibussowitsch PetscCall(PetscFree(contents->tarray)); 16148a46eb9SPierre Jolivet for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i)); 1629566063dSJacob Faibussowitsch PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC)); 1639566063dSJacob Faibussowitsch PetscCall(PetscFree(contents)); 1643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16552c5f739Sprj- } 16652c5f739Sprj- 167a678f235SPierre Jolivet static PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C) 168d71ae5a4SJacob Faibussowitsch { 1696718818eSStefano Zampini Mat_Nest *bA; 1706718818eSStefano Zampini Mat viewB, workC; 17152c5f739Sprj- const PetscScalar *barray; 1726718818eSStefano Zampini PetscInt i, j, M, N, m, n, nr, nc, maxm = 0, ldb; 1734222ddf1SHong Zhang Nest_Dense *contents = NULL; 1746718818eSStefano Zampini PetscBool cisdense; 1756718818eSStefano Zampini Mat A, B; 1766718818eSStefano Zampini PetscReal fill; 17752c5f739Sprj- 17852c5f739Sprj- PetscFunctionBegin; 1790d6f747bSJacob Faibussowitsch MatCheckProduct(C, 1); 18028b400f6SJacob Faibussowitsch PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty"); 1816718818eSStefano Zampini A = C->product->A; 1826718818eSStefano Zampini B = C->product->B; 1836718818eSStefano Zampini fill = C->product->fill; 1846718818eSStefano Zampini bA = (Mat_Nest *)A->data; 1856718818eSStefano Zampini nr = bA->nr; 1866718818eSStefano Zampini nc = bA->nc; 1879566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(C, &m, &n)); 1889566063dSJacob Faibussowitsch PetscCall(MatGetSize(C, &M, &N)); 1890572eedcSPierre Jolivet if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) { 1909566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(B, NULL, &n)); 1919566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 1929566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, NULL)); 1939566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, NULL)); 1949566063dSJacob Faibussowitsch PetscCall(MatSetSizes(C, m, n, M, N)); 1950572eedcSPierre Jolivet } 1969566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, "")); 19748a46eb9SPierre Jolivet if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name)); 1989566063dSJacob Faibussowitsch PetscCall(MatSetUp(C)); 1996718818eSStefano Zampini if (!N) { 2006718818eSStefano Zampini C->ops->productnumeric = MatProductNumeric_Nest_Dense; 2013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 20252c5f739Sprj- } 20352c5f739Sprj- 2049566063dSJacob Faibussowitsch PetscCall(PetscNew(&contents)); 2056718818eSStefano Zampini C->product->data = contents; 2066718818eSStefano Zampini C->product->destroy = MatNest_DenseDestroy; 2079566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC)); 20852c5f739Sprj- contents->k = nr * nc; 20952c5f739Sprj- for (i = 0; i < nr; i++) { 2109566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1)); 21152c5f739Sprj- maxm = PetscMax(maxm, contents->dm[i + 1]); 21252c5f739Sprj- contents->dm[i + 1] += contents->dm[i]; 21352c5f739Sprj- } 21452c5f739Sprj- for (i = 0; i < nc; i++) { 2159566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1)); 21652c5f739Sprj- contents->dn[i + 1] += contents->dn[i]; 21752c5f739Sprj- } 2189566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(maxm * N, &contents->tarray)); 2199566063dSJacob Faibussowitsch PetscCall(MatDenseGetLDA(B, &ldb)); 2209566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 2219566063dSJacob Faibussowitsch PetscCall(MatDenseGetArrayRead(B, &barray)); 22252c5f739Sprj- /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */ 22352c5f739Sprj- for (j = 0; j < nc; j++) { 2249566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[j], &M)); 2258e3a54c0SPierre Jolivet PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB)); 2269566063dSJacob Faibussowitsch PetscCall(MatDenseSetLDA(viewB, ldb)); 22752c5f739Sprj- for (i = 0; i < nr; i++) { 22852c5f739Sprj- if (!bA->m[i][j]) continue; 22952c5f739Sprj- /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */ 2304222ddf1SHong Zhang 2319566063dSJacob Faibussowitsch PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j])); 2324222ddf1SHong Zhang workC = contents->workC[i * nc + j]; 2339566063dSJacob Faibussowitsch PetscCall(MatProductSetType(workC, MATPRODUCT_AB)); 2349566063dSJacob Faibussowitsch PetscCall(MatProductSetAlgorithm(workC, "default")); 2359566063dSJacob Faibussowitsch PetscCall(MatProductSetFill(workC, fill)); 2369566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(workC)); 2379566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(workC)); 2384222ddf1SHong Zhang 2396718818eSStefano Zampini /* since tarray will be shared by all Mat */ 2409566063dSJacob Faibussowitsch PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray)); 2419566063dSJacob Faibussowitsch PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray)); 24252c5f739Sprj- } 2439566063dSJacob Faibussowitsch PetscCall(MatDestroy(&viewB)); 24452c5f739Sprj- } 2459566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArrayRead(B, &barray)); 24652c5f739Sprj- 2476718818eSStefano Zampini C->ops->productnumeric = MatProductNumeric_Nest_Dense; 2483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 24952c5f739Sprj- } 25052c5f739Sprj- 251a678f235SPierre Jolivet static PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C) 252d71ae5a4SJacob Faibussowitsch { 2534222ddf1SHong Zhang Mat_Product *product = C->product; 25452c5f739Sprj- 25552c5f739Sprj- PetscFunctionBegin; 256c57d7d18SPierre Jolivet if (product->type == MATPRODUCT_AB) C->ops->productsymbolic = MatProductSymbolic_Nest_Dense; 2573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 25852c5f739Sprj- } 25952c5f739Sprj- 2600998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeKernel_Nest(Mat A, Vec x, Vec y, PetscBool herm) 261d71ae5a4SJacob Faibussowitsch { 262d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 263207556f9SJed Brown Vec *bx = bA->left, *by = bA->right; 264207556f9SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 265d8588912SDave May 266d8588912SDave May PetscFunctionBegin; 2679566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 2689566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i])); 269207556f9SJed Brown for (j = 0; j < nc; j++) { 2709566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(by[j])); 271609e31cbSJed Brown for (i = 0; i < nr; i++) { 2726c75ac25SJed Brown if (!bA->m[i][j]) continue; 2730998551bSBlanca Mellado Pinto if (herm) PetscCall(MatMultHermitianTransposeAdd(bA->m[i][j], bx[i], by[j], by[j])); /* y[j] <- y[j] + (A[i][j])^H * x[i] */ 2740998551bSBlanca Mellado Pinto else PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j])); /* y[j] <- y[j] + (A[i][j])^T * x[i] */ 275d8588912SDave May } 276d8588912SDave May } 2779566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 2789566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i])); 2793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 280d8588912SDave May } 281d8588912SDave May 2820998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y) 2830998551bSBlanca Mellado Pinto { 2840998551bSBlanca Mellado Pinto PetscFunctionBegin; 2850998551bSBlanca Mellado Pinto PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_FALSE)); 2860998551bSBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 2870998551bSBlanca Mellado Pinto } 2880998551bSBlanca Mellado Pinto 2890998551bSBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Nest(Mat A, Vec x, Vec y) 2900998551bSBlanca Mellado Pinto { 2910998551bSBlanca Mellado Pinto PetscFunctionBegin; 2920998551bSBlanca Mellado Pinto PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_TRUE)); 2930998551bSBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 2940998551bSBlanca Mellado Pinto } 2950998551bSBlanca Mellado Pinto 2960998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeAddKernel_Nest(Mat A, Vec x, Vec y, Vec z, PetscBool herm) 297d71ae5a4SJacob Faibussowitsch { 2989194d70fSJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 2999194d70fSJed Brown Vec *bx = bA->left, *bz = bA->right; 3009194d70fSJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 3019194d70fSJed Brown 3029194d70fSJed Brown PetscFunctionBegin; 3039566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 3049566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i])); 3059194d70fSJed Brown for (j = 0; j < nc; j++) { 3069194d70fSJed Brown if (y != z) { 3079194d70fSJed Brown Vec by; 3089566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by)); 3099566063dSJacob Faibussowitsch PetscCall(VecCopy(by, bz[j])); 3109566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by)); 3119194d70fSJed Brown } 3129194d70fSJed Brown for (i = 0; i < nr; i++) { 3136c75ac25SJed Brown if (!bA->m[i][j]) continue; 3140998551bSBlanca Mellado Pinto if (herm) PetscCall(MatMultHermitianTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j])); /* z[j] <- y[j] + (A[i][j])^H * x[i] */ 3150998551bSBlanca Mellado Pinto else PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j])); /* z[j] <- y[j] + (A[i][j])^T * x[i] */ 3169194d70fSJed Brown } 3179194d70fSJed Brown } 3189566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 3199566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i])); 3203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3219194d70fSJed Brown } 3229194d70fSJed Brown 3230998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z) 3240998551bSBlanca Mellado Pinto { 3250998551bSBlanca Mellado Pinto PetscFunctionBegin; 3260998551bSBlanca Mellado Pinto PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_FALSE)); 3270998551bSBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 3280998551bSBlanca Mellado Pinto } 3290998551bSBlanca Mellado Pinto 3300998551bSBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z) 3310998551bSBlanca Mellado Pinto { 3320998551bSBlanca Mellado Pinto PetscFunctionBegin; 3330998551bSBlanca Mellado Pinto PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_TRUE)); 3340998551bSBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 3350998551bSBlanca Mellado Pinto } 3360998551bSBlanca Mellado Pinto 337d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B) 338d71ae5a4SJacob Faibussowitsch { 339f8170845SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data, *bC; 340f8170845SAlex Fikl Mat C; 341f8170845SAlex Fikl PetscInt i, j, nr = bA->nr, nc = bA->nc; 342f8170845SAlex Fikl 343f8170845SAlex Fikl PetscFunctionBegin; 3447fb60732SBarry Smith if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B)); 345aed4548fSBarry Smith PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place"); 346f8170845SAlex Fikl 347cf37664fSBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) { 348f8170845SAlex Fikl Mat *subs; 349f8170845SAlex Fikl IS *is_row, *is_col; 350f8170845SAlex Fikl 3519566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr * nc, &subs)); 3529566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col)); 3539566063dSJacob Faibussowitsch PetscCall(MatNestGetISs(A, is_row, is_col)); 354cf37664fSBarry Smith if (reuse == MAT_INPLACE_MATRIX) { 355ddeb9bd8SAlex Fikl for (i = 0; i < nr; i++) { 356ad540459SPierre Jolivet for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j]; 357ddeb9bd8SAlex Fikl } 358ddeb9bd8SAlex Fikl } 359ddeb9bd8SAlex Fikl 3609566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C)); 3619566063dSJacob Faibussowitsch PetscCall(PetscFree(subs)); 3629566063dSJacob Faibussowitsch PetscCall(PetscFree2(is_row, is_col)); 363f8170845SAlex Fikl } else { 364f8170845SAlex Fikl C = *B; 365f8170845SAlex Fikl } 366f8170845SAlex Fikl 367f8170845SAlex Fikl bC = (Mat_Nest *)C->data; 368f8170845SAlex Fikl for (i = 0; i < nr; i++) { 369f8170845SAlex Fikl for (j = 0; j < nc; j++) { 370f8170845SAlex Fikl if (bA->m[i][j]) { 371f4f49eeaSPierre Jolivet PetscCall(MatTranspose(bA->m[i][j], reuse, &bC->m[j][i])); 372f8170845SAlex Fikl } else { 373f8170845SAlex Fikl bC->m[j][i] = NULL; 374f8170845SAlex Fikl } 375f8170845SAlex Fikl } 376f8170845SAlex Fikl } 377f8170845SAlex Fikl 378cf37664fSBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) { 379f8170845SAlex Fikl *B = C; 380f8170845SAlex Fikl } else { 3819566063dSJacob Faibussowitsch PetscCall(MatHeaderMerge(A, &C)); 382f8170845SAlex Fikl } 3833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 384f8170845SAlex Fikl } 385f8170845SAlex Fikl 386d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list) 387d71ae5a4SJacob Faibussowitsch { 388e2d7f03fSJed Brown IS *lst = *list; 389e2d7f03fSJed Brown PetscInt i; 390e2d7f03fSJed Brown 391e2d7f03fSJed Brown PetscFunctionBegin; 3923ba16761SJacob Faibussowitsch if (!lst) PetscFunctionReturn(PETSC_SUCCESS); 3939371c9d4SSatish Balay for (i = 0; i < n; i++) 3949371c9d4SSatish Balay if (lst[i]) PetscCall(ISDestroy(&lst[i])); 3959566063dSJacob Faibussowitsch PetscCall(PetscFree(lst)); 3960298fd71SBarry Smith *list = NULL; 3973ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 398e2d7f03fSJed Brown } 399e2d7f03fSJed Brown 400d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatReset_Nest(Mat A) 401d71ae5a4SJacob Faibussowitsch { 402d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 403d8588912SDave May PetscInt i, j; 404d8588912SDave May 405d8588912SDave May PetscFunctionBegin; 406d8588912SDave May /* release the matrices and the place holders */ 4079566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row)); 4089566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col)); 4099566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row)); 4109566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col)); 411d8588912SDave May 4129566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->row_len)); 4139566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->col_len)); 4149566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->nnzstate)); 415d8588912SDave May 4169566063dSJacob Faibussowitsch PetscCall(PetscFree2(vs->left, vs->right)); 417207556f9SJed Brown 418d8588912SDave May /* release the matrices and the place holders */ 419d8588912SDave May if (vs->m) { 420d8588912SDave May for (i = 0; i < vs->nr; i++) { 42148a46eb9SPierre Jolivet for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j])); 422d8588912SDave May } 4238068ee9dSPierre Jolivet PetscCall(PetscFree(vs->m[0])); 4249566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->m)); 425d8588912SDave May } 42606a1af2fSStefano Zampini 42706a1af2fSStefano Zampini /* restore defaults */ 42806a1af2fSStefano Zampini vs->nr = 0; 42906a1af2fSStefano Zampini vs->nc = 0; 43006a1af2fSStefano Zampini vs->splitassembly = PETSC_FALSE; 4313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 43206a1af2fSStefano Zampini } 43306a1af2fSStefano Zampini 434d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Nest(Mat A) 435d71ae5a4SJacob Faibussowitsch { 436362febeeSStefano Zampini PetscFunctionBegin; 4379566063dSJacob Faibussowitsch PetscCall(MatReset_Nest(A)); 4389566063dSJacob Faibussowitsch PetscCall(PetscFree(A->data)); 4399566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL)); 4409566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL)); 4419566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL)); 4429566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL)); 4439566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL)); 4449566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL)); 4459566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL)); 4469566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL)); 4479566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL)); 4489566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL)); 4499566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL)); 4509566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL)); 4519566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL)); 4529566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL)); 4539566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL)); 4549566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL)); 4553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 456d8588912SDave May } 457d8588912SDave May 458d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd) 459d71ae5a4SJacob Faibussowitsch { 460381b8e50SStefano Zampini Mat_Nest *vs = (Mat_Nest *)mat->data; 461381b8e50SStefano Zampini PetscInt i; 462381b8e50SStefano Zampini 463381b8e50SStefano Zampini PetscFunctionBegin; 464381b8e50SStefano Zampini if (dd) *dd = 0; 465381b8e50SStefano Zampini if (!vs->nr) { 466381b8e50SStefano Zampini *missing = PETSC_TRUE; 4673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 468381b8e50SStefano Zampini } 469381b8e50SStefano Zampini *missing = PETSC_FALSE; 470381b8e50SStefano Zampini for (i = 0; i < vs->nr && !(*missing); i++) { 471381b8e50SStefano Zampini *missing = PETSC_TRUE; 472381b8e50SStefano Zampini if (vs->m[i][i]) { 4739566063dSJacob Faibussowitsch PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL)); 47408401ef6SPierre Jolivet PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented"); 475381b8e50SStefano Zampini } 476381b8e50SStefano Zampini } 4773ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 478381b8e50SStefano Zampini } 479381b8e50SStefano Zampini 480d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type) 481d71ae5a4SJacob Faibussowitsch { 482d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 483d8588912SDave May PetscInt i, j; 48406a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 485d8588912SDave May 486d8588912SDave May PetscFunctionBegin; 487d8588912SDave May for (i = 0; i < vs->nr; i++) { 488d8588912SDave May for (j = 0; j < vs->nc; j++) { 48906a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 490e7c19651SJed Brown if (vs->m[i][j]) { 4919566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(vs->m[i][j], type)); 492e7c19651SJed Brown if (!vs->splitassembly) { 493e7c19651SJed Brown /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested 494e7c19651SJed 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 495e7c19651SJed Brown * already performing an assembly, but the result would by more complicated and appears to offer less 496e7c19651SJed Brown * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an 497e7c19651SJed Brown * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives". 498e7c19651SJed Brown */ 4999566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 5009566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate)); 501e7c19651SJed Brown } 502e7c19651SJed Brown } 50306a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate); 50406a1af2fSStefano Zampini vs->nnzstate[i * vs->nc + j] = subnnzstate; 505d8588912SDave May } 506d8588912SDave May } 50706a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 5083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 509d8588912SDave May } 510d8588912SDave May 511d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type) 512d71ae5a4SJacob Faibussowitsch { 513d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 514d8588912SDave May PetscInt i, j; 515d8588912SDave May 516d8588912SDave May PetscFunctionBegin; 517d8588912SDave May for (i = 0; i < vs->nr; i++) { 518d8588912SDave May for (j = 0; j < vs->nc; j++) { 519e7c19651SJed Brown if (vs->m[i][j]) { 52048a46eb9SPierre Jolivet if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 521e7c19651SJed Brown } 522d8588912SDave May } 523d8588912SDave May } 5243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 525d8588912SDave May } 526d8588912SDave May 527d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B) 528d71ae5a4SJacob Faibussowitsch { 529f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 530f349c1fdSJed Brown PetscInt j; 531f349c1fdSJed Brown Mat sub; 532d8588912SDave May 533d8588912SDave May PetscFunctionBegin; 5340298fd71SBarry Smith sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */ 535f349c1fdSJed Brown for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j]; 5369566063dSJacob Faibussowitsch if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 537f349c1fdSJed Brown *B = sub; 5383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 539d8588912SDave May } 540d8588912SDave May 541d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B) 542d71ae5a4SJacob Faibussowitsch { 543f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 544f349c1fdSJed Brown PetscInt i; 545f349c1fdSJed Brown Mat sub; 546f349c1fdSJed Brown 547f349c1fdSJed Brown PetscFunctionBegin; 5480298fd71SBarry Smith sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */ 549f349c1fdSJed Brown for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col]; 5509566063dSJacob Faibussowitsch if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 551f349c1fdSJed Brown *B = sub; 5523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 553d8588912SDave May } 554d8588912SDave May 555d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end) 556d71ae5a4SJacob Faibussowitsch { 55718d228c0SPierre Jolivet PetscInt i, j, size, m; 558f349c1fdSJed Brown PetscBool flg; 55918d228c0SPierre Jolivet IS out, concatenate[2]; 560f349c1fdSJed Brown 561f349c1fdSJed Brown PetscFunctionBegin; 5624f572ea9SToby Isaac PetscAssertPointer(list, 3); 563f349c1fdSJed Brown PetscValidHeaderSpecific(is, IS_CLASSID, 4); 56418d228c0SPierre Jolivet if (begin) { 5654f572ea9SToby Isaac PetscAssertPointer(begin, 5); 56618d228c0SPierre Jolivet *begin = -1; 56718d228c0SPierre Jolivet } 56818d228c0SPierre Jolivet if (end) { 5694f572ea9SToby Isaac PetscAssertPointer(end, 6); 57018d228c0SPierre Jolivet *end = -1; 57118d228c0SPierre Jolivet } 572f349c1fdSJed Brown for (i = 0; i < n; i++) { 573207556f9SJed Brown if (!list[i]) continue; 5749566063dSJacob Faibussowitsch PetscCall(ISEqualUnsorted(list[i], is, &flg)); 575f349c1fdSJed Brown if (flg) { 57618d228c0SPierre Jolivet if (begin) *begin = i; 57718d228c0SPierre Jolivet if (end) *end = i + 1; 5783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 579f349c1fdSJed Brown } 580f349c1fdSJed Brown } 5819566063dSJacob Faibussowitsch PetscCall(ISGetSize(is, &size)); 58218d228c0SPierre Jolivet for (i = 0; i < n - 1; i++) { 58318d228c0SPierre Jolivet if (!list[i]) continue; 58418d228c0SPierre Jolivet m = 0; 5859566063dSJacob Faibussowitsch PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out)); 5869566063dSJacob Faibussowitsch PetscCall(ISGetSize(out, &m)); 58718d228c0SPierre Jolivet for (j = i + 2; j < n && m < size; j++) { 58818d228c0SPierre Jolivet if (list[j]) { 58918d228c0SPierre Jolivet concatenate[0] = out; 59018d228c0SPierre Jolivet concatenate[1] = list[j]; 5919566063dSJacob Faibussowitsch PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out)); 5929566063dSJacob Faibussowitsch PetscCall(ISDestroy(concatenate)); 5939566063dSJacob Faibussowitsch PetscCall(ISGetSize(out, &m)); 59418d228c0SPierre Jolivet } 59518d228c0SPierre Jolivet } 59618d228c0SPierre Jolivet if (m == size) { 5979566063dSJacob Faibussowitsch PetscCall(ISEqualUnsorted(out, is, &flg)); 59818d228c0SPierre Jolivet if (flg) { 59918d228c0SPierre Jolivet if (begin) *begin = i; 60018d228c0SPierre Jolivet if (end) *end = j; 6019566063dSJacob Faibussowitsch PetscCall(ISDestroy(&out)); 6023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 60318d228c0SPierre Jolivet } 60418d228c0SPierre Jolivet } 6059566063dSJacob Faibussowitsch PetscCall(ISDestroy(&out)); 60618d228c0SPierre Jolivet } 6073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 608f349c1fdSJed Brown } 609f349c1fdSJed Brown 610d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B) 611d71ae5a4SJacob Faibussowitsch { 6128188e55aSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 61318d228c0SPierre Jolivet PetscInt lr, lc; 61418d228c0SPierre Jolivet 61518d228c0SPierre Jolivet PetscFunctionBegin; 6169566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 6179566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr)); 6189566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc)); 6199566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE)); 6209566063dSJacob Faibussowitsch PetscCall(MatSetType(*B, MATAIJ)); 6219566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL)); 6229566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL)); 6239566063dSJacob Faibussowitsch PetscCall(MatSetUp(*B)); 6249566063dSJacob Faibussowitsch PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 6259566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 6269566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 6273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 62818d228c0SPierre Jolivet } 62918d228c0SPierre Jolivet 630d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B) 631d71ae5a4SJacob Faibussowitsch { 63218d228c0SPierre Jolivet Mat_Nest *vs = (Mat_Nest *)A->data; 63318d228c0SPierre Jolivet Mat *a; 63418d228c0SPierre Jolivet PetscInt i, j, k, l, nr = rend - rbegin, nc = cend - cbegin; 6358188e55aSJed Brown char keyname[256]; 63618d228c0SPierre Jolivet PetscBool *b; 63718d228c0SPierre Jolivet PetscBool flg; 6388188e55aSJed Brown 6398188e55aSJed Brown PetscFunctionBegin; 6400298fd71SBarry Smith *B = NULL; 6419566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend)); 6429566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B)); 6433ba16761SJacob Faibussowitsch if (*B) PetscFunctionReturn(PETSC_SUCCESS); 6448188e55aSJed Brown 6459566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b)); 64618d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 64718d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 64818d228c0SPierre Jolivet a[i * nc + j] = vs->m[rbegin + i][cbegin + j]; 64918d228c0SPierre Jolivet b[i * nc + j] = PETSC_FALSE; 65018d228c0SPierre Jolivet } 65118d228c0SPierre Jolivet } 65218d228c0SPierre Jolivet if (nc != vs->nc && nr != vs->nr) { 65318d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 65418d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 65518d228c0SPierre Jolivet flg = PETSC_FALSE; 65618d228c0SPierre Jolivet for (k = 0; (k < nr && !flg); k++) { 65718d228c0SPierre Jolivet if (a[j + k * nc]) flg = PETSC_TRUE; 65818d228c0SPierre Jolivet } 65918d228c0SPierre Jolivet if (flg) { 66018d228c0SPierre Jolivet flg = PETSC_FALSE; 66118d228c0SPierre Jolivet for (l = 0; (l < nc && !flg); l++) { 66218d228c0SPierre Jolivet if (a[i * nc + l]) flg = PETSC_TRUE; 66318d228c0SPierre Jolivet } 66418d228c0SPierre Jolivet } 66518d228c0SPierre Jolivet if (!flg) { 66618d228c0SPierre Jolivet b[i * nc + j] = PETSC_TRUE; 6679566063dSJacob Faibussowitsch PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j)); 66818d228c0SPierre Jolivet } 66918d228c0SPierre Jolivet } 67018d228c0SPierre Jolivet } 67118d228c0SPierre Jolivet } 6729566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B)); 67318d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 67418d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 67548a46eb9SPierre Jolivet if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j)); 67618d228c0SPierre Jolivet } 67718d228c0SPierre Jolivet } 6789566063dSJacob Faibussowitsch PetscCall(PetscFree2(a, b)); 6798188e55aSJed Brown (*B)->assembled = A->assembled; 6809566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B)); 6819566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */ 6823ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6838188e55aSJed Brown } 6848188e55aSJed Brown 685d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B) 686d71ae5a4SJacob Faibussowitsch { 687f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 68818d228c0SPierre Jolivet PetscInt rbegin, rend, cbegin, cend; 689f349c1fdSJed Brown 690f349c1fdSJed Brown PetscFunctionBegin; 6919566063dSJacob Faibussowitsch PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend)); 6929566063dSJacob Faibussowitsch PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend)); 69318d228c0SPierre Jolivet if (rend == rbegin + 1 && cend == cbegin + 1) { 69448a46eb9SPierre Jolivet if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin)); 69518d228c0SPierre Jolivet *B = vs->m[rbegin][cbegin]; 69618d228c0SPierre Jolivet } else if (rbegin != -1 && cbegin != -1) { 6979566063dSJacob Faibussowitsch PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B)); 69818d228c0SPierre Jolivet } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set"); 6993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 700f349c1fdSJed Brown } 701f349c1fdSJed Brown 70206a1af2fSStefano Zampini /* 70306a1af2fSStefano Zampini TODO: This does not actually returns a submatrix we can modify 70406a1af2fSStefano Zampini */ 705d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B) 706d71ae5a4SJacob Faibussowitsch { 707f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 708f349c1fdSJed Brown Mat sub; 709f349c1fdSJed Brown 710f349c1fdSJed Brown PetscFunctionBegin; 7119566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub)); 712f349c1fdSJed Brown switch (reuse) { 713f349c1fdSJed Brown case MAT_INITIAL_MATRIX: 7149566063dSJacob Faibussowitsch if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 715f349c1fdSJed Brown *B = sub; 716f349c1fdSJed Brown break; 717d71ae5a4SJacob Faibussowitsch case MAT_REUSE_MATRIX: 718d71ae5a4SJacob Faibussowitsch PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call"); 719d71ae5a4SJacob Faibussowitsch break; 720d71ae5a4SJacob Faibussowitsch case MAT_IGNORE_MATRIX: /* Nothing to do */ 721d71ae5a4SJacob Faibussowitsch break; 722d71ae5a4SJacob Faibussowitsch case MAT_INPLACE_MATRIX: /* Nothing to do */ 723d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet"); 724f349c1fdSJed Brown } 7253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 726f349c1fdSJed Brown } 727f349c1fdSJed Brown 72866976f2fSJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) 729d71ae5a4SJacob Faibussowitsch { 730f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 731f349c1fdSJed Brown Mat sub; 732f349c1fdSJed Brown 733f349c1fdSJed Brown PetscFunctionBegin; 7349566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 735f349c1fdSJed Brown /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */ 7369566063dSJacob Faibussowitsch if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 737f349c1fdSJed Brown *B = sub; 7383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 739d8588912SDave May } 740d8588912SDave May 741d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) 742d71ae5a4SJacob Faibussowitsch { 743f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 744f349c1fdSJed Brown Mat sub; 745d8588912SDave May 746d8588912SDave May PetscFunctionBegin; 7479566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 74808401ef6SPierre Jolivet PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten"); 749f349c1fdSJed Brown if (sub) { 750aed4548fSBarry Smith PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times"); 7519566063dSJacob Faibussowitsch PetscCall(MatDestroy(B)); 752d8588912SDave May } 7533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 754d8588912SDave May } 755d8588912SDave May 756d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v) 757d71ae5a4SJacob Faibussowitsch { 7587874fa86SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 7597874fa86SDave May PetscInt i; 7607874fa86SDave May 7617874fa86SDave May PetscFunctionBegin; 7627874fa86SDave May for (i = 0; i < bA->nr; i++) { 763429bac76SJed Brown Vec bv; 7649566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv)); 7657874fa86SDave May if (bA->m[i][i]) { 7669566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(bA->m[i][i], bv)); 7677874fa86SDave May } else { 7689566063dSJacob Faibussowitsch PetscCall(VecSet(bv, 0.0)); 7697874fa86SDave May } 7709566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv)); 7717874fa86SDave May } 7723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 7737874fa86SDave May } 7747874fa86SDave May 775d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r) 776d71ae5a4SJacob Faibussowitsch { 7777874fa86SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 778429bac76SJed Brown Vec bl, *br; 7797874fa86SDave May PetscInt i, j; 7807874fa86SDave May 7817874fa86SDave May PetscFunctionBegin; 7829566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(bA->nc, &br)); 7832e6472ebSElliott Sales de Andrade if (r) { 7849566063dSJacob Faibussowitsch for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j])); 7852e6472ebSElliott Sales de Andrade } 7862e6472ebSElliott Sales de Andrade bl = NULL; 7877874fa86SDave May for (i = 0; i < bA->nr; i++) { 78848a46eb9SPierre Jolivet if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl)); 7897874fa86SDave May for (j = 0; j < bA->nc; j++) { 79048a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j])); 7917874fa86SDave May } 79248a46eb9SPierre Jolivet if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl)); 7932e6472ebSElliott Sales de Andrade } 7942e6472ebSElliott Sales de Andrade if (r) { 7959566063dSJacob Faibussowitsch for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j])); 7962e6472ebSElliott Sales de Andrade } 7979566063dSJacob Faibussowitsch PetscCall(PetscFree(br)); 7983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 7997874fa86SDave May } 8007874fa86SDave May 801d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a) 802d71ae5a4SJacob Faibussowitsch { 803a061e289SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 804a061e289SJed Brown PetscInt i, j; 805a061e289SJed Brown 806a061e289SJed Brown PetscFunctionBegin; 807a061e289SJed Brown for (i = 0; i < bA->nr; i++) { 808a061e289SJed Brown for (j = 0; j < bA->nc; j++) { 80948a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a)); 810a061e289SJed Brown } 811a061e289SJed Brown } 8123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 813a061e289SJed Brown } 814a061e289SJed Brown 815d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a) 816d71ae5a4SJacob Faibussowitsch { 817a061e289SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 818a061e289SJed Brown PetscInt i; 81906a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 820a061e289SJed Brown 821a061e289SJed Brown PetscFunctionBegin; 822a061e289SJed Brown for (i = 0; i < bA->nr; i++) { 82306a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 82408401ef6SPierre 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); 8259566063dSJacob Faibussowitsch PetscCall(MatShift(bA->m[i][i], a)); 8269566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 82706a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 82806a1af2fSStefano Zampini bA->nnzstate[i * bA->nc + i] = subnnzstate; 829a061e289SJed Brown } 83006a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 8313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 832a061e289SJed Brown } 833a061e289SJed Brown 834d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is) 835d71ae5a4SJacob Faibussowitsch { 83613135bc6SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data; 83713135bc6SAlex Fikl PetscInt i; 83806a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 83913135bc6SAlex Fikl 84013135bc6SAlex Fikl PetscFunctionBegin; 84113135bc6SAlex Fikl for (i = 0; i < bA->nr; i++) { 84206a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 84313135bc6SAlex Fikl Vec bv; 8449566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv)); 84513135bc6SAlex Fikl if (bA->m[i][i]) { 8469566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet(bA->m[i][i], bv, is)); 8479566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 84813135bc6SAlex Fikl } 8499566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv)); 85006a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 85106a1af2fSStefano Zampini bA->nnzstate[i * bA->nc + i] = subnnzstate; 85213135bc6SAlex Fikl } 85306a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 8543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 85513135bc6SAlex Fikl } 85613135bc6SAlex Fikl 857d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx) 858d71ae5a4SJacob Faibussowitsch { 859f8170845SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data; 860f8170845SAlex Fikl PetscInt i, j; 861f8170845SAlex Fikl 862f8170845SAlex Fikl PetscFunctionBegin; 863f8170845SAlex Fikl for (i = 0; i < bA->nr; i++) { 864f8170845SAlex Fikl for (j = 0; j < bA->nc; j++) { 86548a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx)); 866f8170845SAlex Fikl } 867f8170845SAlex Fikl } 8683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 869f8170845SAlex Fikl } 870f8170845SAlex Fikl 871d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left) 872d71ae5a4SJacob Faibussowitsch { 873d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 874d8588912SDave May Vec *L, *R; 875d8588912SDave May MPI_Comm comm; 876d8588912SDave May PetscInt i, j; 877d8588912SDave May 878d8588912SDave May PetscFunctionBegin; 8799566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)A, &comm)); 880d8588912SDave May if (right) { 881d8588912SDave May /* allocate R */ 8829566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bA->nc, &R)); 883d8588912SDave May /* Create the right vectors */ 884d8588912SDave May for (j = 0; j < bA->nc; j++) { 885d8588912SDave May for (i = 0; i < bA->nr; i++) { 886d8588912SDave May if (bA->m[i][j]) { 8879566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL)); 888d8588912SDave May break; 889d8588912SDave May } 890d8588912SDave May } 89108401ef6SPierre Jolivet PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column."); 892d8588912SDave May } 8939566063dSJacob Faibussowitsch PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right)); 894d8588912SDave May /* hand back control to the nest vector */ 89548a46eb9SPierre Jolivet for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j])); 8969566063dSJacob Faibussowitsch PetscCall(PetscFree(R)); 897d8588912SDave May } 898d8588912SDave May 899d8588912SDave May if (left) { 900d8588912SDave May /* allocate L */ 9019566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bA->nr, &L)); 902d8588912SDave May /* Create the left vectors */ 903d8588912SDave May for (i = 0; i < bA->nr; i++) { 904d8588912SDave May for (j = 0; j < bA->nc; j++) { 905d8588912SDave May if (bA->m[i][j]) { 9069566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i])); 907d8588912SDave May break; 908d8588912SDave May } 909d8588912SDave May } 91008401ef6SPierre Jolivet PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row."); 911d8588912SDave May } 912d8588912SDave May 9139566063dSJacob Faibussowitsch PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left)); 91448a46eb9SPierre Jolivet for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i])); 915d8588912SDave May 9169566063dSJacob Faibussowitsch PetscCall(PetscFree(L)); 917d8588912SDave May } 9183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 919d8588912SDave May } 920d8588912SDave May 921d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer) 922d71ae5a4SJacob Faibussowitsch { 923d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 92429e60adbSStefano Zampini PetscBool isascii, viewSub = PETSC_FALSE; 925d8588912SDave May PetscInt i, j; 926d8588912SDave May 927d8588912SDave May PetscFunctionBegin; 9289566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 929d8588912SDave May if (isascii) { 9309566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL)); 9319566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object:\n")); 9329566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 9339566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", bA->nr, bA->nc)); 934d8588912SDave May 9359566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure:\n")); 936d8588912SDave May for (i = 0; i < bA->nr; i++) { 937d8588912SDave May for (j = 0; j < bA->nc; j++) { 93819fd82e9SBarry Smith MatType type; 939270f95d7SJed Brown char name[256] = "", prefix[256] = ""; 940d8588912SDave May PetscInt NR, NC; 941d8588912SDave May PetscBool isNest = PETSC_FALSE; 942d8588912SDave May 943d8588912SDave May if (!bA->m[i][j]) { 9449566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j)); 945d8588912SDave May continue; 946d8588912SDave May } 9479566063dSJacob Faibussowitsch PetscCall(MatGetSize(bA->m[i][j], &NR, &NC)); 9489566063dSJacob Faibussowitsch PetscCall(MatGetType(bA->m[i][j], &type)); 9499566063dSJacob Faibussowitsch if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name)); 9509566063dSJacob Faibussowitsch if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix)); 9519566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest)); 952d8588912SDave May 9539566063dSJacob 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)); 954d8588912SDave May 95529e60adbSStefano Zampini if (isNest || viewSub) { 9569566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */ 9579566063dSJacob Faibussowitsch PetscCall(MatView(bA->m[i][j], viewer)); 9589566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */ 959d8588912SDave May } 960d8588912SDave May } 961d8588912SDave May } 9629566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */ 963d8588912SDave May } 9643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 965d8588912SDave May } 966d8588912SDave May 967d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A) 968d71ae5a4SJacob Faibussowitsch { 969d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 970d8588912SDave May PetscInt i, j; 971d8588912SDave May 972d8588912SDave May PetscFunctionBegin; 973d8588912SDave May for (i = 0; i < bA->nr; i++) { 974d8588912SDave May for (j = 0; j < bA->nc; j++) { 975d8588912SDave May if (!bA->m[i][j]) continue; 9769566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(bA->m[i][j])); 977d8588912SDave May } 978d8588912SDave May } 9793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 980d8588912SDave May } 981d8588912SDave May 982d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str) 983d71ae5a4SJacob Faibussowitsch { 984c222c20dSDavid Ham Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data; 985c222c20dSDavid Ham PetscInt i, j, nr = bA->nr, nc = bA->nc; 98606a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 987c222c20dSDavid Ham 988c222c20dSDavid Ham PetscFunctionBegin; 989aed4548fSBarry 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); 990c222c20dSDavid Ham for (i = 0; i < nr; i++) { 991c222c20dSDavid Ham for (j = 0; j < nc; j++) { 99206a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 99346a2b97cSJed Brown if (bA->m[i][j] && bB->m[i][j]) { 9949566063dSJacob Faibussowitsch PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str)); 99508401ef6SPierre 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); 9969566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate)); 99706a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate); 99806a1af2fSStefano Zampini bB->nnzstate[i * nc + j] = subnnzstate; 999c222c20dSDavid Ham } 1000c222c20dSDavid Ham } 100106a1af2fSStefano Zampini if (nnzstate) B->nonzerostate++; 10023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1003c222c20dSDavid Ham } 1004c222c20dSDavid Ham 1005d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str) 1006d71ae5a4SJacob Faibussowitsch { 10076e76ffeaSPierre Jolivet Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data; 10086e76ffeaSPierre Jolivet PetscInt i, j, nr = bY->nr, nc = bY->nc; 100906a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 10106e76ffeaSPierre Jolivet 10116e76ffeaSPierre Jolivet PetscFunctionBegin; 1012aed4548fSBarry 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); 10136e76ffeaSPierre Jolivet for (i = 0; i < nr; i++) { 10146e76ffeaSPierre Jolivet for (j = 0; j < nc; j++) { 101506a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 10166e76ffeaSPierre Jolivet if (bY->m[i][j] && bX->m[i][j]) { 10179566063dSJacob Faibussowitsch PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str)); 1018c066aebcSStefano Zampini } else if (bX->m[i][j]) { 1019c066aebcSStefano Zampini Mat M; 1020c066aebcSStefano Zampini 1021e75569e9SPierre 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); 10229566063dSJacob Faibussowitsch PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M)); 10239566063dSJacob Faibussowitsch PetscCall(MatNestSetSubMat(Y, i, j, M)); 10249566063dSJacob Faibussowitsch PetscCall(MatDestroy(&M)); 1025c066aebcSStefano Zampini } 10269566063dSJacob Faibussowitsch if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate)); 102706a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate); 102806a1af2fSStefano Zampini bY->nnzstate[i * nc + j] = subnnzstate; 10296e76ffeaSPierre Jolivet } 10306e76ffeaSPierre Jolivet } 103106a1af2fSStefano Zampini if (nnzstate) Y->nonzerostate++; 10323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10336e76ffeaSPierre Jolivet } 10346e76ffeaSPierre Jolivet 1035d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B) 1036d71ae5a4SJacob Faibussowitsch { 1037d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 1038841e96a3SJed Brown Mat *b; 1039841e96a3SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 1040d8588912SDave May 1041d8588912SDave May PetscFunctionBegin; 10429566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr * nc, &b)); 1043841e96a3SJed Brown for (i = 0; i < nr; i++) { 1044841e96a3SJed Brown for (j = 0; j < nc; j++) { 1045841e96a3SJed Brown if (bA->m[i][j]) { 10469566063dSJacob Faibussowitsch PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j])); 1047841e96a3SJed Brown } else { 10480298fd71SBarry Smith b[i * nc + j] = NULL; 1049d8588912SDave May } 1050d8588912SDave May } 1051d8588912SDave May } 10529566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B)); 1053841e96a3SJed Brown /* Give the new MatNest exclusive ownership */ 105448a46eb9SPierre Jolivet for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i])); 10559566063dSJacob Faibussowitsch PetscCall(PetscFree(b)); 1056d8588912SDave May 10579566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 10589566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 10593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1060d8588912SDave May } 1061d8588912SDave May 1062d8588912SDave May /* nest api */ 106366976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat) 1064d71ae5a4SJacob Faibussowitsch { 1065d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 10665fd66863SKarl Rupp 1067d8588912SDave May PetscFunctionBegin; 106808401ef6SPierre 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); 106908401ef6SPierre 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); 1070d8588912SDave May *mat = bA->m[idxm][jdxm]; 10713ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1072d8588912SDave May } 1073d8588912SDave May 10749ba0d327SJed Brown /*@ 107511a5261eSBarry Smith MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST` 1076d8588912SDave May 10772ef1f0ffSBarry Smith Not Collective 1078d8588912SDave May 1079d8588912SDave May Input Parameters: 108011a5261eSBarry Smith + A - `MATNEST` matrix 1081d8588912SDave May . idxm - index of the matrix within the nest matrix 1082629881c0SJed Brown - jdxm - index of the matrix within the nest matrix 1083d8588912SDave May 1084d8588912SDave May Output Parameter: 10852ef1f0ffSBarry Smith . sub - matrix at index `idxm`, `jdxm` within the nest matrix 1086d8588912SDave May 1087d8588912SDave May Level: developer 1088d8588912SDave May 1089fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`, 1090db781477SPatrick Sanan `MatNestGetLocalISs()`, `MatNestGetISs()` 1091d8588912SDave May @*/ 1092d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub) 1093d71ae5a4SJacob Faibussowitsch { 1094d8588912SDave May PetscFunctionBegin; 1095*3536838dSStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1096*3536838dSStefano Zampini PetscValidLogicalCollectiveInt(A, idxm, 2); 1097*3536838dSStefano Zampini PetscValidLogicalCollectiveInt(A, jdxm, 3); 1098*3536838dSStefano Zampini PetscAssertPointer(sub, 4); 1099cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub)); 11003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1101d8588912SDave May } 1102d8588912SDave May 110366976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat) 1104d71ae5a4SJacob Faibussowitsch { 11050782ca92SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 11060782ca92SJed Brown PetscInt m, n, M, N, mi, ni, Mi, Ni; 11070782ca92SJed Brown 11080782ca92SJed Brown PetscFunctionBegin; 110908401ef6SPierre 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); 111008401ef6SPierre 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); 1111*3536838dSStefano Zampini if (mat) { 11129566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 11139566063dSJacob Faibussowitsch PetscCall(MatGetSize(mat, &M, &N)); 11149566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi)); 11159566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi)); 11169566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni)); 11179566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni)); 1118aed4548fSBarry 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); 1119aed4548fSBarry 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); 1120*3536838dSStefano Zampini } 112126fbe8dcSKarl Rupp 112206a1af2fSStefano Zampini /* do not increase object state */ 11233ba16761SJacob Faibussowitsch if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS); 112406a1af2fSStefano Zampini 11259566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat)); 11269566063dSJacob Faibussowitsch PetscCall(MatDestroy(&bA->m[idxm][jdxm])); 11270782ca92SJed Brown bA->m[idxm][jdxm] = mat; 11289566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)A)); 1129*3536838dSStefano Zampini if (mat) PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm])); 1130*3536838dSStefano Zampini else bA->nnzstate[idxm * bA->nc + jdxm] = 0; 113106a1af2fSStefano Zampini A->nonzerostate++; 11323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11330782ca92SJed Brown } 11340782ca92SJed Brown 11359ba0d327SJed Brown /*@ 113611a5261eSBarry Smith MatNestSetSubMat - Set a single submatrix in the `MATNEST` 11370782ca92SJed Brown 11382ef1f0ffSBarry Smith Logically Collective 11390782ca92SJed Brown 11400782ca92SJed Brown Input Parameters: 114111a5261eSBarry Smith + A - `MATNEST` matrix 11420782ca92SJed Brown . idxm - index of the matrix within the nest matrix 11430782ca92SJed Brown . jdxm - index of the matrix within the nest matrix 11442ef1f0ffSBarry Smith - sub - matrix at index `idxm`, `jdxm` within the nest matrix 11452ef1f0ffSBarry Smith 11462ef1f0ffSBarry Smith Level: developer 11470782ca92SJed Brown 11480782ca92SJed Brown Notes: 11490782ca92SJed Brown The new submatrix must have the same size and communicator as that block of the nest. 11500782ca92SJed Brown 11510782ca92SJed Brown This increments the reference count of the submatrix. 11520782ca92SJed Brown 1153fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`, 1154db781477SPatrick Sanan `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()` 11550782ca92SJed Brown @*/ 1156d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub) 1157d71ae5a4SJacob Faibussowitsch { 11580782ca92SJed Brown PetscFunctionBegin; 1159*3536838dSStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1160*3536838dSStefano Zampini PetscValidLogicalCollectiveInt(A, idxm, 2); 1161*3536838dSStefano Zampini PetscValidLogicalCollectiveInt(A, jdxm, 3); 1162*3536838dSStefano Zampini if (sub) PetscValidHeaderSpecific(sub, MAT_CLASSID, 4); 1163*3536838dSStefano Zampini PetscTryMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub)); 11643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11650782ca92SJed Brown } 11660782ca92SJed Brown 116766976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) 1168d71ae5a4SJacob Faibussowitsch { 1169d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 11705fd66863SKarl Rupp 1171d8588912SDave May PetscFunctionBegin; 117226fbe8dcSKarl Rupp if (M) *M = bA->nr; 117326fbe8dcSKarl Rupp if (N) *N = bA->nc; 117426fbe8dcSKarl Rupp if (mat) *mat = bA->m; 11753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1176d8588912SDave May } 1177d8588912SDave May 1178d8588912SDave May /*@C 117911a5261eSBarry Smith MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix. 1180d8588912SDave May 11812ef1f0ffSBarry Smith Not Collective 1182d8588912SDave May 1183f899ff85SJose E. Roman Input Parameter: 1184629881c0SJed Brown . A - nest matrix 1185d8588912SDave May 1186d8d19677SJose E. Roman Output Parameters: 1187629881c0SJed Brown + M - number of rows in the nest matrix 1188d8588912SDave May . N - number of cols in the nest matrix 1189e9d3347aSJose E. Roman - mat - array of matrices 1190d8588912SDave May 11912ef1f0ffSBarry Smith Level: developer 11922ef1f0ffSBarry Smith 119311a5261eSBarry Smith Note: 11942ef1f0ffSBarry Smith The user should not free the array `mat`. 1195d8588912SDave May 1196fe59aa6dSJacob Faibussowitsch Fortran Notes: 119711a5261eSBarry Smith This routine has a calling sequence 1198351962e3SVincent Le Chenadec $ call MatNestGetSubMats(A, M, N, mat, ierr) 119920f4b53cSBarry Smith where the space allocated for the optional argument `mat` is assumed large enough (if provided). 1200e9d3347aSJose E. Roman Matrices in `mat` are returned in row-major order, see `MatCreateNest()` for an example. 1201351962e3SVincent Le Chenadec 1202fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`, 1203db781477SPatrick Sanan `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()` 1204d8588912SDave May @*/ 1205d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) 1206d71ae5a4SJacob Faibussowitsch { 1207d8588912SDave May PetscFunctionBegin; 1208*3536838dSStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1209cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat)); 12103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1211d8588912SDave May } 1212d8588912SDave May 121366976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N) 1214d71ae5a4SJacob Faibussowitsch { 1215d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 1216d8588912SDave May 1217d8588912SDave May PetscFunctionBegin; 121826fbe8dcSKarl Rupp if (M) *M = bA->nr; 121926fbe8dcSKarl Rupp if (N) *N = bA->nc; 12203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1221d8588912SDave May } 1222d8588912SDave May 12239ba0d327SJed Brown /*@ 122411a5261eSBarry Smith MatNestGetSize - Returns the size of the `MATNEST` matrix. 1225d8588912SDave May 12262ef1f0ffSBarry Smith Not Collective 1227d8588912SDave May 1228f899ff85SJose E. Roman Input Parameter: 122911a5261eSBarry Smith . A - `MATNEST` matrix 1230d8588912SDave May 1231d8d19677SJose E. Roman Output Parameters: 1232629881c0SJed Brown + M - number of rows in the nested mat 1233629881c0SJed Brown - N - number of cols in the nested mat 1234d8588912SDave May 1235d8588912SDave May Level: developer 1236d8588912SDave May 1237fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`, 1238db781477SPatrick Sanan `MatNestGetISs()` 1239d8588912SDave May @*/ 1240d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N) 1241d71ae5a4SJacob Faibussowitsch { 1242d8588912SDave May PetscFunctionBegin; 1243*3536838dSStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1244cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N)); 12453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1246d8588912SDave May } 1247d8588912SDave May 1248d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[]) 1249d71ae5a4SJacob Faibussowitsch { 1250900e7ff2SJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 1251900e7ff2SJed Brown PetscInt i; 1252900e7ff2SJed Brown 1253900e7ff2SJed Brown PetscFunctionBegin; 12549371c9d4SSatish Balay if (rows) 12559371c9d4SSatish Balay for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i]; 12569371c9d4SSatish Balay if (cols) 12579371c9d4SSatish Balay for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i]; 12583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1259900e7ff2SJed Brown } 1260900e7ff2SJed Brown 12613a4d7b9aSSatish Balay /*@C 126211a5261eSBarry Smith MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST` 1263900e7ff2SJed Brown 12642ef1f0ffSBarry Smith Not Collective 1265900e7ff2SJed Brown 1266f899ff85SJose E. Roman Input Parameter: 126711a5261eSBarry Smith . A - `MATNEST` matrix 1268900e7ff2SJed Brown 1269d8d19677SJose E. Roman Output Parameters: 1270900e7ff2SJed Brown + rows - array of row index sets 1271900e7ff2SJed Brown - cols - array of column index sets 1272900e7ff2SJed Brown 1273900e7ff2SJed Brown Level: advanced 1274900e7ff2SJed Brown 127511a5261eSBarry Smith Note: 12762ef1f0ffSBarry Smith The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s. 1277900e7ff2SJed Brown 1278fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`, 1279fe59aa6dSJacob Faibussowitsch `MatCreateNest()`, `MatNestSetSubMats()` 1280900e7ff2SJed Brown @*/ 1281d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[]) 1282d71ae5a4SJacob Faibussowitsch { 1283900e7ff2SJed Brown PetscFunctionBegin; 1284900e7ff2SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1285cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 12863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1287900e7ff2SJed Brown } 1288900e7ff2SJed Brown 1289d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[]) 1290d71ae5a4SJacob Faibussowitsch { 1291900e7ff2SJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 1292900e7ff2SJed Brown PetscInt i; 1293900e7ff2SJed Brown 1294900e7ff2SJed Brown PetscFunctionBegin; 12959371c9d4SSatish Balay if (rows) 12969371c9d4SSatish Balay for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i]; 12979371c9d4SSatish Balay if (cols) 12989371c9d4SSatish Balay for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i]; 12993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1300900e7ff2SJed Brown } 1301900e7ff2SJed Brown 1302900e7ff2SJed Brown /*@C 130311a5261eSBarry Smith MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST` 1304900e7ff2SJed Brown 13052ef1f0ffSBarry Smith Not Collective 1306900e7ff2SJed Brown 1307f899ff85SJose E. Roman Input Parameter: 130811a5261eSBarry Smith . A - `MATNEST` matrix 1309900e7ff2SJed Brown 1310d8d19677SJose E. Roman Output Parameters: 13112ef1f0ffSBarry Smith + rows - array of row index sets (or `NULL` to ignore) 13122ef1f0ffSBarry Smith - cols - array of column index sets (or `NULL` to ignore) 1313900e7ff2SJed Brown 1314900e7ff2SJed Brown Level: advanced 1315900e7ff2SJed Brown 131611a5261eSBarry Smith Note: 13172ef1f0ffSBarry Smith The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s. 1318900e7ff2SJed Brown 13191cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`, 1320fe59aa6dSJacob Faibussowitsch `MatNestSetSubMats()`, `MatNestSetSubMat()` 1321900e7ff2SJed Brown @*/ 1322d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[]) 1323d71ae5a4SJacob Faibussowitsch { 1324900e7ff2SJed Brown PetscFunctionBegin; 1325900e7ff2SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1326cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 13273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1328900e7ff2SJed Brown } 1329900e7ff2SJed Brown 133066976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype) 1331d71ae5a4SJacob Faibussowitsch { 1332207556f9SJed Brown PetscBool flg; 1333207556f9SJed Brown 1334207556f9SJed Brown PetscFunctionBegin; 13359566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, VECNEST, &flg)); 1336207556f9SJed Brown /* In reality, this only distinguishes VECNEST and "other" */ 13372a7a6963SBarry Smith if (flg) A->ops->getvecs = MatCreateVecs_Nest; 133812b53f24SSatish Balay else A->ops->getvecs = (PetscErrorCode(*)(Mat, Vec *, Vec *))0; 13393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1340207556f9SJed Brown } 1341207556f9SJed Brown 1342207556f9SJed Brown /*@C 134311a5261eSBarry Smith MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()` 1344207556f9SJed Brown 13452ef1f0ffSBarry Smith Not Collective 1346207556f9SJed Brown 1347207556f9SJed Brown Input Parameters: 134811a5261eSBarry Smith + A - `MATNEST` matrix 134911a5261eSBarry Smith - vtype - `VecType` to use for creating vectors 1350207556f9SJed Brown 1351207556f9SJed Brown Level: developer 1352207556f9SJed Brown 1353fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType` 1354207556f9SJed Brown @*/ 1355d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype) 1356d71ae5a4SJacob Faibussowitsch { 1357207556f9SJed Brown PetscFunctionBegin; 1358*3536838dSStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1359cac4c232SBarry Smith PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype)); 13603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1361207556f9SJed Brown } 1362207556f9SJed Brown 136366976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) 1364d71ae5a4SJacob Faibussowitsch { 1365c8883902SJed Brown Mat_Nest *s = (Mat_Nest *)A->data; 1366c8883902SJed Brown PetscInt i, j, m, n, M, N; 136788ffe2e8SJose E. Roman PetscBool cong, isstd, sametype = PETSC_FALSE; 136888ffe2e8SJose E. Roman VecType vtype, type; 1369d8588912SDave May 1370d8588912SDave May PetscFunctionBegin; 13719566063dSJacob Faibussowitsch PetscCall(MatReset_Nest(A)); 137206a1af2fSStefano Zampini 1373c8883902SJed Brown s->nr = nr; 1374c8883902SJed Brown s->nc = nc; 1375d8588912SDave May 1376c8883902SJed Brown /* Create space for submatrices */ 13779566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &s->m)); 13788068ee9dSPierre Jolivet PetscCall(PetscMalloc1(nr * nc, &s->m[0])); 1379c8883902SJed Brown for (i = 0; i < nr; i++) { 13808068ee9dSPierre Jolivet s->m[i] = s->m[0] + i * nc; 1381c8883902SJed Brown for (j = 0; j < nc; j++) { 1382*3536838dSStefano Zampini s->m[i][j] = a ? a[i * nc + j] : NULL; 1383*3536838dSStefano Zampini PetscCall(PetscObjectReference((PetscObject)s->m[i][j])); 1384d8588912SDave May } 1385d8588912SDave May } 13869566063dSJacob Faibussowitsch PetscCall(MatGetVecType(A, &vtype)); 13879566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd)); 138888ffe2e8SJose E. Roman if (isstd) { 138988ffe2e8SJose E. Roman /* check if all blocks have the same vectype */ 139088ffe2e8SJose E. Roman vtype = NULL; 139188ffe2e8SJose E. Roman for (i = 0; i < nr; i++) { 139288ffe2e8SJose E. Roman for (j = 0; j < nc; j++) { 1393*3536838dSStefano Zampini if (s->m[i][j]) { 139488ffe2e8SJose E. Roman if (!vtype) { /* first visited block */ 1395*3536838dSStefano Zampini PetscCall(MatGetVecType(s->m[i][j], &vtype)); 139688ffe2e8SJose E. Roman sametype = PETSC_TRUE; 139788ffe2e8SJose E. Roman } else if (sametype) { 1398*3536838dSStefano Zampini PetscCall(MatGetVecType(s->m[i][j], &type)); 13999566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, type, &sametype)); 140088ffe2e8SJose E. Roman } 140188ffe2e8SJose E. Roman } 140288ffe2e8SJose E. Roman } 140388ffe2e8SJose E. Roman } 140488ffe2e8SJose E. Roman if (sametype) { /* propagate vectype */ 14059566063dSJacob Faibussowitsch PetscCall(MatSetVecType(A, vtype)); 140688ffe2e8SJose E. Roman } 140788ffe2e8SJose E. Roman } 1408d8588912SDave May 14099566063dSJacob Faibussowitsch PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col)); 1410d8588912SDave May 14119566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &s->row_len)); 14129566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &s->col_len)); 1413c8883902SJed Brown for (i = 0; i < nr; i++) s->row_len[i] = -1; 1414c8883902SJed Brown for (j = 0; j < nc; j++) s->col_len[j] = -1; 1415d8588912SDave May 14169566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr * nc, &s->nnzstate)); 141706a1af2fSStefano Zampini for (i = 0; i < nr; i++) { 141806a1af2fSStefano Zampini for (j = 0; j < nc; j++) { 141948a46eb9SPierre Jolivet if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j])); 142006a1af2fSStefano Zampini } 142106a1af2fSStefano Zampini } 142206a1af2fSStefano Zampini 14239566063dSJacob Faibussowitsch PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N)); 1424d8588912SDave May 14259566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(A->rmap, M)); 14269566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(A->rmap, m)); 14279566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(A->cmap, N)); 14289566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(A->cmap, n)); 1429c8883902SJed Brown 14309566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->rmap)); 14319566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->cmap)); 1432c8883902SJed Brown 143306a1af2fSStefano Zampini /* disable operations that are not supported for non-square matrices, 143406a1af2fSStefano Zampini or matrices for which is_row != is_col */ 14359566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(A, &cong)); 143606a1af2fSStefano Zampini if (cong && nr != nc) cong = PETSC_FALSE; 143706a1af2fSStefano Zampini if (cong) { 143848a46eb9SPierre Jolivet for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong)); 143906a1af2fSStefano Zampini } 144006a1af2fSStefano Zampini if (!cong) { 1441381b8e50SStefano Zampini A->ops->missingdiagonal = NULL; 144206a1af2fSStefano Zampini A->ops->getdiagonal = NULL; 144306a1af2fSStefano Zampini A->ops->shift = NULL; 144406a1af2fSStefano Zampini A->ops->diagonalset = NULL; 144506a1af2fSStefano Zampini } 144606a1af2fSStefano Zampini 14479566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right)); 14489566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)A)); 144906a1af2fSStefano Zampini A->nonzerostate++; 14503ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1451d8588912SDave May } 1452d8588912SDave May 1453c8883902SJed Brown /*@ 145411a5261eSBarry Smith MatNestSetSubMats - Sets the nested submatrices in a `MATNEST` 1455c8883902SJed Brown 1456c3339decSBarry Smith Collective 1457c8883902SJed Brown 1458d8d19677SJose E. Roman Input Parameters: 145911a5261eSBarry Smith + A - `MATNEST` matrix 1460c8883902SJed Brown . nr - number of nested row blocks 14612ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous 1462c8883902SJed Brown . nc - number of nested column blocks 14632ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous 1464*3536838dSStefano Zampini - a - array of nr*nc submatrices, or `NULL` 14652ef1f0ffSBarry Smith 14662ef1f0ffSBarry Smith Level: advanced 1467c8883902SJed Brown 1468e9d3347aSJose E. Roman Notes: 1469*3536838dSStefano Zampini This always resets any block matrix information previously set. 1470*3536838dSStefano Zampini Pass `NULL` in the correspoding entry of `a` for an empty block. 147106a1af2fSStefano Zampini 1472e9d3347aSJose E. Roman In both C and Fortran, `a` must be a row-major order array containing the matrices. See 1473e9d3347aSJose E. Roman `MatCreateNest()` for an example. 1474e9d3347aSJose E. Roman 14751cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()` 1476c8883902SJed Brown @*/ 1477d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) 1478d71ae5a4SJacob Faibussowitsch { 1479c8883902SJed Brown PetscFunctionBegin; 1480c8883902SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1481*3536838dSStefano Zampini PetscValidLogicalCollectiveInt(A, nr, 2); 148208401ef6SPierre Jolivet PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative"); 1483c8883902SJed Brown if (nr && is_row) { 14844f572ea9SToby Isaac PetscAssertPointer(is_row, 3); 1485*3536838dSStefano Zampini for (PetscInt i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3); 1486c8883902SJed Brown } 1487*3536838dSStefano Zampini PetscValidLogicalCollectiveInt(A, nc, 4); 148808401ef6SPierre Jolivet PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative"); 14891664e352SJed Brown if (nc && is_col) { 14904f572ea9SToby Isaac PetscAssertPointer(is_col, 5); 1491*3536838dSStefano Zampini for (PetscInt i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5); 1492c8883902SJed Brown } 1493*3536838dSStefano Zampini PetscTryMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a)); 14943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1495c8883902SJed Brown } 1496d8588912SDave May 1497d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog) 1498d71ae5a4SJacob Faibussowitsch { 149977019fcaSJed Brown PetscBool flg; 150077019fcaSJed Brown PetscInt i, j, m, mi, *ix; 150177019fcaSJed Brown 150277019fcaSJed Brown PetscFunctionBegin; 1503aea6d515SStefano Zampini *ltog = NULL; 150477019fcaSJed Brown for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) { 150577019fcaSJed Brown if (islocal[i]) { 15069566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(islocal[i], &mi)); 150777019fcaSJed Brown flg = PETSC_TRUE; /* We found a non-trivial entry */ 150877019fcaSJed Brown } else { 15099566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mi)); 151077019fcaSJed Brown } 151177019fcaSJed Brown m += mi; 151277019fcaSJed Brown } 15133ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 1514aea6d515SStefano Zampini 15159566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &ix)); 1516165cd838SBarry Smith for (i = 0, m = 0; i < n; i++) { 15170298fd71SBarry Smith ISLocalToGlobalMapping smap = NULL; 1518e108cb99SStefano Zampini Mat sub = NULL; 1519f6d38dbbSStefano Zampini PetscSF sf; 1520f6d38dbbSStefano Zampini PetscLayout map; 1521aea6d515SStefano Zampini const PetscInt *ix2; 152277019fcaSJed Brown 1523165cd838SBarry Smith if (!colflg) { 15249566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 152577019fcaSJed Brown } else { 15269566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 152777019fcaSJed Brown } 1528191fd14bSBarry Smith if (sub) { 1529191fd14bSBarry Smith if (!colflg) { 15309566063dSJacob Faibussowitsch PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL)); 1531191fd14bSBarry Smith } else { 15329566063dSJacob Faibussowitsch PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap)); 1533191fd14bSBarry Smith } 1534191fd14bSBarry Smith } 153577019fcaSJed Brown /* 153677019fcaSJed Brown Now we need to extract the monolithic global indices that correspond to the given split global indices. 153777019fcaSJed 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. 153877019fcaSJed Brown */ 15399566063dSJacob Faibussowitsch PetscCall(ISGetIndices(isglobal[i], &ix2)); 1540aea6d515SStefano Zampini if (islocal[i]) { 1541aea6d515SStefano Zampini PetscInt *ilocal, *iremote; 1542aea6d515SStefano Zampini PetscInt mil, nleaves; 1543aea6d515SStefano Zampini 15449566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(islocal[i], &mi)); 154528b400f6SJacob Faibussowitsch PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map"); 1546aea6d515SStefano Zampini for (j = 0; j < mi; j++) ix[m + j] = j; 15479566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m)); 1548aea6d515SStefano Zampini 1549aea6d515SStefano Zampini /* PetscSFSetGraphLayout does not like negative indices */ 15509566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote)); 1551aea6d515SStefano Zampini for (j = 0, nleaves = 0; j < mi; j++) { 1552aea6d515SStefano Zampini if (ix[m + j] < 0) continue; 1553aea6d515SStefano Zampini ilocal[nleaves] = j; 1554aea6d515SStefano Zampini iremote[nleaves] = ix[m + j]; 1555aea6d515SStefano Zampini nleaves++; 1556aea6d515SStefano Zampini } 15579566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mil)); 15589566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf)); 15599566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map)); 15609566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(map, mil)); 15619566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(map)); 15629566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote)); 15639566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&map)); 15649566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 15659566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 15669566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&sf)); 15679566063dSJacob Faibussowitsch PetscCall(PetscFree2(ilocal, iremote)); 1568aea6d515SStefano Zampini } else { 15699566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mi)); 1570aea6d515SStefano Zampini for (j = 0; j < mi; j++) ix[m + j] = ix2[i]; 1571aea6d515SStefano Zampini } 15729566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(isglobal[i], &ix2)); 157377019fcaSJed Brown m += mi; 157477019fcaSJed Brown } 15759566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog)); 15763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 157777019fcaSJed Brown } 157877019fcaSJed Brown 1579d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */ 1580d8588912SDave May /* 1581d8588912SDave May nprocessors = NP 1582d8588912SDave May Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1)) 1583d8588912SDave May proc 0: => (g_0,h_0,) 1584d8588912SDave May proc 1: => (g_1,h_1,) 1585d8588912SDave May ... 1586d8588912SDave May proc nprocs-1: => (g_NP-1,h_NP-1,) 1587d8588912SDave May 1588d8588912SDave May proc 0: proc 1: proc nprocs-1: 1589d8588912SDave May is[0] = (0,1,2,...,nlocal(g_0)-1) (0,1,...,nlocal(g_1)-1) (0,1,...,nlocal(g_NP-1)) 1590d8588912SDave May 1591d8588912SDave May proc 0: 1592d8588912SDave May is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1) 1593d8588912SDave May proc 1: 1594d8588912SDave May is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1) 1595d8588912SDave May 1596d8588912SDave May proc NP-1: 1597d8588912SDave May is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1) 1598d8588912SDave May */ 1599d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[]) 1600d71ae5a4SJacob Faibussowitsch { 1601e2d7f03fSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 16028188e55aSJed Brown PetscInt i, j, offset, n, nsum, bs; 16030298fd71SBarry Smith Mat sub = NULL; 1604d8588912SDave May 1605d8588912SDave May PetscFunctionBegin; 16069566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &vs->isglobal.row)); 16079566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &vs->isglobal.col)); 1608d8588912SDave May if (is_row) { /* valid IS is passed in */ 1609a5b23f4aSJose E. Roman /* refs on is[] are incremented */ 1610e2d7f03fSJed Brown for (i = 0; i < vs->nr; i++) { 16119566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is_row[i])); 161226fbe8dcSKarl Rupp 1613e2d7f03fSJed Brown vs->isglobal.row[i] = is_row[i]; 1614d8588912SDave May } 16152ae74bdbSJed Brown } else { /* Create the ISs by inspecting sizes of a submatrix in each row */ 16168188e55aSJed Brown nsum = 0; 16178188e55aSJed Brown for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */ 16189566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 161928b400f6SJacob Faibussowitsch PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i); 16209566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, &n, NULL)); 162108401ef6SPierre Jolivet PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 16228188e55aSJed Brown nsum += n; 16238188e55aSJed Brown } 16249566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 162530bc264bSJed Brown offset -= nsum; 1626e2d7f03fSJed Brown for (i = 0; i < vs->nr; i++) { 16279566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 16289566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, &n, NULL)); 16299566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 16309566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i])); 16319566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs)); 16322ae74bdbSJed Brown offset += n; 1633d8588912SDave May } 1634d8588912SDave May } 1635d8588912SDave May 1636d8588912SDave May if (is_col) { /* valid IS is passed in */ 1637a5b23f4aSJose E. Roman /* refs on is[] are incremented */ 1638e2d7f03fSJed Brown for (j = 0; j < vs->nc; j++) { 16399566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is_col[j])); 164026fbe8dcSKarl Rupp 1641e2d7f03fSJed Brown vs->isglobal.col[j] = is_col[j]; 1642d8588912SDave May } 16432ae74bdbSJed Brown } else { /* Create the ISs by inspecting sizes of a submatrix in each column */ 16442ae74bdbSJed Brown offset = A->cmap->rstart; 16458188e55aSJed Brown nsum = 0; 16468188e55aSJed Brown for (j = 0; j < vs->nc; j++) { 16479566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 164828b400f6SJacob Faibussowitsch PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i); 16499566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, NULL, &n)); 165008401ef6SPierre Jolivet PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 16518188e55aSJed Brown nsum += n; 16528188e55aSJed Brown } 16539566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 165430bc264bSJed Brown offset -= nsum; 1655e2d7f03fSJed Brown for (j = 0; j < vs->nc; j++) { 16569566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 16579566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, NULL, &n)); 16589566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 16599566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j])); 16609566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs)); 16612ae74bdbSJed Brown offset += n; 1662d8588912SDave May } 1663d8588912SDave May } 1664e2d7f03fSJed Brown 1665e2d7f03fSJed Brown /* Set up the local ISs */ 16669566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row)); 16679566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col)); 1668e2d7f03fSJed Brown for (i = 0, offset = 0; i < vs->nr; i++) { 1669e2d7f03fSJed Brown IS isloc; 16700298fd71SBarry Smith ISLocalToGlobalMapping rmap = NULL; 1671e2d7f03fSJed Brown PetscInt nlocal, bs; 16729566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 16739566063dSJacob Faibussowitsch if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL)); 1674207556f9SJed Brown if (rmap) { 16759566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 16769566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal)); 16779566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 16789566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(isloc, bs)); 1679207556f9SJed Brown } else { 1680207556f9SJed Brown nlocal = 0; 16810298fd71SBarry Smith isloc = NULL; 1682207556f9SJed Brown } 1683e2d7f03fSJed Brown vs->islocal.row[i] = isloc; 1684e2d7f03fSJed Brown offset += nlocal; 1685e2d7f03fSJed Brown } 16868188e55aSJed Brown for (i = 0, offset = 0; i < vs->nc; i++) { 1687e2d7f03fSJed Brown IS isloc; 16880298fd71SBarry Smith ISLocalToGlobalMapping cmap = NULL; 1689e2d7f03fSJed Brown PetscInt nlocal, bs; 16909566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 16919566063dSJacob Faibussowitsch if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap)); 1692207556f9SJed Brown if (cmap) { 16939566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 16949566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal)); 16959566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 16969566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(isloc, bs)); 1697207556f9SJed Brown } else { 1698207556f9SJed Brown nlocal = 0; 16990298fd71SBarry Smith isloc = NULL; 1700207556f9SJed Brown } 1701e2d7f03fSJed Brown vs->islocal.col[i] = isloc; 1702e2d7f03fSJed Brown offset += nlocal; 1703e2d7f03fSJed Brown } 17040189643fSJed Brown 170577019fcaSJed Brown /* Set up the aggregate ISLocalToGlobalMapping */ 170677019fcaSJed Brown { 170745b6f7e9SBarry Smith ISLocalToGlobalMapping rmap, cmap; 17089566063dSJacob Faibussowitsch PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap)); 17099566063dSJacob Faibussowitsch PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap)); 17109566063dSJacob Faibussowitsch if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap)); 17119566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingDestroy(&rmap)); 17129566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingDestroy(&cmap)); 171377019fcaSJed Brown } 171477019fcaSJed Brown 171576bd3646SJed Brown if (PetscDefined(USE_DEBUG)) { 17160189643fSJed Brown for (i = 0; i < vs->nr; i++) { 17170189643fSJed Brown for (j = 0; j < vs->nc; j++) { 17180189643fSJed Brown PetscInt m, n, M, N, mi, ni, Mi, Ni; 17190189643fSJed Brown Mat B = vs->m[i][j]; 17200189643fSJed Brown if (!B) continue; 17219566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, &M, &N)); 17229566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(B, &m, &n)); 17239566063dSJacob Faibussowitsch PetscCall(ISGetSize(vs->isglobal.row[i], &Mi)); 17249566063dSJacob Faibussowitsch PetscCall(ISGetSize(vs->isglobal.col[j], &Ni)); 17259566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi)); 17269566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni)); 1727aed4548fSBarry 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); 1728aed4548fSBarry 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); 17290189643fSJed Brown } 17300189643fSJed Brown } 173176bd3646SJed Brown } 1732a061e289SJed Brown 1733a061e289SJed Brown /* Set A->assembled if all non-null blocks are currently assembled */ 1734a061e289SJed Brown for (i = 0; i < vs->nr; i++) { 1735a061e289SJed Brown for (j = 0; j < vs->nc; j++) { 17363ba16761SJacob Faibussowitsch if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS); 1737a061e289SJed Brown } 1738a061e289SJed Brown } 1739a061e289SJed Brown A->assembled = PETSC_TRUE; 17403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1741d8588912SDave May } 1742d8588912SDave May 174345c38901SJed Brown /*@C 174411a5261eSBarry Smith MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately 1745659c6bb0SJed Brown 174611a5261eSBarry Smith Collective 1747659c6bb0SJed Brown 1748d8d19677SJose E. Roman Input Parameters: 174911a5261eSBarry Smith + comm - Communicator for the new `MATNEST` 1750659c6bb0SJed Brown . nr - number of nested row blocks 17512ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous 1752659c6bb0SJed Brown . nc - number of nested column blocks 17532ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous 1754e9d3347aSJose E. Roman - a - array of nr*nc submatrices, empty submatrices can be passed using `NULL` 1755659c6bb0SJed Brown 1756659c6bb0SJed Brown Output Parameter: 1757659c6bb0SJed Brown . B - new matrix 1758659c6bb0SJed Brown 1759e9d3347aSJose E. Roman Note: 1760e9d3347aSJose E. Roman In both C and Fortran, `a` must be a row-major order array holding references to the matrices. 1761e9d3347aSJose E. Roman For instance, to represent the matrix 1762e9d3347aSJose E. Roman $\begin{bmatrix} A_{11} & A_{12} \\ A_{21} & A_{22}\end{bmatrix}$ 1763e9d3347aSJose E. Roman one should use `Mat a[4]={A11,A12,A21,A22}`. 1764e9d3347aSJose E. Roman 1765659c6bb0SJed Brown Level: advanced 1766659c6bb0SJed Brown 17671cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`, 1768db781477SPatrick Sanan `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`, 1769db781477SPatrick Sanan `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 1770659c6bb0SJed Brown @*/ 1771d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B) 1772d71ae5a4SJacob Faibussowitsch { 1773d8588912SDave May PetscFunctionBegin; 1774*3536838dSStefano Zampini PetscCall(MatCreate(comm, B)); 1775*3536838dSStefano Zampini PetscCall(MatSetType(*B, MATNEST)); 1776*3536838dSStefano Zampini (*B)->preallocated = PETSC_TRUE; 1777*3536838dSStefano Zampini PetscCall(MatNestSetSubMats(*B, nr, is_row, nc, is_col, a)); 17783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1779d8588912SDave May } 1780659c6bb0SJed Brown 178166976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 1782d71ae5a4SJacob Faibussowitsch { 1783b68353e5Sstefano_zampini Mat_Nest *nest = (Mat_Nest *)A->data; 178423875855Sstefano_zampini Mat *trans; 1785b68353e5Sstefano_zampini PetscScalar **avv; 1786b68353e5Sstefano_zampini PetscScalar *vv; 1787b68353e5Sstefano_zampini PetscInt **aii, **ajj; 1788b68353e5Sstefano_zampini PetscInt *ii, *jj, *ci; 1789b68353e5Sstefano_zampini PetscInt nr, nc, nnz, i, j; 1790b68353e5Sstefano_zampini PetscBool done; 1791b68353e5Sstefano_zampini 1792b68353e5Sstefano_zampini PetscFunctionBegin; 17939566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &nr, &nc)); 1794b68353e5Sstefano_zampini if (reuse == MAT_REUSE_MATRIX) { 1795b68353e5Sstefano_zampini PetscInt rnr; 1796b68353e5Sstefano_zampini 17979566063dSJacob Faibussowitsch PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done)); 179828b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ"); 179908401ef6SPierre Jolivet PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows"); 18009566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArray(*newmat, &vv)); 1801b68353e5Sstefano_zampini } 1802b68353e5Sstefano_zampini /* extract CSR for nested SeqAIJ matrices */ 1803b68353e5Sstefano_zampini nnz = 0; 18049566063dSJacob Faibussowitsch PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans)); 1805b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1806b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1807b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1808b68353e5Sstefano_zampini if (B) { 1809b68353e5Sstefano_zampini PetscScalar *naa; 1810b68353e5Sstefano_zampini PetscInt *nii, *njj, nnr; 181123875855Sstefano_zampini PetscBool istrans; 1812b68353e5Sstefano_zampini 1813013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans)); 181423875855Sstefano_zampini if (istrans) { 181523875855Sstefano_zampini Mat Bt; 181623875855Sstefano_zampini 18179566063dSJacob Faibussowitsch PetscCall(MatTransposeGetMat(B, &Bt)); 18189566063dSJacob Faibussowitsch PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 181923875855Sstefano_zampini B = trans[i * nest->nc + j]; 1820013e2dc7SBarry Smith } else { 1821013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans)); 1822013e2dc7SBarry Smith if (istrans) { 1823013e2dc7SBarry Smith Mat Bt; 1824013e2dc7SBarry Smith 1825013e2dc7SBarry Smith PetscCall(MatHermitianTransposeGetMat(B, &Bt)); 1826013e2dc7SBarry Smith PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 1827013e2dc7SBarry Smith B = trans[i * nest->nc + j]; 1828013e2dc7SBarry Smith } 182923875855Sstefano_zampini } 18309566063dSJacob Faibussowitsch PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done)); 183128b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ"); 18329566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArray(B, &naa)); 1833b68353e5Sstefano_zampini nnz += nii[nnr]; 1834b68353e5Sstefano_zampini 1835b68353e5Sstefano_zampini aii[i * nest->nc + j] = nii; 1836b68353e5Sstefano_zampini ajj[i * nest->nc + j] = njj; 1837b68353e5Sstefano_zampini avv[i * nest->nc + j] = naa; 1838b68353e5Sstefano_zampini } 1839b68353e5Sstefano_zampini } 1840b68353e5Sstefano_zampini } 1841b68353e5Sstefano_zampini if (reuse != MAT_REUSE_MATRIX) { 18429566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr + 1, &ii)); 18439566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &jj)); 18449566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &vv)); 1845b68353e5Sstefano_zampini } else { 184608401ef6SPierre Jolivet PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros"); 1847b68353e5Sstefano_zampini } 1848b68353e5Sstefano_zampini 1849b68353e5Sstefano_zampini /* new row pointer */ 18509566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(ii, nr + 1)); 1851b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1852b68353e5Sstefano_zampini PetscInt ncr, rst; 1853b68353e5Sstefano_zampini 18549566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 18559566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1856b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1857b68353e5Sstefano_zampini if (aii[i * nest->nc + j]) { 1858b68353e5Sstefano_zampini PetscInt *nii = aii[i * nest->nc + j]; 1859b68353e5Sstefano_zampini PetscInt ir; 1860b68353e5Sstefano_zampini 1861b68353e5Sstefano_zampini for (ir = rst; ir < ncr + rst; ++ir) { 1862b68353e5Sstefano_zampini ii[ir + 1] += nii[1] - nii[0]; 1863b68353e5Sstefano_zampini nii++; 1864b68353e5Sstefano_zampini } 1865b68353e5Sstefano_zampini } 1866b68353e5Sstefano_zampini } 1867b68353e5Sstefano_zampini } 1868b68353e5Sstefano_zampini for (i = 0; i < nr; i++) ii[i + 1] += ii[i]; 1869b68353e5Sstefano_zampini 1870b68353e5Sstefano_zampini /* construct CSR for the new matrix */ 18719566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr, &ci)); 1872b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1873b68353e5Sstefano_zampini PetscInt ncr, rst; 1874b68353e5Sstefano_zampini 18759566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 18769566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1877b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1878b68353e5Sstefano_zampini if (aii[i * nest->nc + j]) { 1879b68353e5Sstefano_zampini PetscScalar *nvv = avv[i * nest->nc + j]; 1880b68353e5Sstefano_zampini PetscInt *nii = aii[i * nest->nc + j]; 1881b68353e5Sstefano_zampini PetscInt *njj = ajj[i * nest->nc + j]; 1882b68353e5Sstefano_zampini PetscInt ir, cst; 1883b68353e5Sstefano_zampini 18849566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL)); 1885b68353e5Sstefano_zampini for (ir = rst; ir < ncr + rst; ++ir) { 1886b68353e5Sstefano_zampini PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir]; 1887b68353e5Sstefano_zampini 1888b68353e5Sstefano_zampini for (ij = 0; ij < rsize; ij++) { 1889b68353e5Sstefano_zampini jj[ist + ij] = *njj + cst; 1890b68353e5Sstefano_zampini vv[ist + ij] = *nvv; 1891b68353e5Sstefano_zampini njj++; 1892b68353e5Sstefano_zampini nvv++; 1893b68353e5Sstefano_zampini } 1894b68353e5Sstefano_zampini ci[ir] += rsize; 1895b68353e5Sstefano_zampini nii++; 1896b68353e5Sstefano_zampini } 1897b68353e5Sstefano_zampini } 1898b68353e5Sstefano_zampini } 1899b68353e5Sstefano_zampini } 19009566063dSJacob Faibussowitsch PetscCall(PetscFree(ci)); 1901b68353e5Sstefano_zampini 1902b68353e5Sstefano_zampini /* restore info */ 1903b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1904b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1905b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1906b68353e5Sstefano_zampini if (B) { 1907b68353e5Sstefano_zampini PetscInt nnr = 0, k = i * nest->nc + j; 190823875855Sstefano_zampini 190923875855Sstefano_zampini B = (trans[k] ? trans[k] : B); 19109566063dSJacob Faibussowitsch PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done)); 191128b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ"); 19129566063dSJacob Faibussowitsch PetscCall(MatSeqAIJRestoreArray(B, &avv[k])); 19139566063dSJacob Faibussowitsch PetscCall(MatDestroy(&trans[k])); 1914b68353e5Sstefano_zampini } 1915b68353e5Sstefano_zampini } 1916b68353e5Sstefano_zampini } 19179566063dSJacob Faibussowitsch PetscCall(PetscFree4(aii, ajj, avv, trans)); 1918b68353e5Sstefano_zampini 1919b68353e5Sstefano_zampini /* finalize newmat */ 1920b68353e5Sstefano_zampini if (reuse == MAT_INITIAL_MATRIX) { 19219566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat)); 1922b68353e5Sstefano_zampini } else if (reuse == MAT_INPLACE_MATRIX) { 1923b68353e5Sstefano_zampini Mat B; 1924b68353e5Sstefano_zampini 19259566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B)); 19269566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &B)); 1927b68353e5Sstefano_zampini } 19289566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY)); 19299566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY)); 1930b68353e5Sstefano_zampini { 1931b68353e5Sstefano_zampini Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data); 1932b68353e5Sstefano_zampini a->free_a = PETSC_TRUE; 1933b68353e5Sstefano_zampini a->free_ij = PETSC_TRUE; 1934b68353e5Sstefano_zampini } 19353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1936b68353e5Sstefano_zampini } 1937b68353e5Sstefano_zampini 1938d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X) 1939d71ae5a4SJacob Faibussowitsch { 1940be705e3aSPierre Jolivet Mat_Nest *nest = (Mat_Nest *)X->data; 1941be705e3aSPierre Jolivet PetscInt i, j, k, rstart; 1942be705e3aSPierre Jolivet PetscBool flg; 1943be705e3aSPierre Jolivet 1944be705e3aSPierre Jolivet PetscFunctionBegin; 1945be705e3aSPierre Jolivet /* Fill by row */ 1946be705e3aSPierre Jolivet for (j = 0; j < nest->nc; ++j) { 1947be705e3aSPierre Jolivet /* Using global column indices and ISAllGather() is not scalable. */ 1948be705e3aSPierre Jolivet IS bNis; 1949be705e3aSPierre Jolivet PetscInt bN; 1950be705e3aSPierre Jolivet const PetscInt *bNindices; 19519566063dSJacob Faibussowitsch PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 19529566063dSJacob Faibussowitsch PetscCall(ISGetSize(bNis, &bN)); 19539566063dSJacob Faibussowitsch PetscCall(ISGetIndices(bNis, &bNindices)); 1954be705e3aSPierre Jolivet for (i = 0; i < nest->nr; ++i) { 1955fd8a7442SPierre Jolivet Mat B = nest->m[i][j], D = NULL; 1956be705e3aSPierre Jolivet PetscInt bm, br; 1957be705e3aSPierre Jolivet const PetscInt *bmindices; 1958be705e3aSPierre Jolivet if (!B) continue; 1959013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 1960be705e3aSPierre Jolivet if (flg) { 1961cac4c232SBarry Smith PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 1962cac4c232SBarry Smith PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 19639566063dSJacob Faibussowitsch PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 1964be705e3aSPierre Jolivet B = D; 1965be705e3aSPierre Jolivet } 19669566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 1967be705e3aSPierre Jolivet if (flg) { 1968fd8a7442SPierre Jolivet if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 1969fd8a7442SPierre Jolivet else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 1970be705e3aSPierre Jolivet B = D; 1971be705e3aSPierre Jolivet } 19729566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 19739566063dSJacob Faibussowitsch PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 19749566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 1975be705e3aSPierre Jolivet for (br = 0; br < bm; ++br) { 1976be705e3aSPierre Jolivet PetscInt row = bmindices[br], brncols, *cols; 1977be705e3aSPierre Jolivet const PetscInt *brcols; 1978be705e3aSPierre Jolivet const PetscScalar *brcoldata; 1979be705e3aSPierre Jolivet PetscScalar *vals = NULL; 19809566063dSJacob Faibussowitsch PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 19819566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(brncols, &cols)); 1982be705e3aSPierre Jolivet for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]]; 1983be705e3aSPierre Jolivet /* 1984be705e3aSPierre Jolivet Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match. 1985be705e3aSPierre Jolivet Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES. 1986be705e3aSPierre Jolivet */ 1987be705e3aSPierre Jolivet if (a != 1.0) { 19889566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(brncols, &vals)); 1989be705e3aSPierre Jolivet for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k]; 19909566063dSJacob Faibussowitsch PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES)); 19919566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 1992be705e3aSPierre Jolivet } else { 19939566063dSJacob Faibussowitsch PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES)); 1994be705e3aSPierre Jolivet } 19959566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 19969566063dSJacob Faibussowitsch PetscCall(PetscFree(cols)); 1997be705e3aSPierre Jolivet } 1998fd8a7442SPierre Jolivet if (D) PetscCall(MatDestroy(&D)); 19999566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 2000be705e3aSPierre Jolivet } 20019566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(bNis, &bNindices)); 20029566063dSJacob Faibussowitsch PetscCall(ISDestroy(&bNis)); 2003be705e3aSPierre Jolivet } 20049566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY)); 20059566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY)); 20063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2007be705e3aSPierre Jolivet } 2008be705e3aSPierre Jolivet 200966976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 2010d71ae5a4SJacob Faibussowitsch { 2011629c3df2SDmitry Karpeev Mat_Nest *nest = (Mat_Nest *)A->data; 2012e30678d3SPierre Jolivet PetscInt m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend; 2013b68353e5Sstefano_zampini PetscMPIInt size; 2014629c3df2SDmitry Karpeev Mat C; 2015629c3df2SDmitry Karpeev 2016629c3df2SDmitry Karpeev PetscFunctionBegin; 20179566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 2018b68353e5Sstefano_zampini if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */ 2019b68353e5Sstefano_zampini PetscInt nf; 2020b68353e5Sstefano_zampini PetscBool fast; 2021b68353e5Sstefano_zampini 20229566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(newtype, MATAIJ, &fast)); 202348a46eb9SPierre Jolivet if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast)); 2024b68353e5Sstefano_zampini for (i = 0; i < nest->nr && fast; ++i) { 2025b68353e5Sstefano_zampini for (j = 0; j < nest->nc && fast; ++j) { 2026b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 2027b68353e5Sstefano_zampini if (B) { 20289566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast)); 202923875855Sstefano_zampini if (!fast) { 203023875855Sstefano_zampini PetscBool istrans; 203123875855Sstefano_zampini 2032013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans)); 203323875855Sstefano_zampini if (istrans) { 203423875855Sstefano_zampini Mat Bt; 203523875855Sstefano_zampini 20369566063dSJacob Faibussowitsch PetscCall(MatTransposeGetMat(B, &Bt)); 20379566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 2038013e2dc7SBarry Smith } else { 2039013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans)); 2040013e2dc7SBarry Smith if (istrans) { 2041013e2dc7SBarry Smith Mat Bt; 2042013e2dc7SBarry Smith 2043013e2dc7SBarry Smith PetscCall(MatHermitianTransposeGetMat(B, &Bt)); 2044013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 2045013e2dc7SBarry Smith } 204623875855Sstefano_zampini } 2047b68353e5Sstefano_zampini } 2048b68353e5Sstefano_zampini } 2049b68353e5Sstefano_zampini } 2050b68353e5Sstefano_zampini } 2051b68353e5Sstefano_zampini for (i = 0, nf = 0; i < nest->nr && fast; ++i) { 20529566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast)); 2053b68353e5Sstefano_zampini if (fast) { 2054b68353e5Sstefano_zampini PetscInt f, s; 2055b68353e5Sstefano_zampini 20569566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s)); 20579371c9d4SSatish Balay if (f != nf || s != 1) { 20589371c9d4SSatish Balay fast = PETSC_FALSE; 20599371c9d4SSatish Balay } else { 20609566063dSJacob Faibussowitsch PetscCall(ISGetSize(nest->isglobal.row[i], &f)); 2061b68353e5Sstefano_zampini nf += f; 2062b68353e5Sstefano_zampini } 2063b68353e5Sstefano_zampini } 2064b68353e5Sstefano_zampini } 2065b68353e5Sstefano_zampini for (i = 0, nf = 0; i < nest->nc && fast; ++i) { 20669566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast)); 2067b68353e5Sstefano_zampini if (fast) { 2068b68353e5Sstefano_zampini PetscInt f, s; 2069b68353e5Sstefano_zampini 20709566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s)); 20719371c9d4SSatish Balay if (f != nf || s != 1) { 20729371c9d4SSatish Balay fast = PETSC_FALSE; 20739371c9d4SSatish Balay } else { 20749566063dSJacob Faibussowitsch PetscCall(ISGetSize(nest->isglobal.col[i], &f)); 2075b68353e5Sstefano_zampini nf += f; 2076b68353e5Sstefano_zampini } 2077b68353e5Sstefano_zampini } 2078b68353e5Sstefano_zampini } 2079b68353e5Sstefano_zampini if (fast) { 20809566063dSJacob Faibussowitsch PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat)); 20813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2082b68353e5Sstefano_zampini } 2083b68353e5Sstefano_zampini } 20849566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, &N)); 20859566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, &n)); 20869566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend)); 2087d1487292SPierre Jolivet if (reuse == MAT_REUSE_MATRIX) C = *newmat; 2088d1487292SPierre Jolivet else { 20899566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C)); 20909566063dSJacob Faibussowitsch PetscCall(MatSetType(C, newtype)); 20919566063dSJacob Faibussowitsch PetscCall(MatSetSizes(C, m, n, M, N)); 2092629c3df2SDmitry Karpeev } 20939566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(2 * m, &dnnz)); 2094e30678d3SPierre Jolivet if (m) { 2095629c3df2SDmitry Karpeev onnz = dnnz + m; 2096629c3df2SDmitry Karpeev for (k = 0; k < m; k++) { 2097629c3df2SDmitry Karpeev dnnz[k] = 0; 2098629c3df2SDmitry Karpeev onnz[k] = 0; 2099629c3df2SDmitry Karpeev } 2100e30678d3SPierre Jolivet } 2101629c3df2SDmitry Karpeev for (j = 0; j < nest->nc; ++j) { 2102629c3df2SDmitry Karpeev IS bNis; 2103629c3df2SDmitry Karpeev PetscInt bN; 2104629c3df2SDmitry Karpeev const PetscInt *bNindices; 2105fd8a7442SPierre Jolivet PetscBool flg; 2106629c3df2SDmitry Karpeev /* Using global column indices and ISAllGather() is not scalable. */ 21079566063dSJacob Faibussowitsch PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 21089566063dSJacob Faibussowitsch PetscCall(ISGetSize(bNis, &bN)); 21099566063dSJacob Faibussowitsch PetscCall(ISGetIndices(bNis, &bNindices)); 2110629c3df2SDmitry Karpeev for (i = 0; i < nest->nr; ++i) { 2111629c3df2SDmitry Karpeev PetscSF bmsf; 2112649b366bSFande Kong PetscSFNode *iremote; 2113fd8a7442SPierre Jolivet Mat B = nest->m[i][j], D = NULL; 2114649b366bSFande Kong PetscInt bm, *sub_dnnz, *sub_onnz, br; 2115629c3df2SDmitry Karpeev const PetscInt *bmindices; 2116629c3df2SDmitry Karpeev if (!B) continue; 21179566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 21189566063dSJacob Faibussowitsch PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 21199566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf)); 21209566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &iremote)); 21219566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &sub_dnnz)); 21229566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &sub_onnz)); 2123649b366bSFande Kong for (k = 0; k < bm; ++k) { 2124649b366bSFande Kong sub_dnnz[k] = 0; 2125649b366bSFande Kong sub_onnz[k] = 0; 2126649b366bSFande Kong } 2127dead4d76SPierre Jolivet PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 2128fd8a7442SPierre Jolivet if (flg) { 2129fd8a7442SPierre Jolivet PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2130fd8a7442SPierre Jolivet PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2131fd8a7442SPierre Jolivet PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 2132fd8a7442SPierre Jolivet B = D; 2133fd8a7442SPierre Jolivet } 2134fd8a7442SPierre Jolivet PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 2135fd8a7442SPierre Jolivet if (flg) { 2136fd8a7442SPierre Jolivet if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 2137fd8a7442SPierre Jolivet else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 2138fd8a7442SPierre Jolivet B = D; 2139fd8a7442SPierre Jolivet } 2140629c3df2SDmitry Karpeev /* 2141629c3df2SDmitry Karpeev Locate the owners for all of the locally-owned global row indices for this row block. 2142629c3df2SDmitry Karpeev These determine the roots of PetscSF used to communicate preallocation data to row owners. 2143629c3df2SDmitry Karpeev The roots correspond to the dnnz and onnz entries; thus, there are two roots per row. 2144629c3df2SDmitry Karpeev */ 21459566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 2146629c3df2SDmitry Karpeev for (br = 0; br < bm; ++br) { 2147131c27b5Sprj- PetscInt row = bmindices[br], brncols, col; 2148629c3df2SDmitry Karpeev const PetscInt *brcols; 2149a4b3d3acSMatthew G Knepley PetscInt rowrel = 0; /* row's relative index on its owner rank */ 2150131c27b5Sprj- PetscMPIInt rowowner = 0; 21519566063dSJacob Faibussowitsch PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel)); 2152649b366bSFande Kong /* how many roots */ 21539371c9d4SSatish Balay iremote[br].rank = rowowner; 21549371c9d4SSatish Balay iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */ 2155649b366bSFande Kong /* get nonzero pattern */ 21569566063dSJacob Faibussowitsch PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL)); 2157629c3df2SDmitry Karpeev for (k = 0; k < brncols; k++) { 2158629c3df2SDmitry Karpeev col = bNindices[brcols[k]]; 2159649b366bSFande Kong if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) { 2160649b366bSFande Kong sub_dnnz[br]++; 2161649b366bSFande Kong } else { 2162649b366bSFande Kong sub_onnz[br]++; 2163649b366bSFande Kong } 2164629c3df2SDmitry Karpeev } 21659566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL)); 2166629c3df2SDmitry Karpeev } 2167fd8a7442SPierre Jolivet if (D) PetscCall(MatDestroy(&D)); 21689566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 2169629c3df2SDmitry Karpeev /* bsf will have to take care of disposing of bedges. */ 21709566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 21719566063dSJacob Faibussowitsch PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 21729566063dSJacob Faibussowitsch PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 21739566063dSJacob Faibussowitsch PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 21749566063dSJacob Faibussowitsch PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 21759566063dSJacob Faibussowitsch PetscCall(PetscFree(sub_dnnz)); 21769566063dSJacob Faibussowitsch PetscCall(PetscFree(sub_onnz)); 21779566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&bmsf)); 2178629c3df2SDmitry Karpeev } 21799566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(bNis, &bNindices)); 21809566063dSJacob Faibussowitsch PetscCall(ISDestroy(&bNis)); 218165a4a0a3Sstefano_zampini } 218265a4a0a3Sstefano_zampini /* Resize preallocation if overestimated */ 218365a4a0a3Sstefano_zampini for (i = 0; i < m; i++) { 218465a4a0a3Sstefano_zampini dnnz[i] = PetscMin(dnnz[i], A->cmap->n); 218565a4a0a3Sstefano_zampini onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n); 2186629c3df2SDmitry Karpeev } 21879566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz)); 21889566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz)); 21899566063dSJacob Faibussowitsch PetscCall(PetscFree(dnnz)); 21909566063dSJacob Faibussowitsch PetscCall(MatAXPY_Dense_Nest(C, 1.0, A)); 2191d1487292SPierre Jolivet if (reuse == MAT_INPLACE_MATRIX) { 21929566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &C)); 2193d1487292SPierre Jolivet } else *newmat = C; 21943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2195be705e3aSPierre Jolivet } 2196629c3df2SDmitry Karpeev 219766976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 2198d71ae5a4SJacob Faibussowitsch { 2199629c3df2SDmitry Karpeev Mat B; 2200be705e3aSPierre Jolivet PetscInt m, n, M, N; 2201be705e3aSPierre Jolivet 2202be705e3aSPierre Jolivet PetscFunctionBegin; 22039566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, &N)); 22049566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, &n)); 2205be705e3aSPierre Jolivet if (reuse == MAT_REUSE_MATRIX) { 2206be705e3aSPierre Jolivet B = *newmat; 22079566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(B)); 2208be705e3aSPierre Jolivet } else { 22099566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B)); 2210629c3df2SDmitry Karpeev } 22119566063dSJacob Faibussowitsch PetscCall(MatAXPY_Dense_Nest(B, 1.0, A)); 2212be705e3aSPierre Jolivet if (reuse == MAT_INPLACE_MATRIX) { 22139566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &B)); 2214be705e3aSPierre Jolivet } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B; 22153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2216629c3df2SDmitry Karpeev } 2217629c3df2SDmitry Karpeev 221866976f2fSJacob Faibussowitsch static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has) 2219d71ae5a4SJacob Faibussowitsch { 22208b7d3b4bSBarry Smith Mat_Nest *bA = (Mat_Nest *)mat->data; 22213c6db4c4SPierre Jolivet MatOperation opAdd; 22228b7d3b4bSBarry Smith PetscInt i, j, nr = bA->nr, nc = bA->nc; 22238b7d3b4bSBarry Smith PetscBool flg; 22248b7d3b4bSBarry Smith 22254d86920dSPierre Jolivet PetscFunctionBegin; 222652c5f739Sprj- *has = PETSC_FALSE; 22273c6db4c4SPierre Jolivet if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) { 22283c6db4c4SPierre Jolivet opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD); 22298b7d3b4bSBarry Smith for (j = 0; j < nc; j++) { 22308b7d3b4bSBarry Smith for (i = 0; i < nr; i++) { 22318b7d3b4bSBarry Smith if (!bA->m[i][j]) continue; 22329566063dSJacob Faibussowitsch PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg)); 22333ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 22348b7d3b4bSBarry Smith } 22358b7d3b4bSBarry Smith } 22368b7d3b4bSBarry Smith } 22373c6db4c4SPierre Jolivet if (((void **)mat->ops)[op]) *has = PETSC_TRUE; 22383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 22398b7d3b4bSBarry Smith } 22408b7d3b4bSBarry Smith 2241659c6bb0SJed Brown /*MC 22422ef1f0ffSBarry Smith MATNEST - "nest" - Matrix type consisting of nested submatrices, each stored separately. 2243659c6bb0SJed Brown 2244659c6bb0SJed Brown Level: intermediate 2245659c6bb0SJed Brown 2246659c6bb0SJed Brown Notes: 224711a5261eSBarry Smith This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices. 2248659c6bb0SJed Brown It allows the use of symmetric and block formats for parts of multi-physics simulations. 224911a5261eSBarry Smith It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()` 2250659c6bb0SJed Brown 22518b7d3b4bSBarry Smith Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero 22528b7d3b4bSBarry Smith rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes 22538b7d3b4bSBarry Smith than the nest matrix. 22548b7d3b4bSBarry Smith 22551cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, 2256db781477SPatrick Sanan `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`, 2257db781477SPatrick Sanan `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 2258659c6bb0SJed Brown M*/ 2259d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A) 2260d71ae5a4SJacob Faibussowitsch { 2261c8883902SJed Brown Mat_Nest *s; 2262c8883902SJed Brown 2263c8883902SJed Brown PetscFunctionBegin; 22644dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&s)); 2265c8883902SJed Brown A->data = (void *)s; 2266e7c19651SJed Brown 2267e7c19651SJed Brown s->nr = -1; 2268e7c19651SJed Brown s->nc = -1; 22690298fd71SBarry Smith s->m = NULL; 2270e7c19651SJed Brown s->splitassembly = PETSC_FALSE; 2271c8883902SJed Brown 22729566063dSJacob Faibussowitsch PetscCall(PetscMemzero(A->ops, sizeof(*A->ops))); 227326fbe8dcSKarl Rupp 2274c8883902SJed Brown A->ops->mult = MatMult_Nest; 22759194d70fSJed Brown A->ops->multadd = MatMultAdd_Nest; 2276c8883902SJed Brown A->ops->multtranspose = MatMultTranspose_Nest; 22779194d70fSJed Brown A->ops->multtransposeadd = MatMultTransposeAdd_Nest; 2278f8170845SAlex Fikl A->ops->transpose = MatTranspose_Nest; 22790998551bSBlanca Mellado Pinto A->ops->multhermitiantranspose = MatMultHermitianTranspose_Nest; 22800998551bSBlanca Mellado Pinto A->ops->multhermitiantransposeadd = MatMultHermitianTransposeAdd_Nest; 2281c8883902SJed Brown A->ops->assemblybegin = MatAssemblyBegin_Nest; 2282c8883902SJed Brown A->ops->assemblyend = MatAssemblyEnd_Nest; 2283c8883902SJed Brown A->ops->zeroentries = MatZeroEntries_Nest; 2284c222c20dSDavid Ham A->ops->copy = MatCopy_Nest; 22856e76ffeaSPierre Jolivet A->ops->axpy = MatAXPY_Nest; 2286c8883902SJed Brown A->ops->duplicate = MatDuplicate_Nest; 22877dae84e0SHong Zhang A->ops->createsubmatrix = MatCreateSubMatrix_Nest; 2288c8883902SJed Brown A->ops->destroy = MatDestroy_Nest; 2289c8883902SJed Brown A->ops->view = MatView_Nest; 2290f4259b30SLisandro Dalcin A->ops->getvecs = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */ 2291c8883902SJed Brown A->ops->getlocalsubmatrix = MatGetLocalSubMatrix_Nest; 2292c8883902SJed Brown A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest; 2293429bac76SJed Brown A->ops->getdiagonal = MatGetDiagonal_Nest; 2294429bac76SJed Brown A->ops->diagonalscale = MatDiagonalScale_Nest; 2295a061e289SJed Brown A->ops->scale = MatScale_Nest; 2296a061e289SJed Brown A->ops->shift = MatShift_Nest; 229713135bc6SAlex Fikl A->ops->diagonalset = MatDiagonalSet_Nest; 2298f8170845SAlex Fikl A->ops->setrandom = MatSetRandom_Nest; 22998b7d3b4bSBarry Smith A->ops->hasoperation = MatHasOperation_Nest; 2300381b8e50SStefano Zampini A->ops->missingdiagonal = MatMissingDiagonal_Nest; 2301c8883902SJed Brown 2302f4259b30SLisandro Dalcin A->spptr = NULL; 2303c8883902SJed Brown A->assembled = PETSC_FALSE; 2304c8883902SJed Brown 2305c8883902SJed Brown /* expose Nest api's */ 23069566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest)); 23079566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest)); 23089566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest)); 23099566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest)); 23109566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest)); 23119566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest)); 23129566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest)); 23139566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest)); 23149566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ)); 23159566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ)); 23169566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ)); 23179566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS)); 23189566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense)); 23199566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense)); 23209566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense)); 23219566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense)); 2322c8883902SJed Brown 23239566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST)); 23243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2325c8883902SJed Brown } 2326