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- 251d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Nest_Dense_AB(Mat C) 252d71ae5a4SJacob Faibussowitsch { 2534222ddf1SHong Zhang PetscFunctionBegin; 2546718818eSStefano Zampini C->ops->productsymbolic = MatProductSymbolic_Nest_Dense; 2553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2564222ddf1SHong Zhang } 2574222ddf1SHong Zhang 258a678f235SPierre Jolivet static PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C) 259d71ae5a4SJacob Faibussowitsch { 2604222ddf1SHong Zhang Mat_Product *product = C->product; 26152c5f739Sprj- 26252c5f739Sprj- PetscFunctionBegin; 26348a46eb9SPierre Jolivet if (product->type == MATPRODUCT_AB) PetscCall(MatProductSetFromOptions_Nest_Dense_AB(C)); 2643ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 26552c5f739Sprj- } 26652c5f739Sprj- 267*0998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeKernel_Nest(Mat A, Vec x, Vec y, PetscBool herm) 268d71ae5a4SJacob Faibussowitsch { 269d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 270207556f9SJed Brown Vec *bx = bA->left, *by = bA->right; 271207556f9SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 272d8588912SDave May 273d8588912SDave May PetscFunctionBegin; 2749566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 2759566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i])); 276207556f9SJed Brown for (j = 0; j < nc; j++) { 2779566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(by[j])); 278609e31cbSJed Brown for (i = 0; i < nr; i++) { 2796c75ac25SJed Brown if (!bA->m[i][j]) continue; 280*0998551bSBlanca 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] */ 281*0998551bSBlanca 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] */ 282d8588912SDave May } 283d8588912SDave May } 2849566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 2859566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i])); 2863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 287d8588912SDave May } 288d8588912SDave May 289*0998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y) 290*0998551bSBlanca Mellado Pinto { 291*0998551bSBlanca Mellado Pinto PetscFunctionBegin; 292*0998551bSBlanca Mellado Pinto PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_FALSE)); 293*0998551bSBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 294*0998551bSBlanca Mellado Pinto } 295*0998551bSBlanca Mellado Pinto 296*0998551bSBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Nest(Mat A, Vec x, Vec y) 297*0998551bSBlanca Mellado Pinto { 298*0998551bSBlanca Mellado Pinto PetscFunctionBegin; 299*0998551bSBlanca Mellado Pinto PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_TRUE)); 300*0998551bSBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 301*0998551bSBlanca Mellado Pinto } 302*0998551bSBlanca Mellado Pinto 303*0998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeAddKernel_Nest(Mat A, Vec x, Vec y, Vec z, PetscBool herm) 304d71ae5a4SJacob Faibussowitsch { 3059194d70fSJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 3069194d70fSJed Brown Vec *bx = bA->left, *bz = bA->right; 3079194d70fSJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 3089194d70fSJed Brown 3099194d70fSJed Brown PetscFunctionBegin; 3109566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 3119566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i])); 3129194d70fSJed Brown for (j = 0; j < nc; j++) { 3139194d70fSJed Brown if (y != z) { 3149194d70fSJed Brown Vec by; 3159566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by)); 3169566063dSJacob Faibussowitsch PetscCall(VecCopy(by, bz[j])); 3179566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by)); 3189194d70fSJed Brown } 3199194d70fSJed Brown for (i = 0; i < nr; i++) { 3206c75ac25SJed Brown if (!bA->m[i][j]) continue; 321*0998551bSBlanca 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] */ 322*0998551bSBlanca 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] */ 3239194d70fSJed Brown } 3249194d70fSJed Brown } 3259566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 3269566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i])); 3273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3289194d70fSJed Brown } 3299194d70fSJed Brown 330*0998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z) 331*0998551bSBlanca Mellado Pinto { 332*0998551bSBlanca Mellado Pinto PetscFunctionBegin; 333*0998551bSBlanca Mellado Pinto PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_FALSE)); 334*0998551bSBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 335*0998551bSBlanca Mellado Pinto } 336*0998551bSBlanca Mellado Pinto 337*0998551bSBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z) 338*0998551bSBlanca Mellado Pinto { 339*0998551bSBlanca Mellado Pinto PetscFunctionBegin; 340*0998551bSBlanca Mellado Pinto PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_TRUE)); 341*0998551bSBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 342*0998551bSBlanca Mellado Pinto } 343*0998551bSBlanca Mellado Pinto 344d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B) 345d71ae5a4SJacob Faibussowitsch { 346f8170845SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data, *bC; 347f8170845SAlex Fikl Mat C; 348f8170845SAlex Fikl PetscInt i, j, nr = bA->nr, nc = bA->nc; 349f8170845SAlex Fikl 350f8170845SAlex Fikl PetscFunctionBegin; 3517fb60732SBarry Smith if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B)); 352aed4548fSBarry Smith PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place"); 353f8170845SAlex Fikl 354cf37664fSBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) { 355f8170845SAlex Fikl Mat *subs; 356f8170845SAlex Fikl IS *is_row, *is_col; 357f8170845SAlex Fikl 3589566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr * nc, &subs)); 3599566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col)); 3609566063dSJacob Faibussowitsch PetscCall(MatNestGetISs(A, is_row, is_col)); 361cf37664fSBarry Smith if (reuse == MAT_INPLACE_MATRIX) { 362ddeb9bd8SAlex Fikl for (i = 0; i < nr; i++) { 363ad540459SPierre Jolivet for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j]; 364ddeb9bd8SAlex Fikl } 365ddeb9bd8SAlex Fikl } 366ddeb9bd8SAlex Fikl 3679566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C)); 3689566063dSJacob Faibussowitsch PetscCall(PetscFree(subs)); 3699566063dSJacob Faibussowitsch PetscCall(PetscFree2(is_row, is_col)); 370f8170845SAlex Fikl } else { 371f8170845SAlex Fikl C = *B; 372f8170845SAlex Fikl } 373f8170845SAlex Fikl 374f8170845SAlex Fikl bC = (Mat_Nest *)C->data; 375f8170845SAlex Fikl for (i = 0; i < nr; i++) { 376f8170845SAlex Fikl for (j = 0; j < nc; j++) { 377f8170845SAlex Fikl if (bA->m[i][j]) { 3789566063dSJacob Faibussowitsch PetscCall(MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i]))); 379f8170845SAlex Fikl } else { 380f8170845SAlex Fikl bC->m[j][i] = NULL; 381f8170845SAlex Fikl } 382f8170845SAlex Fikl } 383f8170845SAlex Fikl } 384f8170845SAlex Fikl 385cf37664fSBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) { 386f8170845SAlex Fikl *B = C; 387f8170845SAlex Fikl } else { 3889566063dSJacob Faibussowitsch PetscCall(MatHeaderMerge(A, &C)); 389f8170845SAlex Fikl } 3903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 391f8170845SAlex Fikl } 392f8170845SAlex Fikl 393d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list) 394d71ae5a4SJacob Faibussowitsch { 395e2d7f03fSJed Brown IS *lst = *list; 396e2d7f03fSJed Brown PetscInt i; 397e2d7f03fSJed Brown 398e2d7f03fSJed Brown PetscFunctionBegin; 3993ba16761SJacob Faibussowitsch if (!lst) PetscFunctionReturn(PETSC_SUCCESS); 4009371c9d4SSatish Balay for (i = 0; i < n; i++) 4019371c9d4SSatish Balay if (lst[i]) PetscCall(ISDestroy(&lst[i])); 4029566063dSJacob Faibussowitsch PetscCall(PetscFree(lst)); 4030298fd71SBarry Smith *list = NULL; 4043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 405e2d7f03fSJed Brown } 406e2d7f03fSJed Brown 407d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatReset_Nest(Mat A) 408d71ae5a4SJacob Faibussowitsch { 409d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 410d8588912SDave May PetscInt i, j; 411d8588912SDave May 412d8588912SDave May PetscFunctionBegin; 413d8588912SDave May /* release the matrices and the place holders */ 4149566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row)); 4159566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col)); 4169566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row)); 4179566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col)); 418d8588912SDave May 4199566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->row_len)); 4209566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->col_len)); 4219566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->nnzstate)); 422d8588912SDave May 4239566063dSJacob Faibussowitsch PetscCall(PetscFree2(vs->left, vs->right)); 424207556f9SJed Brown 425d8588912SDave May /* release the matrices and the place holders */ 426d8588912SDave May if (vs->m) { 427d8588912SDave May for (i = 0; i < vs->nr; i++) { 42848a46eb9SPierre Jolivet for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j])); 4299566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->m[i])); 430d8588912SDave May } 4319566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->m)); 432d8588912SDave May } 43306a1af2fSStefano Zampini 43406a1af2fSStefano Zampini /* restore defaults */ 43506a1af2fSStefano Zampini vs->nr = 0; 43606a1af2fSStefano Zampini vs->nc = 0; 43706a1af2fSStefano Zampini vs->splitassembly = PETSC_FALSE; 4383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 43906a1af2fSStefano Zampini } 44006a1af2fSStefano Zampini 441d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Nest(Mat A) 442d71ae5a4SJacob Faibussowitsch { 443362febeeSStefano Zampini PetscFunctionBegin; 4449566063dSJacob Faibussowitsch PetscCall(MatReset_Nest(A)); 4459566063dSJacob Faibussowitsch PetscCall(PetscFree(A->data)); 4469566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL)); 4479566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL)); 4489566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL)); 4499566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL)); 4509566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL)); 4519566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL)); 4529566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL)); 4539566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL)); 4549566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL)); 4559566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL)); 4569566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL)); 4579566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL)); 4589566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL)); 4599566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL)); 4609566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL)); 4619566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL)); 4629566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", NULL)); 4633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 464d8588912SDave May } 465d8588912SDave May 466d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd) 467d71ae5a4SJacob Faibussowitsch { 468381b8e50SStefano Zampini Mat_Nest *vs = (Mat_Nest *)mat->data; 469381b8e50SStefano Zampini PetscInt i; 470381b8e50SStefano Zampini 471381b8e50SStefano Zampini PetscFunctionBegin; 472381b8e50SStefano Zampini if (dd) *dd = 0; 473381b8e50SStefano Zampini if (!vs->nr) { 474381b8e50SStefano Zampini *missing = PETSC_TRUE; 4753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 476381b8e50SStefano Zampini } 477381b8e50SStefano Zampini *missing = PETSC_FALSE; 478381b8e50SStefano Zampini for (i = 0; i < vs->nr && !(*missing); i++) { 479381b8e50SStefano Zampini *missing = PETSC_TRUE; 480381b8e50SStefano Zampini if (vs->m[i][i]) { 4819566063dSJacob Faibussowitsch PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL)); 48208401ef6SPierre Jolivet PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented"); 483381b8e50SStefano Zampini } 484381b8e50SStefano Zampini } 4853ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 486381b8e50SStefano Zampini } 487381b8e50SStefano Zampini 488d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type) 489d71ae5a4SJacob Faibussowitsch { 490d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 491d8588912SDave May PetscInt i, j; 49206a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 493d8588912SDave May 494d8588912SDave May PetscFunctionBegin; 495d8588912SDave May for (i = 0; i < vs->nr; i++) { 496d8588912SDave May for (j = 0; j < vs->nc; j++) { 49706a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 498e7c19651SJed Brown if (vs->m[i][j]) { 4999566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(vs->m[i][j], type)); 500e7c19651SJed Brown if (!vs->splitassembly) { 501e7c19651SJed Brown /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested 502e7c19651SJed 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 503e7c19651SJed Brown * already performing an assembly, but the result would by more complicated and appears to offer less 504e7c19651SJed Brown * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an 505e7c19651SJed Brown * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives". 506e7c19651SJed Brown */ 5079566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 5089566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate)); 509e7c19651SJed Brown } 510e7c19651SJed Brown } 51106a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate); 51206a1af2fSStefano Zampini vs->nnzstate[i * vs->nc + j] = subnnzstate; 513d8588912SDave May } 514d8588912SDave May } 51506a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 5163ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 517d8588912SDave May } 518d8588912SDave May 519d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type) 520d71ae5a4SJacob Faibussowitsch { 521d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 522d8588912SDave May PetscInt i, j; 523d8588912SDave May 524d8588912SDave May PetscFunctionBegin; 525d8588912SDave May for (i = 0; i < vs->nr; i++) { 526d8588912SDave May for (j = 0; j < vs->nc; j++) { 527e7c19651SJed Brown if (vs->m[i][j]) { 52848a46eb9SPierre Jolivet if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 529e7c19651SJed Brown } 530d8588912SDave May } 531d8588912SDave May } 5323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 533d8588912SDave May } 534d8588912SDave May 535d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B) 536d71ae5a4SJacob Faibussowitsch { 537f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 538f349c1fdSJed Brown PetscInt j; 539f349c1fdSJed Brown Mat sub; 540d8588912SDave May 541d8588912SDave May PetscFunctionBegin; 5420298fd71SBarry Smith sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */ 543f349c1fdSJed Brown for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j]; 5449566063dSJacob Faibussowitsch if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 545f349c1fdSJed Brown *B = sub; 5463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 547d8588912SDave May } 548d8588912SDave May 549d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B) 550d71ae5a4SJacob Faibussowitsch { 551f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 552f349c1fdSJed Brown PetscInt i; 553f349c1fdSJed Brown Mat sub; 554f349c1fdSJed Brown 555f349c1fdSJed Brown PetscFunctionBegin; 5560298fd71SBarry Smith sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */ 557f349c1fdSJed Brown for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col]; 5589566063dSJacob Faibussowitsch if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 559f349c1fdSJed Brown *B = sub; 5603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 561d8588912SDave May } 562d8588912SDave May 563d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end) 564d71ae5a4SJacob Faibussowitsch { 56518d228c0SPierre Jolivet PetscInt i, j, size, m; 566f349c1fdSJed Brown PetscBool flg; 56718d228c0SPierre Jolivet IS out, concatenate[2]; 568f349c1fdSJed Brown 569f349c1fdSJed Brown PetscFunctionBegin; 5704f572ea9SToby Isaac PetscAssertPointer(list, 3); 571f349c1fdSJed Brown PetscValidHeaderSpecific(is, IS_CLASSID, 4); 57218d228c0SPierre Jolivet if (begin) { 5734f572ea9SToby Isaac PetscAssertPointer(begin, 5); 57418d228c0SPierre Jolivet *begin = -1; 57518d228c0SPierre Jolivet } 57618d228c0SPierre Jolivet if (end) { 5774f572ea9SToby Isaac PetscAssertPointer(end, 6); 57818d228c0SPierre Jolivet *end = -1; 57918d228c0SPierre Jolivet } 580f349c1fdSJed Brown for (i = 0; i < n; i++) { 581207556f9SJed Brown if (!list[i]) continue; 5829566063dSJacob Faibussowitsch PetscCall(ISEqualUnsorted(list[i], is, &flg)); 583f349c1fdSJed Brown if (flg) { 58418d228c0SPierre Jolivet if (begin) *begin = i; 58518d228c0SPierre Jolivet if (end) *end = i + 1; 5863ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 587f349c1fdSJed Brown } 588f349c1fdSJed Brown } 5899566063dSJacob Faibussowitsch PetscCall(ISGetSize(is, &size)); 59018d228c0SPierre Jolivet for (i = 0; i < n - 1; i++) { 59118d228c0SPierre Jolivet if (!list[i]) continue; 59218d228c0SPierre Jolivet m = 0; 5939566063dSJacob Faibussowitsch PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out)); 5949566063dSJacob Faibussowitsch PetscCall(ISGetSize(out, &m)); 59518d228c0SPierre Jolivet for (j = i + 2; j < n && m < size; j++) { 59618d228c0SPierre Jolivet if (list[j]) { 59718d228c0SPierre Jolivet concatenate[0] = out; 59818d228c0SPierre Jolivet concatenate[1] = list[j]; 5999566063dSJacob Faibussowitsch PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out)); 6009566063dSJacob Faibussowitsch PetscCall(ISDestroy(concatenate)); 6019566063dSJacob Faibussowitsch PetscCall(ISGetSize(out, &m)); 60218d228c0SPierre Jolivet } 60318d228c0SPierre Jolivet } 60418d228c0SPierre Jolivet if (m == size) { 6059566063dSJacob Faibussowitsch PetscCall(ISEqualUnsorted(out, is, &flg)); 60618d228c0SPierre Jolivet if (flg) { 60718d228c0SPierre Jolivet if (begin) *begin = i; 60818d228c0SPierre Jolivet if (end) *end = j; 6099566063dSJacob Faibussowitsch PetscCall(ISDestroy(&out)); 6103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 61118d228c0SPierre Jolivet } 61218d228c0SPierre Jolivet } 6139566063dSJacob Faibussowitsch PetscCall(ISDestroy(&out)); 61418d228c0SPierre Jolivet } 6153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 616f349c1fdSJed Brown } 617f349c1fdSJed Brown 618d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B) 619d71ae5a4SJacob Faibussowitsch { 6208188e55aSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 62118d228c0SPierre Jolivet PetscInt lr, lc; 62218d228c0SPierre Jolivet 62318d228c0SPierre Jolivet PetscFunctionBegin; 6249566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 6259566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr)); 6269566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc)); 6279566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE)); 6289566063dSJacob Faibussowitsch PetscCall(MatSetType(*B, MATAIJ)); 6299566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL)); 6309566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL)); 6319566063dSJacob Faibussowitsch PetscCall(MatSetUp(*B)); 6329566063dSJacob Faibussowitsch PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 6339566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 6349566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 6353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 63618d228c0SPierre Jolivet } 63718d228c0SPierre Jolivet 638d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B) 639d71ae5a4SJacob Faibussowitsch { 64018d228c0SPierre Jolivet Mat_Nest *vs = (Mat_Nest *)A->data; 64118d228c0SPierre Jolivet Mat *a; 64218d228c0SPierre Jolivet PetscInt i, j, k, l, nr = rend - rbegin, nc = cend - cbegin; 6438188e55aSJed Brown char keyname[256]; 64418d228c0SPierre Jolivet PetscBool *b; 64518d228c0SPierre Jolivet PetscBool flg; 6468188e55aSJed Brown 6478188e55aSJed Brown PetscFunctionBegin; 6480298fd71SBarry Smith *B = NULL; 6499566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend)); 6509566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B)); 6513ba16761SJacob Faibussowitsch if (*B) PetscFunctionReturn(PETSC_SUCCESS); 6528188e55aSJed Brown 6539566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b)); 65418d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 65518d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 65618d228c0SPierre Jolivet a[i * nc + j] = vs->m[rbegin + i][cbegin + j]; 65718d228c0SPierre Jolivet b[i * nc + j] = PETSC_FALSE; 65818d228c0SPierre Jolivet } 65918d228c0SPierre Jolivet } 66018d228c0SPierre Jolivet if (nc != vs->nc && nr != vs->nr) { 66118d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 66218d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 66318d228c0SPierre Jolivet flg = PETSC_FALSE; 66418d228c0SPierre Jolivet for (k = 0; (k < nr && !flg); k++) { 66518d228c0SPierre Jolivet if (a[j + k * nc]) flg = PETSC_TRUE; 66618d228c0SPierre Jolivet } 66718d228c0SPierre Jolivet if (flg) { 66818d228c0SPierre Jolivet flg = PETSC_FALSE; 66918d228c0SPierre Jolivet for (l = 0; (l < nc && !flg); l++) { 67018d228c0SPierre Jolivet if (a[i * nc + l]) flg = PETSC_TRUE; 67118d228c0SPierre Jolivet } 67218d228c0SPierre Jolivet } 67318d228c0SPierre Jolivet if (!flg) { 67418d228c0SPierre Jolivet b[i * nc + j] = PETSC_TRUE; 6759566063dSJacob Faibussowitsch PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j)); 67618d228c0SPierre Jolivet } 67718d228c0SPierre Jolivet } 67818d228c0SPierre Jolivet } 67918d228c0SPierre Jolivet } 6809566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B)); 68118d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 68218d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 68348a46eb9SPierre Jolivet if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j)); 68418d228c0SPierre Jolivet } 68518d228c0SPierre Jolivet } 6869566063dSJacob Faibussowitsch PetscCall(PetscFree2(a, b)); 6878188e55aSJed Brown (*B)->assembled = A->assembled; 6889566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B)); 6899566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */ 6903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6918188e55aSJed Brown } 6928188e55aSJed Brown 693d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B) 694d71ae5a4SJacob Faibussowitsch { 695f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 69618d228c0SPierre Jolivet PetscInt rbegin, rend, cbegin, cend; 697f349c1fdSJed Brown 698f349c1fdSJed Brown PetscFunctionBegin; 6999566063dSJacob Faibussowitsch PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend)); 7009566063dSJacob Faibussowitsch PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend)); 70118d228c0SPierre Jolivet if (rend == rbegin + 1 && cend == cbegin + 1) { 70248a46eb9SPierre Jolivet if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin)); 70318d228c0SPierre Jolivet *B = vs->m[rbegin][cbegin]; 70418d228c0SPierre Jolivet } else if (rbegin != -1 && cbegin != -1) { 7059566063dSJacob Faibussowitsch PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B)); 70618d228c0SPierre Jolivet } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set"); 7073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 708f349c1fdSJed Brown } 709f349c1fdSJed Brown 71006a1af2fSStefano Zampini /* 71106a1af2fSStefano Zampini TODO: This does not actually returns a submatrix we can modify 71206a1af2fSStefano Zampini */ 713d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B) 714d71ae5a4SJacob Faibussowitsch { 715f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 716f349c1fdSJed Brown Mat sub; 717f349c1fdSJed Brown 718f349c1fdSJed Brown PetscFunctionBegin; 7199566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub)); 720f349c1fdSJed Brown switch (reuse) { 721f349c1fdSJed Brown case MAT_INITIAL_MATRIX: 7229566063dSJacob Faibussowitsch if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 723f349c1fdSJed Brown *B = sub; 724f349c1fdSJed Brown break; 725d71ae5a4SJacob Faibussowitsch case MAT_REUSE_MATRIX: 726d71ae5a4SJacob Faibussowitsch PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call"); 727d71ae5a4SJacob Faibussowitsch break; 728d71ae5a4SJacob Faibussowitsch case MAT_IGNORE_MATRIX: /* Nothing to do */ 729d71ae5a4SJacob Faibussowitsch break; 730d71ae5a4SJacob Faibussowitsch case MAT_INPLACE_MATRIX: /* Nothing to do */ 731d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet"); 732f349c1fdSJed Brown } 7333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 734f349c1fdSJed Brown } 735f349c1fdSJed Brown 73666976f2fSJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) 737d71ae5a4SJacob Faibussowitsch { 738f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 739f349c1fdSJed Brown Mat sub; 740f349c1fdSJed Brown 741f349c1fdSJed Brown PetscFunctionBegin; 7429566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 743f349c1fdSJed Brown /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */ 7449566063dSJacob Faibussowitsch if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 745f349c1fdSJed Brown *B = sub; 7463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 747d8588912SDave May } 748d8588912SDave May 749d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) 750d71ae5a4SJacob Faibussowitsch { 751f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 752f349c1fdSJed Brown Mat sub; 753d8588912SDave May 754d8588912SDave May PetscFunctionBegin; 7559566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 75608401ef6SPierre Jolivet PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten"); 757f349c1fdSJed Brown if (sub) { 758aed4548fSBarry Smith PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times"); 7599566063dSJacob Faibussowitsch PetscCall(MatDestroy(B)); 760d8588912SDave May } 7613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 762d8588912SDave May } 763d8588912SDave May 764d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v) 765d71ae5a4SJacob Faibussowitsch { 7667874fa86SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 7677874fa86SDave May PetscInt i; 7687874fa86SDave May 7697874fa86SDave May PetscFunctionBegin; 7707874fa86SDave May for (i = 0; i < bA->nr; i++) { 771429bac76SJed Brown Vec bv; 7729566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv)); 7737874fa86SDave May if (bA->m[i][i]) { 7749566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(bA->m[i][i], bv)); 7757874fa86SDave May } else { 7769566063dSJacob Faibussowitsch PetscCall(VecSet(bv, 0.0)); 7777874fa86SDave May } 7789566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv)); 7797874fa86SDave May } 7803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 7817874fa86SDave May } 7827874fa86SDave May 783d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r) 784d71ae5a4SJacob Faibussowitsch { 7857874fa86SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 786429bac76SJed Brown Vec bl, *br; 7877874fa86SDave May PetscInt i, j; 7887874fa86SDave May 7897874fa86SDave May PetscFunctionBegin; 7909566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(bA->nc, &br)); 7912e6472ebSElliott Sales de Andrade if (r) { 7929566063dSJacob Faibussowitsch for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j])); 7932e6472ebSElliott Sales de Andrade } 7942e6472ebSElliott Sales de Andrade bl = NULL; 7957874fa86SDave May for (i = 0; i < bA->nr; i++) { 79648a46eb9SPierre Jolivet if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl)); 7977874fa86SDave May for (j = 0; j < bA->nc; j++) { 79848a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j])); 7997874fa86SDave May } 80048a46eb9SPierre Jolivet if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl)); 8012e6472ebSElliott Sales de Andrade } 8022e6472ebSElliott Sales de Andrade if (r) { 8039566063dSJacob Faibussowitsch for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j])); 8042e6472ebSElliott Sales de Andrade } 8059566063dSJacob Faibussowitsch PetscCall(PetscFree(br)); 8063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 8077874fa86SDave May } 8087874fa86SDave May 809d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a) 810d71ae5a4SJacob Faibussowitsch { 811a061e289SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 812a061e289SJed Brown PetscInt i, j; 813a061e289SJed Brown 814a061e289SJed Brown PetscFunctionBegin; 815a061e289SJed Brown for (i = 0; i < bA->nr; i++) { 816a061e289SJed Brown for (j = 0; j < bA->nc; j++) { 81748a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a)); 818a061e289SJed Brown } 819a061e289SJed Brown } 8203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 821a061e289SJed Brown } 822a061e289SJed Brown 823d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a) 824d71ae5a4SJacob Faibussowitsch { 825a061e289SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 826a061e289SJed Brown PetscInt i; 82706a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 828a061e289SJed Brown 829a061e289SJed Brown PetscFunctionBegin; 830a061e289SJed Brown for (i = 0; i < bA->nr; i++) { 83106a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 83208401ef6SPierre 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); 8339566063dSJacob Faibussowitsch PetscCall(MatShift(bA->m[i][i], a)); 8349566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 83506a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 83606a1af2fSStefano Zampini bA->nnzstate[i * bA->nc + i] = subnnzstate; 837a061e289SJed Brown } 83806a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 8393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 840a061e289SJed Brown } 841a061e289SJed Brown 842d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is) 843d71ae5a4SJacob Faibussowitsch { 84413135bc6SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data; 84513135bc6SAlex Fikl PetscInt i; 84606a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 84713135bc6SAlex Fikl 84813135bc6SAlex Fikl PetscFunctionBegin; 84913135bc6SAlex Fikl for (i = 0; i < bA->nr; i++) { 85006a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 85113135bc6SAlex Fikl Vec bv; 8529566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv)); 85313135bc6SAlex Fikl if (bA->m[i][i]) { 8549566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet(bA->m[i][i], bv, is)); 8559566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 85613135bc6SAlex Fikl } 8579566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv)); 85806a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 85906a1af2fSStefano Zampini bA->nnzstate[i * bA->nc + i] = subnnzstate; 86013135bc6SAlex Fikl } 86106a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 8623ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 86313135bc6SAlex Fikl } 86413135bc6SAlex Fikl 865d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx) 866d71ae5a4SJacob Faibussowitsch { 867f8170845SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data; 868f8170845SAlex Fikl PetscInt i, j; 869f8170845SAlex Fikl 870f8170845SAlex Fikl PetscFunctionBegin; 871f8170845SAlex Fikl for (i = 0; i < bA->nr; i++) { 872f8170845SAlex Fikl for (j = 0; j < bA->nc; j++) { 87348a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx)); 874f8170845SAlex Fikl } 875f8170845SAlex Fikl } 8763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 877f8170845SAlex Fikl } 878f8170845SAlex Fikl 879d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left) 880d71ae5a4SJacob Faibussowitsch { 881d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 882d8588912SDave May Vec *L, *R; 883d8588912SDave May MPI_Comm comm; 884d8588912SDave May PetscInt i, j; 885d8588912SDave May 886d8588912SDave May PetscFunctionBegin; 8879566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)A, &comm)); 888d8588912SDave May if (right) { 889d8588912SDave May /* allocate R */ 8909566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bA->nc, &R)); 891d8588912SDave May /* Create the right vectors */ 892d8588912SDave May for (j = 0; j < bA->nc; j++) { 893d8588912SDave May for (i = 0; i < bA->nr; i++) { 894d8588912SDave May if (bA->m[i][j]) { 8959566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL)); 896d8588912SDave May break; 897d8588912SDave May } 898d8588912SDave May } 89908401ef6SPierre Jolivet PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column."); 900d8588912SDave May } 9019566063dSJacob Faibussowitsch PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right)); 902d8588912SDave May /* hand back control to the nest vector */ 90348a46eb9SPierre Jolivet for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j])); 9049566063dSJacob Faibussowitsch PetscCall(PetscFree(R)); 905d8588912SDave May } 906d8588912SDave May 907d8588912SDave May if (left) { 908d8588912SDave May /* allocate L */ 9099566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bA->nr, &L)); 910d8588912SDave May /* Create the left vectors */ 911d8588912SDave May for (i = 0; i < bA->nr; i++) { 912d8588912SDave May for (j = 0; j < bA->nc; j++) { 913d8588912SDave May if (bA->m[i][j]) { 9149566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i])); 915d8588912SDave May break; 916d8588912SDave May } 917d8588912SDave May } 91808401ef6SPierre Jolivet PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row."); 919d8588912SDave May } 920d8588912SDave May 9219566063dSJacob Faibussowitsch PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left)); 92248a46eb9SPierre Jolivet for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i])); 923d8588912SDave May 9249566063dSJacob Faibussowitsch PetscCall(PetscFree(L)); 925d8588912SDave May } 9263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 927d8588912SDave May } 928d8588912SDave May 929d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer) 930d71ae5a4SJacob Faibussowitsch { 931d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 93229e60adbSStefano Zampini PetscBool isascii, viewSub = PETSC_FALSE; 933d8588912SDave May PetscInt i, j; 934d8588912SDave May 935d8588912SDave May PetscFunctionBegin; 9369566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 937d8588912SDave May if (isascii) { 9389566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL)); 9399566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object:\n")); 9409566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 9419566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", bA->nr, bA->nc)); 942d8588912SDave May 9439566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure:\n")); 944d8588912SDave May for (i = 0; i < bA->nr; i++) { 945d8588912SDave May for (j = 0; j < bA->nc; j++) { 94619fd82e9SBarry Smith MatType type; 947270f95d7SJed Brown char name[256] = "", prefix[256] = ""; 948d8588912SDave May PetscInt NR, NC; 949d8588912SDave May PetscBool isNest = PETSC_FALSE; 950d8588912SDave May 951d8588912SDave May if (!bA->m[i][j]) { 9529566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j)); 953d8588912SDave May continue; 954d8588912SDave May } 9559566063dSJacob Faibussowitsch PetscCall(MatGetSize(bA->m[i][j], &NR, &NC)); 9569566063dSJacob Faibussowitsch PetscCall(MatGetType(bA->m[i][j], &type)); 9579566063dSJacob Faibussowitsch if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name)); 9589566063dSJacob Faibussowitsch if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix)); 9599566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest)); 960d8588912SDave May 9619566063dSJacob 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)); 962d8588912SDave May 96329e60adbSStefano Zampini if (isNest || viewSub) { 9649566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */ 9659566063dSJacob Faibussowitsch PetscCall(MatView(bA->m[i][j], viewer)); 9669566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */ 967d8588912SDave May } 968d8588912SDave May } 969d8588912SDave May } 9709566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */ 971d8588912SDave May } 9723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 973d8588912SDave May } 974d8588912SDave May 975d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A) 976d71ae5a4SJacob Faibussowitsch { 977d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 978d8588912SDave May PetscInt i, j; 979d8588912SDave May 980d8588912SDave May PetscFunctionBegin; 981d8588912SDave May for (i = 0; i < bA->nr; i++) { 982d8588912SDave May for (j = 0; j < bA->nc; j++) { 983d8588912SDave May if (!bA->m[i][j]) continue; 9849566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(bA->m[i][j])); 985d8588912SDave May } 986d8588912SDave May } 9873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 988d8588912SDave May } 989d8588912SDave May 990d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str) 991d71ae5a4SJacob Faibussowitsch { 992c222c20dSDavid Ham Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data; 993c222c20dSDavid Ham PetscInt i, j, nr = bA->nr, nc = bA->nc; 99406a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 995c222c20dSDavid Ham 996c222c20dSDavid Ham PetscFunctionBegin; 997aed4548fSBarry 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); 998c222c20dSDavid Ham for (i = 0; i < nr; i++) { 999c222c20dSDavid Ham for (j = 0; j < nc; j++) { 100006a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 100146a2b97cSJed Brown if (bA->m[i][j] && bB->m[i][j]) { 10029566063dSJacob Faibussowitsch PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str)); 100308401ef6SPierre 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); 10049566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate)); 100506a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate); 100606a1af2fSStefano Zampini bB->nnzstate[i * nc + j] = subnnzstate; 1007c222c20dSDavid Ham } 1008c222c20dSDavid Ham } 100906a1af2fSStefano Zampini if (nnzstate) B->nonzerostate++; 10103ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1011c222c20dSDavid Ham } 1012c222c20dSDavid Ham 1013d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str) 1014d71ae5a4SJacob Faibussowitsch { 10156e76ffeaSPierre Jolivet Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data; 10166e76ffeaSPierre Jolivet PetscInt i, j, nr = bY->nr, nc = bY->nc; 101706a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 10186e76ffeaSPierre Jolivet 10196e76ffeaSPierre Jolivet PetscFunctionBegin; 1020aed4548fSBarry 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); 10216e76ffeaSPierre Jolivet for (i = 0; i < nr; i++) { 10226e76ffeaSPierre Jolivet for (j = 0; j < nc; j++) { 102306a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 10246e76ffeaSPierre Jolivet if (bY->m[i][j] && bX->m[i][j]) { 10259566063dSJacob Faibussowitsch PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str)); 1026c066aebcSStefano Zampini } else if (bX->m[i][j]) { 1027c066aebcSStefano Zampini Mat M; 1028c066aebcSStefano Zampini 1029e75569e9SPierre 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); 10309566063dSJacob Faibussowitsch PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M)); 10319566063dSJacob Faibussowitsch PetscCall(MatNestSetSubMat(Y, i, j, M)); 10329566063dSJacob Faibussowitsch PetscCall(MatDestroy(&M)); 1033c066aebcSStefano Zampini } 10349566063dSJacob Faibussowitsch if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate)); 103506a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate); 103606a1af2fSStefano Zampini bY->nnzstate[i * nc + j] = subnnzstate; 10376e76ffeaSPierre Jolivet } 10386e76ffeaSPierre Jolivet } 103906a1af2fSStefano Zampini if (nnzstate) Y->nonzerostate++; 10403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10416e76ffeaSPierre Jolivet } 10426e76ffeaSPierre Jolivet 1043d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B) 1044d71ae5a4SJacob Faibussowitsch { 1045d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 1046841e96a3SJed Brown Mat *b; 1047841e96a3SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 1048d8588912SDave May 1049d8588912SDave May PetscFunctionBegin; 10509566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr * nc, &b)); 1051841e96a3SJed Brown for (i = 0; i < nr; i++) { 1052841e96a3SJed Brown for (j = 0; j < nc; j++) { 1053841e96a3SJed Brown if (bA->m[i][j]) { 10549566063dSJacob Faibussowitsch PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j])); 1055841e96a3SJed Brown } else { 10560298fd71SBarry Smith b[i * nc + j] = NULL; 1057d8588912SDave May } 1058d8588912SDave May } 1059d8588912SDave May } 10609566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B)); 1061841e96a3SJed Brown /* Give the new MatNest exclusive ownership */ 106248a46eb9SPierre Jolivet for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i])); 10639566063dSJacob Faibussowitsch PetscCall(PetscFree(b)); 1064d8588912SDave May 10659566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 10669566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 10673ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1068d8588912SDave May } 1069d8588912SDave May 1070d8588912SDave May /* nest api */ 107166976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat) 1072d71ae5a4SJacob Faibussowitsch { 1073d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 10745fd66863SKarl Rupp 1075d8588912SDave May PetscFunctionBegin; 107608401ef6SPierre Jolivet PetscCheck(idxm < bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm, bA->nr - 1); 107708401ef6SPierre Jolivet PetscCheck(jdxm < bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT, jdxm, bA->nc - 1); 1078d8588912SDave May *mat = bA->m[idxm][jdxm]; 10793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1080d8588912SDave May } 1081d8588912SDave May 10829ba0d327SJed Brown /*@ 108311a5261eSBarry Smith MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST` 1084d8588912SDave May 10852ef1f0ffSBarry Smith Not Collective 1086d8588912SDave May 1087d8588912SDave May Input Parameters: 108811a5261eSBarry Smith + A - `MATNEST` matrix 1089d8588912SDave May . idxm - index of the matrix within the nest matrix 1090629881c0SJed Brown - jdxm - index of the matrix within the nest matrix 1091d8588912SDave May 1092d8588912SDave May Output Parameter: 10932ef1f0ffSBarry Smith . sub - matrix at index `idxm`, `jdxm` within the nest matrix 1094d8588912SDave May 1095d8588912SDave May Level: developer 1096d8588912SDave May 1097fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`, 1098db781477SPatrick Sanan `MatNestGetLocalISs()`, `MatNestGetISs()` 1099d8588912SDave May @*/ 1100d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub) 1101d71ae5a4SJacob Faibussowitsch { 1102d8588912SDave May PetscFunctionBegin; 1103cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub)); 11043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1105d8588912SDave May } 1106d8588912SDave May 110766976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat) 1108d71ae5a4SJacob Faibussowitsch { 11090782ca92SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 11100782ca92SJed Brown PetscInt m, n, M, N, mi, ni, Mi, Ni; 11110782ca92SJed Brown 11120782ca92SJed Brown PetscFunctionBegin; 111308401ef6SPierre 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); 111408401ef6SPierre 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); 11159566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 11169566063dSJacob Faibussowitsch PetscCall(MatGetSize(mat, &M, &N)); 11179566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi)); 11189566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi)); 11199566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni)); 11209566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni)); 1121aed4548fSBarry 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); 1122aed4548fSBarry 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); 112326fbe8dcSKarl Rupp 112406a1af2fSStefano Zampini /* do not increase object state */ 11253ba16761SJacob Faibussowitsch if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS); 112606a1af2fSStefano Zampini 11279566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat)); 11289566063dSJacob Faibussowitsch PetscCall(MatDestroy(&bA->m[idxm][jdxm])); 11290782ca92SJed Brown bA->m[idxm][jdxm] = mat; 11309566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)A)); 11319566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm])); 113206a1af2fSStefano Zampini A->nonzerostate++; 11333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11340782ca92SJed Brown } 11350782ca92SJed Brown 11369ba0d327SJed Brown /*@ 113711a5261eSBarry Smith MatNestSetSubMat - Set a single submatrix in the `MATNEST` 11380782ca92SJed Brown 11392ef1f0ffSBarry Smith Logically Collective 11400782ca92SJed Brown 11410782ca92SJed Brown Input Parameters: 114211a5261eSBarry Smith + A - `MATNEST` matrix 11430782ca92SJed Brown . idxm - index of the matrix within the nest matrix 11440782ca92SJed Brown . jdxm - index of the matrix within the nest matrix 11452ef1f0ffSBarry Smith - sub - matrix at index `idxm`, `jdxm` within the nest matrix 11462ef1f0ffSBarry Smith 11472ef1f0ffSBarry Smith Level: developer 11480782ca92SJed Brown 11490782ca92SJed Brown Notes: 11500782ca92SJed Brown The new submatrix must have the same size and communicator as that block of the nest. 11510782ca92SJed Brown 11520782ca92SJed Brown This increments the reference count of the submatrix. 11530782ca92SJed Brown 1154fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`, 1155db781477SPatrick Sanan `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()` 11560782ca92SJed Brown @*/ 1157d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub) 1158d71ae5a4SJacob Faibussowitsch { 11590782ca92SJed Brown PetscFunctionBegin; 1160cac4c232SBarry Smith PetscUseMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub)); 11613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11620782ca92SJed Brown } 11630782ca92SJed Brown 116466976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) 1165d71ae5a4SJacob Faibussowitsch { 1166d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 11675fd66863SKarl Rupp 1168d8588912SDave May PetscFunctionBegin; 116926fbe8dcSKarl Rupp if (M) *M = bA->nr; 117026fbe8dcSKarl Rupp if (N) *N = bA->nc; 117126fbe8dcSKarl Rupp if (mat) *mat = bA->m; 11723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1173d8588912SDave May } 1174d8588912SDave May 1175d8588912SDave May /*@C 117611a5261eSBarry Smith MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix. 1177d8588912SDave May 11782ef1f0ffSBarry Smith Not Collective 1179d8588912SDave May 1180f899ff85SJose E. Roman Input Parameter: 1181629881c0SJed Brown . A - nest matrix 1182d8588912SDave May 1183d8d19677SJose E. Roman Output Parameters: 1184629881c0SJed Brown + M - number of rows in the nest matrix 1185d8588912SDave May . N - number of cols in the nest matrix 1186629881c0SJed Brown - mat - 2d array of matrices 1187d8588912SDave May 11882ef1f0ffSBarry Smith Level: developer 11892ef1f0ffSBarry Smith 119011a5261eSBarry Smith Note: 11912ef1f0ffSBarry Smith The user should not free the array `mat`. 1192d8588912SDave May 1193fe59aa6dSJacob Faibussowitsch Fortran Notes: 119411a5261eSBarry Smith This routine has a calling sequence 1195351962e3SVincent Le Chenadec $ call MatNestGetSubMats(A, M, N, mat, ierr) 119620f4b53cSBarry Smith where the space allocated for the optional argument `mat` is assumed large enough (if provided). 1197351962e3SVincent Le Chenadec 1198fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`, 1199db781477SPatrick Sanan `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()` 1200d8588912SDave May @*/ 1201d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) 1202d71ae5a4SJacob Faibussowitsch { 1203d8588912SDave May PetscFunctionBegin; 1204cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat)); 12053ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1206d8588912SDave May } 1207d8588912SDave May 120866976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N) 1209d71ae5a4SJacob Faibussowitsch { 1210d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 1211d8588912SDave May 1212d8588912SDave May PetscFunctionBegin; 121326fbe8dcSKarl Rupp if (M) *M = bA->nr; 121426fbe8dcSKarl Rupp if (N) *N = bA->nc; 12153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1216d8588912SDave May } 1217d8588912SDave May 12189ba0d327SJed Brown /*@ 121911a5261eSBarry Smith MatNestGetSize - Returns the size of the `MATNEST` matrix. 1220d8588912SDave May 12212ef1f0ffSBarry Smith Not Collective 1222d8588912SDave May 1223f899ff85SJose E. Roman Input Parameter: 122411a5261eSBarry Smith . A - `MATNEST` matrix 1225d8588912SDave May 1226d8d19677SJose E. Roman Output Parameters: 1227629881c0SJed Brown + M - number of rows in the nested mat 1228629881c0SJed Brown - N - number of cols in the nested mat 1229d8588912SDave May 1230d8588912SDave May Level: developer 1231d8588912SDave May 1232fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`, 1233db781477SPatrick Sanan `MatNestGetISs()` 1234d8588912SDave May @*/ 1235d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N) 1236d71ae5a4SJacob Faibussowitsch { 1237d8588912SDave May PetscFunctionBegin; 1238cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N)); 12393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1240d8588912SDave May } 1241d8588912SDave May 1242d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[]) 1243d71ae5a4SJacob Faibussowitsch { 1244900e7ff2SJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 1245900e7ff2SJed Brown PetscInt i; 1246900e7ff2SJed Brown 1247900e7ff2SJed Brown PetscFunctionBegin; 12489371c9d4SSatish Balay if (rows) 12499371c9d4SSatish Balay for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i]; 12509371c9d4SSatish Balay if (cols) 12519371c9d4SSatish Balay for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i]; 12523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1253900e7ff2SJed Brown } 1254900e7ff2SJed Brown 12553a4d7b9aSSatish Balay /*@C 125611a5261eSBarry Smith MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST` 1257900e7ff2SJed Brown 12582ef1f0ffSBarry Smith Not Collective 1259900e7ff2SJed Brown 1260f899ff85SJose E. Roman Input Parameter: 126111a5261eSBarry Smith . A - `MATNEST` matrix 1262900e7ff2SJed Brown 1263d8d19677SJose E. Roman Output Parameters: 1264900e7ff2SJed Brown + rows - array of row index sets 1265900e7ff2SJed Brown - cols - array of column index sets 1266900e7ff2SJed Brown 1267900e7ff2SJed Brown Level: advanced 1268900e7ff2SJed Brown 126911a5261eSBarry Smith Note: 12702ef1f0ffSBarry Smith The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s. 1271900e7ff2SJed Brown 1272fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`, 1273fe59aa6dSJacob Faibussowitsch `MatCreateNest()`, `MatNestSetSubMats()` 1274900e7ff2SJed Brown @*/ 1275d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[]) 1276d71ae5a4SJacob Faibussowitsch { 1277900e7ff2SJed Brown PetscFunctionBegin; 1278900e7ff2SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1279cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 12803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1281900e7ff2SJed Brown } 1282900e7ff2SJed Brown 1283d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[]) 1284d71ae5a4SJacob Faibussowitsch { 1285900e7ff2SJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 1286900e7ff2SJed Brown PetscInt i; 1287900e7ff2SJed Brown 1288900e7ff2SJed Brown PetscFunctionBegin; 12899371c9d4SSatish Balay if (rows) 12909371c9d4SSatish Balay for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i]; 12919371c9d4SSatish Balay if (cols) 12929371c9d4SSatish Balay for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i]; 12933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1294900e7ff2SJed Brown } 1295900e7ff2SJed Brown 1296900e7ff2SJed Brown /*@C 129711a5261eSBarry Smith MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST` 1298900e7ff2SJed Brown 12992ef1f0ffSBarry Smith Not Collective 1300900e7ff2SJed Brown 1301f899ff85SJose E. Roman Input Parameter: 130211a5261eSBarry Smith . A - `MATNEST` matrix 1303900e7ff2SJed Brown 1304d8d19677SJose E. Roman Output Parameters: 13052ef1f0ffSBarry Smith + rows - array of row index sets (or `NULL` to ignore) 13062ef1f0ffSBarry Smith - cols - array of column index sets (or `NULL` to ignore) 1307900e7ff2SJed Brown 1308900e7ff2SJed Brown Level: advanced 1309900e7ff2SJed Brown 131011a5261eSBarry Smith Note: 13112ef1f0ffSBarry Smith The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s. 1312900e7ff2SJed Brown 13131cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`, 1314fe59aa6dSJacob Faibussowitsch `MatNestSetSubMats()`, `MatNestSetSubMat()` 1315900e7ff2SJed Brown @*/ 1316d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[]) 1317d71ae5a4SJacob Faibussowitsch { 1318900e7ff2SJed Brown PetscFunctionBegin; 1319900e7ff2SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1320cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 13213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1322900e7ff2SJed Brown } 1323900e7ff2SJed Brown 132466976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype) 1325d71ae5a4SJacob Faibussowitsch { 1326207556f9SJed Brown PetscBool flg; 1327207556f9SJed Brown 1328207556f9SJed Brown PetscFunctionBegin; 13299566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, VECNEST, &flg)); 1330207556f9SJed Brown /* In reality, this only distinguishes VECNEST and "other" */ 13312a7a6963SBarry Smith if (flg) A->ops->getvecs = MatCreateVecs_Nest; 133212b53f24SSatish Balay else A->ops->getvecs = (PetscErrorCode(*)(Mat, Vec *, Vec *))0; 13333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1334207556f9SJed Brown } 1335207556f9SJed Brown 1336207556f9SJed Brown /*@C 133711a5261eSBarry Smith MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()` 1338207556f9SJed Brown 13392ef1f0ffSBarry Smith Not Collective 1340207556f9SJed Brown 1341207556f9SJed Brown Input Parameters: 134211a5261eSBarry Smith + A - `MATNEST` matrix 134311a5261eSBarry Smith - vtype - `VecType` to use for creating vectors 1344207556f9SJed Brown 1345207556f9SJed Brown Level: developer 1346207556f9SJed Brown 1347fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType` 1348207556f9SJed Brown @*/ 1349d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype) 1350d71ae5a4SJacob Faibussowitsch { 1351207556f9SJed Brown PetscFunctionBegin; 1352cac4c232SBarry Smith PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype)); 13533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1354207556f9SJed Brown } 1355207556f9SJed Brown 135666976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) 1357d71ae5a4SJacob Faibussowitsch { 1358c8883902SJed Brown Mat_Nest *s = (Mat_Nest *)A->data; 1359c8883902SJed Brown PetscInt i, j, m, n, M, N; 136088ffe2e8SJose E. Roman PetscBool cong, isstd, sametype = PETSC_FALSE; 136188ffe2e8SJose E. Roman VecType vtype, type; 1362d8588912SDave May 1363d8588912SDave May PetscFunctionBegin; 13649566063dSJacob Faibussowitsch PetscCall(MatReset_Nest(A)); 136506a1af2fSStefano Zampini 1366c8883902SJed Brown s->nr = nr; 1367c8883902SJed Brown s->nc = nc; 1368d8588912SDave May 1369c8883902SJed Brown /* Create space for submatrices */ 13709566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &s->m)); 137148a46eb9SPierre Jolivet for (i = 0; i < nr; i++) PetscCall(PetscMalloc1(nc, &s->m[i])); 1372c8883902SJed Brown for (i = 0; i < nr; i++) { 1373c8883902SJed Brown for (j = 0; j < nc; j++) { 1374c8883902SJed Brown s->m[i][j] = a[i * nc + j]; 137548a46eb9SPierre Jolivet if (a[i * nc + j]) PetscCall(PetscObjectReference((PetscObject)a[i * nc + j])); 1376d8588912SDave May } 1377d8588912SDave May } 13789566063dSJacob Faibussowitsch PetscCall(MatGetVecType(A, &vtype)); 13799566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd)); 138088ffe2e8SJose E. Roman if (isstd) { 138188ffe2e8SJose E. Roman /* check if all blocks have the same vectype */ 138288ffe2e8SJose E. Roman vtype = NULL; 138388ffe2e8SJose E. Roman for (i = 0; i < nr; i++) { 138488ffe2e8SJose E. Roman for (j = 0; j < nc; j++) { 138588ffe2e8SJose E. Roman if (a[i * nc + j]) { 138688ffe2e8SJose E. Roman if (!vtype) { /* first visited block */ 13879566063dSJacob Faibussowitsch PetscCall(MatGetVecType(a[i * nc + j], &vtype)); 138888ffe2e8SJose E. Roman sametype = PETSC_TRUE; 138988ffe2e8SJose E. Roman } else if (sametype) { 13909566063dSJacob Faibussowitsch PetscCall(MatGetVecType(a[i * nc + j], &type)); 13919566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, type, &sametype)); 139288ffe2e8SJose E. Roman } 139388ffe2e8SJose E. Roman } 139488ffe2e8SJose E. Roman } 139588ffe2e8SJose E. Roman } 139688ffe2e8SJose E. Roman if (sametype) { /* propagate vectype */ 13979566063dSJacob Faibussowitsch PetscCall(MatSetVecType(A, vtype)); 139888ffe2e8SJose E. Roman } 139988ffe2e8SJose E. Roman } 1400d8588912SDave May 14019566063dSJacob Faibussowitsch PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col)); 1402d8588912SDave May 14039566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &s->row_len)); 14049566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &s->col_len)); 1405c8883902SJed Brown for (i = 0; i < nr; i++) s->row_len[i] = -1; 1406c8883902SJed Brown for (j = 0; j < nc; j++) s->col_len[j] = -1; 1407d8588912SDave May 14089566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr * nc, &s->nnzstate)); 140906a1af2fSStefano Zampini for (i = 0; i < nr; i++) { 141006a1af2fSStefano Zampini for (j = 0; j < nc; j++) { 141148a46eb9SPierre Jolivet if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j])); 141206a1af2fSStefano Zampini } 141306a1af2fSStefano Zampini } 141406a1af2fSStefano Zampini 14159566063dSJacob Faibussowitsch PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N)); 1416d8588912SDave May 14179566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(A->rmap, M)); 14189566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(A->rmap, m)); 14199566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(A->cmap, N)); 14209566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(A->cmap, n)); 1421c8883902SJed Brown 14229566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->rmap)); 14239566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->cmap)); 1424c8883902SJed Brown 142506a1af2fSStefano Zampini /* disable operations that are not supported for non-square matrices, 142606a1af2fSStefano Zampini or matrices for which is_row != is_col */ 14279566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(A, &cong)); 142806a1af2fSStefano Zampini if (cong && nr != nc) cong = PETSC_FALSE; 142906a1af2fSStefano Zampini if (cong) { 143048a46eb9SPierre Jolivet for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong)); 143106a1af2fSStefano Zampini } 143206a1af2fSStefano Zampini if (!cong) { 1433381b8e50SStefano Zampini A->ops->missingdiagonal = NULL; 143406a1af2fSStefano Zampini A->ops->getdiagonal = NULL; 143506a1af2fSStefano Zampini A->ops->shift = NULL; 143606a1af2fSStefano Zampini A->ops->diagonalset = NULL; 143706a1af2fSStefano Zampini } 143806a1af2fSStefano Zampini 14399566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right)); 14409566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)A)); 144106a1af2fSStefano Zampini A->nonzerostate++; 14423ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1443d8588912SDave May } 1444d8588912SDave May 1445c8883902SJed Brown /*@ 144611a5261eSBarry Smith MatNestSetSubMats - Sets the nested submatrices in a `MATNEST` 1447c8883902SJed Brown 1448c3339decSBarry Smith Collective 1449c8883902SJed Brown 1450d8d19677SJose E. Roman Input Parameters: 145111a5261eSBarry Smith + A - `MATNEST` matrix 1452c8883902SJed Brown . nr - number of nested row blocks 14532ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous 1454c8883902SJed Brown . nc - number of nested column blocks 14552ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous 14562ef1f0ffSBarry Smith - a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using `NULL` 14572ef1f0ffSBarry Smith 14582ef1f0ffSBarry Smith Level: advanced 1459c8883902SJed Brown 146011a5261eSBarry Smith Note: 146111a5261eSBarry Smith This always resets any submatrix information previously set 146206a1af2fSStefano Zampini 14631cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()` 1464c8883902SJed Brown @*/ 1465d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) 1466d71ae5a4SJacob Faibussowitsch { 146706a1af2fSStefano Zampini PetscInt i; 1468c8883902SJed Brown 1469c8883902SJed Brown PetscFunctionBegin; 1470c8883902SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 147108401ef6SPierre Jolivet PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative"); 1472c8883902SJed Brown if (nr && is_row) { 14734f572ea9SToby Isaac PetscAssertPointer(is_row, 3); 1474c8883902SJed Brown for (i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3); 1475c8883902SJed Brown } 147608401ef6SPierre Jolivet PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative"); 14771664e352SJed Brown if (nc && is_col) { 14784f572ea9SToby Isaac PetscAssertPointer(is_col, 5); 14799b30a8f6SBarry Smith for (i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5); 1480c8883902SJed Brown } 14814f572ea9SToby Isaac if (nr * nc > 0) PetscAssertPointer(a, 6); 1482cac4c232SBarry Smith PetscUseMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a)); 14833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1484c8883902SJed Brown } 1485d8588912SDave May 1486d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog) 1487d71ae5a4SJacob Faibussowitsch { 148877019fcaSJed Brown PetscBool flg; 148977019fcaSJed Brown PetscInt i, j, m, mi, *ix; 149077019fcaSJed Brown 149177019fcaSJed Brown PetscFunctionBegin; 1492aea6d515SStefano Zampini *ltog = NULL; 149377019fcaSJed Brown for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) { 149477019fcaSJed Brown if (islocal[i]) { 14959566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(islocal[i], &mi)); 149677019fcaSJed Brown flg = PETSC_TRUE; /* We found a non-trivial entry */ 149777019fcaSJed Brown } else { 14989566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mi)); 149977019fcaSJed Brown } 150077019fcaSJed Brown m += mi; 150177019fcaSJed Brown } 15023ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 1503aea6d515SStefano Zampini 15049566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &ix)); 1505165cd838SBarry Smith for (i = 0, m = 0; i < n; i++) { 15060298fd71SBarry Smith ISLocalToGlobalMapping smap = NULL; 1507e108cb99SStefano Zampini Mat sub = NULL; 1508f6d38dbbSStefano Zampini PetscSF sf; 1509f6d38dbbSStefano Zampini PetscLayout map; 1510aea6d515SStefano Zampini const PetscInt *ix2; 151177019fcaSJed Brown 1512165cd838SBarry Smith if (!colflg) { 15139566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 151477019fcaSJed Brown } else { 15159566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 151677019fcaSJed Brown } 1517191fd14bSBarry Smith if (sub) { 1518191fd14bSBarry Smith if (!colflg) { 15199566063dSJacob Faibussowitsch PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL)); 1520191fd14bSBarry Smith } else { 15219566063dSJacob Faibussowitsch PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap)); 1522191fd14bSBarry Smith } 1523191fd14bSBarry Smith } 152477019fcaSJed Brown /* 152577019fcaSJed Brown Now we need to extract the monolithic global indices that correspond to the given split global indices. 152677019fcaSJed 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. 152777019fcaSJed Brown */ 15289566063dSJacob Faibussowitsch PetscCall(ISGetIndices(isglobal[i], &ix2)); 1529aea6d515SStefano Zampini if (islocal[i]) { 1530aea6d515SStefano Zampini PetscInt *ilocal, *iremote; 1531aea6d515SStefano Zampini PetscInt mil, nleaves; 1532aea6d515SStefano Zampini 15339566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(islocal[i], &mi)); 153428b400f6SJacob Faibussowitsch PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map"); 1535aea6d515SStefano Zampini for (j = 0; j < mi; j++) ix[m + j] = j; 15369566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m)); 1537aea6d515SStefano Zampini 1538aea6d515SStefano Zampini /* PetscSFSetGraphLayout does not like negative indices */ 15399566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote)); 1540aea6d515SStefano Zampini for (j = 0, nleaves = 0; j < mi; j++) { 1541aea6d515SStefano Zampini if (ix[m + j] < 0) continue; 1542aea6d515SStefano Zampini ilocal[nleaves] = j; 1543aea6d515SStefano Zampini iremote[nleaves] = ix[m + j]; 1544aea6d515SStefano Zampini nleaves++; 1545aea6d515SStefano Zampini } 15469566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mil)); 15479566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf)); 15489566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map)); 15499566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(map, mil)); 15509566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(map)); 15519566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote)); 15529566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&map)); 15539566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 15549566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 15559566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&sf)); 15569566063dSJacob Faibussowitsch PetscCall(PetscFree2(ilocal, iremote)); 1557aea6d515SStefano Zampini } else { 15589566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mi)); 1559aea6d515SStefano Zampini for (j = 0; j < mi; j++) ix[m + j] = ix2[i]; 1560aea6d515SStefano Zampini } 15619566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(isglobal[i], &ix2)); 156277019fcaSJed Brown m += mi; 156377019fcaSJed Brown } 15649566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog)); 15653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 156677019fcaSJed Brown } 156777019fcaSJed Brown 1568d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */ 1569d8588912SDave May /* 1570d8588912SDave May nprocessors = NP 1571d8588912SDave May Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1)) 1572d8588912SDave May proc 0: => (g_0,h_0,) 1573d8588912SDave May proc 1: => (g_1,h_1,) 1574d8588912SDave May ... 1575d8588912SDave May proc nprocs-1: => (g_NP-1,h_NP-1,) 1576d8588912SDave May 1577d8588912SDave May proc 0: proc 1: proc nprocs-1: 1578d8588912SDave May is[0] = (0,1,2,...,nlocal(g_0)-1) (0,1,...,nlocal(g_1)-1) (0,1,...,nlocal(g_NP-1)) 1579d8588912SDave May 1580d8588912SDave May proc 0: 1581d8588912SDave May is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1) 1582d8588912SDave May proc 1: 1583d8588912SDave May is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1) 1584d8588912SDave May 1585d8588912SDave May proc NP-1: 1586d8588912SDave May is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1) 1587d8588912SDave May */ 1588d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[]) 1589d71ae5a4SJacob Faibussowitsch { 1590e2d7f03fSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 15918188e55aSJed Brown PetscInt i, j, offset, n, nsum, bs; 15920298fd71SBarry Smith Mat sub = NULL; 1593d8588912SDave May 1594d8588912SDave May PetscFunctionBegin; 15959566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &vs->isglobal.row)); 15969566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &vs->isglobal.col)); 1597d8588912SDave May if (is_row) { /* valid IS is passed in */ 1598a5b23f4aSJose E. Roman /* refs on is[] are incremented */ 1599e2d7f03fSJed Brown for (i = 0; i < vs->nr; i++) { 16009566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is_row[i])); 160126fbe8dcSKarl Rupp 1602e2d7f03fSJed Brown vs->isglobal.row[i] = is_row[i]; 1603d8588912SDave May } 16042ae74bdbSJed Brown } else { /* Create the ISs by inspecting sizes of a submatrix in each row */ 16058188e55aSJed Brown nsum = 0; 16068188e55aSJed Brown for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */ 16079566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 160828b400f6SJacob Faibussowitsch PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i); 16099566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, &n, NULL)); 161008401ef6SPierre Jolivet PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 16118188e55aSJed Brown nsum += n; 16128188e55aSJed Brown } 16139566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 161430bc264bSJed Brown offset -= nsum; 1615e2d7f03fSJed Brown for (i = 0; i < vs->nr; i++) { 16169566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 16179566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, &n, NULL)); 16189566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 16199566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i])); 16209566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs)); 16212ae74bdbSJed Brown offset += n; 1622d8588912SDave May } 1623d8588912SDave May } 1624d8588912SDave May 1625d8588912SDave May if (is_col) { /* valid IS is passed in */ 1626a5b23f4aSJose E. Roman /* refs on is[] are incremented */ 1627e2d7f03fSJed Brown for (j = 0; j < vs->nc; j++) { 16289566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is_col[j])); 162926fbe8dcSKarl Rupp 1630e2d7f03fSJed Brown vs->isglobal.col[j] = is_col[j]; 1631d8588912SDave May } 16322ae74bdbSJed Brown } else { /* Create the ISs by inspecting sizes of a submatrix in each column */ 16332ae74bdbSJed Brown offset = A->cmap->rstart; 16348188e55aSJed Brown nsum = 0; 16358188e55aSJed Brown for (j = 0; j < vs->nc; j++) { 16369566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 163728b400f6SJacob Faibussowitsch PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i); 16389566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, NULL, &n)); 163908401ef6SPierre Jolivet PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 16408188e55aSJed Brown nsum += n; 16418188e55aSJed Brown } 16429566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 164330bc264bSJed Brown offset -= nsum; 1644e2d7f03fSJed Brown for (j = 0; j < vs->nc; j++) { 16459566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 16469566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, NULL, &n)); 16479566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 16489566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j])); 16499566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs)); 16502ae74bdbSJed Brown offset += n; 1651d8588912SDave May } 1652d8588912SDave May } 1653e2d7f03fSJed Brown 1654e2d7f03fSJed Brown /* Set up the local ISs */ 16559566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row)); 16569566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col)); 1657e2d7f03fSJed Brown for (i = 0, offset = 0; i < vs->nr; i++) { 1658e2d7f03fSJed Brown IS isloc; 16590298fd71SBarry Smith ISLocalToGlobalMapping rmap = NULL; 1660e2d7f03fSJed Brown PetscInt nlocal, bs; 16619566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 16629566063dSJacob Faibussowitsch if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL)); 1663207556f9SJed Brown if (rmap) { 16649566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 16659566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal)); 16669566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 16679566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(isloc, bs)); 1668207556f9SJed Brown } else { 1669207556f9SJed Brown nlocal = 0; 16700298fd71SBarry Smith isloc = NULL; 1671207556f9SJed Brown } 1672e2d7f03fSJed Brown vs->islocal.row[i] = isloc; 1673e2d7f03fSJed Brown offset += nlocal; 1674e2d7f03fSJed Brown } 16758188e55aSJed Brown for (i = 0, offset = 0; i < vs->nc; i++) { 1676e2d7f03fSJed Brown IS isloc; 16770298fd71SBarry Smith ISLocalToGlobalMapping cmap = NULL; 1678e2d7f03fSJed Brown PetscInt nlocal, bs; 16799566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 16809566063dSJacob Faibussowitsch if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap)); 1681207556f9SJed Brown if (cmap) { 16829566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 16839566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal)); 16849566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 16859566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(isloc, bs)); 1686207556f9SJed Brown } else { 1687207556f9SJed Brown nlocal = 0; 16880298fd71SBarry Smith isloc = NULL; 1689207556f9SJed Brown } 1690e2d7f03fSJed Brown vs->islocal.col[i] = isloc; 1691e2d7f03fSJed Brown offset += nlocal; 1692e2d7f03fSJed Brown } 16930189643fSJed Brown 169477019fcaSJed Brown /* Set up the aggregate ISLocalToGlobalMapping */ 169577019fcaSJed Brown { 169645b6f7e9SBarry Smith ISLocalToGlobalMapping rmap, cmap; 16979566063dSJacob Faibussowitsch PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap)); 16989566063dSJacob Faibussowitsch PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap)); 16999566063dSJacob Faibussowitsch if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap)); 17009566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingDestroy(&rmap)); 17019566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingDestroy(&cmap)); 170277019fcaSJed Brown } 170377019fcaSJed Brown 170476bd3646SJed Brown if (PetscDefined(USE_DEBUG)) { 17050189643fSJed Brown for (i = 0; i < vs->nr; i++) { 17060189643fSJed Brown for (j = 0; j < vs->nc; j++) { 17070189643fSJed Brown PetscInt m, n, M, N, mi, ni, Mi, Ni; 17080189643fSJed Brown Mat B = vs->m[i][j]; 17090189643fSJed Brown if (!B) continue; 17109566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, &M, &N)); 17119566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(B, &m, &n)); 17129566063dSJacob Faibussowitsch PetscCall(ISGetSize(vs->isglobal.row[i], &Mi)); 17139566063dSJacob Faibussowitsch PetscCall(ISGetSize(vs->isglobal.col[j], &Ni)); 17149566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi)); 17159566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni)); 1716aed4548fSBarry 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); 1717aed4548fSBarry 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); 17180189643fSJed Brown } 17190189643fSJed Brown } 172076bd3646SJed Brown } 1721a061e289SJed Brown 1722a061e289SJed Brown /* Set A->assembled if all non-null blocks are currently assembled */ 1723a061e289SJed Brown for (i = 0; i < vs->nr; i++) { 1724a061e289SJed Brown for (j = 0; j < vs->nc; j++) { 17253ba16761SJacob Faibussowitsch if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS); 1726a061e289SJed Brown } 1727a061e289SJed Brown } 1728a061e289SJed Brown A->assembled = PETSC_TRUE; 17293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1730d8588912SDave May } 1731d8588912SDave May 173245c38901SJed Brown /*@C 173311a5261eSBarry Smith MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately 1734659c6bb0SJed Brown 173511a5261eSBarry Smith Collective 1736659c6bb0SJed Brown 1737d8d19677SJose E. Roman Input Parameters: 173811a5261eSBarry Smith + comm - Communicator for the new `MATNEST` 1739659c6bb0SJed Brown . nr - number of nested row blocks 17402ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous 1741659c6bb0SJed Brown . nc - number of nested column blocks 17422ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous 17432ef1f0ffSBarry Smith - a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using `NULL` 1744659c6bb0SJed Brown 1745659c6bb0SJed Brown Output Parameter: 1746659c6bb0SJed Brown . B - new matrix 1747659c6bb0SJed Brown 1748659c6bb0SJed Brown Level: advanced 1749659c6bb0SJed Brown 17501cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`, 1751db781477SPatrick Sanan `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`, 1752db781477SPatrick Sanan `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 1753659c6bb0SJed Brown @*/ 1754d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B) 1755d71ae5a4SJacob Faibussowitsch { 1756d8588912SDave May Mat A; 1757d8588912SDave May 1758d8588912SDave May PetscFunctionBegin; 1759f4259b30SLisandro Dalcin *B = NULL; 17609566063dSJacob Faibussowitsch PetscCall(MatCreate(comm, &A)); 17619566063dSJacob Faibussowitsch PetscCall(MatSetType(A, MATNEST)); 176291a28eb3SBarry Smith A->preallocated = PETSC_TRUE; 17639566063dSJacob Faibussowitsch PetscCall(MatNestSetSubMats(A, nr, is_row, nc, is_col, a)); 1764d8588912SDave May *B = A; 17653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1766d8588912SDave May } 1767659c6bb0SJed Brown 176866976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 1769d71ae5a4SJacob Faibussowitsch { 1770b68353e5Sstefano_zampini Mat_Nest *nest = (Mat_Nest *)A->data; 177123875855Sstefano_zampini Mat *trans; 1772b68353e5Sstefano_zampini PetscScalar **avv; 1773b68353e5Sstefano_zampini PetscScalar *vv; 1774b68353e5Sstefano_zampini PetscInt **aii, **ajj; 1775b68353e5Sstefano_zampini PetscInt *ii, *jj, *ci; 1776b68353e5Sstefano_zampini PetscInt nr, nc, nnz, i, j; 1777b68353e5Sstefano_zampini PetscBool done; 1778b68353e5Sstefano_zampini 1779b68353e5Sstefano_zampini PetscFunctionBegin; 17809566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &nr, &nc)); 1781b68353e5Sstefano_zampini if (reuse == MAT_REUSE_MATRIX) { 1782b68353e5Sstefano_zampini PetscInt rnr; 1783b68353e5Sstefano_zampini 17849566063dSJacob Faibussowitsch PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done)); 178528b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ"); 178608401ef6SPierre Jolivet PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows"); 17879566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArray(*newmat, &vv)); 1788b68353e5Sstefano_zampini } 1789b68353e5Sstefano_zampini /* extract CSR for nested SeqAIJ matrices */ 1790b68353e5Sstefano_zampini nnz = 0; 17919566063dSJacob Faibussowitsch PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans)); 1792b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1793b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1794b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1795b68353e5Sstefano_zampini if (B) { 1796b68353e5Sstefano_zampini PetscScalar *naa; 1797b68353e5Sstefano_zampini PetscInt *nii, *njj, nnr; 179823875855Sstefano_zampini PetscBool istrans; 1799b68353e5Sstefano_zampini 1800013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans)); 180123875855Sstefano_zampini if (istrans) { 180223875855Sstefano_zampini Mat Bt; 180323875855Sstefano_zampini 18049566063dSJacob Faibussowitsch PetscCall(MatTransposeGetMat(B, &Bt)); 18059566063dSJacob Faibussowitsch PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 180623875855Sstefano_zampini B = trans[i * nest->nc + j]; 1807013e2dc7SBarry Smith } else { 1808013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans)); 1809013e2dc7SBarry Smith if (istrans) { 1810013e2dc7SBarry Smith Mat Bt; 1811013e2dc7SBarry Smith 1812013e2dc7SBarry Smith PetscCall(MatHermitianTransposeGetMat(B, &Bt)); 1813013e2dc7SBarry Smith PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 1814013e2dc7SBarry Smith B = trans[i * nest->nc + j]; 1815013e2dc7SBarry Smith } 181623875855Sstefano_zampini } 18179566063dSJacob Faibussowitsch PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done)); 181828b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ"); 18199566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArray(B, &naa)); 1820b68353e5Sstefano_zampini nnz += nii[nnr]; 1821b68353e5Sstefano_zampini 1822b68353e5Sstefano_zampini aii[i * nest->nc + j] = nii; 1823b68353e5Sstefano_zampini ajj[i * nest->nc + j] = njj; 1824b68353e5Sstefano_zampini avv[i * nest->nc + j] = naa; 1825b68353e5Sstefano_zampini } 1826b68353e5Sstefano_zampini } 1827b68353e5Sstefano_zampini } 1828b68353e5Sstefano_zampini if (reuse != MAT_REUSE_MATRIX) { 18299566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr + 1, &ii)); 18309566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &jj)); 18319566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &vv)); 1832b68353e5Sstefano_zampini } else { 183308401ef6SPierre Jolivet PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros"); 1834b68353e5Sstefano_zampini } 1835b68353e5Sstefano_zampini 1836b68353e5Sstefano_zampini /* new row pointer */ 18379566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(ii, nr + 1)); 1838b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1839b68353e5Sstefano_zampini PetscInt ncr, rst; 1840b68353e5Sstefano_zampini 18419566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 18429566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1843b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1844b68353e5Sstefano_zampini if (aii[i * nest->nc + j]) { 1845b68353e5Sstefano_zampini PetscInt *nii = aii[i * nest->nc + j]; 1846b68353e5Sstefano_zampini PetscInt ir; 1847b68353e5Sstefano_zampini 1848b68353e5Sstefano_zampini for (ir = rst; ir < ncr + rst; ++ir) { 1849b68353e5Sstefano_zampini ii[ir + 1] += nii[1] - nii[0]; 1850b68353e5Sstefano_zampini nii++; 1851b68353e5Sstefano_zampini } 1852b68353e5Sstefano_zampini } 1853b68353e5Sstefano_zampini } 1854b68353e5Sstefano_zampini } 1855b68353e5Sstefano_zampini for (i = 0; i < nr; i++) ii[i + 1] += ii[i]; 1856b68353e5Sstefano_zampini 1857b68353e5Sstefano_zampini /* construct CSR for the new matrix */ 18589566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr, &ci)); 1859b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1860b68353e5Sstefano_zampini PetscInt ncr, rst; 1861b68353e5Sstefano_zampini 18629566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 18639566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1864b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1865b68353e5Sstefano_zampini if (aii[i * nest->nc + j]) { 1866b68353e5Sstefano_zampini PetscScalar *nvv = avv[i * nest->nc + j]; 1867b68353e5Sstefano_zampini PetscInt *nii = aii[i * nest->nc + j]; 1868b68353e5Sstefano_zampini PetscInt *njj = ajj[i * nest->nc + j]; 1869b68353e5Sstefano_zampini PetscInt ir, cst; 1870b68353e5Sstefano_zampini 18719566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL)); 1872b68353e5Sstefano_zampini for (ir = rst; ir < ncr + rst; ++ir) { 1873b68353e5Sstefano_zampini PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir]; 1874b68353e5Sstefano_zampini 1875b68353e5Sstefano_zampini for (ij = 0; ij < rsize; ij++) { 1876b68353e5Sstefano_zampini jj[ist + ij] = *njj + cst; 1877b68353e5Sstefano_zampini vv[ist + ij] = *nvv; 1878b68353e5Sstefano_zampini njj++; 1879b68353e5Sstefano_zampini nvv++; 1880b68353e5Sstefano_zampini } 1881b68353e5Sstefano_zampini ci[ir] += rsize; 1882b68353e5Sstefano_zampini nii++; 1883b68353e5Sstefano_zampini } 1884b68353e5Sstefano_zampini } 1885b68353e5Sstefano_zampini } 1886b68353e5Sstefano_zampini } 18879566063dSJacob Faibussowitsch PetscCall(PetscFree(ci)); 1888b68353e5Sstefano_zampini 1889b68353e5Sstefano_zampini /* restore info */ 1890b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1891b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1892b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1893b68353e5Sstefano_zampini if (B) { 1894b68353e5Sstefano_zampini PetscInt nnr = 0, k = i * nest->nc + j; 189523875855Sstefano_zampini 189623875855Sstefano_zampini B = (trans[k] ? trans[k] : B); 18979566063dSJacob Faibussowitsch PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done)); 189828b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ"); 18999566063dSJacob Faibussowitsch PetscCall(MatSeqAIJRestoreArray(B, &avv[k])); 19009566063dSJacob Faibussowitsch PetscCall(MatDestroy(&trans[k])); 1901b68353e5Sstefano_zampini } 1902b68353e5Sstefano_zampini } 1903b68353e5Sstefano_zampini } 19049566063dSJacob Faibussowitsch PetscCall(PetscFree4(aii, ajj, avv, trans)); 1905b68353e5Sstefano_zampini 1906b68353e5Sstefano_zampini /* finalize newmat */ 1907b68353e5Sstefano_zampini if (reuse == MAT_INITIAL_MATRIX) { 19089566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat)); 1909b68353e5Sstefano_zampini } else if (reuse == MAT_INPLACE_MATRIX) { 1910b68353e5Sstefano_zampini Mat B; 1911b68353e5Sstefano_zampini 19129566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B)); 19139566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &B)); 1914b68353e5Sstefano_zampini } 19159566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY)); 19169566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY)); 1917b68353e5Sstefano_zampini { 1918b68353e5Sstefano_zampini Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data); 1919b68353e5Sstefano_zampini a->free_a = PETSC_TRUE; 1920b68353e5Sstefano_zampini a->free_ij = PETSC_TRUE; 1921b68353e5Sstefano_zampini } 19223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1923b68353e5Sstefano_zampini } 1924b68353e5Sstefano_zampini 1925d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X) 1926d71ae5a4SJacob Faibussowitsch { 1927be705e3aSPierre Jolivet Mat_Nest *nest = (Mat_Nest *)X->data; 1928be705e3aSPierre Jolivet PetscInt i, j, k, rstart; 1929be705e3aSPierre Jolivet PetscBool flg; 1930be705e3aSPierre Jolivet 1931be705e3aSPierre Jolivet PetscFunctionBegin; 1932be705e3aSPierre Jolivet /* Fill by row */ 1933be705e3aSPierre Jolivet for (j = 0; j < nest->nc; ++j) { 1934be705e3aSPierre Jolivet /* Using global column indices and ISAllGather() is not scalable. */ 1935be705e3aSPierre Jolivet IS bNis; 1936be705e3aSPierre Jolivet PetscInt bN; 1937be705e3aSPierre Jolivet const PetscInt *bNindices; 19389566063dSJacob Faibussowitsch PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 19399566063dSJacob Faibussowitsch PetscCall(ISGetSize(bNis, &bN)); 19409566063dSJacob Faibussowitsch PetscCall(ISGetIndices(bNis, &bNindices)); 1941be705e3aSPierre Jolivet for (i = 0; i < nest->nr; ++i) { 1942fd8a7442SPierre Jolivet Mat B = nest->m[i][j], D = NULL; 1943be705e3aSPierre Jolivet PetscInt bm, br; 1944be705e3aSPierre Jolivet const PetscInt *bmindices; 1945be705e3aSPierre Jolivet if (!B) continue; 1946013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 1947be705e3aSPierre Jolivet if (flg) { 1948cac4c232SBarry Smith PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 1949cac4c232SBarry Smith PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 19509566063dSJacob Faibussowitsch PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 1951be705e3aSPierre Jolivet B = D; 1952be705e3aSPierre Jolivet } 19539566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 1954be705e3aSPierre Jolivet if (flg) { 1955fd8a7442SPierre Jolivet if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 1956fd8a7442SPierre Jolivet else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 1957be705e3aSPierre Jolivet B = D; 1958be705e3aSPierre Jolivet } 19599566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 19609566063dSJacob Faibussowitsch PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 19619566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 1962be705e3aSPierre Jolivet for (br = 0; br < bm; ++br) { 1963be705e3aSPierre Jolivet PetscInt row = bmindices[br], brncols, *cols; 1964be705e3aSPierre Jolivet const PetscInt *brcols; 1965be705e3aSPierre Jolivet const PetscScalar *brcoldata; 1966be705e3aSPierre Jolivet PetscScalar *vals = NULL; 19679566063dSJacob Faibussowitsch PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 19689566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(brncols, &cols)); 1969be705e3aSPierre Jolivet for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]]; 1970be705e3aSPierre Jolivet /* 1971be705e3aSPierre Jolivet Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match. 1972be705e3aSPierre Jolivet Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES. 1973be705e3aSPierre Jolivet */ 1974be705e3aSPierre Jolivet if (a != 1.0) { 19759566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(brncols, &vals)); 1976be705e3aSPierre Jolivet for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k]; 19779566063dSJacob Faibussowitsch PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES)); 19789566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 1979be705e3aSPierre Jolivet } else { 19809566063dSJacob Faibussowitsch PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES)); 1981be705e3aSPierre Jolivet } 19829566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 19839566063dSJacob Faibussowitsch PetscCall(PetscFree(cols)); 1984be705e3aSPierre Jolivet } 1985fd8a7442SPierre Jolivet if (D) PetscCall(MatDestroy(&D)); 19869566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 1987be705e3aSPierre Jolivet } 19889566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(bNis, &bNindices)); 19899566063dSJacob Faibussowitsch PetscCall(ISDestroy(&bNis)); 1990be705e3aSPierre Jolivet } 19919566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY)); 19929566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY)); 19933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1994be705e3aSPierre Jolivet } 1995be705e3aSPierre Jolivet 199666976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 1997d71ae5a4SJacob Faibussowitsch { 1998629c3df2SDmitry Karpeev Mat_Nest *nest = (Mat_Nest *)A->data; 1999e30678d3SPierre Jolivet PetscInt m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend; 2000b68353e5Sstefano_zampini PetscMPIInt size; 2001629c3df2SDmitry Karpeev Mat C; 2002629c3df2SDmitry Karpeev 2003629c3df2SDmitry Karpeev PetscFunctionBegin; 20049566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 2005b68353e5Sstefano_zampini if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */ 2006b68353e5Sstefano_zampini PetscInt nf; 2007b68353e5Sstefano_zampini PetscBool fast; 2008b68353e5Sstefano_zampini 20099566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(newtype, MATAIJ, &fast)); 201048a46eb9SPierre Jolivet if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast)); 2011b68353e5Sstefano_zampini for (i = 0; i < nest->nr && fast; ++i) { 2012b68353e5Sstefano_zampini for (j = 0; j < nest->nc && fast; ++j) { 2013b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 2014b68353e5Sstefano_zampini if (B) { 20159566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast)); 201623875855Sstefano_zampini if (!fast) { 201723875855Sstefano_zampini PetscBool istrans; 201823875855Sstefano_zampini 2019013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans)); 202023875855Sstefano_zampini if (istrans) { 202123875855Sstefano_zampini Mat Bt; 202223875855Sstefano_zampini 20239566063dSJacob Faibussowitsch PetscCall(MatTransposeGetMat(B, &Bt)); 20249566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 2025013e2dc7SBarry Smith } else { 2026013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans)); 2027013e2dc7SBarry Smith if (istrans) { 2028013e2dc7SBarry Smith Mat Bt; 2029013e2dc7SBarry Smith 2030013e2dc7SBarry Smith PetscCall(MatHermitianTransposeGetMat(B, &Bt)); 2031013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 2032013e2dc7SBarry Smith } 203323875855Sstefano_zampini } 2034b68353e5Sstefano_zampini } 2035b68353e5Sstefano_zampini } 2036b68353e5Sstefano_zampini } 2037b68353e5Sstefano_zampini } 2038b68353e5Sstefano_zampini for (i = 0, nf = 0; i < nest->nr && fast; ++i) { 20399566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast)); 2040b68353e5Sstefano_zampini if (fast) { 2041b68353e5Sstefano_zampini PetscInt f, s; 2042b68353e5Sstefano_zampini 20439566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s)); 20449371c9d4SSatish Balay if (f != nf || s != 1) { 20459371c9d4SSatish Balay fast = PETSC_FALSE; 20469371c9d4SSatish Balay } else { 20479566063dSJacob Faibussowitsch PetscCall(ISGetSize(nest->isglobal.row[i], &f)); 2048b68353e5Sstefano_zampini nf += f; 2049b68353e5Sstefano_zampini } 2050b68353e5Sstefano_zampini } 2051b68353e5Sstefano_zampini } 2052b68353e5Sstefano_zampini for (i = 0, nf = 0; i < nest->nc && fast; ++i) { 20539566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast)); 2054b68353e5Sstefano_zampini if (fast) { 2055b68353e5Sstefano_zampini PetscInt f, s; 2056b68353e5Sstefano_zampini 20579566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s)); 20589371c9d4SSatish Balay if (f != nf || s != 1) { 20599371c9d4SSatish Balay fast = PETSC_FALSE; 20609371c9d4SSatish Balay } else { 20619566063dSJacob Faibussowitsch PetscCall(ISGetSize(nest->isglobal.col[i], &f)); 2062b68353e5Sstefano_zampini nf += f; 2063b68353e5Sstefano_zampini } 2064b68353e5Sstefano_zampini } 2065b68353e5Sstefano_zampini } 2066b68353e5Sstefano_zampini if (fast) { 20679566063dSJacob Faibussowitsch PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat)); 20683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2069b68353e5Sstefano_zampini } 2070b68353e5Sstefano_zampini } 20719566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, &N)); 20729566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, &n)); 20739566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend)); 2074d1487292SPierre Jolivet if (reuse == MAT_REUSE_MATRIX) C = *newmat; 2075d1487292SPierre Jolivet else { 20769566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C)); 20779566063dSJacob Faibussowitsch PetscCall(MatSetType(C, newtype)); 20789566063dSJacob Faibussowitsch PetscCall(MatSetSizes(C, m, n, M, N)); 2079629c3df2SDmitry Karpeev } 20809566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(2 * m, &dnnz)); 2081e30678d3SPierre Jolivet if (m) { 2082629c3df2SDmitry Karpeev onnz = dnnz + m; 2083629c3df2SDmitry Karpeev for (k = 0; k < m; k++) { 2084629c3df2SDmitry Karpeev dnnz[k] = 0; 2085629c3df2SDmitry Karpeev onnz[k] = 0; 2086629c3df2SDmitry Karpeev } 2087e30678d3SPierre Jolivet } 2088629c3df2SDmitry Karpeev for (j = 0; j < nest->nc; ++j) { 2089629c3df2SDmitry Karpeev IS bNis; 2090629c3df2SDmitry Karpeev PetscInt bN; 2091629c3df2SDmitry Karpeev const PetscInt *bNindices; 2092fd8a7442SPierre Jolivet PetscBool flg; 2093629c3df2SDmitry Karpeev /* Using global column indices and ISAllGather() is not scalable. */ 20949566063dSJacob Faibussowitsch PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 20959566063dSJacob Faibussowitsch PetscCall(ISGetSize(bNis, &bN)); 20969566063dSJacob Faibussowitsch PetscCall(ISGetIndices(bNis, &bNindices)); 2097629c3df2SDmitry Karpeev for (i = 0; i < nest->nr; ++i) { 2098629c3df2SDmitry Karpeev PetscSF bmsf; 2099649b366bSFande Kong PetscSFNode *iremote; 2100fd8a7442SPierre Jolivet Mat B = nest->m[i][j], D = NULL; 2101649b366bSFande Kong PetscInt bm, *sub_dnnz, *sub_onnz, br; 2102629c3df2SDmitry Karpeev const PetscInt *bmindices; 2103629c3df2SDmitry Karpeev if (!B) continue; 21049566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 21059566063dSJacob Faibussowitsch PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 21069566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf)); 21079566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &iremote)); 21089566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &sub_dnnz)); 21099566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &sub_onnz)); 2110649b366bSFande Kong for (k = 0; k < bm; ++k) { 2111649b366bSFande Kong sub_dnnz[k] = 0; 2112649b366bSFande Kong sub_onnz[k] = 0; 2113649b366bSFande Kong } 2114dead4d76SPierre Jolivet PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 2115fd8a7442SPierre Jolivet if (flg) { 2116fd8a7442SPierre Jolivet PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2117fd8a7442SPierre Jolivet PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2118fd8a7442SPierre Jolivet PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 2119fd8a7442SPierre Jolivet B = D; 2120fd8a7442SPierre Jolivet } 2121fd8a7442SPierre Jolivet PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 2122fd8a7442SPierre Jolivet if (flg) { 2123fd8a7442SPierre Jolivet if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 2124fd8a7442SPierre Jolivet else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 2125fd8a7442SPierre Jolivet B = D; 2126fd8a7442SPierre Jolivet } 2127629c3df2SDmitry Karpeev /* 2128629c3df2SDmitry Karpeev Locate the owners for all of the locally-owned global row indices for this row block. 2129629c3df2SDmitry Karpeev These determine the roots of PetscSF used to communicate preallocation data to row owners. 2130629c3df2SDmitry Karpeev The roots correspond to the dnnz and onnz entries; thus, there are two roots per row. 2131629c3df2SDmitry Karpeev */ 21329566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 2133629c3df2SDmitry Karpeev for (br = 0; br < bm; ++br) { 2134131c27b5Sprj- PetscInt row = bmindices[br], brncols, col; 2135629c3df2SDmitry Karpeev const PetscInt *brcols; 2136a4b3d3acSMatthew G Knepley PetscInt rowrel = 0; /* row's relative index on its owner rank */ 2137131c27b5Sprj- PetscMPIInt rowowner = 0; 21389566063dSJacob Faibussowitsch PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel)); 2139649b366bSFande Kong /* how many roots */ 21409371c9d4SSatish Balay iremote[br].rank = rowowner; 21419371c9d4SSatish Balay iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */ 2142649b366bSFande Kong /* get nonzero pattern */ 21439566063dSJacob Faibussowitsch PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL)); 2144629c3df2SDmitry Karpeev for (k = 0; k < brncols; k++) { 2145629c3df2SDmitry Karpeev col = bNindices[brcols[k]]; 2146649b366bSFande Kong if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) { 2147649b366bSFande Kong sub_dnnz[br]++; 2148649b366bSFande Kong } else { 2149649b366bSFande Kong sub_onnz[br]++; 2150649b366bSFande Kong } 2151629c3df2SDmitry Karpeev } 21529566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL)); 2153629c3df2SDmitry Karpeev } 2154fd8a7442SPierre Jolivet if (D) PetscCall(MatDestroy(&D)); 21559566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 2156629c3df2SDmitry Karpeev /* bsf will have to take care of disposing of bedges. */ 21579566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 21589566063dSJacob Faibussowitsch PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 21599566063dSJacob Faibussowitsch PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 21609566063dSJacob Faibussowitsch PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 21619566063dSJacob Faibussowitsch PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 21629566063dSJacob Faibussowitsch PetscCall(PetscFree(sub_dnnz)); 21639566063dSJacob Faibussowitsch PetscCall(PetscFree(sub_onnz)); 21649566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&bmsf)); 2165629c3df2SDmitry Karpeev } 21669566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(bNis, &bNindices)); 21679566063dSJacob Faibussowitsch PetscCall(ISDestroy(&bNis)); 216865a4a0a3Sstefano_zampini } 216965a4a0a3Sstefano_zampini /* Resize preallocation if overestimated */ 217065a4a0a3Sstefano_zampini for (i = 0; i < m; i++) { 217165a4a0a3Sstefano_zampini dnnz[i] = PetscMin(dnnz[i], A->cmap->n); 217265a4a0a3Sstefano_zampini onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n); 2173629c3df2SDmitry Karpeev } 21749566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz)); 21759566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz)); 21769566063dSJacob Faibussowitsch PetscCall(PetscFree(dnnz)); 21779566063dSJacob Faibussowitsch PetscCall(MatAXPY_Dense_Nest(C, 1.0, A)); 2178d1487292SPierre Jolivet if (reuse == MAT_INPLACE_MATRIX) { 21799566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &C)); 2180d1487292SPierre Jolivet } else *newmat = C; 21813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2182be705e3aSPierre Jolivet } 2183629c3df2SDmitry Karpeev 218466976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 2185d71ae5a4SJacob Faibussowitsch { 2186629c3df2SDmitry Karpeev Mat B; 2187be705e3aSPierre Jolivet PetscInt m, n, M, N; 2188be705e3aSPierre Jolivet 2189be705e3aSPierre Jolivet PetscFunctionBegin; 21909566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, &N)); 21919566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, &n)); 2192be705e3aSPierre Jolivet if (reuse == MAT_REUSE_MATRIX) { 2193be705e3aSPierre Jolivet B = *newmat; 21949566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(B)); 2195be705e3aSPierre Jolivet } else { 21969566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B)); 2197629c3df2SDmitry Karpeev } 21989566063dSJacob Faibussowitsch PetscCall(MatAXPY_Dense_Nest(B, 1.0, A)); 2199be705e3aSPierre Jolivet if (reuse == MAT_INPLACE_MATRIX) { 22009566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &B)); 2201be705e3aSPierre Jolivet } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B; 22023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2203629c3df2SDmitry Karpeev } 2204629c3df2SDmitry Karpeev 220566976f2fSJacob Faibussowitsch static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has) 2206d71ae5a4SJacob Faibussowitsch { 22078b7d3b4bSBarry Smith Mat_Nest *bA = (Mat_Nest *)mat->data; 22083c6db4c4SPierre Jolivet MatOperation opAdd; 22098b7d3b4bSBarry Smith PetscInt i, j, nr = bA->nr, nc = bA->nc; 22108b7d3b4bSBarry Smith PetscBool flg; 221152c5f739Sprj- PetscFunctionBegin; 22128b7d3b4bSBarry Smith 221352c5f739Sprj- *has = PETSC_FALSE; 22143c6db4c4SPierre Jolivet if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) { 22153c6db4c4SPierre Jolivet opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD); 22168b7d3b4bSBarry Smith for (j = 0; j < nc; j++) { 22178b7d3b4bSBarry Smith for (i = 0; i < nr; i++) { 22188b7d3b4bSBarry Smith if (!bA->m[i][j]) continue; 22199566063dSJacob Faibussowitsch PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg)); 22203ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 22218b7d3b4bSBarry Smith } 22228b7d3b4bSBarry Smith } 22238b7d3b4bSBarry Smith } 22243c6db4c4SPierre Jolivet if (((void **)mat->ops)[op]) *has = PETSC_TRUE; 22253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 22268b7d3b4bSBarry Smith } 22278b7d3b4bSBarry Smith 2228659c6bb0SJed Brown /*MC 22292ef1f0ffSBarry Smith MATNEST - "nest" - Matrix type consisting of nested submatrices, each stored separately. 2230659c6bb0SJed Brown 2231659c6bb0SJed Brown Level: intermediate 2232659c6bb0SJed Brown 2233659c6bb0SJed Brown Notes: 223411a5261eSBarry Smith This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices. 2235659c6bb0SJed Brown It allows the use of symmetric and block formats for parts of multi-physics simulations. 223611a5261eSBarry Smith It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()` 2237659c6bb0SJed Brown 22388b7d3b4bSBarry Smith Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero 22398b7d3b4bSBarry Smith rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes 22408b7d3b4bSBarry Smith than the nest matrix. 22418b7d3b4bSBarry Smith 22421cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, 2243db781477SPatrick Sanan `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`, 2244db781477SPatrick Sanan `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 2245659c6bb0SJed Brown M*/ 2246d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A) 2247d71ae5a4SJacob Faibussowitsch { 2248c8883902SJed Brown Mat_Nest *s; 2249c8883902SJed Brown 2250c8883902SJed Brown PetscFunctionBegin; 22514dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&s)); 2252c8883902SJed Brown A->data = (void *)s; 2253e7c19651SJed Brown 2254e7c19651SJed Brown s->nr = -1; 2255e7c19651SJed Brown s->nc = -1; 22560298fd71SBarry Smith s->m = NULL; 2257e7c19651SJed Brown s->splitassembly = PETSC_FALSE; 2258c8883902SJed Brown 22599566063dSJacob Faibussowitsch PetscCall(PetscMemzero(A->ops, sizeof(*A->ops))); 226026fbe8dcSKarl Rupp 2261c8883902SJed Brown A->ops->mult = MatMult_Nest; 22629194d70fSJed Brown A->ops->multadd = MatMultAdd_Nest; 2263c8883902SJed Brown A->ops->multtranspose = MatMultTranspose_Nest; 22649194d70fSJed Brown A->ops->multtransposeadd = MatMultTransposeAdd_Nest; 2265f8170845SAlex Fikl A->ops->transpose = MatTranspose_Nest; 2266*0998551bSBlanca Mellado Pinto A->ops->multhermitiantranspose = MatMultHermitianTranspose_Nest; 2267*0998551bSBlanca Mellado Pinto A->ops->multhermitiantransposeadd = MatMultHermitianTransposeAdd_Nest; 2268c8883902SJed Brown A->ops->assemblybegin = MatAssemblyBegin_Nest; 2269c8883902SJed Brown A->ops->assemblyend = MatAssemblyEnd_Nest; 2270c8883902SJed Brown A->ops->zeroentries = MatZeroEntries_Nest; 2271c222c20dSDavid Ham A->ops->copy = MatCopy_Nest; 22726e76ffeaSPierre Jolivet A->ops->axpy = MatAXPY_Nest; 2273c8883902SJed Brown A->ops->duplicate = MatDuplicate_Nest; 22747dae84e0SHong Zhang A->ops->createsubmatrix = MatCreateSubMatrix_Nest; 2275c8883902SJed Brown A->ops->destroy = MatDestroy_Nest; 2276c8883902SJed Brown A->ops->view = MatView_Nest; 2277f4259b30SLisandro Dalcin A->ops->getvecs = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */ 2278c8883902SJed Brown A->ops->getlocalsubmatrix = MatGetLocalSubMatrix_Nest; 2279c8883902SJed Brown A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest; 2280429bac76SJed Brown A->ops->getdiagonal = MatGetDiagonal_Nest; 2281429bac76SJed Brown A->ops->diagonalscale = MatDiagonalScale_Nest; 2282a061e289SJed Brown A->ops->scale = MatScale_Nest; 2283a061e289SJed Brown A->ops->shift = MatShift_Nest; 228413135bc6SAlex Fikl A->ops->diagonalset = MatDiagonalSet_Nest; 2285f8170845SAlex Fikl A->ops->setrandom = MatSetRandom_Nest; 22868b7d3b4bSBarry Smith A->ops->hasoperation = MatHasOperation_Nest; 2287381b8e50SStefano Zampini A->ops->missingdiagonal = MatMissingDiagonal_Nest; 2288c8883902SJed Brown 2289f4259b30SLisandro Dalcin A->spptr = NULL; 2290c8883902SJed Brown A->assembled = PETSC_FALSE; 2291c8883902SJed Brown 2292c8883902SJed Brown /* expose Nest api's */ 22939566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest)); 22949566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest)); 22959566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest)); 22969566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest)); 22979566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest)); 22989566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest)); 22999566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest)); 23009566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest)); 23019566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ)); 23029566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ)); 23039566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ)); 23049566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS)); 23059566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense)); 23069566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense)); 23079566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense)); 23089566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense)); 23099566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", MatProductSetFromOptions_Nest_Dense)); 2310c8883902SJed Brown 23119566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST)); 23123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2313c8883902SJed Brown } 2314