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 } 33d8588912SDave May PetscFunctionReturn(0); 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])); 56d8588912SDave May PetscFunctionReturn(0); 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])); 839194d70fSJed Brown PetscFunctionReturn(0); 849194d70fSJed Brown } 859194d70fSJed Brown 8652c5f739Sprj- typedef struct { 8752c5f739Sprj- Mat *workC; /* array of Mat with specific containers depending on the underlying MatMatMult implementation */ 8852c5f739Sprj- PetscScalar *tarray; /* buffer for storing all temporary products A[i][j] B[j] */ 8952c5f739Sprj- PetscInt *dm, *dn, k; /* displacements and number of submatrices */ 9052c5f739Sprj- } Nest_Dense; 9152c5f739Sprj- 92d71ae5a4SJacob Faibussowitsch PETSC_INTERN 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; 1036718818eSStefano Zampini MatCheckProduct(C, 3); 1046718818eSStefano Zampini A = C->product->A; 1056718818eSStefano Zampini B = C->product->B; 1069566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 1076718818eSStefano Zampini if (!N) { 1089566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 1099566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 1106718818eSStefano Zampini PetscFunctionReturn(0); 1116718818eSStefano Zampini } 1126718818eSStefano Zampini contents = (Nest_Dense *)C->product->data; 11328b400f6SJacob Faibussowitsch PetscCheck(contents, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty"); 1146718818eSStefano Zampini bA = (Mat_Nest *)A->data; 1156718818eSStefano Zampini nr = bA->nr; 1166718818eSStefano Zampini nc = bA->nc; 1179566063dSJacob Faibussowitsch PetscCall(MatDenseGetLDA(B, &ldb)); 1189566063dSJacob Faibussowitsch PetscCall(MatDenseGetLDA(C, &ldc)); 1199566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(C)); 1209566063dSJacob Faibussowitsch PetscCall(MatDenseGetArrayRead(B, &barray)); 1219566063dSJacob Faibussowitsch PetscCall(MatDenseGetArray(C, &carray)); 12252c5f739Sprj- for (i = 0; i < nr; i++) { 1239566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.row[i], &M)); 1249566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dm[i + 1] - contents->dm[i], PETSC_DECIDE, M, N, carray + contents->dm[i], &viewC)); 1259566063dSJacob Faibussowitsch PetscCall(MatDenseSetLDA(viewC, ldc)); 12652c5f739Sprj- for (j = 0; j < nc; j++) { 12752c5f739Sprj- if (!bA->m[i][j]) continue; 1289566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[j], &M)); 1299566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, (PetscScalar *)(barray + contents->dn[j]), &viewB)); 1309566063dSJacob Faibussowitsch PetscCall(MatDenseSetLDA(viewB, ldb)); 1314222ddf1SHong Zhang 1324222ddf1SHong Zhang /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */ 1334222ddf1SHong Zhang workC = contents->workC[i * nc + j]; 1344222ddf1SHong Zhang productB = workC->product->B; 1354222ddf1SHong Zhang workC->product->B = viewB; /* use newly created dense matrix viewB */ 1369566063dSJacob Faibussowitsch PetscCall(MatProductNumeric(workC)); 1379566063dSJacob Faibussowitsch PetscCall(MatDestroy(&viewB)); 1384222ddf1SHong Zhang workC->product->B = productB; /* resume original B */ 1394222ddf1SHong Zhang 14052c5f739Sprj- /* C[i] <- workC + C[i] */ 1419566063dSJacob Faibussowitsch PetscCall(MatAXPY(viewC, 1.0, contents->workC[i * nc + j], SAME_NONZERO_PATTERN)); 14252c5f739Sprj- } 1439566063dSJacob Faibussowitsch PetscCall(MatDestroy(&viewC)); 14452c5f739Sprj- } 1459566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArray(C, &carray)); 1469566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArrayRead(B, &barray)); 1474222ddf1SHong Zhang 1489566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 1499566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 15052c5f739Sprj- PetscFunctionReturn(0); 15152c5f739Sprj- } 15252c5f739Sprj- 153d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNest_DenseDestroy(void *ctx) 154d71ae5a4SJacob Faibussowitsch { 15552c5f739Sprj- Nest_Dense *contents = (Nest_Dense *)ctx; 15652c5f739Sprj- PetscInt i; 15752c5f739Sprj- 15852c5f739Sprj- PetscFunctionBegin; 1599566063dSJacob Faibussowitsch PetscCall(PetscFree(contents->tarray)); 16048a46eb9SPierre Jolivet for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i)); 1619566063dSJacob Faibussowitsch PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC)); 1629566063dSJacob Faibussowitsch PetscCall(PetscFree(contents)); 16352c5f739Sprj- PetscFunctionReturn(0); 16452c5f739Sprj- } 16552c5f739Sprj- 166d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C) 167d71ae5a4SJacob Faibussowitsch { 1686718818eSStefano Zampini Mat_Nest *bA; 1696718818eSStefano Zampini Mat viewB, workC; 17052c5f739Sprj- const PetscScalar *barray; 1716718818eSStefano Zampini PetscInt i, j, M, N, m, n, nr, nc, maxm = 0, ldb; 1724222ddf1SHong Zhang Nest_Dense *contents = NULL; 1736718818eSStefano Zampini PetscBool cisdense; 1746718818eSStefano Zampini Mat A, B; 1756718818eSStefano Zampini PetscReal fill; 17652c5f739Sprj- 17752c5f739Sprj- PetscFunctionBegin; 1786718818eSStefano Zampini MatCheckProduct(C, 4); 17928b400f6SJacob Faibussowitsch PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty"); 1806718818eSStefano Zampini A = C->product->A; 1816718818eSStefano Zampini B = C->product->B; 1826718818eSStefano Zampini fill = C->product->fill; 1836718818eSStefano Zampini bA = (Mat_Nest *)A->data; 1846718818eSStefano Zampini nr = bA->nr; 1856718818eSStefano Zampini nc = bA->nc; 1869566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(C, &m, &n)); 1879566063dSJacob Faibussowitsch PetscCall(MatGetSize(C, &M, &N)); 1880572eedcSPierre Jolivet if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) { 1899566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(B, NULL, &n)); 1909566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 1919566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, NULL)); 1929566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, NULL)); 1939566063dSJacob Faibussowitsch PetscCall(MatSetSizes(C, m, n, M, N)); 1940572eedcSPierre Jolivet } 1959566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, "")); 19648a46eb9SPierre Jolivet if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name)); 1979566063dSJacob Faibussowitsch PetscCall(MatSetUp(C)); 1986718818eSStefano Zampini if (!N) { 1996718818eSStefano Zampini C->ops->productnumeric = MatProductNumeric_Nest_Dense; 2006718818eSStefano Zampini PetscFunctionReturn(0); 20152c5f739Sprj- } 20252c5f739Sprj- 2039566063dSJacob Faibussowitsch PetscCall(PetscNew(&contents)); 2046718818eSStefano Zampini C->product->data = contents; 2056718818eSStefano Zampini C->product->destroy = MatNest_DenseDestroy; 2069566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC)); 20752c5f739Sprj- contents->k = nr * nc; 20852c5f739Sprj- for (i = 0; i < nr; i++) { 2099566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1)); 21052c5f739Sprj- maxm = PetscMax(maxm, contents->dm[i + 1]); 21152c5f739Sprj- contents->dm[i + 1] += contents->dm[i]; 21252c5f739Sprj- } 21352c5f739Sprj- for (i = 0; i < nc; i++) { 2149566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1)); 21552c5f739Sprj- contents->dn[i + 1] += contents->dn[i]; 21652c5f739Sprj- } 2179566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(maxm * N, &contents->tarray)); 2189566063dSJacob Faibussowitsch PetscCall(MatDenseGetLDA(B, &ldb)); 2199566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 2209566063dSJacob Faibussowitsch PetscCall(MatDenseGetArrayRead(B, &barray)); 22152c5f739Sprj- /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */ 22252c5f739Sprj- for (j = 0; j < nc; j++) { 2239566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[j], &M)); 2249566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, (PetscScalar *)(barray + contents->dn[j]), &viewB)); 2259566063dSJacob Faibussowitsch PetscCall(MatDenseSetLDA(viewB, ldb)); 22652c5f739Sprj- for (i = 0; i < nr; i++) { 22752c5f739Sprj- if (!bA->m[i][j]) continue; 22852c5f739Sprj- /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */ 2294222ddf1SHong Zhang 2309566063dSJacob Faibussowitsch PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j])); 2314222ddf1SHong Zhang workC = contents->workC[i * nc + j]; 2329566063dSJacob Faibussowitsch PetscCall(MatProductSetType(workC, MATPRODUCT_AB)); 2339566063dSJacob Faibussowitsch PetscCall(MatProductSetAlgorithm(workC, "default")); 2349566063dSJacob Faibussowitsch PetscCall(MatProductSetFill(workC, fill)); 2359566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(workC)); 2369566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(workC)); 2374222ddf1SHong Zhang 2386718818eSStefano Zampini /* since tarray will be shared by all Mat */ 2399566063dSJacob Faibussowitsch PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray)); 2409566063dSJacob Faibussowitsch PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray)); 24152c5f739Sprj- } 2429566063dSJacob Faibussowitsch PetscCall(MatDestroy(&viewB)); 24352c5f739Sprj- } 2449566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArrayRead(B, &barray)); 24552c5f739Sprj- 2466718818eSStefano Zampini C->ops->productnumeric = MatProductNumeric_Nest_Dense; 24752c5f739Sprj- PetscFunctionReturn(0); 24852c5f739Sprj- } 24952c5f739Sprj- 2504222ddf1SHong Zhang /* --------------------------------------------------------- */ 251d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatProductSetFromOptions_Nest_Dense_AB(Mat C) 252d71ae5a4SJacob Faibussowitsch { 2534222ddf1SHong Zhang PetscFunctionBegin; 2546718818eSStefano Zampini C->ops->productsymbolic = MatProductSymbolic_Nest_Dense; 2554222ddf1SHong Zhang PetscFunctionReturn(0); 2564222ddf1SHong Zhang } 2574222ddf1SHong Zhang 258d71ae5a4SJacob Faibussowitsch PETSC_INTERN 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)); 26452c5f739Sprj- PetscFunctionReturn(0); 26552c5f739Sprj- } 2664222ddf1SHong Zhang /* --------------------------------------------------------- */ 26752c5f739Sprj- 268d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y) 269d71ae5a4SJacob Faibussowitsch { 270d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 271207556f9SJed Brown Vec *bx = bA->left, *by = bA->right; 272207556f9SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 273d8588912SDave May 274d8588912SDave May PetscFunctionBegin; 2759566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 2769566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i])); 277207556f9SJed Brown for (j = 0; j < nc; j++) { 2789566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(by[j])); 279609e31cbSJed Brown for (i = 0; i < nr; i++) { 2806c75ac25SJed Brown if (!bA->m[i][j]) continue; 281609e31cbSJed Brown /* y[j] <- y[j] + (A[i][j])^T * x[i] */ 2829566063dSJacob Faibussowitsch PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j])); 283d8588912SDave May } 284d8588912SDave May } 2859566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 2869566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i])); 287d8588912SDave May PetscFunctionReturn(0); 288d8588912SDave May } 289d8588912SDave May 290d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z) 291d71ae5a4SJacob Faibussowitsch { 2929194d70fSJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 2939194d70fSJed Brown Vec *bx = bA->left, *bz = bA->right; 2949194d70fSJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 2959194d70fSJed Brown 2969194d70fSJed Brown PetscFunctionBegin; 2979566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 2989566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i])); 2999194d70fSJed Brown for (j = 0; j < nc; j++) { 3009194d70fSJed Brown if (y != z) { 3019194d70fSJed Brown Vec by; 3029566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by)); 3039566063dSJacob Faibussowitsch PetscCall(VecCopy(by, bz[j])); 3049566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by)); 3059194d70fSJed Brown } 3069194d70fSJed Brown for (i = 0; i < nr; i++) { 3076c75ac25SJed Brown if (!bA->m[i][j]) continue; 3089194d70fSJed Brown /* z[j] <- y[j] + (A[i][j])^T * x[i] */ 3099566063dSJacob Faibussowitsch PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j])); 3109194d70fSJed Brown } 3119194d70fSJed Brown } 3129566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 3139566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i])); 3149194d70fSJed Brown PetscFunctionReturn(0); 3159194d70fSJed Brown } 3169194d70fSJed Brown 317d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B) 318d71ae5a4SJacob Faibussowitsch { 319f8170845SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data, *bC; 320f8170845SAlex Fikl Mat C; 321f8170845SAlex Fikl PetscInt i, j, nr = bA->nr, nc = bA->nc; 322f8170845SAlex Fikl 323f8170845SAlex Fikl PetscFunctionBegin; 3247fb60732SBarry Smith if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B)); 325aed4548fSBarry Smith PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place"); 326f8170845SAlex Fikl 327cf37664fSBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) { 328f8170845SAlex Fikl Mat *subs; 329f8170845SAlex Fikl IS *is_row, *is_col; 330f8170845SAlex Fikl 3319566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr * nc, &subs)); 3329566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col)); 3339566063dSJacob Faibussowitsch PetscCall(MatNestGetISs(A, is_row, is_col)); 334cf37664fSBarry Smith if (reuse == MAT_INPLACE_MATRIX) { 335ddeb9bd8SAlex Fikl for (i = 0; i < nr; i++) { 336ad540459SPierre Jolivet for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j]; 337ddeb9bd8SAlex Fikl } 338ddeb9bd8SAlex Fikl } 339ddeb9bd8SAlex Fikl 3409566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C)); 3419566063dSJacob Faibussowitsch PetscCall(PetscFree(subs)); 3429566063dSJacob Faibussowitsch PetscCall(PetscFree2(is_row, is_col)); 343f8170845SAlex Fikl } else { 344f8170845SAlex Fikl C = *B; 345f8170845SAlex Fikl } 346f8170845SAlex Fikl 347f8170845SAlex Fikl bC = (Mat_Nest *)C->data; 348f8170845SAlex Fikl for (i = 0; i < nr; i++) { 349f8170845SAlex Fikl for (j = 0; j < nc; j++) { 350f8170845SAlex Fikl if (bA->m[i][j]) { 3519566063dSJacob Faibussowitsch PetscCall(MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i]))); 352f8170845SAlex Fikl } else { 353f8170845SAlex Fikl bC->m[j][i] = NULL; 354f8170845SAlex Fikl } 355f8170845SAlex Fikl } 356f8170845SAlex Fikl } 357f8170845SAlex Fikl 358cf37664fSBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) { 359f8170845SAlex Fikl *B = C; 360f8170845SAlex Fikl } else { 3619566063dSJacob Faibussowitsch PetscCall(MatHeaderMerge(A, &C)); 362f8170845SAlex Fikl } 363f8170845SAlex Fikl PetscFunctionReturn(0); 364f8170845SAlex Fikl } 365f8170845SAlex Fikl 366d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list) 367d71ae5a4SJacob Faibussowitsch { 368e2d7f03fSJed Brown IS *lst = *list; 369e2d7f03fSJed Brown PetscInt i; 370e2d7f03fSJed Brown 371e2d7f03fSJed Brown PetscFunctionBegin; 372e2d7f03fSJed Brown if (!lst) PetscFunctionReturn(0); 3739371c9d4SSatish Balay for (i = 0; i < n; i++) 3749371c9d4SSatish Balay if (lst[i]) PetscCall(ISDestroy(&lst[i])); 3759566063dSJacob Faibussowitsch PetscCall(PetscFree(lst)); 3760298fd71SBarry Smith *list = NULL; 377e2d7f03fSJed Brown PetscFunctionReturn(0); 378e2d7f03fSJed Brown } 379e2d7f03fSJed Brown 380d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatReset_Nest(Mat A) 381d71ae5a4SJacob Faibussowitsch { 382d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 383d8588912SDave May PetscInt i, j; 384d8588912SDave May 385d8588912SDave May PetscFunctionBegin; 386d8588912SDave May /* release the matrices and the place holders */ 3879566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row)); 3889566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col)); 3899566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row)); 3909566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col)); 391d8588912SDave May 3929566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->row_len)); 3939566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->col_len)); 3949566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->nnzstate)); 395d8588912SDave May 3969566063dSJacob Faibussowitsch PetscCall(PetscFree2(vs->left, vs->right)); 397207556f9SJed Brown 398d8588912SDave May /* release the matrices and the place holders */ 399d8588912SDave May if (vs->m) { 400d8588912SDave May for (i = 0; i < vs->nr; i++) { 40148a46eb9SPierre Jolivet for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j])); 4029566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->m[i])); 403d8588912SDave May } 4049566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->m)); 405d8588912SDave May } 40606a1af2fSStefano Zampini 40706a1af2fSStefano Zampini /* restore defaults */ 40806a1af2fSStefano Zampini vs->nr = 0; 40906a1af2fSStefano Zampini vs->nc = 0; 41006a1af2fSStefano Zampini vs->splitassembly = PETSC_FALSE; 41106a1af2fSStefano Zampini PetscFunctionReturn(0); 41206a1af2fSStefano Zampini } 41306a1af2fSStefano Zampini 414d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Nest(Mat A) 415d71ae5a4SJacob Faibussowitsch { 416362febeeSStefano Zampini PetscFunctionBegin; 4179566063dSJacob Faibussowitsch PetscCall(MatReset_Nest(A)); 4189566063dSJacob Faibussowitsch PetscCall(PetscFree(A->data)); 4199566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL)); 4209566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL)); 4219566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL)); 4229566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL)); 4239566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL)); 4249566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL)); 4259566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL)); 4269566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL)); 4279566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL)); 4289566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL)); 4299566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL)); 4309566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL)); 4319566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL)); 4329566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL)); 4339566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL)); 4349566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL)); 4359566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", NULL)); 436d8588912SDave May PetscFunctionReturn(0); 437d8588912SDave May } 438d8588912SDave May 439d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd) 440d71ae5a4SJacob Faibussowitsch { 441381b8e50SStefano Zampini Mat_Nest *vs = (Mat_Nest *)mat->data; 442381b8e50SStefano Zampini PetscInt i; 443381b8e50SStefano Zampini 444381b8e50SStefano Zampini PetscFunctionBegin; 445381b8e50SStefano Zampini if (dd) *dd = 0; 446381b8e50SStefano Zampini if (!vs->nr) { 447381b8e50SStefano Zampini *missing = PETSC_TRUE; 448381b8e50SStefano Zampini PetscFunctionReturn(0); 449381b8e50SStefano Zampini } 450381b8e50SStefano Zampini *missing = PETSC_FALSE; 451381b8e50SStefano Zampini for (i = 0; i < vs->nr && !(*missing); i++) { 452381b8e50SStefano Zampini *missing = PETSC_TRUE; 453381b8e50SStefano Zampini if (vs->m[i][i]) { 4549566063dSJacob Faibussowitsch PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL)); 45508401ef6SPierre Jolivet PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented"); 456381b8e50SStefano Zampini } 457381b8e50SStefano Zampini } 458381b8e50SStefano Zampini PetscFunctionReturn(0); 459381b8e50SStefano Zampini } 460381b8e50SStefano Zampini 461d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type) 462d71ae5a4SJacob Faibussowitsch { 463d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 464d8588912SDave May PetscInt i, j; 46506a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 466d8588912SDave May 467d8588912SDave May PetscFunctionBegin; 468d8588912SDave May for (i = 0; i < vs->nr; i++) { 469d8588912SDave May for (j = 0; j < vs->nc; j++) { 47006a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 471e7c19651SJed Brown if (vs->m[i][j]) { 4729566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(vs->m[i][j], type)); 473e7c19651SJed Brown if (!vs->splitassembly) { 474e7c19651SJed Brown /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested 475e7c19651SJed 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 476e7c19651SJed Brown * already performing an assembly, but the result would by more complicated and appears to offer less 477e7c19651SJed Brown * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an 478e7c19651SJed Brown * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives". 479e7c19651SJed Brown */ 4809566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 4819566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate)); 482e7c19651SJed Brown } 483e7c19651SJed Brown } 48406a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate); 48506a1af2fSStefano Zampini vs->nnzstate[i * vs->nc + j] = subnnzstate; 486d8588912SDave May } 487d8588912SDave May } 48806a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 489d8588912SDave May PetscFunctionReturn(0); 490d8588912SDave May } 491d8588912SDave May 492d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type) 493d71ae5a4SJacob Faibussowitsch { 494d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 495d8588912SDave May PetscInt i, j; 496d8588912SDave May 497d8588912SDave May PetscFunctionBegin; 498d8588912SDave May for (i = 0; i < vs->nr; i++) { 499d8588912SDave May for (j = 0; j < vs->nc; j++) { 500e7c19651SJed Brown if (vs->m[i][j]) { 50148a46eb9SPierre Jolivet if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 502e7c19651SJed Brown } 503d8588912SDave May } 504d8588912SDave May } 505d8588912SDave May PetscFunctionReturn(0); 506d8588912SDave May } 507d8588912SDave May 508d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B) 509d71ae5a4SJacob Faibussowitsch { 510f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 511f349c1fdSJed Brown PetscInt j; 512f349c1fdSJed Brown Mat sub; 513d8588912SDave May 514d8588912SDave May PetscFunctionBegin; 5150298fd71SBarry Smith sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */ 516f349c1fdSJed Brown for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j]; 5179566063dSJacob Faibussowitsch if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 518f349c1fdSJed Brown *B = sub; 519f349c1fdSJed Brown PetscFunctionReturn(0); 520d8588912SDave May } 521d8588912SDave May 522d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B) 523d71ae5a4SJacob Faibussowitsch { 524f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 525f349c1fdSJed Brown PetscInt i; 526f349c1fdSJed Brown Mat sub; 527f349c1fdSJed Brown 528f349c1fdSJed Brown PetscFunctionBegin; 5290298fd71SBarry Smith sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */ 530f349c1fdSJed Brown for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col]; 5319566063dSJacob Faibussowitsch if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 532f349c1fdSJed Brown *B = sub; 533f349c1fdSJed Brown PetscFunctionReturn(0); 534d8588912SDave May } 535d8588912SDave May 536d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end) 537d71ae5a4SJacob Faibussowitsch { 53818d228c0SPierre Jolivet PetscInt i, j, size, m; 539f349c1fdSJed Brown PetscBool flg; 54018d228c0SPierre Jolivet IS out, concatenate[2]; 541f349c1fdSJed Brown 542f349c1fdSJed Brown PetscFunctionBegin; 543f349c1fdSJed Brown PetscValidPointer(list, 3); 544f349c1fdSJed Brown PetscValidHeaderSpecific(is, IS_CLASSID, 4); 54518d228c0SPierre Jolivet if (begin) { 54618d228c0SPierre Jolivet PetscValidIntPointer(begin, 5); 54718d228c0SPierre Jolivet *begin = -1; 54818d228c0SPierre Jolivet } 54918d228c0SPierre Jolivet if (end) { 55018d228c0SPierre Jolivet PetscValidIntPointer(end, 6); 55118d228c0SPierre Jolivet *end = -1; 55218d228c0SPierre Jolivet } 553f349c1fdSJed Brown for (i = 0; i < n; i++) { 554207556f9SJed Brown if (!list[i]) continue; 5559566063dSJacob Faibussowitsch PetscCall(ISEqualUnsorted(list[i], is, &flg)); 556f349c1fdSJed Brown if (flg) { 55718d228c0SPierre Jolivet if (begin) *begin = i; 55818d228c0SPierre Jolivet if (end) *end = i + 1; 559f349c1fdSJed Brown PetscFunctionReturn(0); 560f349c1fdSJed Brown } 561f349c1fdSJed Brown } 5629566063dSJacob Faibussowitsch PetscCall(ISGetSize(is, &size)); 56318d228c0SPierre Jolivet for (i = 0; i < n - 1; i++) { 56418d228c0SPierre Jolivet if (!list[i]) continue; 56518d228c0SPierre Jolivet m = 0; 5669566063dSJacob Faibussowitsch PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out)); 5679566063dSJacob Faibussowitsch PetscCall(ISGetSize(out, &m)); 56818d228c0SPierre Jolivet for (j = i + 2; j < n && m < size; j++) { 56918d228c0SPierre Jolivet if (list[j]) { 57018d228c0SPierre Jolivet concatenate[0] = out; 57118d228c0SPierre Jolivet concatenate[1] = list[j]; 5729566063dSJacob Faibussowitsch PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out)); 5739566063dSJacob Faibussowitsch PetscCall(ISDestroy(concatenate)); 5749566063dSJacob Faibussowitsch PetscCall(ISGetSize(out, &m)); 57518d228c0SPierre Jolivet } 57618d228c0SPierre Jolivet } 57718d228c0SPierre Jolivet if (m == size) { 5789566063dSJacob Faibussowitsch PetscCall(ISEqualUnsorted(out, is, &flg)); 57918d228c0SPierre Jolivet if (flg) { 58018d228c0SPierre Jolivet if (begin) *begin = i; 58118d228c0SPierre Jolivet if (end) *end = j; 5829566063dSJacob Faibussowitsch PetscCall(ISDestroy(&out)); 58318d228c0SPierre Jolivet PetscFunctionReturn(0); 58418d228c0SPierre Jolivet } 58518d228c0SPierre Jolivet } 5869566063dSJacob Faibussowitsch PetscCall(ISDestroy(&out)); 58718d228c0SPierre Jolivet } 58818d228c0SPierre Jolivet PetscFunctionReturn(0); 589f349c1fdSJed Brown } 590f349c1fdSJed Brown 591d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B) 592d71ae5a4SJacob Faibussowitsch { 5938188e55aSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 59418d228c0SPierre Jolivet PetscInt lr, lc; 59518d228c0SPierre Jolivet 59618d228c0SPierre Jolivet PetscFunctionBegin; 5979566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 5989566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr)); 5999566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc)); 6009566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE)); 6019566063dSJacob Faibussowitsch PetscCall(MatSetType(*B, MATAIJ)); 6029566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL)); 6039566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL)); 6049566063dSJacob Faibussowitsch PetscCall(MatSetUp(*B)); 6059566063dSJacob Faibussowitsch PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 6069566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 6079566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 60818d228c0SPierre Jolivet PetscFunctionReturn(0); 60918d228c0SPierre Jolivet } 61018d228c0SPierre Jolivet 611d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B) 612d71ae5a4SJacob Faibussowitsch { 61318d228c0SPierre Jolivet Mat_Nest *vs = (Mat_Nest *)A->data; 61418d228c0SPierre Jolivet Mat *a; 61518d228c0SPierre Jolivet PetscInt i, j, k, l, nr = rend - rbegin, nc = cend - cbegin; 6168188e55aSJed Brown char keyname[256]; 61718d228c0SPierre Jolivet PetscBool *b; 61818d228c0SPierre Jolivet PetscBool flg; 6198188e55aSJed Brown 6208188e55aSJed Brown PetscFunctionBegin; 6210298fd71SBarry Smith *B = NULL; 6229566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend)); 6239566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B)); 6248188e55aSJed Brown if (*B) PetscFunctionReturn(0); 6258188e55aSJed Brown 6269566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b)); 62718d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 62818d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 62918d228c0SPierre Jolivet a[i * nc + j] = vs->m[rbegin + i][cbegin + j]; 63018d228c0SPierre Jolivet b[i * nc + j] = PETSC_FALSE; 63118d228c0SPierre Jolivet } 63218d228c0SPierre Jolivet } 63318d228c0SPierre Jolivet if (nc != vs->nc && nr != vs->nr) { 63418d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 63518d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 63618d228c0SPierre Jolivet flg = PETSC_FALSE; 63718d228c0SPierre Jolivet for (k = 0; (k < nr && !flg); k++) { 63818d228c0SPierre Jolivet if (a[j + k * nc]) flg = PETSC_TRUE; 63918d228c0SPierre Jolivet } 64018d228c0SPierre Jolivet if (flg) { 64118d228c0SPierre Jolivet flg = PETSC_FALSE; 64218d228c0SPierre Jolivet for (l = 0; (l < nc && !flg); l++) { 64318d228c0SPierre Jolivet if (a[i * nc + l]) flg = PETSC_TRUE; 64418d228c0SPierre Jolivet } 64518d228c0SPierre Jolivet } 64618d228c0SPierre Jolivet if (!flg) { 64718d228c0SPierre Jolivet b[i * nc + j] = PETSC_TRUE; 6489566063dSJacob Faibussowitsch PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j)); 64918d228c0SPierre Jolivet } 65018d228c0SPierre Jolivet } 65118d228c0SPierre Jolivet } 65218d228c0SPierre Jolivet } 6539566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B)); 65418d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 65518d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 65648a46eb9SPierre Jolivet if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j)); 65718d228c0SPierre Jolivet } 65818d228c0SPierre Jolivet } 6599566063dSJacob Faibussowitsch PetscCall(PetscFree2(a, b)); 6608188e55aSJed Brown (*B)->assembled = A->assembled; 6619566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B)); 6629566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */ 6638188e55aSJed Brown PetscFunctionReturn(0); 6648188e55aSJed Brown } 6658188e55aSJed Brown 666d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B) 667d71ae5a4SJacob Faibussowitsch { 668f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 66918d228c0SPierre Jolivet PetscInt rbegin, rend, cbegin, cend; 670f349c1fdSJed Brown 671f349c1fdSJed Brown PetscFunctionBegin; 6729566063dSJacob Faibussowitsch PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend)); 6739566063dSJacob Faibussowitsch PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend)); 67418d228c0SPierre Jolivet if (rend == rbegin + 1 && cend == cbegin + 1) { 67548a46eb9SPierre Jolivet if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin)); 67618d228c0SPierre Jolivet *B = vs->m[rbegin][cbegin]; 67718d228c0SPierre Jolivet } else if (rbegin != -1 && cbegin != -1) { 6789566063dSJacob Faibussowitsch PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B)); 67918d228c0SPierre Jolivet } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set"); 680f349c1fdSJed Brown PetscFunctionReturn(0); 681f349c1fdSJed Brown } 682f349c1fdSJed Brown 68306a1af2fSStefano Zampini /* 68406a1af2fSStefano Zampini TODO: This does not actually returns a submatrix we can modify 68506a1af2fSStefano Zampini */ 686d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B) 687d71ae5a4SJacob Faibussowitsch { 688f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 689f349c1fdSJed Brown Mat sub; 690f349c1fdSJed Brown 691f349c1fdSJed Brown PetscFunctionBegin; 6929566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub)); 693f349c1fdSJed Brown switch (reuse) { 694f349c1fdSJed Brown case MAT_INITIAL_MATRIX: 6959566063dSJacob Faibussowitsch if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 696f349c1fdSJed Brown *B = sub; 697f349c1fdSJed Brown break; 698d71ae5a4SJacob Faibussowitsch case MAT_REUSE_MATRIX: 699d71ae5a4SJacob Faibussowitsch PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call"); 700d71ae5a4SJacob Faibussowitsch break; 701d71ae5a4SJacob Faibussowitsch case MAT_IGNORE_MATRIX: /* Nothing to do */ 702d71ae5a4SJacob Faibussowitsch break; 703d71ae5a4SJacob Faibussowitsch case MAT_INPLACE_MATRIX: /* Nothing to do */ 704d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet"); 705f349c1fdSJed Brown } 706f349c1fdSJed Brown PetscFunctionReturn(0); 707f349c1fdSJed Brown } 708f349c1fdSJed Brown 709d71ae5a4SJacob Faibussowitsch PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) 710d71ae5a4SJacob Faibussowitsch { 711f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 712f349c1fdSJed Brown Mat sub; 713f349c1fdSJed Brown 714f349c1fdSJed Brown PetscFunctionBegin; 7159566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 716f349c1fdSJed Brown /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */ 7179566063dSJacob Faibussowitsch if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 718f349c1fdSJed Brown *B = sub; 719d8588912SDave May PetscFunctionReturn(0); 720d8588912SDave May } 721d8588912SDave May 722d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) 723d71ae5a4SJacob Faibussowitsch { 724f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 725f349c1fdSJed Brown Mat sub; 726d8588912SDave May 727d8588912SDave May PetscFunctionBegin; 7289566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 72908401ef6SPierre Jolivet PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten"); 730f349c1fdSJed Brown if (sub) { 731aed4548fSBarry Smith PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times"); 7329566063dSJacob Faibussowitsch PetscCall(MatDestroy(B)); 733d8588912SDave May } 734d8588912SDave May PetscFunctionReturn(0); 735d8588912SDave May } 736d8588912SDave May 737d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v) 738d71ae5a4SJacob Faibussowitsch { 7397874fa86SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 7407874fa86SDave May PetscInt i; 7417874fa86SDave May 7427874fa86SDave May PetscFunctionBegin; 7437874fa86SDave May for (i = 0; i < bA->nr; i++) { 744429bac76SJed Brown Vec bv; 7459566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv)); 7467874fa86SDave May if (bA->m[i][i]) { 7479566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(bA->m[i][i], bv)); 7487874fa86SDave May } else { 7499566063dSJacob Faibussowitsch PetscCall(VecSet(bv, 0.0)); 7507874fa86SDave May } 7519566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv)); 7527874fa86SDave May } 7537874fa86SDave May PetscFunctionReturn(0); 7547874fa86SDave May } 7557874fa86SDave May 756d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r) 757d71ae5a4SJacob Faibussowitsch { 7587874fa86SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 759429bac76SJed Brown Vec bl, *br; 7607874fa86SDave May PetscInt i, j; 7617874fa86SDave May 7627874fa86SDave May PetscFunctionBegin; 7639566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(bA->nc, &br)); 7642e6472ebSElliott Sales de Andrade if (r) { 7659566063dSJacob Faibussowitsch for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j])); 7662e6472ebSElliott Sales de Andrade } 7672e6472ebSElliott Sales de Andrade bl = NULL; 7687874fa86SDave May for (i = 0; i < bA->nr; i++) { 76948a46eb9SPierre Jolivet if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl)); 7707874fa86SDave May for (j = 0; j < bA->nc; j++) { 77148a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j])); 7727874fa86SDave May } 77348a46eb9SPierre Jolivet if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl)); 7742e6472ebSElliott Sales de Andrade } 7752e6472ebSElliott Sales de Andrade if (r) { 7769566063dSJacob Faibussowitsch for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j])); 7772e6472ebSElliott Sales de Andrade } 7789566063dSJacob Faibussowitsch PetscCall(PetscFree(br)); 7797874fa86SDave May PetscFunctionReturn(0); 7807874fa86SDave May } 7817874fa86SDave May 782d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a) 783d71ae5a4SJacob Faibussowitsch { 784a061e289SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 785a061e289SJed Brown PetscInt i, j; 786a061e289SJed Brown 787a061e289SJed Brown PetscFunctionBegin; 788a061e289SJed Brown for (i = 0; i < bA->nr; i++) { 789a061e289SJed Brown for (j = 0; j < bA->nc; j++) { 79048a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a)); 791a061e289SJed Brown } 792a061e289SJed Brown } 793a061e289SJed Brown PetscFunctionReturn(0); 794a061e289SJed Brown } 795a061e289SJed Brown 796d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a) 797d71ae5a4SJacob Faibussowitsch { 798a061e289SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 799a061e289SJed Brown PetscInt i; 80006a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 801a061e289SJed Brown 802a061e289SJed Brown PetscFunctionBegin; 803a061e289SJed Brown for (i = 0; i < bA->nr; i++) { 80406a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 80508401ef6SPierre 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); 8069566063dSJacob Faibussowitsch PetscCall(MatShift(bA->m[i][i], a)); 8079566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 80806a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 80906a1af2fSStefano Zampini bA->nnzstate[i * bA->nc + i] = subnnzstate; 810a061e289SJed Brown } 81106a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 812a061e289SJed Brown PetscFunctionReturn(0); 813a061e289SJed Brown } 814a061e289SJed Brown 815d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is) 816d71ae5a4SJacob Faibussowitsch { 81713135bc6SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data; 81813135bc6SAlex Fikl PetscInt i; 81906a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 82013135bc6SAlex Fikl 82113135bc6SAlex Fikl PetscFunctionBegin; 82213135bc6SAlex Fikl for (i = 0; i < bA->nr; i++) { 82306a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 82413135bc6SAlex Fikl Vec bv; 8259566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv)); 82613135bc6SAlex Fikl if (bA->m[i][i]) { 8279566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet(bA->m[i][i], bv, is)); 8289566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 82913135bc6SAlex Fikl } 8309566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv)); 83106a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 83206a1af2fSStefano Zampini bA->nnzstate[i * bA->nc + i] = subnnzstate; 83313135bc6SAlex Fikl } 83406a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 83513135bc6SAlex Fikl PetscFunctionReturn(0); 83613135bc6SAlex Fikl } 83713135bc6SAlex Fikl 838d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx) 839d71ae5a4SJacob Faibussowitsch { 840f8170845SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data; 841f8170845SAlex Fikl PetscInt i, j; 842f8170845SAlex Fikl 843f8170845SAlex Fikl PetscFunctionBegin; 844f8170845SAlex Fikl for (i = 0; i < bA->nr; i++) { 845f8170845SAlex Fikl for (j = 0; j < bA->nc; j++) { 84648a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx)); 847f8170845SAlex Fikl } 848f8170845SAlex Fikl } 849f8170845SAlex Fikl PetscFunctionReturn(0); 850f8170845SAlex Fikl } 851f8170845SAlex Fikl 852d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left) 853d71ae5a4SJacob Faibussowitsch { 854d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 855d8588912SDave May Vec *L, *R; 856d8588912SDave May MPI_Comm comm; 857d8588912SDave May PetscInt i, j; 858d8588912SDave May 859d8588912SDave May PetscFunctionBegin; 8609566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)A, &comm)); 861d8588912SDave May if (right) { 862d8588912SDave May /* allocate R */ 8639566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bA->nc, &R)); 864d8588912SDave May /* Create the right vectors */ 865d8588912SDave May for (j = 0; j < bA->nc; j++) { 866d8588912SDave May for (i = 0; i < bA->nr; i++) { 867d8588912SDave May if (bA->m[i][j]) { 8689566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL)); 869d8588912SDave May break; 870d8588912SDave May } 871d8588912SDave May } 87208401ef6SPierre Jolivet PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column."); 873d8588912SDave May } 8749566063dSJacob Faibussowitsch PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right)); 875d8588912SDave May /* hand back control to the nest vector */ 87648a46eb9SPierre Jolivet for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j])); 8779566063dSJacob Faibussowitsch PetscCall(PetscFree(R)); 878d8588912SDave May } 879d8588912SDave May 880d8588912SDave May if (left) { 881d8588912SDave May /* allocate L */ 8829566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bA->nr, &L)); 883d8588912SDave May /* Create the left vectors */ 884d8588912SDave May for (i = 0; i < bA->nr; i++) { 885d8588912SDave May for (j = 0; j < bA->nc; j++) { 886d8588912SDave May if (bA->m[i][j]) { 8879566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i])); 888d8588912SDave May break; 889d8588912SDave May } 890d8588912SDave May } 89108401ef6SPierre Jolivet PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row."); 892d8588912SDave May } 893d8588912SDave May 8949566063dSJacob Faibussowitsch PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left)); 89548a46eb9SPierre Jolivet for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i])); 896d8588912SDave May 8979566063dSJacob Faibussowitsch PetscCall(PetscFree(L)); 898d8588912SDave May } 899d8588912SDave May PetscFunctionReturn(0); 900d8588912SDave May } 901d8588912SDave May 902d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer) 903d71ae5a4SJacob Faibussowitsch { 904d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 90529e60adbSStefano Zampini PetscBool isascii, viewSub = PETSC_FALSE; 906d8588912SDave May PetscInt i, j; 907d8588912SDave May 908d8588912SDave May PetscFunctionBegin; 9099566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 910d8588912SDave May if (isascii) { 9119566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL)); 9129566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object: \n")); 9139566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 9149566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT " \n", bA->nr, bA->nc)); 915d8588912SDave May 9169566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure: \n")); 917d8588912SDave May for (i = 0; i < bA->nr; i++) { 918d8588912SDave May for (j = 0; j < bA->nc; j++) { 91919fd82e9SBarry Smith MatType type; 920270f95d7SJed Brown char name[256] = "", prefix[256] = ""; 921d8588912SDave May PetscInt NR, NC; 922d8588912SDave May PetscBool isNest = PETSC_FALSE; 923d8588912SDave May 924d8588912SDave May if (!bA->m[i][j]) { 9259566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL \n", i, j)); 926d8588912SDave May continue; 927d8588912SDave May } 9289566063dSJacob Faibussowitsch PetscCall(MatGetSize(bA->m[i][j], &NR, &NC)); 9299566063dSJacob Faibussowitsch PetscCall(MatGetType(bA->m[i][j], &type)); 9309566063dSJacob Faibussowitsch if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name)); 9319566063dSJacob Faibussowitsch if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix)); 9329566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest)); 933d8588912SDave May 9349566063dSJacob 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)); 935d8588912SDave May 93629e60adbSStefano Zampini if (isNest || viewSub) { 9379566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */ 9389566063dSJacob Faibussowitsch PetscCall(MatView(bA->m[i][j], viewer)); 9399566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */ 940d8588912SDave May } 941d8588912SDave May } 942d8588912SDave May } 9439566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */ 944d8588912SDave May } 945d8588912SDave May PetscFunctionReturn(0); 946d8588912SDave May } 947d8588912SDave May 948d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A) 949d71ae5a4SJacob Faibussowitsch { 950d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 951d8588912SDave May PetscInt i, j; 952d8588912SDave May 953d8588912SDave May PetscFunctionBegin; 954d8588912SDave May for (i = 0; i < bA->nr; i++) { 955d8588912SDave May for (j = 0; j < bA->nc; j++) { 956d8588912SDave May if (!bA->m[i][j]) continue; 9579566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(bA->m[i][j])); 958d8588912SDave May } 959d8588912SDave May } 960d8588912SDave May PetscFunctionReturn(0); 961d8588912SDave May } 962d8588912SDave May 963d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str) 964d71ae5a4SJacob Faibussowitsch { 965c222c20dSDavid Ham Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data; 966c222c20dSDavid Ham PetscInt i, j, nr = bA->nr, nc = bA->nc; 96706a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 968c222c20dSDavid Ham 969c222c20dSDavid Ham PetscFunctionBegin; 970aed4548fSBarry 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); 971c222c20dSDavid Ham for (i = 0; i < nr; i++) { 972c222c20dSDavid Ham for (j = 0; j < nc; j++) { 97306a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 97446a2b97cSJed Brown if (bA->m[i][j] && bB->m[i][j]) { 9759566063dSJacob Faibussowitsch PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str)); 97608401ef6SPierre 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); 9779566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate)); 97806a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate); 97906a1af2fSStefano Zampini bB->nnzstate[i * nc + j] = subnnzstate; 980c222c20dSDavid Ham } 981c222c20dSDavid Ham } 98206a1af2fSStefano Zampini if (nnzstate) B->nonzerostate++; 983c222c20dSDavid Ham PetscFunctionReturn(0); 984c222c20dSDavid Ham } 985c222c20dSDavid Ham 986d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str) 987d71ae5a4SJacob Faibussowitsch { 9886e76ffeaSPierre Jolivet Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data; 9896e76ffeaSPierre Jolivet PetscInt i, j, nr = bY->nr, nc = bY->nc; 99006a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 9916e76ffeaSPierre Jolivet 9926e76ffeaSPierre Jolivet PetscFunctionBegin; 993aed4548fSBarry 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); 9946e76ffeaSPierre Jolivet for (i = 0; i < nr; i++) { 9956e76ffeaSPierre Jolivet for (j = 0; j < nc; j++) { 99606a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 9976e76ffeaSPierre Jolivet if (bY->m[i][j] && bX->m[i][j]) { 9989566063dSJacob Faibussowitsch PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str)); 999c066aebcSStefano Zampini } else if (bX->m[i][j]) { 1000c066aebcSStefano Zampini Mat M; 1001c066aebcSStefano Zampini 100208401ef6SPierre Jolivet PetscCheck(str == DIFFERENT_NONZERO_PATTERN, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN", i, j); 10039566063dSJacob Faibussowitsch PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M)); 10049566063dSJacob Faibussowitsch PetscCall(MatNestSetSubMat(Y, i, j, M)); 10059566063dSJacob Faibussowitsch PetscCall(MatDestroy(&M)); 1006c066aebcSStefano Zampini } 10079566063dSJacob Faibussowitsch if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate)); 100806a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate); 100906a1af2fSStefano Zampini bY->nnzstate[i * nc + j] = subnnzstate; 10106e76ffeaSPierre Jolivet } 10116e76ffeaSPierre Jolivet } 101206a1af2fSStefano Zampini if (nnzstate) Y->nonzerostate++; 10136e76ffeaSPierre Jolivet PetscFunctionReturn(0); 10146e76ffeaSPierre Jolivet } 10156e76ffeaSPierre Jolivet 1016d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B) 1017d71ae5a4SJacob Faibussowitsch { 1018d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 1019841e96a3SJed Brown Mat *b; 1020841e96a3SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 1021d8588912SDave May 1022d8588912SDave May PetscFunctionBegin; 10239566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr * nc, &b)); 1024841e96a3SJed Brown for (i = 0; i < nr; i++) { 1025841e96a3SJed Brown for (j = 0; j < nc; j++) { 1026841e96a3SJed Brown if (bA->m[i][j]) { 10279566063dSJacob Faibussowitsch PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j])); 1028841e96a3SJed Brown } else { 10290298fd71SBarry Smith b[i * nc + j] = NULL; 1030d8588912SDave May } 1031d8588912SDave May } 1032d8588912SDave May } 10339566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B)); 1034841e96a3SJed Brown /* Give the new MatNest exclusive ownership */ 103548a46eb9SPierre Jolivet for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i])); 10369566063dSJacob Faibussowitsch PetscCall(PetscFree(b)); 1037d8588912SDave May 10389566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 10399566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 1040d8588912SDave May PetscFunctionReturn(0); 1041d8588912SDave May } 1042d8588912SDave May 1043d8588912SDave May /* nest api */ 1044d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat) 1045d71ae5a4SJacob Faibussowitsch { 1046d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 10475fd66863SKarl Rupp 1048d8588912SDave May PetscFunctionBegin; 104908401ef6SPierre 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); 105008401ef6SPierre 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); 1051d8588912SDave May *mat = bA->m[idxm][jdxm]; 1052d8588912SDave May PetscFunctionReturn(0); 1053d8588912SDave May } 1054d8588912SDave May 10559ba0d327SJed Brown /*@ 105611a5261eSBarry Smith MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST` 1057d8588912SDave May 1058d8588912SDave May Not collective 1059d8588912SDave May 1060d8588912SDave May Input Parameters: 106111a5261eSBarry Smith + A - `MATNEST` matrix 1062d8588912SDave May . idxm - index of the matrix within the nest matrix 1063629881c0SJed Brown - jdxm - index of the matrix within the nest matrix 1064d8588912SDave May 1065d8588912SDave May Output Parameter: 1066d8588912SDave May . sub - matrix at index idxm,jdxm within the nest matrix 1067d8588912SDave May 1068d8588912SDave May Level: developer 1069d8588912SDave May 107011a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MATNEST`, `MatNestSetSubMat()`, 1071db781477SPatrick Sanan `MatNestGetLocalISs()`, `MatNestGetISs()` 1072d8588912SDave May @*/ 1073d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub) 1074d71ae5a4SJacob Faibussowitsch { 1075d8588912SDave May PetscFunctionBegin; 1076cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub)); 1077d8588912SDave May PetscFunctionReturn(0); 1078d8588912SDave May } 1079d8588912SDave May 1080d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat) 1081d71ae5a4SJacob Faibussowitsch { 10820782ca92SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 10830782ca92SJed Brown PetscInt m, n, M, N, mi, ni, Mi, Ni; 10840782ca92SJed Brown 10850782ca92SJed Brown PetscFunctionBegin; 108608401ef6SPierre 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); 108708401ef6SPierre 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); 10889566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 10899566063dSJacob Faibussowitsch PetscCall(MatGetSize(mat, &M, &N)); 10909566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi)); 10919566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi)); 10929566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni)); 10939566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni)); 1094aed4548fSBarry 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); 1095aed4548fSBarry 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); 109626fbe8dcSKarl Rupp 109706a1af2fSStefano Zampini /* do not increase object state */ 109806a1af2fSStefano Zampini if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(0); 109906a1af2fSStefano Zampini 11009566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat)); 11019566063dSJacob Faibussowitsch PetscCall(MatDestroy(&bA->m[idxm][jdxm])); 11020782ca92SJed Brown bA->m[idxm][jdxm] = mat; 11039566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)A)); 11049566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm])); 110506a1af2fSStefano Zampini A->nonzerostate++; 11060782ca92SJed Brown PetscFunctionReturn(0); 11070782ca92SJed Brown } 11080782ca92SJed Brown 11099ba0d327SJed Brown /*@ 111011a5261eSBarry Smith MatNestSetSubMat - Set a single submatrix in the `MATNEST` 11110782ca92SJed Brown 11120782ca92SJed Brown Logically collective on the submatrix communicator 11130782ca92SJed Brown 11140782ca92SJed Brown Input Parameters: 111511a5261eSBarry Smith + A - `MATNEST` matrix 11160782ca92SJed Brown . idxm - index of the matrix within the nest matrix 11170782ca92SJed Brown . jdxm - index of the matrix within the nest matrix 11180782ca92SJed Brown - sub - matrix at index idxm,jdxm within the nest matrix 11190782ca92SJed Brown 11200782ca92SJed Brown Notes: 11210782ca92SJed Brown The new submatrix must have the same size and communicator as that block of the nest. 11220782ca92SJed Brown 11230782ca92SJed Brown This increments the reference count of the submatrix. 11240782ca92SJed Brown 11250782ca92SJed Brown Level: developer 11260782ca92SJed Brown 112711a5261eSBarry Smith .seealso: `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MATNEST`, `MatCreateNest()`, 1128db781477SPatrick Sanan `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()` 11290782ca92SJed Brown @*/ 1130d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub) 1131d71ae5a4SJacob Faibussowitsch { 11320782ca92SJed Brown PetscFunctionBegin; 1133cac4c232SBarry Smith PetscUseMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub)); 11340782ca92SJed Brown PetscFunctionReturn(0); 11350782ca92SJed Brown } 11360782ca92SJed Brown 1137d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) 1138d71ae5a4SJacob Faibussowitsch { 1139d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 11405fd66863SKarl Rupp 1141d8588912SDave May PetscFunctionBegin; 114226fbe8dcSKarl Rupp if (M) *M = bA->nr; 114326fbe8dcSKarl Rupp if (N) *N = bA->nc; 114426fbe8dcSKarl Rupp if (mat) *mat = bA->m; 1145d8588912SDave May PetscFunctionReturn(0); 1146d8588912SDave May } 1147d8588912SDave May 1148d8588912SDave May /*@C 114911a5261eSBarry Smith MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix. 1150d8588912SDave May 1151d8588912SDave May Not collective 1152d8588912SDave May 1153f899ff85SJose E. Roman Input Parameter: 1154629881c0SJed Brown . A - nest matrix 1155d8588912SDave May 1156d8d19677SJose E. Roman Output Parameters: 1157629881c0SJed Brown + M - number of rows in the nest matrix 1158d8588912SDave May . N - number of cols in the nest matrix 1159629881c0SJed Brown - mat - 2d array of matrices 1160d8588912SDave May 116111a5261eSBarry Smith Note: 1162d8588912SDave May The user should not free the array mat. 1163d8588912SDave May 116411a5261eSBarry Smith Fortran Note: 116511a5261eSBarry Smith This routine has a calling sequence 1166351962e3SVincent Le Chenadec $ call MatNestGetSubMats(A, M, N, mat, ierr) 1167351962e3SVincent Le Chenadec where the space allocated for the optional argument mat is assumed large enough (if provided). 1168351962e3SVincent Le Chenadec 1169d8588912SDave May Level: developer 1170d8588912SDave May 117111a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MATNEST`, `MatCreateNest()`, 1172db781477SPatrick Sanan `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()` 1173d8588912SDave May @*/ 1174d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) 1175d71ae5a4SJacob Faibussowitsch { 1176d8588912SDave May PetscFunctionBegin; 1177cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat)); 1178d8588912SDave May PetscFunctionReturn(0); 1179d8588912SDave May } 1180d8588912SDave May 1181d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N) 1182d71ae5a4SJacob Faibussowitsch { 1183d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 1184d8588912SDave May 1185d8588912SDave May PetscFunctionBegin; 118626fbe8dcSKarl Rupp if (M) *M = bA->nr; 118726fbe8dcSKarl Rupp if (N) *N = bA->nc; 1188d8588912SDave May PetscFunctionReturn(0); 1189d8588912SDave May } 1190d8588912SDave May 11919ba0d327SJed Brown /*@ 119211a5261eSBarry Smith MatNestGetSize - Returns the size of the `MATNEST` matrix. 1193d8588912SDave May 1194d8588912SDave May Not collective 1195d8588912SDave May 1196f899ff85SJose E. Roman Input Parameter: 119711a5261eSBarry Smith . A - `MATNEST` matrix 1198d8588912SDave May 1199d8d19677SJose E. Roman Output Parameters: 1200629881c0SJed Brown + M - number of rows in the nested mat 1201629881c0SJed Brown - N - number of cols in the nested mat 1202d8588912SDave May 1203d8588912SDave May Level: developer 1204d8588912SDave May 120511a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MATNEST`, `MatCreateNest()`, `MatNestGetLocalISs()`, 1206db781477SPatrick Sanan `MatNestGetISs()` 1207d8588912SDave May @*/ 1208d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N) 1209d71ae5a4SJacob Faibussowitsch { 1210d8588912SDave May PetscFunctionBegin; 1211cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N)); 1212d8588912SDave May PetscFunctionReturn(0); 1213d8588912SDave May } 1214d8588912SDave May 1215d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[]) 1216d71ae5a4SJacob Faibussowitsch { 1217900e7ff2SJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 1218900e7ff2SJed Brown PetscInt i; 1219900e7ff2SJed Brown 1220900e7ff2SJed Brown PetscFunctionBegin; 12219371c9d4SSatish Balay if (rows) 12229371c9d4SSatish Balay for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i]; 12239371c9d4SSatish Balay if (cols) 12249371c9d4SSatish Balay for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i]; 1225900e7ff2SJed Brown PetscFunctionReturn(0); 1226900e7ff2SJed Brown } 1227900e7ff2SJed Brown 12283a4d7b9aSSatish Balay /*@C 122911a5261eSBarry Smith MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST` 1230900e7ff2SJed Brown 1231900e7ff2SJed Brown Not collective 1232900e7ff2SJed Brown 1233f899ff85SJose E. Roman Input Parameter: 123411a5261eSBarry Smith . A - `MATNEST` matrix 1235900e7ff2SJed Brown 1236d8d19677SJose E. Roman Output Parameters: 1237900e7ff2SJed Brown + rows - array of row index sets 1238900e7ff2SJed Brown - cols - array of column index sets 1239900e7ff2SJed Brown 1240900e7ff2SJed Brown Level: advanced 1241900e7ff2SJed Brown 124211a5261eSBarry Smith Note: 1243900e7ff2SJed Brown The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs. 1244900e7ff2SJed Brown 124511a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`, `MATNEST`, 1246db781477SPatrick Sanan `MatCreateNest()`, `MatNestGetSubMats()`, `MatNestSetSubMats()` 1247900e7ff2SJed Brown @*/ 1248d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[]) 1249d71ae5a4SJacob Faibussowitsch { 1250900e7ff2SJed Brown PetscFunctionBegin; 1251900e7ff2SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1252cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 1253900e7ff2SJed Brown PetscFunctionReturn(0); 1254900e7ff2SJed Brown } 1255900e7ff2SJed Brown 1256d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[]) 1257d71ae5a4SJacob Faibussowitsch { 1258900e7ff2SJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 1259900e7ff2SJed Brown PetscInt i; 1260900e7ff2SJed Brown 1261900e7ff2SJed Brown PetscFunctionBegin; 12629371c9d4SSatish Balay if (rows) 12639371c9d4SSatish Balay for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i]; 12649371c9d4SSatish Balay if (cols) 12659371c9d4SSatish Balay for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i]; 1266900e7ff2SJed Brown PetscFunctionReturn(0); 1267900e7ff2SJed Brown } 1268900e7ff2SJed Brown 1269900e7ff2SJed Brown /*@C 127011a5261eSBarry Smith MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST` 1271900e7ff2SJed Brown 1272900e7ff2SJed Brown Not collective 1273900e7ff2SJed Brown 1274f899ff85SJose E. Roman Input Parameter: 127511a5261eSBarry Smith . A - `MATNEST` matrix 1276900e7ff2SJed Brown 1277d8d19677SJose E. Roman Output Parameters: 12780298fd71SBarry Smith + rows - array of row index sets (or NULL to ignore) 12790298fd71SBarry Smith - cols - array of column index sets (or NULL to ignore) 1280900e7ff2SJed Brown 1281900e7ff2SJed Brown Level: advanced 1282900e7ff2SJed Brown 128311a5261eSBarry Smith Note: 1284900e7ff2SJed Brown The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs. 1285900e7ff2SJed Brown 128611a5261eSBarry Smith .seealso: `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`, 1287db781477SPatrick Sanan `MATNEST`, `MatNestSetSubMats()`, `MatNestSetSubMat()` 1288900e7ff2SJed Brown @*/ 1289d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[]) 1290d71ae5a4SJacob Faibussowitsch { 1291900e7ff2SJed Brown PetscFunctionBegin; 1292900e7ff2SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1293cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 1294900e7ff2SJed Brown PetscFunctionReturn(0); 1295900e7ff2SJed Brown } 1296900e7ff2SJed Brown 1297d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype) 1298d71ae5a4SJacob Faibussowitsch { 1299207556f9SJed Brown PetscBool flg; 1300207556f9SJed Brown 1301207556f9SJed Brown PetscFunctionBegin; 13029566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, VECNEST, &flg)); 1303207556f9SJed Brown /* In reality, this only distinguishes VECNEST and "other" */ 13042a7a6963SBarry Smith if (flg) A->ops->getvecs = MatCreateVecs_Nest; 130512b53f24SSatish Balay else A->ops->getvecs = (PetscErrorCode(*)(Mat, Vec *, Vec *))0; 1306207556f9SJed Brown PetscFunctionReturn(0); 1307207556f9SJed Brown } 1308207556f9SJed Brown 1309207556f9SJed Brown /*@C 131011a5261eSBarry Smith MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()` 1311207556f9SJed Brown 1312207556f9SJed Brown Not collective 1313207556f9SJed Brown 1314207556f9SJed Brown Input Parameters: 131511a5261eSBarry Smith + A - `MATNEST` matrix 131611a5261eSBarry Smith - vtype - `VecType` to use for creating vectors 1317207556f9SJed Brown 1318207556f9SJed Brown Level: developer 1319207556f9SJed Brown 132011a5261eSBarry Smith .seealso: `MATNEST`, `MatCreateVecs()`, `MATNEST`, `MatCreateNest()`, `VecType` 1321207556f9SJed Brown @*/ 1322d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype) 1323d71ae5a4SJacob Faibussowitsch { 1324207556f9SJed Brown PetscFunctionBegin; 1325cac4c232SBarry Smith PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype)); 1326207556f9SJed Brown PetscFunctionReturn(0); 1327207556f9SJed Brown } 1328207556f9SJed Brown 1329d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) 1330d71ae5a4SJacob Faibussowitsch { 1331c8883902SJed Brown Mat_Nest *s = (Mat_Nest *)A->data; 1332c8883902SJed Brown PetscInt i, j, m, n, M, N; 133388ffe2e8SJose E. Roman PetscBool cong, isstd, sametype = PETSC_FALSE; 133488ffe2e8SJose E. Roman VecType vtype, type; 1335d8588912SDave May 1336d8588912SDave May PetscFunctionBegin; 13379566063dSJacob Faibussowitsch PetscCall(MatReset_Nest(A)); 133806a1af2fSStefano Zampini 1339c8883902SJed Brown s->nr = nr; 1340c8883902SJed Brown s->nc = nc; 1341d8588912SDave May 1342c8883902SJed Brown /* Create space for submatrices */ 13439566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &s->m)); 134448a46eb9SPierre Jolivet for (i = 0; i < nr; i++) PetscCall(PetscMalloc1(nc, &s->m[i])); 1345c8883902SJed Brown for (i = 0; i < nr; i++) { 1346c8883902SJed Brown for (j = 0; j < nc; j++) { 1347c8883902SJed Brown s->m[i][j] = a[i * nc + j]; 134848a46eb9SPierre Jolivet if (a[i * nc + j]) PetscCall(PetscObjectReference((PetscObject)a[i * nc + j])); 1349d8588912SDave May } 1350d8588912SDave May } 13519566063dSJacob Faibussowitsch PetscCall(MatGetVecType(A, &vtype)); 13529566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd)); 135388ffe2e8SJose E. Roman if (isstd) { 135488ffe2e8SJose E. Roman /* check if all blocks have the same vectype */ 135588ffe2e8SJose E. Roman vtype = NULL; 135688ffe2e8SJose E. Roman for (i = 0; i < nr; i++) { 135788ffe2e8SJose E. Roman for (j = 0; j < nc; j++) { 135888ffe2e8SJose E. Roman if (a[i * nc + j]) { 135988ffe2e8SJose E. Roman if (!vtype) { /* first visited block */ 13609566063dSJacob Faibussowitsch PetscCall(MatGetVecType(a[i * nc + j], &vtype)); 136188ffe2e8SJose E. Roman sametype = PETSC_TRUE; 136288ffe2e8SJose E. Roman } else if (sametype) { 13639566063dSJacob Faibussowitsch PetscCall(MatGetVecType(a[i * nc + j], &type)); 13649566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, type, &sametype)); 136588ffe2e8SJose E. Roman } 136688ffe2e8SJose E. Roman } 136788ffe2e8SJose E. Roman } 136888ffe2e8SJose E. Roman } 136988ffe2e8SJose E. Roman if (sametype) { /* propagate vectype */ 13709566063dSJacob Faibussowitsch PetscCall(MatSetVecType(A, vtype)); 137188ffe2e8SJose E. Roman } 137288ffe2e8SJose E. Roman } 1373d8588912SDave May 13749566063dSJacob Faibussowitsch PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col)); 1375d8588912SDave May 13769566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &s->row_len)); 13779566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &s->col_len)); 1378c8883902SJed Brown for (i = 0; i < nr; i++) s->row_len[i] = -1; 1379c8883902SJed Brown for (j = 0; j < nc; j++) s->col_len[j] = -1; 1380d8588912SDave May 13819566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr * nc, &s->nnzstate)); 138206a1af2fSStefano Zampini for (i = 0; i < nr; i++) { 138306a1af2fSStefano Zampini for (j = 0; j < nc; j++) { 138448a46eb9SPierre Jolivet if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j])); 138506a1af2fSStefano Zampini } 138606a1af2fSStefano Zampini } 138706a1af2fSStefano Zampini 13889566063dSJacob Faibussowitsch PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N)); 1389d8588912SDave May 13909566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(A->rmap, M)); 13919566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(A->rmap, m)); 13929566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(A->cmap, N)); 13939566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(A->cmap, n)); 1394c8883902SJed Brown 13959566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->rmap)); 13969566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->cmap)); 1397c8883902SJed Brown 139806a1af2fSStefano Zampini /* disable operations that are not supported for non-square matrices, 139906a1af2fSStefano Zampini or matrices for which is_row != is_col */ 14009566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(A, &cong)); 140106a1af2fSStefano Zampini if (cong && nr != nc) cong = PETSC_FALSE; 140206a1af2fSStefano Zampini if (cong) { 140348a46eb9SPierre Jolivet for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong)); 140406a1af2fSStefano Zampini } 140506a1af2fSStefano Zampini if (!cong) { 1406381b8e50SStefano Zampini A->ops->missingdiagonal = NULL; 140706a1af2fSStefano Zampini A->ops->getdiagonal = NULL; 140806a1af2fSStefano Zampini A->ops->shift = NULL; 140906a1af2fSStefano Zampini A->ops->diagonalset = NULL; 141006a1af2fSStefano Zampini } 141106a1af2fSStefano Zampini 14129566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right)); 14139566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)A)); 141406a1af2fSStefano Zampini A->nonzerostate++; 1415d8588912SDave May PetscFunctionReturn(0); 1416d8588912SDave May } 1417d8588912SDave May 1418c8883902SJed Brown /*@ 141911a5261eSBarry Smith MatNestSetSubMats - Sets the nested submatrices in a `MATNEST` 1420c8883902SJed Brown 1421*c3339decSBarry Smith Collective 1422c8883902SJed Brown 1423d8d19677SJose E. Roman Input Parameters: 142411a5261eSBarry Smith + A - `MATNEST` matrix 1425c8883902SJed Brown . nr - number of nested row blocks 14260298fd71SBarry Smith . is_row - index sets for each nested row block, or NULL to make contiguous 1427c8883902SJed Brown . nc - number of nested column blocks 14280298fd71SBarry Smith . is_col - index sets for each nested column block, or NULL to make contiguous 14290298fd71SBarry Smith - a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL 1430c8883902SJed Brown 143111a5261eSBarry Smith Note: 143211a5261eSBarry Smith This always resets any submatrix information previously set 143306a1af2fSStefano Zampini 1434c8883902SJed Brown Level: advanced 1435c8883902SJed Brown 143611a5261eSBarry Smith .seealso: `MATNEST`, `MatCreateNest()`, `MATNEST`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()` 1437c8883902SJed Brown @*/ 1438d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) 1439d71ae5a4SJacob Faibussowitsch { 144006a1af2fSStefano Zampini PetscInt i; 1441c8883902SJed Brown 1442c8883902SJed Brown PetscFunctionBegin; 1443c8883902SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 144408401ef6SPierre Jolivet PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative"); 1445c8883902SJed Brown if (nr && is_row) { 1446c8883902SJed Brown PetscValidPointer(is_row, 3); 1447c8883902SJed Brown for (i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3); 1448c8883902SJed Brown } 144908401ef6SPierre Jolivet PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative"); 14501664e352SJed Brown if (nc && is_col) { 1451c8883902SJed Brown PetscValidPointer(is_col, 5); 14529b30a8f6SBarry Smith for (i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5); 1453c8883902SJed Brown } 145406a1af2fSStefano Zampini if (nr * nc > 0) PetscValidPointer(a, 6); 1455cac4c232SBarry Smith PetscUseMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a)); 1456c8883902SJed Brown PetscFunctionReturn(0); 1457c8883902SJed Brown } 1458d8588912SDave May 1459d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog) 1460d71ae5a4SJacob Faibussowitsch { 146177019fcaSJed Brown PetscBool flg; 146277019fcaSJed Brown PetscInt i, j, m, mi, *ix; 146377019fcaSJed Brown 146477019fcaSJed Brown PetscFunctionBegin; 1465aea6d515SStefano Zampini *ltog = NULL; 146677019fcaSJed Brown for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) { 146777019fcaSJed Brown if (islocal[i]) { 14689566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(islocal[i], &mi)); 146977019fcaSJed Brown flg = PETSC_TRUE; /* We found a non-trivial entry */ 147077019fcaSJed Brown } else { 14719566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mi)); 147277019fcaSJed Brown } 147377019fcaSJed Brown m += mi; 147477019fcaSJed Brown } 1475aea6d515SStefano Zampini if (!flg) PetscFunctionReturn(0); 1476aea6d515SStefano Zampini 14779566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &ix)); 1478165cd838SBarry Smith for (i = 0, m = 0; i < n; i++) { 14790298fd71SBarry Smith ISLocalToGlobalMapping smap = NULL; 1480e108cb99SStefano Zampini Mat sub = NULL; 1481f6d38dbbSStefano Zampini PetscSF sf; 1482f6d38dbbSStefano Zampini PetscLayout map; 1483aea6d515SStefano Zampini const PetscInt *ix2; 148477019fcaSJed Brown 1485165cd838SBarry Smith if (!colflg) { 14869566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 148777019fcaSJed Brown } else { 14889566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 148977019fcaSJed Brown } 1490191fd14bSBarry Smith if (sub) { 1491191fd14bSBarry Smith if (!colflg) { 14929566063dSJacob Faibussowitsch PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL)); 1493191fd14bSBarry Smith } else { 14949566063dSJacob Faibussowitsch PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap)); 1495191fd14bSBarry Smith } 1496191fd14bSBarry Smith } 149777019fcaSJed Brown /* 149877019fcaSJed Brown Now we need to extract the monolithic global indices that correspond to the given split global indices. 149977019fcaSJed 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. 150077019fcaSJed Brown */ 15019566063dSJacob Faibussowitsch PetscCall(ISGetIndices(isglobal[i], &ix2)); 1502aea6d515SStefano Zampini if (islocal[i]) { 1503aea6d515SStefano Zampini PetscInt *ilocal, *iremote; 1504aea6d515SStefano Zampini PetscInt mil, nleaves; 1505aea6d515SStefano Zampini 15069566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(islocal[i], &mi)); 150728b400f6SJacob Faibussowitsch PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map"); 1508aea6d515SStefano Zampini for (j = 0; j < mi; j++) ix[m + j] = j; 15099566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m)); 1510aea6d515SStefano Zampini 1511aea6d515SStefano Zampini /* PetscSFSetGraphLayout does not like negative indices */ 15129566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote)); 1513aea6d515SStefano Zampini for (j = 0, nleaves = 0; j < mi; j++) { 1514aea6d515SStefano Zampini if (ix[m + j] < 0) continue; 1515aea6d515SStefano Zampini ilocal[nleaves] = j; 1516aea6d515SStefano Zampini iremote[nleaves] = ix[m + j]; 1517aea6d515SStefano Zampini nleaves++; 1518aea6d515SStefano Zampini } 15199566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mil)); 15209566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf)); 15219566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map)); 15229566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(map, mil)); 15239566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(map)); 15249566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote)); 15259566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&map)); 15269566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 15279566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 15289566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&sf)); 15299566063dSJacob Faibussowitsch PetscCall(PetscFree2(ilocal, iremote)); 1530aea6d515SStefano Zampini } else { 15319566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mi)); 1532aea6d515SStefano Zampini for (j = 0; j < mi; j++) ix[m + j] = ix2[i]; 1533aea6d515SStefano Zampini } 15349566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(isglobal[i], &ix2)); 153577019fcaSJed Brown m += mi; 153677019fcaSJed Brown } 15379566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog)); 153877019fcaSJed Brown PetscFunctionReturn(0); 153977019fcaSJed Brown } 154077019fcaSJed Brown 1541d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */ 1542d8588912SDave May /* 1543d8588912SDave May nprocessors = NP 1544d8588912SDave May Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1)) 1545d8588912SDave May proc 0: => (g_0,h_0,) 1546d8588912SDave May proc 1: => (g_1,h_1,) 1547d8588912SDave May ... 1548d8588912SDave May proc nprocs-1: => (g_NP-1,h_NP-1,) 1549d8588912SDave May 1550d8588912SDave May proc 0: proc 1: proc nprocs-1: 1551d8588912SDave May is[0] = (0,1,2,...,nlocal(g_0)-1) (0,1,...,nlocal(g_1)-1) (0,1,...,nlocal(g_NP-1)) 1552d8588912SDave May 1553d8588912SDave May proc 0: 1554d8588912SDave May is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1) 1555d8588912SDave May proc 1: 1556d8588912SDave May is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1) 1557d8588912SDave May 1558d8588912SDave May proc NP-1: 1559d8588912SDave May is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1) 1560d8588912SDave May */ 1561d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[]) 1562d71ae5a4SJacob Faibussowitsch { 1563e2d7f03fSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 15648188e55aSJed Brown PetscInt i, j, offset, n, nsum, bs; 15650298fd71SBarry Smith Mat sub = NULL; 1566d8588912SDave May 1567d8588912SDave May PetscFunctionBegin; 15689566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &vs->isglobal.row)); 15699566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &vs->isglobal.col)); 1570d8588912SDave May if (is_row) { /* valid IS is passed in */ 1571a5b23f4aSJose E. Roman /* refs on is[] are incremented */ 1572e2d7f03fSJed Brown for (i = 0; i < vs->nr; i++) { 15739566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is_row[i])); 157426fbe8dcSKarl Rupp 1575e2d7f03fSJed Brown vs->isglobal.row[i] = is_row[i]; 1576d8588912SDave May } 15772ae74bdbSJed Brown } else { /* Create the ISs by inspecting sizes of a submatrix in each row */ 15788188e55aSJed Brown nsum = 0; 15798188e55aSJed Brown for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */ 15809566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 158128b400f6SJacob Faibussowitsch PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i); 15829566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, &n, NULL)); 158308401ef6SPierre Jolivet PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 15848188e55aSJed Brown nsum += n; 15858188e55aSJed Brown } 15869566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 158730bc264bSJed Brown offset -= nsum; 1588e2d7f03fSJed Brown for (i = 0; i < vs->nr; i++) { 15899566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 15909566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, &n, NULL)); 15919566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 15929566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i])); 15939566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs)); 15942ae74bdbSJed Brown offset += n; 1595d8588912SDave May } 1596d8588912SDave May } 1597d8588912SDave May 1598d8588912SDave May if (is_col) { /* valid IS is passed in */ 1599a5b23f4aSJose E. Roman /* refs on is[] are incremented */ 1600e2d7f03fSJed Brown for (j = 0; j < vs->nc; j++) { 16019566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is_col[j])); 160226fbe8dcSKarl Rupp 1603e2d7f03fSJed Brown vs->isglobal.col[j] = is_col[j]; 1604d8588912SDave May } 16052ae74bdbSJed Brown } else { /* Create the ISs by inspecting sizes of a submatrix in each column */ 16062ae74bdbSJed Brown offset = A->cmap->rstart; 16078188e55aSJed Brown nsum = 0; 16088188e55aSJed Brown for (j = 0; j < vs->nc; j++) { 16099566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 161028b400f6SJacob Faibussowitsch PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i); 16119566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, NULL, &n)); 161208401ef6SPierre Jolivet PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 16138188e55aSJed Brown nsum += n; 16148188e55aSJed Brown } 16159566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 161630bc264bSJed Brown offset -= nsum; 1617e2d7f03fSJed Brown for (j = 0; j < vs->nc; j++) { 16189566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 16199566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, NULL, &n)); 16209566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 16219566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j])); 16229566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs)); 16232ae74bdbSJed Brown offset += n; 1624d8588912SDave May } 1625d8588912SDave May } 1626e2d7f03fSJed Brown 1627e2d7f03fSJed Brown /* Set up the local ISs */ 16289566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row)); 16299566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col)); 1630e2d7f03fSJed Brown for (i = 0, offset = 0; i < vs->nr; i++) { 1631e2d7f03fSJed Brown IS isloc; 16320298fd71SBarry Smith ISLocalToGlobalMapping rmap = NULL; 1633e2d7f03fSJed Brown PetscInt nlocal, bs; 16349566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 16359566063dSJacob Faibussowitsch if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL)); 1636207556f9SJed Brown if (rmap) { 16379566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 16389566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal)); 16399566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 16409566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(isloc, bs)); 1641207556f9SJed Brown } else { 1642207556f9SJed Brown nlocal = 0; 16430298fd71SBarry Smith isloc = NULL; 1644207556f9SJed Brown } 1645e2d7f03fSJed Brown vs->islocal.row[i] = isloc; 1646e2d7f03fSJed Brown offset += nlocal; 1647e2d7f03fSJed Brown } 16488188e55aSJed Brown for (i = 0, offset = 0; i < vs->nc; i++) { 1649e2d7f03fSJed Brown IS isloc; 16500298fd71SBarry Smith ISLocalToGlobalMapping cmap = NULL; 1651e2d7f03fSJed Brown PetscInt nlocal, bs; 16529566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 16539566063dSJacob Faibussowitsch if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap)); 1654207556f9SJed Brown if (cmap) { 16559566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 16569566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal)); 16579566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 16589566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(isloc, bs)); 1659207556f9SJed Brown } else { 1660207556f9SJed Brown nlocal = 0; 16610298fd71SBarry Smith isloc = NULL; 1662207556f9SJed Brown } 1663e2d7f03fSJed Brown vs->islocal.col[i] = isloc; 1664e2d7f03fSJed Brown offset += nlocal; 1665e2d7f03fSJed Brown } 16660189643fSJed Brown 166777019fcaSJed Brown /* Set up the aggregate ISLocalToGlobalMapping */ 166877019fcaSJed Brown { 166945b6f7e9SBarry Smith ISLocalToGlobalMapping rmap, cmap; 16709566063dSJacob Faibussowitsch PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap)); 16719566063dSJacob Faibussowitsch PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap)); 16729566063dSJacob Faibussowitsch if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap)); 16739566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingDestroy(&rmap)); 16749566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingDestroy(&cmap)); 167577019fcaSJed Brown } 167677019fcaSJed Brown 167776bd3646SJed Brown if (PetscDefined(USE_DEBUG)) { 16780189643fSJed Brown for (i = 0; i < vs->nr; i++) { 16790189643fSJed Brown for (j = 0; j < vs->nc; j++) { 16800189643fSJed Brown PetscInt m, n, M, N, mi, ni, Mi, Ni; 16810189643fSJed Brown Mat B = vs->m[i][j]; 16820189643fSJed Brown if (!B) continue; 16839566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, &M, &N)); 16849566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(B, &m, &n)); 16859566063dSJacob Faibussowitsch PetscCall(ISGetSize(vs->isglobal.row[i], &Mi)); 16869566063dSJacob Faibussowitsch PetscCall(ISGetSize(vs->isglobal.col[j], &Ni)); 16879566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi)); 16889566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni)); 1689aed4548fSBarry 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); 1690aed4548fSBarry 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); 16910189643fSJed Brown } 16920189643fSJed Brown } 169376bd3646SJed Brown } 1694a061e289SJed Brown 1695a061e289SJed Brown /* Set A->assembled if all non-null blocks are currently assembled */ 1696a061e289SJed Brown for (i = 0; i < vs->nr; i++) { 1697a061e289SJed Brown for (j = 0; j < vs->nc; j++) { 1698a061e289SJed Brown if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0); 1699a061e289SJed Brown } 1700a061e289SJed Brown } 1701a061e289SJed Brown A->assembled = PETSC_TRUE; 1702d8588912SDave May PetscFunctionReturn(0); 1703d8588912SDave May } 1704d8588912SDave May 170545c38901SJed Brown /*@C 170611a5261eSBarry Smith MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately 1707659c6bb0SJed Brown 170811a5261eSBarry Smith Collective 1709659c6bb0SJed Brown 1710d8d19677SJose E. Roman Input Parameters: 171111a5261eSBarry Smith + comm - Communicator for the new `MATNEST` 1712659c6bb0SJed Brown . nr - number of nested row blocks 17130298fd71SBarry Smith . is_row - index sets for each nested row block, or NULL to make contiguous 1714659c6bb0SJed Brown . nc - number of nested column blocks 17150298fd71SBarry Smith . is_col - index sets for each nested column block, or NULL to make contiguous 17160298fd71SBarry Smith - a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL 1717659c6bb0SJed Brown 1718659c6bb0SJed Brown Output Parameter: 1719659c6bb0SJed Brown . B - new matrix 1720659c6bb0SJed Brown 1721659c6bb0SJed Brown Level: advanced 1722659c6bb0SJed Brown 172311a5261eSBarry Smith .seealso: `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MATNEST`, `MatNestSetSubMat()`, 1724db781477SPatrick Sanan `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`, 1725db781477SPatrick Sanan `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 1726659c6bb0SJed Brown @*/ 1727d71ae5a4SJacob Faibussowitsch PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B) 1728d71ae5a4SJacob Faibussowitsch { 1729d8588912SDave May Mat A; 1730d8588912SDave May 1731d8588912SDave May PetscFunctionBegin; 1732f4259b30SLisandro Dalcin *B = NULL; 17339566063dSJacob Faibussowitsch PetscCall(MatCreate(comm, &A)); 17349566063dSJacob Faibussowitsch PetscCall(MatSetType(A, MATNEST)); 173591a28eb3SBarry Smith A->preallocated = PETSC_TRUE; 17369566063dSJacob Faibussowitsch PetscCall(MatNestSetSubMats(A, nr, is_row, nc, is_col, a)); 1737d8588912SDave May *B = A; 1738d8588912SDave May PetscFunctionReturn(0); 1739d8588912SDave May } 1740659c6bb0SJed Brown 1741d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 1742d71ae5a4SJacob Faibussowitsch { 1743b68353e5Sstefano_zampini Mat_Nest *nest = (Mat_Nest *)A->data; 174423875855Sstefano_zampini Mat *trans; 1745b68353e5Sstefano_zampini PetscScalar **avv; 1746b68353e5Sstefano_zampini PetscScalar *vv; 1747b68353e5Sstefano_zampini PetscInt **aii, **ajj; 1748b68353e5Sstefano_zampini PetscInt *ii, *jj, *ci; 1749b68353e5Sstefano_zampini PetscInt nr, nc, nnz, i, j; 1750b68353e5Sstefano_zampini PetscBool done; 1751b68353e5Sstefano_zampini 1752b68353e5Sstefano_zampini PetscFunctionBegin; 17539566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &nr, &nc)); 1754b68353e5Sstefano_zampini if (reuse == MAT_REUSE_MATRIX) { 1755b68353e5Sstefano_zampini PetscInt rnr; 1756b68353e5Sstefano_zampini 17579566063dSJacob Faibussowitsch PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done)); 175828b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ"); 175908401ef6SPierre Jolivet PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows"); 17609566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArray(*newmat, &vv)); 1761b68353e5Sstefano_zampini } 1762b68353e5Sstefano_zampini /* extract CSR for nested SeqAIJ matrices */ 1763b68353e5Sstefano_zampini nnz = 0; 17649566063dSJacob Faibussowitsch PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans)); 1765b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1766b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1767b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1768b68353e5Sstefano_zampini if (B) { 1769b68353e5Sstefano_zampini PetscScalar *naa; 1770b68353e5Sstefano_zampini PetscInt *nii, *njj, nnr; 177123875855Sstefano_zampini PetscBool istrans; 1772b68353e5Sstefano_zampini 1773013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans)); 177423875855Sstefano_zampini if (istrans) { 177523875855Sstefano_zampini Mat Bt; 177623875855Sstefano_zampini 17779566063dSJacob Faibussowitsch PetscCall(MatTransposeGetMat(B, &Bt)); 17789566063dSJacob Faibussowitsch PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 177923875855Sstefano_zampini B = trans[i * nest->nc + j]; 1780013e2dc7SBarry Smith } else { 1781013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans)); 1782013e2dc7SBarry Smith if (istrans) { 1783013e2dc7SBarry Smith Mat Bt; 1784013e2dc7SBarry Smith 1785013e2dc7SBarry Smith PetscCall(MatHermitianTransposeGetMat(B, &Bt)); 1786013e2dc7SBarry Smith PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 1787013e2dc7SBarry Smith B = trans[i * nest->nc + j]; 1788013e2dc7SBarry Smith } 178923875855Sstefano_zampini } 17909566063dSJacob Faibussowitsch PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done)); 179128b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ"); 17929566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArray(B, &naa)); 1793b68353e5Sstefano_zampini nnz += nii[nnr]; 1794b68353e5Sstefano_zampini 1795b68353e5Sstefano_zampini aii[i * nest->nc + j] = nii; 1796b68353e5Sstefano_zampini ajj[i * nest->nc + j] = njj; 1797b68353e5Sstefano_zampini avv[i * nest->nc + j] = naa; 1798b68353e5Sstefano_zampini } 1799b68353e5Sstefano_zampini } 1800b68353e5Sstefano_zampini } 1801b68353e5Sstefano_zampini if (reuse != MAT_REUSE_MATRIX) { 18029566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr + 1, &ii)); 18039566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &jj)); 18049566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &vv)); 1805b68353e5Sstefano_zampini } else { 180608401ef6SPierre Jolivet PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros"); 1807b68353e5Sstefano_zampini } 1808b68353e5Sstefano_zampini 1809b68353e5Sstefano_zampini /* new row pointer */ 18109566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(ii, nr + 1)); 1811b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1812b68353e5Sstefano_zampini PetscInt ncr, rst; 1813b68353e5Sstefano_zampini 18149566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 18159566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1816b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1817b68353e5Sstefano_zampini if (aii[i * nest->nc + j]) { 1818b68353e5Sstefano_zampini PetscInt *nii = aii[i * nest->nc + j]; 1819b68353e5Sstefano_zampini PetscInt ir; 1820b68353e5Sstefano_zampini 1821b68353e5Sstefano_zampini for (ir = rst; ir < ncr + rst; ++ir) { 1822b68353e5Sstefano_zampini ii[ir + 1] += nii[1] - nii[0]; 1823b68353e5Sstefano_zampini nii++; 1824b68353e5Sstefano_zampini } 1825b68353e5Sstefano_zampini } 1826b68353e5Sstefano_zampini } 1827b68353e5Sstefano_zampini } 1828b68353e5Sstefano_zampini for (i = 0; i < nr; i++) ii[i + 1] += ii[i]; 1829b68353e5Sstefano_zampini 1830b68353e5Sstefano_zampini /* construct CSR for the new matrix */ 18319566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr, &ci)); 1832b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1833b68353e5Sstefano_zampini PetscInt ncr, rst; 1834b68353e5Sstefano_zampini 18359566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 18369566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1837b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1838b68353e5Sstefano_zampini if (aii[i * nest->nc + j]) { 1839b68353e5Sstefano_zampini PetscScalar *nvv = avv[i * nest->nc + j]; 1840b68353e5Sstefano_zampini PetscInt *nii = aii[i * nest->nc + j]; 1841b68353e5Sstefano_zampini PetscInt *njj = ajj[i * nest->nc + j]; 1842b68353e5Sstefano_zampini PetscInt ir, cst; 1843b68353e5Sstefano_zampini 18449566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL)); 1845b68353e5Sstefano_zampini for (ir = rst; ir < ncr + rst; ++ir) { 1846b68353e5Sstefano_zampini PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir]; 1847b68353e5Sstefano_zampini 1848b68353e5Sstefano_zampini for (ij = 0; ij < rsize; ij++) { 1849b68353e5Sstefano_zampini jj[ist + ij] = *njj + cst; 1850b68353e5Sstefano_zampini vv[ist + ij] = *nvv; 1851b68353e5Sstefano_zampini njj++; 1852b68353e5Sstefano_zampini nvv++; 1853b68353e5Sstefano_zampini } 1854b68353e5Sstefano_zampini ci[ir] += rsize; 1855b68353e5Sstefano_zampini nii++; 1856b68353e5Sstefano_zampini } 1857b68353e5Sstefano_zampini } 1858b68353e5Sstefano_zampini } 1859b68353e5Sstefano_zampini } 18609566063dSJacob Faibussowitsch PetscCall(PetscFree(ci)); 1861b68353e5Sstefano_zampini 1862b68353e5Sstefano_zampini /* restore info */ 1863b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1864b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1865b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1866b68353e5Sstefano_zampini if (B) { 1867b68353e5Sstefano_zampini PetscInt nnr = 0, k = i * nest->nc + j; 186823875855Sstefano_zampini 186923875855Sstefano_zampini B = (trans[k] ? trans[k] : B); 18709566063dSJacob Faibussowitsch PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done)); 187128b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ"); 18729566063dSJacob Faibussowitsch PetscCall(MatSeqAIJRestoreArray(B, &avv[k])); 18739566063dSJacob Faibussowitsch PetscCall(MatDestroy(&trans[k])); 1874b68353e5Sstefano_zampini } 1875b68353e5Sstefano_zampini } 1876b68353e5Sstefano_zampini } 18779566063dSJacob Faibussowitsch PetscCall(PetscFree4(aii, ajj, avv, trans)); 1878b68353e5Sstefano_zampini 1879b68353e5Sstefano_zampini /* finalize newmat */ 1880b68353e5Sstefano_zampini if (reuse == MAT_INITIAL_MATRIX) { 18819566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat)); 1882b68353e5Sstefano_zampini } else if (reuse == MAT_INPLACE_MATRIX) { 1883b68353e5Sstefano_zampini Mat B; 1884b68353e5Sstefano_zampini 18859566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B)); 18869566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &B)); 1887b68353e5Sstefano_zampini } 18889566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY)); 18899566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY)); 1890b68353e5Sstefano_zampini { 1891b68353e5Sstefano_zampini Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data); 1892b68353e5Sstefano_zampini a->free_a = PETSC_TRUE; 1893b68353e5Sstefano_zampini a->free_ij = PETSC_TRUE; 1894b68353e5Sstefano_zampini } 1895b68353e5Sstefano_zampini PetscFunctionReturn(0); 1896b68353e5Sstefano_zampini } 1897b68353e5Sstefano_zampini 1898d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X) 1899d71ae5a4SJacob Faibussowitsch { 1900be705e3aSPierre Jolivet Mat_Nest *nest = (Mat_Nest *)X->data; 1901be705e3aSPierre Jolivet PetscInt i, j, k, rstart; 1902be705e3aSPierre Jolivet PetscBool flg; 1903be705e3aSPierre Jolivet 1904be705e3aSPierre Jolivet PetscFunctionBegin; 1905be705e3aSPierre Jolivet /* Fill by row */ 1906be705e3aSPierre Jolivet for (j = 0; j < nest->nc; ++j) { 1907be705e3aSPierre Jolivet /* Using global column indices and ISAllGather() is not scalable. */ 1908be705e3aSPierre Jolivet IS bNis; 1909be705e3aSPierre Jolivet PetscInt bN; 1910be705e3aSPierre Jolivet const PetscInt *bNindices; 19119566063dSJacob Faibussowitsch PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 19129566063dSJacob Faibussowitsch PetscCall(ISGetSize(bNis, &bN)); 19139566063dSJacob Faibussowitsch PetscCall(ISGetIndices(bNis, &bNindices)); 1914be705e3aSPierre Jolivet for (i = 0; i < nest->nr; ++i) { 1915fd8a7442SPierre Jolivet Mat B = nest->m[i][j], D = NULL; 1916be705e3aSPierre Jolivet PetscInt bm, br; 1917be705e3aSPierre Jolivet const PetscInt *bmindices; 1918be705e3aSPierre Jolivet if (!B) continue; 1919013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 1920be705e3aSPierre Jolivet if (flg) { 1921cac4c232SBarry Smith PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 1922cac4c232SBarry Smith PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 19239566063dSJacob Faibussowitsch PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 1924be705e3aSPierre Jolivet B = D; 1925be705e3aSPierre Jolivet } 19269566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 1927be705e3aSPierre Jolivet if (flg) { 1928fd8a7442SPierre Jolivet if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 1929fd8a7442SPierre Jolivet else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 1930be705e3aSPierre Jolivet B = D; 1931be705e3aSPierre Jolivet } 19329566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 19339566063dSJacob Faibussowitsch PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 19349566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 1935be705e3aSPierre Jolivet for (br = 0; br < bm; ++br) { 1936be705e3aSPierre Jolivet PetscInt row = bmindices[br], brncols, *cols; 1937be705e3aSPierre Jolivet const PetscInt *brcols; 1938be705e3aSPierre Jolivet const PetscScalar *brcoldata; 1939be705e3aSPierre Jolivet PetscScalar *vals = NULL; 19409566063dSJacob Faibussowitsch PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 19419566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(brncols, &cols)); 1942be705e3aSPierre Jolivet for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]]; 1943be705e3aSPierre Jolivet /* 1944be705e3aSPierre Jolivet Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match. 1945be705e3aSPierre Jolivet Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES. 1946be705e3aSPierre Jolivet */ 1947be705e3aSPierre Jolivet if (a != 1.0) { 19489566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(brncols, &vals)); 1949be705e3aSPierre Jolivet for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k]; 19509566063dSJacob Faibussowitsch PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES)); 19519566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 1952be705e3aSPierre Jolivet } else { 19539566063dSJacob Faibussowitsch PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES)); 1954be705e3aSPierre Jolivet } 19559566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 19569566063dSJacob Faibussowitsch PetscCall(PetscFree(cols)); 1957be705e3aSPierre Jolivet } 1958fd8a7442SPierre Jolivet if (D) PetscCall(MatDestroy(&D)); 19599566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 1960be705e3aSPierre Jolivet } 19619566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(bNis, &bNindices)); 19629566063dSJacob Faibussowitsch PetscCall(ISDestroy(&bNis)); 1963be705e3aSPierre Jolivet } 19649566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY)); 19659566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY)); 1966be705e3aSPierre Jolivet PetscFunctionReturn(0); 1967be705e3aSPierre Jolivet } 1968be705e3aSPierre Jolivet 1969d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 1970d71ae5a4SJacob Faibussowitsch { 1971629c3df2SDmitry Karpeev Mat_Nest *nest = (Mat_Nest *)A->data; 1972be705e3aSPierre Jolivet PetscInt m, n, M, N, i, j, k, *dnnz, *onnz, rstart, cstart, cend; 1973b68353e5Sstefano_zampini PetscMPIInt size; 1974629c3df2SDmitry Karpeev Mat C; 1975629c3df2SDmitry Karpeev 1976629c3df2SDmitry Karpeev PetscFunctionBegin; 19779566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 1978b68353e5Sstefano_zampini if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */ 1979b68353e5Sstefano_zampini PetscInt nf; 1980b68353e5Sstefano_zampini PetscBool fast; 1981b68353e5Sstefano_zampini 19829566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(newtype, MATAIJ, &fast)); 198348a46eb9SPierre Jolivet if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast)); 1984b68353e5Sstefano_zampini for (i = 0; i < nest->nr && fast; ++i) { 1985b68353e5Sstefano_zampini for (j = 0; j < nest->nc && fast; ++j) { 1986b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1987b68353e5Sstefano_zampini if (B) { 19889566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast)); 198923875855Sstefano_zampini if (!fast) { 199023875855Sstefano_zampini PetscBool istrans; 199123875855Sstefano_zampini 1992013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans)); 199323875855Sstefano_zampini if (istrans) { 199423875855Sstefano_zampini Mat Bt; 199523875855Sstefano_zampini 19969566063dSJacob Faibussowitsch PetscCall(MatTransposeGetMat(B, &Bt)); 19979566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 1998013e2dc7SBarry Smith } else { 1999013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans)); 2000013e2dc7SBarry Smith if (istrans) { 2001013e2dc7SBarry Smith Mat Bt; 2002013e2dc7SBarry Smith 2003013e2dc7SBarry Smith PetscCall(MatHermitianTransposeGetMat(B, &Bt)); 2004013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 2005013e2dc7SBarry Smith } 200623875855Sstefano_zampini } 2007b68353e5Sstefano_zampini } 2008b68353e5Sstefano_zampini } 2009b68353e5Sstefano_zampini } 2010b68353e5Sstefano_zampini } 2011b68353e5Sstefano_zampini for (i = 0, nf = 0; i < nest->nr && fast; ++i) { 20129566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast)); 2013b68353e5Sstefano_zampini if (fast) { 2014b68353e5Sstefano_zampini PetscInt f, s; 2015b68353e5Sstefano_zampini 20169566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s)); 20179371c9d4SSatish Balay if (f != nf || s != 1) { 20189371c9d4SSatish Balay fast = PETSC_FALSE; 20199371c9d4SSatish Balay } else { 20209566063dSJacob Faibussowitsch PetscCall(ISGetSize(nest->isglobal.row[i], &f)); 2021b68353e5Sstefano_zampini nf += f; 2022b68353e5Sstefano_zampini } 2023b68353e5Sstefano_zampini } 2024b68353e5Sstefano_zampini } 2025b68353e5Sstefano_zampini for (i = 0, nf = 0; i < nest->nc && fast; ++i) { 20269566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast)); 2027b68353e5Sstefano_zampini if (fast) { 2028b68353e5Sstefano_zampini PetscInt f, s; 2029b68353e5Sstefano_zampini 20309566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s)); 20319371c9d4SSatish Balay if (f != nf || s != 1) { 20329371c9d4SSatish Balay fast = PETSC_FALSE; 20339371c9d4SSatish Balay } else { 20349566063dSJacob Faibussowitsch PetscCall(ISGetSize(nest->isglobal.col[i], &f)); 2035b68353e5Sstefano_zampini nf += f; 2036b68353e5Sstefano_zampini } 2037b68353e5Sstefano_zampini } 2038b68353e5Sstefano_zampini } 2039b68353e5Sstefano_zampini if (fast) { 20409566063dSJacob Faibussowitsch PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat)); 2041b68353e5Sstefano_zampini PetscFunctionReturn(0); 2042b68353e5Sstefano_zampini } 2043b68353e5Sstefano_zampini } 20449566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, &N)); 20459566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, &n)); 20469566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend)); 2047d1487292SPierre Jolivet if (reuse == MAT_REUSE_MATRIX) C = *newmat; 2048d1487292SPierre Jolivet else { 20499566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C)); 20509566063dSJacob Faibussowitsch PetscCall(MatSetType(C, newtype)); 20519566063dSJacob Faibussowitsch PetscCall(MatSetSizes(C, m, n, M, N)); 2052629c3df2SDmitry Karpeev } 20539566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(2 * m, &dnnz)); 2054629c3df2SDmitry Karpeev onnz = dnnz + m; 2055629c3df2SDmitry Karpeev for (k = 0; k < m; k++) { 2056629c3df2SDmitry Karpeev dnnz[k] = 0; 2057629c3df2SDmitry Karpeev onnz[k] = 0; 2058629c3df2SDmitry Karpeev } 2059629c3df2SDmitry Karpeev for (j = 0; j < nest->nc; ++j) { 2060629c3df2SDmitry Karpeev IS bNis; 2061629c3df2SDmitry Karpeev PetscInt bN; 2062629c3df2SDmitry Karpeev const PetscInt *bNindices; 2063fd8a7442SPierre Jolivet PetscBool flg; 2064629c3df2SDmitry Karpeev /* Using global column indices and ISAllGather() is not scalable. */ 20659566063dSJacob Faibussowitsch PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 20669566063dSJacob Faibussowitsch PetscCall(ISGetSize(bNis, &bN)); 20679566063dSJacob Faibussowitsch PetscCall(ISGetIndices(bNis, &bNindices)); 2068629c3df2SDmitry Karpeev for (i = 0; i < nest->nr; ++i) { 2069629c3df2SDmitry Karpeev PetscSF bmsf; 2070649b366bSFande Kong PetscSFNode *iremote; 2071fd8a7442SPierre Jolivet Mat B = nest->m[i][j], D = NULL; 2072649b366bSFande Kong PetscInt bm, *sub_dnnz, *sub_onnz, br; 2073629c3df2SDmitry Karpeev const PetscInt *bmindices; 2074629c3df2SDmitry Karpeev if (!B) continue; 20759566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 20769566063dSJacob Faibussowitsch PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 20779566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf)); 20789566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &iremote)); 20799566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &sub_dnnz)); 20809566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &sub_onnz)); 2081649b366bSFande Kong for (k = 0; k < bm; ++k) { 2082649b366bSFande Kong sub_dnnz[k] = 0; 2083649b366bSFande Kong sub_onnz[k] = 0; 2084649b366bSFande Kong } 2085013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &flg)); 2086fd8a7442SPierre Jolivet if (flg) { 2087fd8a7442SPierre Jolivet PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2088fd8a7442SPierre Jolivet PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2089fd8a7442SPierre Jolivet PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 2090fd8a7442SPierre Jolivet B = D; 2091fd8a7442SPierre Jolivet } 2092fd8a7442SPierre Jolivet PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 2093fd8a7442SPierre Jolivet if (flg) { 2094fd8a7442SPierre Jolivet if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 2095fd8a7442SPierre Jolivet else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 2096fd8a7442SPierre Jolivet B = D; 2097fd8a7442SPierre Jolivet } 2098629c3df2SDmitry Karpeev /* 2099629c3df2SDmitry Karpeev Locate the owners for all of the locally-owned global row indices for this row block. 2100629c3df2SDmitry Karpeev These determine the roots of PetscSF used to communicate preallocation data to row owners. 2101629c3df2SDmitry Karpeev The roots correspond to the dnnz and onnz entries; thus, there are two roots per row. 2102629c3df2SDmitry Karpeev */ 21039566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 2104629c3df2SDmitry Karpeev for (br = 0; br < bm; ++br) { 2105131c27b5Sprj- PetscInt row = bmindices[br], brncols, col; 2106629c3df2SDmitry Karpeev const PetscInt *brcols; 2107a4b3d3acSMatthew G Knepley PetscInt rowrel = 0; /* row's relative index on its owner rank */ 2108131c27b5Sprj- PetscMPIInt rowowner = 0; 21099566063dSJacob Faibussowitsch PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel)); 2110649b366bSFande Kong /* how many roots */ 21119371c9d4SSatish Balay iremote[br].rank = rowowner; 21129371c9d4SSatish Balay iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */ 2113649b366bSFande Kong /* get nonzero pattern */ 21149566063dSJacob Faibussowitsch PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL)); 2115629c3df2SDmitry Karpeev for (k = 0; k < brncols; k++) { 2116629c3df2SDmitry Karpeev col = bNindices[brcols[k]]; 2117649b366bSFande Kong if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) { 2118649b366bSFande Kong sub_dnnz[br]++; 2119649b366bSFande Kong } else { 2120649b366bSFande Kong sub_onnz[br]++; 2121649b366bSFande Kong } 2122629c3df2SDmitry Karpeev } 21239566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL)); 2124629c3df2SDmitry Karpeev } 2125fd8a7442SPierre Jolivet if (D) PetscCall(MatDestroy(&D)); 21269566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 2127629c3df2SDmitry Karpeev /* bsf will have to take care of disposing of bedges. */ 21289566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 21299566063dSJacob Faibussowitsch PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 21309566063dSJacob Faibussowitsch PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 21319566063dSJacob Faibussowitsch PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 21329566063dSJacob Faibussowitsch PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 21339566063dSJacob Faibussowitsch PetscCall(PetscFree(sub_dnnz)); 21349566063dSJacob Faibussowitsch PetscCall(PetscFree(sub_onnz)); 21359566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&bmsf)); 2136629c3df2SDmitry Karpeev } 21379566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(bNis, &bNindices)); 21389566063dSJacob Faibussowitsch PetscCall(ISDestroy(&bNis)); 213965a4a0a3Sstefano_zampini } 214065a4a0a3Sstefano_zampini /* Resize preallocation if overestimated */ 214165a4a0a3Sstefano_zampini for (i = 0; i < m; i++) { 214265a4a0a3Sstefano_zampini dnnz[i] = PetscMin(dnnz[i], A->cmap->n); 214365a4a0a3Sstefano_zampini onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n); 2144629c3df2SDmitry Karpeev } 21459566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz)); 21469566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz)); 21479566063dSJacob Faibussowitsch PetscCall(PetscFree(dnnz)); 21489566063dSJacob Faibussowitsch PetscCall(MatAXPY_Dense_Nest(C, 1.0, A)); 2149d1487292SPierre Jolivet if (reuse == MAT_INPLACE_MATRIX) { 21509566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &C)); 2151d1487292SPierre Jolivet } else *newmat = C; 2152be705e3aSPierre Jolivet PetscFunctionReturn(0); 2153be705e3aSPierre Jolivet } 2154629c3df2SDmitry Karpeev 2155d71ae5a4SJacob Faibussowitsch PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 2156d71ae5a4SJacob Faibussowitsch { 2157629c3df2SDmitry Karpeev Mat B; 2158be705e3aSPierre Jolivet PetscInt m, n, M, N; 2159be705e3aSPierre Jolivet 2160be705e3aSPierre Jolivet PetscFunctionBegin; 21619566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, &N)); 21629566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, &n)); 2163be705e3aSPierre Jolivet if (reuse == MAT_REUSE_MATRIX) { 2164be705e3aSPierre Jolivet B = *newmat; 21659566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(B)); 2166be705e3aSPierre Jolivet } else { 21679566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B)); 2168629c3df2SDmitry Karpeev } 21699566063dSJacob Faibussowitsch PetscCall(MatAXPY_Dense_Nest(B, 1.0, A)); 2170be705e3aSPierre Jolivet if (reuse == MAT_INPLACE_MATRIX) { 21719566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &B)); 2172be705e3aSPierre Jolivet } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B; 2173629c3df2SDmitry Karpeev PetscFunctionReturn(0); 2174629c3df2SDmitry Karpeev } 2175629c3df2SDmitry Karpeev 2176d71ae5a4SJacob Faibussowitsch PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has) 2177d71ae5a4SJacob Faibussowitsch { 21788b7d3b4bSBarry Smith Mat_Nest *bA = (Mat_Nest *)mat->data; 21793c6db4c4SPierre Jolivet MatOperation opAdd; 21808b7d3b4bSBarry Smith PetscInt i, j, nr = bA->nr, nc = bA->nc; 21818b7d3b4bSBarry Smith PetscBool flg; 218252c5f739Sprj- PetscFunctionBegin; 21838b7d3b4bSBarry Smith 218452c5f739Sprj- *has = PETSC_FALSE; 21853c6db4c4SPierre Jolivet if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) { 21863c6db4c4SPierre Jolivet opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD); 21878b7d3b4bSBarry Smith for (j = 0; j < nc; j++) { 21888b7d3b4bSBarry Smith for (i = 0; i < nr; i++) { 21898b7d3b4bSBarry Smith if (!bA->m[i][j]) continue; 21909566063dSJacob Faibussowitsch PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg)); 21918b7d3b4bSBarry Smith if (!flg) PetscFunctionReturn(0); 21928b7d3b4bSBarry Smith } 21938b7d3b4bSBarry Smith } 21948b7d3b4bSBarry Smith } 21953c6db4c4SPierre Jolivet if (((void **)mat->ops)[op]) *has = PETSC_TRUE; 21968b7d3b4bSBarry Smith PetscFunctionReturn(0); 21978b7d3b4bSBarry Smith } 21988b7d3b4bSBarry Smith 2199659c6bb0SJed Brown /*MC 2200659c6bb0SJed Brown MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately. 2201659c6bb0SJed Brown 2202659c6bb0SJed Brown Level: intermediate 2203659c6bb0SJed Brown 2204659c6bb0SJed Brown Notes: 220511a5261eSBarry Smith This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices. 2206659c6bb0SJed Brown It allows the use of symmetric and block formats for parts of multi-physics simulations. 220711a5261eSBarry Smith It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()` 2208659c6bb0SJed Brown 22098b7d3b4bSBarry Smith Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero 22108b7d3b4bSBarry Smith rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes 22118b7d3b4bSBarry Smith than the nest matrix. 22128b7d3b4bSBarry Smith 221311a5261eSBarry Smith .seealso: `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, 2214db781477SPatrick Sanan `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`, 2215db781477SPatrick Sanan `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 2216659c6bb0SJed Brown M*/ 2217d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A) 2218d71ae5a4SJacob Faibussowitsch { 2219c8883902SJed Brown Mat_Nest *s; 2220c8883902SJed Brown 2221c8883902SJed Brown PetscFunctionBegin; 22224dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&s)); 2223c8883902SJed Brown A->data = (void *)s; 2224e7c19651SJed Brown 2225e7c19651SJed Brown s->nr = -1; 2226e7c19651SJed Brown s->nc = -1; 22270298fd71SBarry Smith s->m = NULL; 2228e7c19651SJed Brown s->splitassembly = PETSC_FALSE; 2229c8883902SJed Brown 22309566063dSJacob Faibussowitsch PetscCall(PetscMemzero(A->ops, sizeof(*A->ops))); 223126fbe8dcSKarl Rupp 2232c8883902SJed Brown A->ops->mult = MatMult_Nest; 22339194d70fSJed Brown A->ops->multadd = MatMultAdd_Nest; 2234c8883902SJed Brown A->ops->multtranspose = MatMultTranspose_Nest; 22359194d70fSJed Brown A->ops->multtransposeadd = MatMultTransposeAdd_Nest; 2236f8170845SAlex Fikl A->ops->transpose = MatTranspose_Nest; 2237c8883902SJed Brown A->ops->assemblybegin = MatAssemblyBegin_Nest; 2238c8883902SJed Brown A->ops->assemblyend = MatAssemblyEnd_Nest; 2239c8883902SJed Brown A->ops->zeroentries = MatZeroEntries_Nest; 2240c222c20dSDavid Ham A->ops->copy = MatCopy_Nest; 22416e76ffeaSPierre Jolivet A->ops->axpy = MatAXPY_Nest; 2242c8883902SJed Brown A->ops->duplicate = MatDuplicate_Nest; 22437dae84e0SHong Zhang A->ops->createsubmatrix = MatCreateSubMatrix_Nest; 2244c8883902SJed Brown A->ops->destroy = MatDestroy_Nest; 2245c8883902SJed Brown A->ops->view = MatView_Nest; 2246f4259b30SLisandro Dalcin A->ops->getvecs = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */ 2247c8883902SJed Brown A->ops->getlocalsubmatrix = MatGetLocalSubMatrix_Nest; 2248c8883902SJed Brown A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest; 2249429bac76SJed Brown A->ops->getdiagonal = MatGetDiagonal_Nest; 2250429bac76SJed Brown A->ops->diagonalscale = MatDiagonalScale_Nest; 2251a061e289SJed Brown A->ops->scale = MatScale_Nest; 2252a061e289SJed Brown A->ops->shift = MatShift_Nest; 225313135bc6SAlex Fikl A->ops->diagonalset = MatDiagonalSet_Nest; 2254f8170845SAlex Fikl A->ops->setrandom = MatSetRandom_Nest; 22558b7d3b4bSBarry Smith A->ops->hasoperation = MatHasOperation_Nest; 2256381b8e50SStefano Zampini A->ops->missingdiagonal = MatMissingDiagonal_Nest; 2257c8883902SJed Brown 2258f4259b30SLisandro Dalcin A->spptr = NULL; 2259c8883902SJed Brown A->assembled = PETSC_FALSE; 2260c8883902SJed Brown 2261c8883902SJed Brown /* expose Nest api's */ 22629566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest)); 22639566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest)); 22649566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest)); 22659566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest)); 22669566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest)); 22679566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest)); 22689566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest)); 22699566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest)); 22709566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ)); 22719566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ)); 22729566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ)); 22739566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS)); 22749566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense)); 22759566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense)); 22769566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense)); 22779566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense)); 22789566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", MatProductSetFromOptions_Nest_Dense)); 2279c8883902SJed Brown 22809566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST)); 2281c8883902SJed Brown PetscFunctionReturn(0); 2282c8883902SJed Brown } 2283