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 */ 129371c9d4SSatish Balay static PetscErrorCode MatNestGetSizes_Private(Mat A, PetscInt *m, PetscInt *n, PetscInt *M, PetscInt *N) { 13d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 148188e55aSJed Brown PetscInt i, j; 15d8588912SDave May 16d8588912SDave May PetscFunctionBegin; 178188e55aSJed Brown *m = *n = *M = *N = 0; 188188e55aSJed Brown for (i = 0; i < bA->nr; i++) { /* rows */ 198188e55aSJed Brown PetscInt sm, sM; 209566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[i], &sm)); 219566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.row[i], &sM)); 228188e55aSJed Brown *m += sm; 238188e55aSJed Brown *M += sM; 24d8588912SDave May } 258188e55aSJed Brown for (j = 0; j < bA->nc; j++) { /* cols */ 268188e55aSJed Brown PetscInt sn, sN; 279566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[j], &sn)); 289566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[j], &sN)); 298188e55aSJed Brown *n += sn; 308188e55aSJed Brown *N += sN; 31d8588912SDave May } 32d8588912SDave May PetscFunctionReturn(0); 33d8588912SDave May } 34d8588912SDave May 35d8588912SDave May /* operations */ 369371c9d4SSatish Balay static PetscErrorCode MatMult_Nest(Mat A, Vec x, Vec y) { 37d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 38207556f9SJed Brown Vec *bx = bA->right, *by = bA->left; 39207556f9SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 40d8588912SDave May 41d8588912SDave May PetscFunctionBegin; 429566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by[i])); 439566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i])); 44207556f9SJed Brown for (i = 0; i < nr; i++) { 459566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(by[i])); 46207556f9SJed Brown for (j = 0; j < nc; j++) { 47207556f9SJed Brown if (!bA->m[i][j]) continue; 48d8588912SDave May /* y[i] <- y[i] + A[i][j] * x[j] */ 499566063dSJacob Faibussowitsch PetscCall(MatMultAdd(bA->m[i][j], bx[j], by[i], by[i])); 50d8588912SDave May } 51d8588912SDave May } 529566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by[i])); 539566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i])); 54d8588912SDave May PetscFunctionReturn(0); 55d8588912SDave May } 56d8588912SDave May 579371c9d4SSatish Balay static PetscErrorCode MatMultAdd_Nest(Mat A, Vec x, Vec y, Vec z) { 589194d70fSJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 599194d70fSJed Brown Vec *bx = bA->right, *bz = bA->left; 609194d70fSJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 619194d70fSJed Brown 629194d70fSJed Brown PetscFunctionBegin; 639566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(z, bA->isglobal.row[i], &bz[i])); 649566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i])); 659194d70fSJed Brown for (i = 0; i < nr; i++) { 669194d70fSJed Brown if (y != z) { 679194d70fSJed Brown Vec by; 689566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by)); 699566063dSJacob Faibussowitsch PetscCall(VecCopy(by, bz[i])); 709566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by)); 719194d70fSJed Brown } 729194d70fSJed Brown for (j = 0; j < nc; j++) { 739194d70fSJed Brown if (!bA->m[i][j]) continue; 749194d70fSJed Brown /* y[i] <- y[i] + A[i][j] * x[j] */ 759566063dSJacob Faibussowitsch PetscCall(MatMultAdd(bA->m[i][j], bx[j], bz[i], bz[i])); 769194d70fSJed Brown } 779194d70fSJed Brown } 789566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.row[i], &bz[i])); 799566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i])); 809194d70fSJed Brown PetscFunctionReturn(0); 819194d70fSJed Brown } 829194d70fSJed Brown 8352c5f739Sprj- typedef struct { 8452c5f739Sprj- Mat *workC; /* array of Mat with specific containers depending on the underlying MatMatMult implementation */ 8552c5f739Sprj- PetscScalar *tarray; /* buffer for storing all temporary products A[i][j] B[j] */ 8652c5f739Sprj- PetscInt *dm, *dn, k; /* displacements and number of submatrices */ 8752c5f739Sprj- } Nest_Dense; 8852c5f739Sprj- 899371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatProductNumeric_Nest_Dense(Mat C) { 906718818eSStefano Zampini Mat_Nest *bA; 9152c5f739Sprj- Nest_Dense *contents; 926718818eSStefano Zampini Mat viewB, viewC, productB, workC; 9352c5f739Sprj- const PetscScalar *barray; 9452c5f739Sprj- PetscScalar *carray; 956718818eSStefano Zampini PetscInt i, j, M, N, nr, nc, ldb, ldc; 966718818eSStefano Zampini Mat A, B; 9752c5f739Sprj- 9852c5f739Sprj- PetscFunctionBegin; 996718818eSStefano Zampini MatCheckProduct(C, 3); 1006718818eSStefano Zampini A = C->product->A; 1016718818eSStefano Zampini B = C->product->B; 1029566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 1036718818eSStefano Zampini if (!N) { 1049566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 1059566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 1066718818eSStefano Zampini PetscFunctionReturn(0); 1076718818eSStefano Zampini } 1086718818eSStefano Zampini contents = (Nest_Dense *)C->product->data; 10928b400f6SJacob Faibussowitsch PetscCheck(contents, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty"); 1106718818eSStefano Zampini bA = (Mat_Nest *)A->data; 1116718818eSStefano Zampini nr = bA->nr; 1126718818eSStefano Zampini nc = bA->nc; 1139566063dSJacob Faibussowitsch PetscCall(MatDenseGetLDA(B, &ldb)); 1149566063dSJacob Faibussowitsch PetscCall(MatDenseGetLDA(C, &ldc)); 1159566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(C)); 1169566063dSJacob Faibussowitsch PetscCall(MatDenseGetArrayRead(B, &barray)); 1179566063dSJacob Faibussowitsch PetscCall(MatDenseGetArray(C, &carray)); 11852c5f739Sprj- for (i = 0; i < nr; i++) { 1199566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.row[i], &M)); 1209566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dm[i + 1] - contents->dm[i], PETSC_DECIDE, M, N, carray + contents->dm[i], &viewC)); 1219566063dSJacob Faibussowitsch PetscCall(MatDenseSetLDA(viewC, ldc)); 12252c5f739Sprj- for (j = 0; j < nc; j++) { 12352c5f739Sprj- if (!bA->m[i][j]) continue; 1249566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[j], &M)); 1259566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, (PetscScalar *)(barray + contents->dn[j]), &viewB)); 1269566063dSJacob Faibussowitsch PetscCall(MatDenseSetLDA(viewB, ldb)); 1274222ddf1SHong Zhang 1284222ddf1SHong Zhang /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */ 1294222ddf1SHong Zhang workC = contents->workC[i * nc + j]; 1304222ddf1SHong Zhang productB = workC->product->B; 1314222ddf1SHong Zhang workC->product->B = viewB; /* use newly created dense matrix viewB */ 1329566063dSJacob Faibussowitsch PetscCall(MatProductNumeric(workC)); 1339566063dSJacob Faibussowitsch PetscCall(MatDestroy(&viewB)); 1344222ddf1SHong Zhang workC->product->B = productB; /* resume original B */ 1354222ddf1SHong Zhang 13652c5f739Sprj- /* C[i] <- workC + C[i] */ 1379566063dSJacob Faibussowitsch PetscCall(MatAXPY(viewC, 1.0, contents->workC[i * nc + j], SAME_NONZERO_PATTERN)); 13852c5f739Sprj- } 1399566063dSJacob Faibussowitsch PetscCall(MatDestroy(&viewC)); 14052c5f739Sprj- } 1419566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArray(C, &carray)); 1429566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArrayRead(B, &barray)); 1434222ddf1SHong Zhang 1449566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 1459566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 14652c5f739Sprj- PetscFunctionReturn(0); 14752c5f739Sprj- } 14852c5f739Sprj- 1499371c9d4SSatish Balay PetscErrorCode MatNest_DenseDestroy(void *ctx) { 15052c5f739Sprj- Nest_Dense *contents = (Nest_Dense *)ctx; 15152c5f739Sprj- PetscInt i; 15252c5f739Sprj- 15352c5f739Sprj- PetscFunctionBegin; 1549566063dSJacob Faibussowitsch PetscCall(PetscFree(contents->tarray)); 155*48a46eb9SPierre Jolivet for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i)); 1569566063dSJacob Faibussowitsch PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC)); 1579566063dSJacob Faibussowitsch PetscCall(PetscFree(contents)); 15852c5f739Sprj- PetscFunctionReturn(0); 15952c5f739Sprj- } 16052c5f739Sprj- 1619371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C) { 1626718818eSStefano Zampini Mat_Nest *bA; 1636718818eSStefano Zampini Mat viewB, workC; 16452c5f739Sprj- const PetscScalar *barray; 1656718818eSStefano Zampini PetscInt i, j, M, N, m, n, nr, nc, maxm = 0, ldb; 1664222ddf1SHong Zhang Nest_Dense *contents = NULL; 1676718818eSStefano Zampini PetscBool cisdense; 1686718818eSStefano Zampini Mat A, B; 1696718818eSStefano Zampini PetscReal fill; 17052c5f739Sprj- 17152c5f739Sprj- PetscFunctionBegin; 1726718818eSStefano Zampini MatCheckProduct(C, 4); 17328b400f6SJacob Faibussowitsch PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty"); 1746718818eSStefano Zampini A = C->product->A; 1756718818eSStefano Zampini B = C->product->B; 1766718818eSStefano Zampini fill = C->product->fill; 1776718818eSStefano Zampini bA = (Mat_Nest *)A->data; 1786718818eSStefano Zampini nr = bA->nr; 1796718818eSStefano Zampini nc = bA->nc; 1809566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(C, &m, &n)); 1819566063dSJacob Faibussowitsch PetscCall(MatGetSize(C, &M, &N)); 1820572eedcSPierre Jolivet if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) { 1839566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(B, NULL, &n)); 1849566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 1859566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, NULL)); 1869566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, NULL)); 1879566063dSJacob Faibussowitsch PetscCall(MatSetSizes(C, m, n, M, N)); 1880572eedcSPierre Jolivet } 1899566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, "")); 190*48a46eb9SPierre Jolivet if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name)); 1919566063dSJacob Faibussowitsch PetscCall(MatSetUp(C)); 1926718818eSStefano Zampini if (!N) { 1936718818eSStefano Zampini C->ops->productnumeric = MatProductNumeric_Nest_Dense; 1946718818eSStefano Zampini PetscFunctionReturn(0); 19552c5f739Sprj- } 19652c5f739Sprj- 1979566063dSJacob Faibussowitsch PetscCall(PetscNew(&contents)); 1986718818eSStefano Zampini C->product->data = contents; 1996718818eSStefano Zampini C->product->destroy = MatNest_DenseDestroy; 2009566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC)); 20152c5f739Sprj- contents->k = nr * nc; 20252c5f739Sprj- for (i = 0; i < nr; i++) { 2039566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1)); 20452c5f739Sprj- maxm = PetscMax(maxm, contents->dm[i + 1]); 20552c5f739Sprj- contents->dm[i + 1] += contents->dm[i]; 20652c5f739Sprj- } 20752c5f739Sprj- for (i = 0; i < nc; i++) { 2089566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1)); 20952c5f739Sprj- contents->dn[i + 1] += contents->dn[i]; 21052c5f739Sprj- } 2119566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(maxm * N, &contents->tarray)); 2129566063dSJacob Faibussowitsch PetscCall(MatDenseGetLDA(B, &ldb)); 2139566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 2149566063dSJacob Faibussowitsch PetscCall(MatDenseGetArrayRead(B, &barray)); 21552c5f739Sprj- /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */ 21652c5f739Sprj- for (j = 0; j < nc; j++) { 2179566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[j], &M)); 2189566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, (PetscScalar *)(barray + contents->dn[j]), &viewB)); 2199566063dSJacob Faibussowitsch PetscCall(MatDenseSetLDA(viewB, ldb)); 22052c5f739Sprj- for (i = 0; i < nr; i++) { 22152c5f739Sprj- if (!bA->m[i][j]) continue; 22252c5f739Sprj- /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */ 2234222ddf1SHong Zhang 2249566063dSJacob Faibussowitsch PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j])); 2254222ddf1SHong Zhang workC = contents->workC[i * nc + j]; 2269566063dSJacob Faibussowitsch PetscCall(MatProductSetType(workC, MATPRODUCT_AB)); 2279566063dSJacob Faibussowitsch PetscCall(MatProductSetAlgorithm(workC, "default")); 2289566063dSJacob Faibussowitsch PetscCall(MatProductSetFill(workC, fill)); 2299566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(workC)); 2309566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(workC)); 2314222ddf1SHong Zhang 2326718818eSStefano Zampini /* since tarray will be shared by all Mat */ 2339566063dSJacob Faibussowitsch PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray)); 2349566063dSJacob Faibussowitsch PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray)); 23552c5f739Sprj- } 2369566063dSJacob Faibussowitsch PetscCall(MatDestroy(&viewB)); 23752c5f739Sprj- } 2389566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArrayRead(B, &barray)); 23952c5f739Sprj- 2406718818eSStefano Zampini C->ops->productnumeric = MatProductNumeric_Nest_Dense; 24152c5f739Sprj- PetscFunctionReturn(0); 24252c5f739Sprj- } 24352c5f739Sprj- 2444222ddf1SHong Zhang /* --------------------------------------------------------- */ 2459371c9d4SSatish Balay static PetscErrorCode MatProductSetFromOptions_Nest_Dense_AB(Mat C) { 2464222ddf1SHong Zhang PetscFunctionBegin; 2476718818eSStefano Zampini C->ops->productsymbolic = MatProductSymbolic_Nest_Dense; 2484222ddf1SHong Zhang PetscFunctionReturn(0); 2494222ddf1SHong Zhang } 2504222ddf1SHong Zhang 2519371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C) { 2524222ddf1SHong Zhang Mat_Product *product = C->product; 25352c5f739Sprj- 25452c5f739Sprj- PetscFunctionBegin; 255*48a46eb9SPierre Jolivet if (product->type == MATPRODUCT_AB) PetscCall(MatProductSetFromOptions_Nest_Dense_AB(C)); 25652c5f739Sprj- PetscFunctionReturn(0); 25752c5f739Sprj- } 2584222ddf1SHong Zhang /* --------------------------------------------------------- */ 25952c5f739Sprj- 2609371c9d4SSatish Balay static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y) { 261d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 262207556f9SJed Brown Vec *bx = bA->left, *by = bA->right; 263207556f9SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 264d8588912SDave May 265d8588912SDave May PetscFunctionBegin; 2669566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 2679566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i])); 268207556f9SJed Brown for (j = 0; j < nc; j++) { 2699566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(by[j])); 270609e31cbSJed Brown for (i = 0; i < nr; i++) { 2716c75ac25SJed Brown if (!bA->m[i][j]) continue; 272609e31cbSJed Brown /* y[j] <- y[j] + (A[i][j])^T * x[i] */ 2739566063dSJacob Faibussowitsch PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j])); 274d8588912SDave May } 275d8588912SDave May } 2769566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 2779566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i])); 278d8588912SDave May PetscFunctionReturn(0); 279d8588912SDave May } 280d8588912SDave May 2819371c9d4SSatish Balay static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z) { 2829194d70fSJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 2839194d70fSJed Brown Vec *bx = bA->left, *bz = bA->right; 2849194d70fSJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 2859194d70fSJed Brown 2869194d70fSJed Brown PetscFunctionBegin; 2879566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 2889566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i])); 2899194d70fSJed Brown for (j = 0; j < nc; j++) { 2909194d70fSJed Brown if (y != z) { 2919194d70fSJed Brown Vec by; 2929566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by)); 2939566063dSJacob Faibussowitsch PetscCall(VecCopy(by, bz[j])); 2949566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by)); 2959194d70fSJed Brown } 2969194d70fSJed Brown for (i = 0; i < nr; i++) { 2976c75ac25SJed Brown if (!bA->m[i][j]) continue; 2989194d70fSJed Brown /* z[j] <- y[j] + (A[i][j])^T * x[i] */ 2999566063dSJacob Faibussowitsch PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j])); 3009194d70fSJed Brown } 3019194d70fSJed Brown } 3029566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 3039566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i])); 3049194d70fSJed Brown PetscFunctionReturn(0); 3059194d70fSJed Brown } 3069194d70fSJed Brown 3079371c9d4SSatish Balay static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B) { 308f8170845SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data, *bC; 309f8170845SAlex Fikl Mat C; 310f8170845SAlex Fikl PetscInt i, j, nr = bA->nr, nc = bA->nc; 311f8170845SAlex Fikl 312f8170845SAlex Fikl PetscFunctionBegin; 3137fb60732SBarry Smith if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B)); 314aed4548fSBarry Smith PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place"); 315f8170845SAlex Fikl 316cf37664fSBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) { 317f8170845SAlex Fikl Mat *subs; 318f8170845SAlex Fikl IS *is_row, *is_col; 319f8170845SAlex Fikl 3209566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr * nc, &subs)); 3219566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col)); 3229566063dSJacob Faibussowitsch PetscCall(MatNestGetISs(A, is_row, is_col)); 323cf37664fSBarry Smith if (reuse == MAT_INPLACE_MATRIX) { 324ddeb9bd8SAlex Fikl for (i = 0; i < nr; i++) { 3259371c9d4SSatish Balay for (j = 0; j < nc; j++) { subs[i + nr * j] = bA->m[i][j]; } 326ddeb9bd8SAlex Fikl } 327ddeb9bd8SAlex Fikl } 328ddeb9bd8SAlex Fikl 3299566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C)); 3309566063dSJacob Faibussowitsch PetscCall(PetscFree(subs)); 3319566063dSJacob Faibussowitsch PetscCall(PetscFree2(is_row, is_col)); 332f8170845SAlex Fikl } else { 333f8170845SAlex Fikl C = *B; 334f8170845SAlex Fikl } 335f8170845SAlex Fikl 336f8170845SAlex Fikl bC = (Mat_Nest *)C->data; 337f8170845SAlex Fikl for (i = 0; i < nr; i++) { 338f8170845SAlex Fikl for (j = 0; j < nc; j++) { 339f8170845SAlex Fikl if (bA->m[i][j]) { 3409566063dSJacob Faibussowitsch PetscCall(MatTranspose(bA->m[i][j], reuse, &(bC->m[j][i]))); 341f8170845SAlex Fikl } else { 342f8170845SAlex Fikl bC->m[j][i] = NULL; 343f8170845SAlex Fikl } 344f8170845SAlex Fikl } 345f8170845SAlex Fikl } 346f8170845SAlex Fikl 347cf37664fSBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) { 348f8170845SAlex Fikl *B = C; 349f8170845SAlex Fikl } else { 3509566063dSJacob Faibussowitsch PetscCall(MatHeaderMerge(A, &C)); 351f8170845SAlex Fikl } 352f8170845SAlex Fikl PetscFunctionReturn(0); 353f8170845SAlex Fikl } 354f8170845SAlex Fikl 3559371c9d4SSatish Balay static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list) { 356e2d7f03fSJed Brown IS *lst = *list; 357e2d7f03fSJed Brown PetscInt i; 358e2d7f03fSJed Brown 359e2d7f03fSJed Brown PetscFunctionBegin; 360e2d7f03fSJed Brown if (!lst) PetscFunctionReturn(0); 3619371c9d4SSatish Balay for (i = 0; i < n; i++) 3629371c9d4SSatish Balay if (lst[i]) PetscCall(ISDestroy(&lst[i])); 3639566063dSJacob Faibussowitsch PetscCall(PetscFree(lst)); 3640298fd71SBarry Smith *list = NULL; 365e2d7f03fSJed Brown PetscFunctionReturn(0); 366e2d7f03fSJed Brown } 367e2d7f03fSJed Brown 3689371c9d4SSatish Balay static PetscErrorCode MatReset_Nest(Mat A) { 369d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 370d8588912SDave May PetscInt i, j; 371d8588912SDave May 372d8588912SDave May PetscFunctionBegin; 373d8588912SDave May /* release the matrices and the place holders */ 3749566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row)); 3759566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col)); 3769566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row)); 3779566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col)); 378d8588912SDave May 3799566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->row_len)); 3809566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->col_len)); 3819566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->nnzstate)); 382d8588912SDave May 3839566063dSJacob Faibussowitsch PetscCall(PetscFree2(vs->left, vs->right)); 384207556f9SJed Brown 385d8588912SDave May /* release the matrices and the place holders */ 386d8588912SDave May if (vs->m) { 387d8588912SDave May for (i = 0; i < vs->nr; i++) { 388*48a46eb9SPierre Jolivet for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j])); 3899566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->m[i])); 390d8588912SDave May } 3919566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->m)); 392d8588912SDave May } 39306a1af2fSStefano Zampini 39406a1af2fSStefano Zampini /* restore defaults */ 39506a1af2fSStefano Zampini vs->nr = 0; 39606a1af2fSStefano Zampini vs->nc = 0; 39706a1af2fSStefano Zampini vs->splitassembly = PETSC_FALSE; 39806a1af2fSStefano Zampini PetscFunctionReturn(0); 39906a1af2fSStefano Zampini } 40006a1af2fSStefano Zampini 4019371c9d4SSatish Balay static PetscErrorCode MatDestroy_Nest(Mat A) { 402362febeeSStefano Zampini PetscFunctionBegin; 4039566063dSJacob Faibussowitsch PetscCall(MatReset_Nest(A)); 4049566063dSJacob Faibussowitsch PetscCall(PetscFree(A->data)); 4059566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL)); 4069566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL)); 4079566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL)); 4089566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL)); 4099566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL)); 4109566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL)); 4119566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL)); 4129566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL)); 4139566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL)); 4149566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL)); 4159566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL)); 4169566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL)); 4179566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL)); 4189566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL)); 4199566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL)); 4209566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL)); 4219566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", NULL)); 422d8588912SDave May PetscFunctionReturn(0); 423d8588912SDave May } 424d8588912SDave May 4259371c9d4SSatish Balay static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd) { 426381b8e50SStefano Zampini Mat_Nest *vs = (Mat_Nest *)mat->data; 427381b8e50SStefano Zampini PetscInt i; 428381b8e50SStefano Zampini 429381b8e50SStefano Zampini PetscFunctionBegin; 430381b8e50SStefano Zampini if (dd) *dd = 0; 431381b8e50SStefano Zampini if (!vs->nr) { 432381b8e50SStefano Zampini *missing = PETSC_TRUE; 433381b8e50SStefano Zampini PetscFunctionReturn(0); 434381b8e50SStefano Zampini } 435381b8e50SStefano Zampini *missing = PETSC_FALSE; 436381b8e50SStefano Zampini for (i = 0; i < vs->nr && !(*missing); i++) { 437381b8e50SStefano Zampini *missing = PETSC_TRUE; 438381b8e50SStefano Zampini if (vs->m[i][i]) { 4399566063dSJacob Faibussowitsch PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL)); 44008401ef6SPierre Jolivet PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented"); 441381b8e50SStefano Zampini } 442381b8e50SStefano Zampini } 443381b8e50SStefano Zampini PetscFunctionReturn(0); 444381b8e50SStefano Zampini } 445381b8e50SStefano Zampini 4469371c9d4SSatish Balay static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type) { 447d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 448d8588912SDave May PetscInt i, j; 44906a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 450d8588912SDave May 451d8588912SDave May PetscFunctionBegin; 452d8588912SDave May for (i = 0; i < vs->nr; i++) { 453d8588912SDave May for (j = 0; j < vs->nc; j++) { 45406a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 455e7c19651SJed Brown if (vs->m[i][j]) { 4569566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(vs->m[i][j], type)); 457e7c19651SJed Brown if (!vs->splitassembly) { 458e7c19651SJed Brown /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested 459e7c19651SJed 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 460e7c19651SJed Brown * already performing an assembly, but the result would by more complicated and appears to offer less 461e7c19651SJed Brown * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an 462e7c19651SJed Brown * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives". 463e7c19651SJed Brown */ 4649566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 4659566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate)); 466e7c19651SJed Brown } 467e7c19651SJed Brown } 46806a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate); 46906a1af2fSStefano Zampini vs->nnzstate[i * vs->nc + j] = subnnzstate; 470d8588912SDave May } 471d8588912SDave May } 47206a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 473d8588912SDave May PetscFunctionReturn(0); 474d8588912SDave May } 475d8588912SDave May 4769371c9d4SSatish Balay static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type) { 477d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 478d8588912SDave May PetscInt i, j; 479d8588912SDave May 480d8588912SDave May PetscFunctionBegin; 481d8588912SDave May for (i = 0; i < vs->nr; i++) { 482d8588912SDave May for (j = 0; j < vs->nc; j++) { 483e7c19651SJed Brown if (vs->m[i][j]) { 484*48a46eb9SPierre Jolivet if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 485e7c19651SJed Brown } 486d8588912SDave May } 487d8588912SDave May } 488d8588912SDave May PetscFunctionReturn(0); 489d8588912SDave May } 490d8588912SDave May 4919371c9d4SSatish Balay static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B) { 492f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 493f349c1fdSJed Brown PetscInt j; 494f349c1fdSJed Brown Mat sub; 495d8588912SDave May 496d8588912SDave May PetscFunctionBegin; 4970298fd71SBarry Smith sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */ 498f349c1fdSJed Brown for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j]; 4999566063dSJacob Faibussowitsch if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 500f349c1fdSJed Brown *B = sub; 501f349c1fdSJed Brown PetscFunctionReturn(0); 502d8588912SDave May } 503d8588912SDave May 5049371c9d4SSatish Balay static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B) { 505f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 506f349c1fdSJed Brown PetscInt i; 507f349c1fdSJed Brown Mat sub; 508f349c1fdSJed Brown 509f349c1fdSJed Brown PetscFunctionBegin; 5100298fd71SBarry Smith sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */ 511f349c1fdSJed Brown for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col]; 5129566063dSJacob Faibussowitsch if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 513f349c1fdSJed Brown *B = sub; 514f349c1fdSJed Brown PetscFunctionReturn(0); 515d8588912SDave May } 516d8588912SDave May 5179371c9d4SSatish Balay static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end) { 51818d228c0SPierre Jolivet PetscInt i, j, size, m; 519f349c1fdSJed Brown PetscBool flg; 52018d228c0SPierre Jolivet IS out, concatenate[2]; 521f349c1fdSJed Brown 522f349c1fdSJed Brown PetscFunctionBegin; 523f349c1fdSJed Brown PetscValidPointer(list, 3); 524f349c1fdSJed Brown PetscValidHeaderSpecific(is, IS_CLASSID, 4); 52518d228c0SPierre Jolivet if (begin) { 52618d228c0SPierre Jolivet PetscValidIntPointer(begin, 5); 52718d228c0SPierre Jolivet *begin = -1; 52818d228c0SPierre Jolivet } 52918d228c0SPierre Jolivet if (end) { 53018d228c0SPierre Jolivet PetscValidIntPointer(end, 6); 53118d228c0SPierre Jolivet *end = -1; 53218d228c0SPierre Jolivet } 533f349c1fdSJed Brown for (i = 0; i < n; i++) { 534207556f9SJed Brown if (!list[i]) continue; 5359566063dSJacob Faibussowitsch PetscCall(ISEqualUnsorted(list[i], is, &flg)); 536f349c1fdSJed Brown if (flg) { 53718d228c0SPierre Jolivet if (begin) *begin = i; 53818d228c0SPierre Jolivet if (end) *end = i + 1; 539f349c1fdSJed Brown PetscFunctionReturn(0); 540f349c1fdSJed Brown } 541f349c1fdSJed Brown } 5429566063dSJacob Faibussowitsch PetscCall(ISGetSize(is, &size)); 54318d228c0SPierre Jolivet for (i = 0; i < n - 1; i++) { 54418d228c0SPierre Jolivet if (!list[i]) continue; 54518d228c0SPierre Jolivet m = 0; 5469566063dSJacob Faibussowitsch PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out)); 5479566063dSJacob Faibussowitsch PetscCall(ISGetSize(out, &m)); 54818d228c0SPierre Jolivet for (j = i + 2; j < n && m < size; j++) { 54918d228c0SPierre Jolivet if (list[j]) { 55018d228c0SPierre Jolivet concatenate[0] = out; 55118d228c0SPierre Jolivet concatenate[1] = list[j]; 5529566063dSJacob Faibussowitsch PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out)); 5539566063dSJacob Faibussowitsch PetscCall(ISDestroy(concatenate)); 5549566063dSJacob Faibussowitsch PetscCall(ISGetSize(out, &m)); 55518d228c0SPierre Jolivet } 55618d228c0SPierre Jolivet } 55718d228c0SPierre Jolivet if (m == size) { 5589566063dSJacob Faibussowitsch PetscCall(ISEqualUnsorted(out, is, &flg)); 55918d228c0SPierre Jolivet if (flg) { 56018d228c0SPierre Jolivet if (begin) *begin = i; 56118d228c0SPierre Jolivet if (end) *end = j; 5629566063dSJacob Faibussowitsch PetscCall(ISDestroy(&out)); 56318d228c0SPierre Jolivet PetscFunctionReturn(0); 56418d228c0SPierre Jolivet } 56518d228c0SPierre Jolivet } 5669566063dSJacob Faibussowitsch PetscCall(ISDestroy(&out)); 56718d228c0SPierre Jolivet } 56818d228c0SPierre Jolivet PetscFunctionReturn(0); 569f349c1fdSJed Brown } 570f349c1fdSJed Brown 5719371c9d4SSatish Balay static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B) { 5728188e55aSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 57318d228c0SPierre Jolivet PetscInt lr, lc; 57418d228c0SPierre Jolivet 57518d228c0SPierre Jolivet PetscFunctionBegin; 5769566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 5779566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr)); 5789566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc)); 5799566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE)); 5809566063dSJacob Faibussowitsch PetscCall(MatSetType(*B, MATAIJ)); 5819566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL)); 5829566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL)); 5839566063dSJacob Faibussowitsch PetscCall(MatSetUp(*B)); 5849566063dSJacob Faibussowitsch PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 5859566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 5869566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 58718d228c0SPierre Jolivet PetscFunctionReturn(0); 58818d228c0SPierre Jolivet } 58918d228c0SPierre Jolivet 5909371c9d4SSatish Balay static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B) { 59118d228c0SPierre Jolivet Mat_Nest *vs = (Mat_Nest *)A->data; 59218d228c0SPierre Jolivet Mat *a; 59318d228c0SPierre Jolivet PetscInt i, j, k, l, nr = rend - rbegin, nc = cend - cbegin; 5948188e55aSJed Brown char keyname[256]; 59518d228c0SPierre Jolivet PetscBool *b; 59618d228c0SPierre Jolivet PetscBool flg; 5978188e55aSJed Brown 5988188e55aSJed Brown PetscFunctionBegin; 5990298fd71SBarry Smith *B = NULL; 6009566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend)); 6019566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B)); 6028188e55aSJed Brown if (*B) PetscFunctionReturn(0); 6038188e55aSJed Brown 6049566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b)); 60518d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 60618d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 60718d228c0SPierre Jolivet a[i * nc + j] = vs->m[rbegin + i][cbegin + j]; 60818d228c0SPierre Jolivet b[i * nc + j] = PETSC_FALSE; 60918d228c0SPierre Jolivet } 61018d228c0SPierre Jolivet } 61118d228c0SPierre Jolivet if (nc != vs->nc && nr != vs->nr) { 61218d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 61318d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 61418d228c0SPierre Jolivet flg = PETSC_FALSE; 61518d228c0SPierre Jolivet for (k = 0; (k < nr && !flg); k++) { 61618d228c0SPierre Jolivet if (a[j + k * nc]) flg = PETSC_TRUE; 61718d228c0SPierre Jolivet } 61818d228c0SPierre Jolivet if (flg) { 61918d228c0SPierre Jolivet flg = PETSC_FALSE; 62018d228c0SPierre Jolivet for (l = 0; (l < nc && !flg); l++) { 62118d228c0SPierre Jolivet if (a[i * nc + l]) flg = PETSC_TRUE; 62218d228c0SPierre Jolivet } 62318d228c0SPierre Jolivet } 62418d228c0SPierre Jolivet if (!flg) { 62518d228c0SPierre Jolivet b[i * nc + j] = PETSC_TRUE; 6269566063dSJacob Faibussowitsch PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j)); 62718d228c0SPierre Jolivet } 62818d228c0SPierre Jolivet } 62918d228c0SPierre Jolivet } 63018d228c0SPierre Jolivet } 6319566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B)); 63218d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 63318d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 634*48a46eb9SPierre Jolivet if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j)); 63518d228c0SPierre Jolivet } 63618d228c0SPierre Jolivet } 6379566063dSJacob Faibussowitsch PetscCall(PetscFree2(a, b)); 6388188e55aSJed Brown (*B)->assembled = A->assembled; 6399566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B)); 6409566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */ 6418188e55aSJed Brown PetscFunctionReturn(0); 6428188e55aSJed Brown } 6438188e55aSJed Brown 6449371c9d4SSatish Balay static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B) { 645f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 64618d228c0SPierre Jolivet PetscInt rbegin, rend, cbegin, cend; 647f349c1fdSJed Brown 648f349c1fdSJed Brown PetscFunctionBegin; 6499566063dSJacob Faibussowitsch PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend)); 6509566063dSJacob Faibussowitsch PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend)); 65118d228c0SPierre Jolivet if (rend == rbegin + 1 && cend == cbegin + 1) { 652*48a46eb9SPierre Jolivet if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin)); 65318d228c0SPierre Jolivet *B = vs->m[rbegin][cbegin]; 65418d228c0SPierre Jolivet } else if (rbegin != -1 && cbegin != -1) { 6559566063dSJacob Faibussowitsch PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B)); 65618d228c0SPierre Jolivet } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set"); 657f349c1fdSJed Brown PetscFunctionReturn(0); 658f349c1fdSJed Brown } 659f349c1fdSJed Brown 66006a1af2fSStefano Zampini /* 66106a1af2fSStefano Zampini TODO: This does not actually returns a submatrix we can modify 66206a1af2fSStefano Zampini */ 6639371c9d4SSatish Balay static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B) { 664f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 665f349c1fdSJed Brown Mat sub; 666f349c1fdSJed Brown 667f349c1fdSJed Brown PetscFunctionBegin; 6689566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub)); 669f349c1fdSJed Brown switch (reuse) { 670f349c1fdSJed Brown case MAT_INITIAL_MATRIX: 6719566063dSJacob Faibussowitsch if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 672f349c1fdSJed Brown *B = sub; 673f349c1fdSJed Brown break; 6749371c9d4SSatish Balay case MAT_REUSE_MATRIX: PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call"); break; 6759371c9d4SSatish Balay case MAT_IGNORE_MATRIX: /* Nothing to do */ break; 6769371c9d4SSatish Balay case MAT_INPLACE_MATRIX: /* Nothing to do */ SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet"); 677f349c1fdSJed Brown } 678f349c1fdSJed Brown PetscFunctionReturn(0); 679f349c1fdSJed Brown } 680f349c1fdSJed Brown 6819371c9d4SSatish Balay PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) { 682f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 683f349c1fdSJed Brown Mat sub; 684f349c1fdSJed Brown 685f349c1fdSJed Brown PetscFunctionBegin; 6869566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 687f349c1fdSJed Brown /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */ 6889566063dSJacob Faibussowitsch if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 689f349c1fdSJed Brown *B = sub; 690d8588912SDave May PetscFunctionReturn(0); 691d8588912SDave May } 692d8588912SDave May 6939371c9d4SSatish Balay static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) { 694f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 695f349c1fdSJed Brown Mat sub; 696d8588912SDave May 697d8588912SDave May PetscFunctionBegin; 6989566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 69908401ef6SPierre Jolivet PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten"); 700f349c1fdSJed Brown if (sub) { 701aed4548fSBarry Smith PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times"); 7029566063dSJacob Faibussowitsch PetscCall(MatDestroy(B)); 703d8588912SDave May } 704d8588912SDave May PetscFunctionReturn(0); 705d8588912SDave May } 706d8588912SDave May 7079371c9d4SSatish Balay static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v) { 7087874fa86SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 7097874fa86SDave May PetscInt i; 7107874fa86SDave May 7117874fa86SDave May PetscFunctionBegin; 7127874fa86SDave May for (i = 0; i < bA->nr; i++) { 713429bac76SJed Brown Vec bv; 7149566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv)); 7157874fa86SDave May if (bA->m[i][i]) { 7169566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(bA->m[i][i], bv)); 7177874fa86SDave May } else { 7189566063dSJacob Faibussowitsch PetscCall(VecSet(bv, 0.0)); 7197874fa86SDave May } 7209566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv)); 7217874fa86SDave May } 7227874fa86SDave May PetscFunctionReturn(0); 7237874fa86SDave May } 7247874fa86SDave May 7259371c9d4SSatish Balay static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r) { 7267874fa86SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 727429bac76SJed Brown Vec bl, *br; 7287874fa86SDave May PetscInt i, j; 7297874fa86SDave May 7307874fa86SDave May PetscFunctionBegin; 7319566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(bA->nc, &br)); 7322e6472ebSElliott Sales de Andrade if (r) { 7339566063dSJacob Faibussowitsch for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j])); 7342e6472ebSElliott Sales de Andrade } 7352e6472ebSElliott Sales de Andrade bl = NULL; 7367874fa86SDave May for (i = 0; i < bA->nr; i++) { 737*48a46eb9SPierre Jolivet if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl)); 7387874fa86SDave May for (j = 0; j < bA->nc; j++) { 739*48a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j])); 7407874fa86SDave May } 741*48a46eb9SPierre Jolivet if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl)); 7422e6472ebSElliott Sales de Andrade } 7432e6472ebSElliott Sales de Andrade if (r) { 7449566063dSJacob Faibussowitsch for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j])); 7452e6472ebSElliott Sales de Andrade } 7469566063dSJacob Faibussowitsch PetscCall(PetscFree(br)); 7477874fa86SDave May PetscFunctionReturn(0); 7487874fa86SDave May } 7497874fa86SDave May 7509371c9d4SSatish Balay static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a) { 751a061e289SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 752a061e289SJed Brown PetscInt i, j; 753a061e289SJed Brown 754a061e289SJed Brown PetscFunctionBegin; 755a061e289SJed Brown for (i = 0; i < bA->nr; i++) { 756a061e289SJed Brown for (j = 0; j < bA->nc; j++) { 757*48a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a)); 758a061e289SJed Brown } 759a061e289SJed Brown } 760a061e289SJed Brown PetscFunctionReturn(0); 761a061e289SJed Brown } 762a061e289SJed Brown 7639371c9d4SSatish Balay static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a) { 764a061e289SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 765a061e289SJed Brown PetscInt i; 76606a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 767a061e289SJed Brown 768a061e289SJed Brown PetscFunctionBegin; 769a061e289SJed Brown for (i = 0; i < bA->nr; i++) { 77006a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 77108401ef6SPierre 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); 7729566063dSJacob Faibussowitsch PetscCall(MatShift(bA->m[i][i], a)); 7739566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 77406a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 77506a1af2fSStefano Zampini bA->nnzstate[i * bA->nc + i] = subnnzstate; 776a061e289SJed Brown } 77706a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 778a061e289SJed Brown PetscFunctionReturn(0); 779a061e289SJed Brown } 780a061e289SJed Brown 7819371c9d4SSatish Balay static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is) { 78213135bc6SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data; 78313135bc6SAlex Fikl PetscInt i; 78406a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 78513135bc6SAlex Fikl 78613135bc6SAlex Fikl PetscFunctionBegin; 78713135bc6SAlex Fikl for (i = 0; i < bA->nr; i++) { 78806a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 78913135bc6SAlex Fikl Vec bv; 7909566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv)); 79113135bc6SAlex Fikl if (bA->m[i][i]) { 7929566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet(bA->m[i][i], bv, is)); 7939566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 79413135bc6SAlex Fikl } 7959566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv)); 79606a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 79706a1af2fSStefano Zampini bA->nnzstate[i * bA->nc + i] = subnnzstate; 79813135bc6SAlex Fikl } 79906a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 80013135bc6SAlex Fikl PetscFunctionReturn(0); 80113135bc6SAlex Fikl } 80213135bc6SAlex Fikl 8039371c9d4SSatish Balay static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx) { 804f8170845SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data; 805f8170845SAlex Fikl PetscInt i, j; 806f8170845SAlex Fikl 807f8170845SAlex Fikl PetscFunctionBegin; 808f8170845SAlex Fikl for (i = 0; i < bA->nr; i++) { 809f8170845SAlex Fikl for (j = 0; j < bA->nc; j++) { 810*48a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx)); 811f8170845SAlex Fikl } 812f8170845SAlex Fikl } 813f8170845SAlex Fikl PetscFunctionReturn(0); 814f8170845SAlex Fikl } 815f8170845SAlex Fikl 8169371c9d4SSatish Balay static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left) { 817d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 818d8588912SDave May Vec *L, *R; 819d8588912SDave May MPI_Comm comm; 820d8588912SDave May PetscInt i, j; 821d8588912SDave May 822d8588912SDave May PetscFunctionBegin; 8239566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)A, &comm)); 824d8588912SDave May if (right) { 825d8588912SDave May /* allocate R */ 8269566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bA->nc, &R)); 827d8588912SDave May /* Create the right vectors */ 828d8588912SDave May for (j = 0; j < bA->nc; j++) { 829d8588912SDave May for (i = 0; i < bA->nr; i++) { 830d8588912SDave May if (bA->m[i][j]) { 8319566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL)); 832d8588912SDave May break; 833d8588912SDave May } 834d8588912SDave May } 83508401ef6SPierre Jolivet PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column."); 836d8588912SDave May } 8379566063dSJacob Faibussowitsch PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right)); 838d8588912SDave May /* hand back control to the nest vector */ 839*48a46eb9SPierre Jolivet for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j])); 8409566063dSJacob Faibussowitsch PetscCall(PetscFree(R)); 841d8588912SDave May } 842d8588912SDave May 843d8588912SDave May if (left) { 844d8588912SDave May /* allocate L */ 8459566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bA->nr, &L)); 846d8588912SDave May /* Create the left vectors */ 847d8588912SDave May for (i = 0; i < bA->nr; i++) { 848d8588912SDave May for (j = 0; j < bA->nc; j++) { 849d8588912SDave May if (bA->m[i][j]) { 8509566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i])); 851d8588912SDave May break; 852d8588912SDave May } 853d8588912SDave May } 85408401ef6SPierre Jolivet PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row."); 855d8588912SDave May } 856d8588912SDave May 8579566063dSJacob Faibussowitsch PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left)); 858*48a46eb9SPierre Jolivet for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i])); 859d8588912SDave May 8609566063dSJacob Faibussowitsch PetscCall(PetscFree(L)); 861d8588912SDave May } 862d8588912SDave May PetscFunctionReturn(0); 863d8588912SDave May } 864d8588912SDave May 8659371c9d4SSatish Balay static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer) { 866d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 86729e60adbSStefano Zampini PetscBool isascii, viewSub = PETSC_FALSE; 868d8588912SDave May PetscInt i, j; 869d8588912SDave May 870d8588912SDave May PetscFunctionBegin; 8719566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 872d8588912SDave May if (isascii) { 8739566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL)); 8749566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object: \n")); 8759566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 8769566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT " \n", bA->nr, bA->nc)); 877d8588912SDave May 8789566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure: \n")); 879d8588912SDave May for (i = 0; i < bA->nr; i++) { 880d8588912SDave May for (j = 0; j < bA->nc; j++) { 88119fd82e9SBarry Smith MatType type; 882270f95d7SJed Brown char name[256] = "", prefix[256] = ""; 883d8588912SDave May PetscInt NR, NC; 884d8588912SDave May PetscBool isNest = PETSC_FALSE; 885d8588912SDave May 886d8588912SDave May if (!bA->m[i][j]) { 8879566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL \n", i, j)); 888d8588912SDave May continue; 889d8588912SDave May } 8909566063dSJacob Faibussowitsch PetscCall(MatGetSize(bA->m[i][j], &NR, &NC)); 8919566063dSJacob Faibussowitsch PetscCall(MatGetType(bA->m[i][j], &type)); 8929566063dSJacob Faibussowitsch if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name)); 8939566063dSJacob Faibussowitsch if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix)); 8949566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest)); 895d8588912SDave May 8969566063dSJacob 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)); 897d8588912SDave May 89829e60adbSStefano Zampini if (isNest || viewSub) { 8999566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */ 9009566063dSJacob Faibussowitsch PetscCall(MatView(bA->m[i][j], viewer)); 9019566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */ 902d8588912SDave May } 903d8588912SDave May } 904d8588912SDave May } 9059566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */ 906d8588912SDave May } 907d8588912SDave May PetscFunctionReturn(0); 908d8588912SDave May } 909d8588912SDave May 9109371c9d4SSatish Balay static PetscErrorCode MatZeroEntries_Nest(Mat A) { 911d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 912d8588912SDave May PetscInt i, j; 913d8588912SDave May 914d8588912SDave May PetscFunctionBegin; 915d8588912SDave May for (i = 0; i < bA->nr; i++) { 916d8588912SDave May for (j = 0; j < bA->nc; j++) { 917d8588912SDave May if (!bA->m[i][j]) continue; 9189566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(bA->m[i][j])); 919d8588912SDave May } 920d8588912SDave May } 921d8588912SDave May PetscFunctionReturn(0); 922d8588912SDave May } 923d8588912SDave May 9249371c9d4SSatish Balay static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str) { 925c222c20dSDavid Ham Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data; 926c222c20dSDavid Ham PetscInt i, j, nr = bA->nr, nc = bA->nc; 92706a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 928c222c20dSDavid Ham 929c222c20dSDavid Ham PetscFunctionBegin; 930aed4548fSBarry 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); 931c222c20dSDavid Ham for (i = 0; i < nr; i++) { 932c222c20dSDavid Ham for (j = 0; j < nc; j++) { 93306a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 93446a2b97cSJed Brown if (bA->m[i][j] && bB->m[i][j]) { 9359566063dSJacob Faibussowitsch PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str)); 93608401ef6SPierre 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); 9379566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate)); 93806a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate); 93906a1af2fSStefano Zampini bB->nnzstate[i * nc + j] = subnnzstate; 940c222c20dSDavid Ham } 941c222c20dSDavid Ham } 94206a1af2fSStefano Zampini if (nnzstate) B->nonzerostate++; 943c222c20dSDavid Ham PetscFunctionReturn(0); 944c222c20dSDavid Ham } 945c222c20dSDavid Ham 9469371c9d4SSatish Balay static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str) { 9476e76ffeaSPierre Jolivet Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data; 9486e76ffeaSPierre Jolivet PetscInt i, j, nr = bY->nr, nc = bY->nc; 94906a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 9506e76ffeaSPierre Jolivet 9516e76ffeaSPierre Jolivet PetscFunctionBegin; 952aed4548fSBarry 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); 9536e76ffeaSPierre Jolivet for (i = 0; i < nr; i++) { 9546e76ffeaSPierre Jolivet for (j = 0; j < nc; j++) { 95506a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 9566e76ffeaSPierre Jolivet if (bY->m[i][j] && bX->m[i][j]) { 9579566063dSJacob Faibussowitsch PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str)); 958c066aebcSStefano Zampini } else if (bX->m[i][j]) { 959c066aebcSStefano Zampini Mat M; 960c066aebcSStefano Zampini 96108401ef6SPierre 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); 9629566063dSJacob Faibussowitsch PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M)); 9639566063dSJacob Faibussowitsch PetscCall(MatNestSetSubMat(Y, i, j, M)); 9649566063dSJacob Faibussowitsch PetscCall(MatDestroy(&M)); 965c066aebcSStefano Zampini } 9669566063dSJacob Faibussowitsch if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate)); 96706a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate); 96806a1af2fSStefano Zampini bY->nnzstate[i * nc + j] = subnnzstate; 9696e76ffeaSPierre Jolivet } 9706e76ffeaSPierre Jolivet } 97106a1af2fSStefano Zampini if (nnzstate) Y->nonzerostate++; 9726e76ffeaSPierre Jolivet PetscFunctionReturn(0); 9736e76ffeaSPierre Jolivet } 9746e76ffeaSPierre Jolivet 9759371c9d4SSatish Balay static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B) { 976d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 977841e96a3SJed Brown Mat *b; 978841e96a3SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 979d8588912SDave May 980d8588912SDave May PetscFunctionBegin; 9819566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr * nc, &b)); 982841e96a3SJed Brown for (i = 0; i < nr; i++) { 983841e96a3SJed Brown for (j = 0; j < nc; j++) { 984841e96a3SJed Brown if (bA->m[i][j]) { 9859566063dSJacob Faibussowitsch PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j])); 986841e96a3SJed Brown } else { 9870298fd71SBarry Smith b[i * nc + j] = NULL; 988d8588912SDave May } 989d8588912SDave May } 990d8588912SDave May } 9919566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B)); 992841e96a3SJed Brown /* Give the new MatNest exclusive ownership */ 993*48a46eb9SPierre Jolivet for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i])); 9949566063dSJacob Faibussowitsch PetscCall(PetscFree(b)); 995d8588912SDave May 9969566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 9979566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 998d8588912SDave May PetscFunctionReturn(0); 999d8588912SDave May } 1000d8588912SDave May 1001d8588912SDave May /* nest api */ 10029371c9d4SSatish Balay PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat) { 1003d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 10045fd66863SKarl Rupp 1005d8588912SDave May PetscFunctionBegin; 100608401ef6SPierre 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); 100708401ef6SPierre 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); 1008d8588912SDave May *mat = bA->m[idxm][jdxm]; 1009d8588912SDave May PetscFunctionReturn(0); 1010d8588912SDave May } 1011d8588912SDave May 10129ba0d327SJed Brown /*@ 1013d8588912SDave May MatNestGetSubMat - Returns a single, sub-matrix from a nest matrix. 1014d8588912SDave May 1015d8588912SDave May Not collective 1016d8588912SDave May 1017d8588912SDave May Input Parameters: 1018629881c0SJed Brown + A - nest matrix 1019d8588912SDave May . idxm - index of the matrix within the nest matrix 1020629881c0SJed Brown - jdxm - index of the matrix within the nest matrix 1021d8588912SDave May 1022d8588912SDave May Output Parameter: 1023d8588912SDave May . sub - matrix at index idxm,jdxm within the nest matrix 1024d8588912SDave May 1025d8588912SDave May Level: developer 1026d8588912SDave May 1027db781477SPatrick Sanan .seealso: `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MATNEST`, `MatNestSetSubMat()`, 1028db781477SPatrick Sanan `MatNestGetLocalISs()`, `MatNestGetISs()` 1029d8588912SDave May @*/ 10309371c9d4SSatish Balay PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub) { 1031d8588912SDave May PetscFunctionBegin; 1032cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub)); 1033d8588912SDave May PetscFunctionReturn(0); 1034d8588912SDave May } 1035d8588912SDave May 10369371c9d4SSatish Balay PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat) { 10370782ca92SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 10380782ca92SJed Brown PetscInt m, n, M, N, mi, ni, Mi, Ni; 10390782ca92SJed Brown 10400782ca92SJed Brown PetscFunctionBegin; 104108401ef6SPierre 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); 104208401ef6SPierre 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); 10439566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 10449566063dSJacob Faibussowitsch PetscCall(MatGetSize(mat, &M, &N)); 10459566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi)); 10469566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi)); 10479566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni)); 10489566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni)); 1049aed4548fSBarry 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); 1050aed4548fSBarry 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); 105126fbe8dcSKarl Rupp 105206a1af2fSStefano Zampini /* do not increase object state */ 105306a1af2fSStefano Zampini if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(0); 105406a1af2fSStefano Zampini 10559566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat)); 10569566063dSJacob Faibussowitsch PetscCall(MatDestroy(&bA->m[idxm][jdxm])); 10570782ca92SJed Brown bA->m[idxm][jdxm] = mat; 10589566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)A)); 10599566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm])); 106006a1af2fSStefano Zampini A->nonzerostate++; 10610782ca92SJed Brown PetscFunctionReturn(0); 10620782ca92SJed Brown } 10630782ca92SJed Brown 10649ba0d327SJed Brown /*@ 10650782ca92SJed Brown MatNestSetSubMat - Set a single submatrix in the nest matrix. 10660782ca92SJed Brown 10670782ca92SJed Brown Logically collective on the submatrix communicator 10680782ca92SJed Brown 10690782ca92SJed Brown Input Parameters: 10700782ca92SJed Brown + A - nest matrix 10710782ca92SJed Brown . idxm - index of the matrix within the nest matrix 10720782ca92SJed Brown . jdxm - index of the matrix within the nest matrix 10730782ca92SJed Brown - sub - matrix at index idxm,jdxm within the nest matrix 10740782ca92SJed Brown 10750782ca92SJed Brown Notes: 10760782ca92SJed Brown The new submatrix must have the same size and communicator as that block of the nest. 10770782ca92SJed Brown 10780782ca92SJed Brown This increments the reference count of the submatrix. 10790782ca92SJed Brown 10800782ca92SJed Brown Level: developer 10810782ca92SJed Brown 1082db781477SPatrick Sanan .seealso: `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MATNEST`, `MatCreateNest()`, 1083db781477SPatrick Sanan `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()` 10840782ca92SJed Brown @*/ 10859371c9d4SSatish Balay PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub) { 10860782ca92SJed Brown PetscFunctionBegin; 1087cac4c232SBarry Smith PetscUseMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub)); 10880782ca92SJed Brown PetscFunctionReturn(0); 10890782ca92SJed Brown } 10900782ca92SJed Brown 10919371c9d4SSatish Balay PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) { 1092d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 10935fd66863SKarl Rupp 1094d8588912SDave May PetscFunctionBegin; 109526fbe8dcSKarl Rupp if (M) *M = bA->nr; 109626fbe8dcSKarl Rupp if (N) *N = bA->nc; 109726fbe8dcSKarl Rupp if (mat) *mat = bA->m; 1098d8588912SDave May PetscFunctionReturn(0); 1099d8588912SDave May } 1100d8588912SDave May 1101d8588912SDave May /*@C 1102d8588912SDave May MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a nest matrix. 1103d8588912SDave May 1104d8588912SDave May Not collective 1105d8588912SDave May 1106f899ff85SJose E. Roman Input Parameter: 1107629881c0SJed Brown . A - nest matrix 1108d8588912SDave May 1109d8d19677SJose E. Roman Output Parameters: 1110629881c0SJed Brown + M - number of rows in the nest matrix 1111d8588912SDave May . N - number of cols in the nest matrix 1112629881c0SJed Brown - mat - 2d array of matrices 1113d8588912SDave May 1114d8588912SDave May Notes: 1115d8588912SDave May 1116d8588912SDave May The user should not free the array mat. 1117d8588912SDave May 1118351962e3SVincent Le Chenadec In Fortran, this routine has a calling sequence 1119351962e3SVincent Le Chenadec $ call MatNestGetSubMats(A, M, N, mat, ierr) 1120351962e3SVincent Le Chenadec where the space allocated for the optional argument mat is assumed large enough (if provided). 1121351962e3SVincent Le Chenadec 1122d8588912SDave May Level: developer 1123d8588912SDave May 1124db781477SPatrick Sanan .seealso: `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MATNEST`, `MatCreateNest()`, 1125db781477SPatrick Sanan `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()` 1126d8588912SDave May @*/ 11279371c9d4SSatish Balay PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) { 1128d8588912SDave May PetscFunctionBegin; 1129cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat)); 1130d8588912SDave May PetscFunctionReturn(0); 1131d8588912SDave May } 1132d8588912SDave May 11339371c9d4SSatish Balay PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N) { 1134d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 1135d8588912SDave May 1136d8588912SDave May PetscFunctionBegin; 113726fbe8dcSKarl Rupp if (M) *M = bA->nr; 113826fbe8dcSKarl Rupp if (N) *N = bA->nc; 1139d8588912SDave May PetscFunctionReturn(0); 1140d8588912SDave May } 1141d8588912SDave May 11429ba0d327SJed Brown /*@ 1143d8588912SDave May MatNestGetSize - Returns the size of the nest matrix. 1144d8588912SDave May 1145d8588912SDave May Not collective 1146d8588912SDave May 1147f899ff85SJose E. Roman Input Parameter: 1148d8588912SDave May . A - nest matrix 1149d8588912SDave May 1150d8d19677SJose E. Roman Output Parameters: 1151629881c0SJed Brown + M - number of rows in the nested mat 1152629881c0SJed Brown - N - number of cols in the nested mat 1153d8588912SDave May 1154d8588912SDave May Notes: 1155d8588912SDave May 1156d8588912SDave May Level: developer 1157d8588912SDave May 1158db781477SPatrick Sanan .seealso: `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MATNEST`, `MatCreateNest()`, `MatNestGetLocalISs()`, 1159db781477SPatrick Sanan `MatNestGetISs()` 1160d8588912SDave May @*/ 11619371c9d4SSatish Balay PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N) { 1162d8588912SDave May PetscFunctionBegin; 1163cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N)); 1164d8588912SDave May PetscFunctionReturn(0); 1165d8588912SDave May } 1166d8588912SDave May 11679371c9d4SSatish Balay static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[]) { 1168900e7ff2SJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 1169900e7ff2SJed Brown PetscInt i; 1170900e7ff2SJed Brown 1171900e7ff2SJed Brown PetscFunctionBegin; 11729371c9d4SSatish Balay if (rows) 11739371c9d4SSatish Balay for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i]; 11749371c9d4SSatish Balay if (cols) 11759371c9d4SSatish Balay for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i]; 1176900e7ff2SJed Brown PetscFunctionReturn(0); 1177900e7ff2SJed Brown } 1178900e7ff2SJed Brown 11793a4d7b9aSSatish Balay /*@C 1180900e7ff2SJed Brown MatNestGetISs - Returns the index sets partitioning the row and column spaces 1181900e7ff2SJed Brown 1182900e7ff2SJed Brown Not collective 1183900e7ff2SJed Brown 1184f899ff85SJose E. Roman Input Parameter: 1185900e7ff2SJed Brown . A - nest matrix 1186900e7ff2SJed Brown 1187d8d19677SJose E. Roman Output Parameters: 1188900e7ff2SJed Brown + rows - array of row index sets 1189900e7ff2SJed Brown - cols - array of column index sets 1190900e7ff2SJed Brown 1191900e7ff2SJed Brown Level: advanced 1192900e7ff2SJed Brown 1193900e7ff2SJed Brown Notes: 1194900e7ff2SJed Brown The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs. 1195900e7ff2SJed Brown 1196db781477SPatrick Sanan .seealso: `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`, `MATNEST`, 1197db781477SPatrick Sanan `MatCreateNest()`, `MatNestGetSubMats()`, `MatNestSetSubMats()` 1198900e7ff2SJed Brown @*/ 11999371c9d4SSatish Balay PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[]) { 1200900e7ff2SJed Brown PetscFunctionBegin; 1201900e7ff2SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1202cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 1203900e7ff2SJed Brown PetscFunctionReturn(0); 1204900e7ff2SJed Brown } 1205900e7ff2SJed Brown 12069371c9d4SSatish Balay static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[]) { 1207900e7ff2SJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 1208900e7ff2SJed Brown PetscInt i; 1209900e7ff2SJed Brown 1210900e7ff2SJed Brown PetscFunctionBegin; 12119371c9d4SSatish Balay if (rows) 12129371c9d4SSatish Balay for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i]; 12139371c9d4SSatish Balay if (cols) 12149371c9d4SSatish Balay for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i]; 1215900e7ff2SJed Brown PetscFunctionReturn(0); 1216900e7ff2SJed Brown } 1217900e7ff2SJed Brown 1218900e7ff2SJed Brown /*@C 1219900e7ff2SJed Brown MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces 1220900e7ff2SJed Brown 1221900e7ff2SJed Brown Not collective 1222900e7ff2SJed Brown 1223f899ff85SJose E. Roman Input Parameter: 1224900e7ff2SJed Brown . A - nest matrix 1225900e7ff2SJed Brown 1226d8d19677SJose E. Roman Output Parameters: 12270298fd71SBarry Smith + rows - array of row index sets (or NULL to ignore) 12280298fd71SBarry Smith - cols - array of column index sets (or NULL to ignore) 1229900e7ff2SJed Brown 1230900e7ff2SJed Brown Level: advanced 1231900e7ff2SJed Brown 1232900e7ff2SJed Brown Notes: 1233900e7ff2SJed Brown The user must have allocated arrays of the correct size. The reference count is not increased on the returned ISs. 1234900e7ff2SJed Brown 1235db781477SPatrick Sanan .seealso: `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`, 1236db781477SPatrick Sanan `MATNEST`, `MatNestSetSubMats()`, `MatNestSetSubMat()` 1237900e7ff2SJed Brown @*/ 12389371c9d4SSatish Balay PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[]) { 1239900e7ff2SJed Brown PetscFunctionBegin; 1240900e7ff2SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1241cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 1242900e7ff2SJed Brown PetscFunctionReturn(0); 1243900e7ff2SJed Brown } 1244900e7ff2SJed Brown 12459371c9d4SSatish Balay PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype) { 1246207556f9SJed Brown PetscBool flg; 1247207556f9SJed Brown 1248207556f9SJed Brown PetscFunctionBegin; 12499566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, VECNEST, &flg)); 1250207556f9SJed Brown /* In reality, this only distinguishes VECNEST and "other" */ 12512a7a6963SBarry Smith if (flg) A->ops->getvecs = MatCreateVecs_Nest; 125212b53f24SSatish Balay else A->ops->getvecs = (PetscErrorCode(*)(Mat, Vec *, Vec *))0; 1253207556f9SJed Brown PetscFunctionReturn(0); 1254207556f9SJed Brown } 1255207556f9SJed Brown 1256207556f9SJed Brown /*@C 12572a7a6963SBarry Smith MatNestSetVecType - Sets the type of Vec returned by MatCreateVecs() 1258207556f9SJed Brown 1259207556f9SJed Brown Not collective 1260207556f9SJed Brown 1261207556f9SJed Brown Input Parameters: 1262207556f9SJed Brown + A - nest matrix 1263207556f9SJed Brown - vtype - type to use for creating vectors 1264207556f9SJed Brown 1265207556f9SJed Brown Notes: 1266207556f9SJed Brown 1267207556f9SJed Brown Level: developer 1268207556f9SJed Brown 1269db781477SPatrick Sanan .seealso: `MatCreateVecs()`, `MATNEST`, `MatCreateNest()` 1270207556f9SJed Brown @*/ 12719371c9d4SSatish Balay PetscErrorCode MatNestSetVecType(Mat A, VecType vtype) { 1272207556f9SJed Brown PetscFunctionBegin; 1273cac4c232SBarry Smith PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype)); 1274207556f9SJed Brown PetscFunctionReturn(0); 1275207556f9SJed Brown } 1276207556f9SJed Brown 12779371c9d4SSatish Balay PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) { 1278c8883902SJed Brown Mat_Nest *s = (Mat_Nest *)A->data; 1279c8883902SJed Brown PetscInt i, j, m, n, M, N; 128088ffe2e8SJose E. Roman PetscBool cong, isstd, sametype = PETSC_FALSE; 128188ffe2e8SJose E. Roman VecType vtype, type; 1282d8588912SDave May 1283d8588912SDave May PetscFunctionBegin; 12849566063dSJacob Faibussowitsch PetscCall(MatReset_Nest(A)); 128506a1af2fSStefano Zampini 1286c8883902SJed Brown s->nr = nr; 1287c8883902SJed Brown s->nc = nc; 1288d8588912SDave May 1289c8883902SJed Brown /* Create space for submatrices */ 12909566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &s->m)); 1291*48a46eb9SPierre Jolivet for (i = 0; i < nr; i++) PetscCall(PetscMalloc1(nc, &s->m[i])); 1292c8883902SJed Brown for (i = 0; i < nr; i++) { 1293c8883902SJed Brown for (j = 0; j < nc; j++) { 1294c8883902SJed Brown s->m[i][j] = a[i * nc + j]; 1295*48a46eb9SPierre Jolivet if (a[i * nc + j]) PetscCall(PetscObjectReference((PetscObject)a[i * nc + j])); 1296d8588912SDave May } 1297d8588912SDave May } 12989566063dSJacob Faibussowitsch PetscCall(MatGetVecType(A, &vtype)); 12999566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd)); 130088ffe2e8SJose E. Roman if (isstd) { 130188ffe2e8SJose E. Roman /* check if all blocks have the same vectype */ 130288ffe2e8SJose E. Roman vtype = NULL; 130388ffe2e8SJose E. Roman for (i = 0; i < nr; i++) { 130488ffe2e8SJose E. Roman for (j = 0; j < nc; j++) { 130588ffe2e8SJose E. Roman if (a[i * nc + j]) { 130688ffe2e8SJose E. Roman if (!vtype) { /* first visited block */ 13079566063dSJacob Faibussowitsch PetscCall(MatGetVecType(a[i * nc + j], &vtype)); 130888ffe2e8SJose E. Roman sametype = PETSC_TRUE; 130988ffe2e8SJose E. Roman } else if (sametype) { 13109566063dSJacob Faibussowitsch PetscCall(MatGetVecType(a[i * nc + j], &type)); 13119566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, type, &sametype)); 131288ffe2e8SJose E. Roman } 131388ffe2e8SJose E. Roman } 131488ffe2e8SJose E. Roman } 131588ffe2e8SJose E. Roman } 131688ffe2e8SJose E. Roman if (sametype) { /* propagate vectype */ 13179566063dSJacob Faibussowitsch PetscCall(MatSetVecType(A, vtype)); 131888ffe2e8SJose E. Roman } 131988ffe2e8SJose E. Roman } 1320d8588912SDave May 13219566063dSJacob Faibussowitsch PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col)); 1322d8588912SDave May 13239566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &s->row_len)); 13249566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &s->col_len)); 1325c8883902SJed Brown for (i = 0; i < nr; i++) s->row_len[i] = -1; 1326c8883902SJed Brown for (j = 0; j < nc; j++) s->col_len[j] = -1; 1327d8588912SDave May 13289566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr * nc, &s->nnzstate)); 132906a1af2fSStefano Zampini for (i = 0; i < nr; i++) { 133006a1af2fSStefano Zampini for (j = 0; j < nc; j++) { 1331*48a46eb9SPierre Jolivet if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j])); 133206a1af2fSStefano Zampini } 133306a1af2fSStefano Zampini } 133406a1af2fSStefano Zampini 13359566063dSJacob Faibussowitsch PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N)); 1336d8588912SDave May 13379566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(A->rmap, M)); 13389566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(A->rmap, m)); 13399566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(A->cmap, N)); 13409566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(A->cmap, n)); 1341c8883902SJed Brown 13429566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->rmap)); 13439566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->cmap)); 1344c8883902SJed Brown 134506a1af2fSStefano Zampini /* disable operations that are not supported for non-square matrices, 134606a1af2fSStefano Zampini or matrices for which is_row != is_col */ 13479566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(A, &cong)); 134806a1af2fSStefano Zampini if (cong && nr != nc) cong = PETSC_FALSE; 134906a1af2fSStefano Zampini if (cong) { 1350*48a46eb9SPierre Jolivet for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong)); 135106a1af2fSStefano Zampini } 135206a1af2fSStefano Zampini if (!cong) { 1353381b8e50SStefano Zampini A->ops->missingdiagonal = NULL; 135406a1af2fSStefano Zampini A->ops->getdiagonal = NULL; 135506a1af2fSStefano Zampini A->ops->shift = NULL; 135606a1af2fSStefano Zampini A->ops->diagonalset = NULL; 135706a1af2fSStefano Zampini } 135806a1af2fSStefano Zampini 13599566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right)); 13609566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)A)); 136106a1af2fSStefano Zampini A->nonzerostate++; 1362d8588912SDave May PetscFunctionReturn(0); 1363d8588912SDave May } 1364d8588912SDave May 1365c8883902SJed Brown /*@ 1366c8883902SJed Brown MatNestSetSubMats - Sets the nested submatrices 1367c8883902SJed Brown 1368c8883902SJed Brown Collective on Mat 1369c8883902SJed Brown 1370d8d19677SJose E. Roman Input Parameters: 1371ffd6319bSRichard Tran Mills + A - nested matrix 1372c8883902SJed Brown . nr - number of nested row blocks 13730298fd71SBarry Smith . is_row - index sets for each nested row block, or NULL to make contiguous 1374c8883902SJed Brown . nc - number of nested column blocks 13750298fd71SBarry Smith . is_col - index sets for each nested column block, or NULL to make contiguous 13760298fd71SBarry Smith - a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL 1377c8883902SJed Brown 137806a1af2fSStefano Zampini Notes: this always resets any submatrix information previously set 137906a1af2fSStefano Zampini 1380c8883902SJed Brown Level: advanced 1381c8883902SJed Brown 1382db781477SPatrick Sanan .seealso: `MatCreateNest()`, `MATNEST`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()` 1383c8883902SJed Brown @*/ 13849371c9d4SSatish Balay PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) { 138506a1af2fSStefano Zampini PetscInt i; 1386c8883902SJed Brown 1387c8883902SJed Brown PetscFunctionBegin; 1388c8883902SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 138908401ef6SPierre Jolivet PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative"); 1390c8883902SJed Brown if (nr && is_row) { 1391c8883902SJed Brown PetscValidPointer(is_row, 3); 1392c8883902SJed Brown for (i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3); 1393c8883902SJed Brown } 139408401ef6SPierre Jolivet PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative"); 13951664e352SJed Brown if (nc && is_col) { 1396c8883902SJed Brown PetscValidPointer(is_col, 5); 13979b30a8f6SBarry Smith for (i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5); 1398c8883902SJed Brown } 139906a1af2fSStefano Zampini if (nr * nc > 0) PetscValidPointer(a, 6); 1400cac4c232SBarry Smith PetscUseMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a)); 1401c8883902SJed Brown PetscFunctionReturn(0); 1402c8883902SJed Brown } 1403d8588912SDave May 14049371c9d4SSatish Balay static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog) { 140577019fcaSJed Brown PetscBool flg; 140677019fcaSJed Brown PetscInt i, j, m, mi, *ix; 140777019fcaSJed Brown 140877019fcaSJed Brown PetscFunctionBegin; 1409aea6d515SStefano Zampini *ltog = NULL; 141077019fcaSJed Brown for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) { 141177019fcaSJed Brown if (islocal[i]) { 14129566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(islocal[i], &mi)); 141377019fcaSJed Brown flg = PETSC_TRUE; /* We found a non-trivial entry */ 141477019fcaSJed Brown } else { 14159566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mi)); 141677019fcaSJed Brown } 141777019fcaSJed Brown m += mi; 141877019fcaSJed Brown } 1419aea6d515SStefano Zampini if (!flg) PetscFunctionReturn(0); 1420aea6d515SStefano Zampini 14219566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &ix)); 1422165cd838SBarry Smith for (i = 0, m = 0; i < n; i++) { 14230298fd71SBarry Smith ISLocalToGlobalMapping smap = NULL; 1424e108cb99SStefano Zampini Mat sub = NULL; 1425f6d38dbbSStefano Zampini PetscSF sf; 1426f6d38dbbSStefano Zampini PetscLayout map; 1427aea6d515SStefano Zampini const PetscInt *ix2; 142877019fcaSJed Brown 1429165cd838SBarry Smith if (!colflg) { 14309566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 143177019fcaSJed Brown } else { 14329566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 143377019fcaSJed Brown } 1434191fd14bSBarry Smith if (sub) { 1435191fd14bSBarry Smith if (!colflg) { 14369566063dSJacob Faibussowitsch PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL)); 1437191fd14bSBarry Smith } else { 14389566063dSJacob Faibussowitsch PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap)); 1439191fd14bSBarry Smith } 1440191fd14bSBarry Smith } 144177019fcaSJed Brown /* 144277019fcaSJed Brown Now we need to extract the monolithic global indices that correspond to the given split global indices. 144377019fcaSJed 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. 144477019fcaSJed Brown */ 14459566063dSJacob Faibussowitsch PetscCall(ISGetIndices(isglobal[i], &ix2)); 1446aea6d515SStefano Zampini if (islocal[i]) { 1447aea6d515SStefano Zampini PetscInt *ilocal, *iremote; 1448aea6d515SStefano Zampini PetscInt mil, nleaves; 1449aea6d515SStefano Zampini 14509566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(islocal[i], &mi)); 145128b400f6SJacob Faibussowitsch PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map"); 1452aea6d515SStefano Zampini for (j = 0; j < mi; j++) ix[m + j] = j; 14539566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m)); 1454aea6d515SStefano Zampini 1455aea6d515SStefano Zampini /* PetscSFSetGraphLayout does not like negative indices */ 14569566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote)); 1457aea6d515SStefano Zampini for (j = 0, nleaves = 0; j < mi; j++) { 1458aea6d515SStefano Zampini if (ix[m + j] < 0) continue; 1459aea6d515SStefano Zampini ilocal[nleaves] = j; 1460aea6d515SStefano Zampini iremote[nleaves] = ix[m + j]; 1461aea6d515SStefano Zampini nleaves++; 1462aea6d515SStefano Zampini } 14639566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mil)); 14649566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf)); 14659566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map)); 14669566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(map, mil)); 14679566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(map)); 14689566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote)); 14699566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&map)); 14709566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 14719566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 14729566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&sf)); 14739566063dSJacob Faibussowitsch PetscCall(PetscFree2(ilocal, iremote)); 1474aea6d515SStefano Zampini } else { 14759566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mi)); 1476aea6d515SStefano Zampini for (j = 0; j < mi; j++) ix[m + j] = ix2[i]; 1477aea6d515SStefano Zampini } 14789566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(isglobal[i], &ix2)); 147977019fcaSJed Brown m += mi; 148077019fcaSJed Brown } 14819566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog)); 148277019fcaSJed Brown PetscFunctionReturn(0); 148377019fcaSJed Brown } 148477019fcaSJed Brown 1485d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */ 1486d8588912SDave May /* 1487d8588912SDave May nprocessors = NP 1488d8588912SDave May Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1)) 1489d8588912SDave May proc 0: => (g_0,h_0,) 1490d8588912SDave May proc 1: => (g_1,h_1,) 1491d8588912SDave May ... 1492d8588912SDave May proc nprocs-1: => (g_NP-1,h_NP-1,) 1493d8588912SDave May 1494d8588912SDave May proc 0: proc 1: proc nprocs-1: 1495d8588912SDave May is[0] = (0,1,2,...,nlocal(g_0)-1) (0,1,...,nlocal(g_1)-1) (0,1,...,nlocal(g_NP-1)) 1496d8588912SDave May 1497d8588912SDave May proc 0: 1498d8588912SDave May is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1) 1499d8588912SDave May proc 1: 1500d8588912SDave May is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1) 1501d8588912SDave May 1502d8588912SDave May proc NP-1: 1503d8588912SDave May is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1) 1504d8588912SDave May */ 15059371c9d4SSatish Balay static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[]) { 1506e2d7f03fSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 15078188e55aSJed Brown PetscInt i, j, offset, n, nsum, bs; 15080298fd71SBarry Smith Mat sub = NULL; 1509d8588912SDave May 1510d8588912SDave May PetscFunctionBegin; 15119566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &vs->isglobal.row)); 15129566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &vs->isglobal.col)); 1513d8588912SDave May if (is_row) { /* valid IS is passed in */ 1514a5b23f4aSJose E. Roman /* refs on is[] are incremented */ 1515e2d7f03fSJed Brown for (i = 0; i < vs->nr; i++) { 15169566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is_row[i])); 151726fbe8dcSKarl Rupp 1518e2d7f03fSJed Brown vs->isglobal.row[i] = is_row[i]; 1519d8588912SDave May } 15202ae74bdbSJed Brown } else { /* Create the ISs by inspecting sizes of a submatrix in each row */ 15218188e55aSJed Brown nsum = 0; 15228188e55aSJed Brown for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */ 15239566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 152428b400f6SJacob Faibussowitsch PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i); 15259566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, &n, NULL)); 152608401ef6SPierre Jolivet PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 15278188e55aSJed Brown nsum += n; 15288188e55aSJed Brown } 15299566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 153030bc264bSJed Brown offset -= nsum; 1531e2d7f03fSJed Brown for (i = 0; i < vs->nr; i++) { 15329566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 15339566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, &n, NULL)); 15349566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 15359566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i])); 15369566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs)); 15372ae74bdbSJed Brown offset += n; 1538d8588912SDave May } 1539d8588912SDave May } 1540d8588912SDave May 1541d8588912SDave May if (is_col) { /* valid IS is passed in */ 1542a5b23f4aSJose E. Roman /* refs on is[] are incremented */ 1543e2d7f03fSJed Brown for (j = 0; j < vs->nc; j++) { 15449566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is_col[j])); 154526fbe8dcSKarl Rupp 1546e2d7f03fSJed Brown vs->isglobal.col[j] = is_col[j]; 1547d8588912SDave May } 15482ae74bdbSJed Brown } else { /* Create the ISs by inspecting sizes of a submatrix in each column */ 15492ae74bdbSJed Brown offset = A->cmap->rstart; 15508188e55aSJed Brown nsum = 0; 15518188e55aSJed Brown for (j = 0; j < vs->nc; j++) { 15529566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 155328b400f6SJacob Faibussowitsch PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i); 15549566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, NULL, &n)); 155508401ef6SPierre Jolivet PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 15568188e55aSJed Brown nsum += n; 15578188e55aSJed Brown } 15589566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 155930bc264bSJed Brown offset -= nsum; 1560e2d7f03fSJed Brown for (j = 0; j < vs->nc; j++) { 15619566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 15629566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, NULL, &n)); 15639566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 15649566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j])); 15659566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs)); 15662ae74bdbSJed Brown offset += n; 1567d8588912SDave May } 1568d8588912SDave May } 1569e2d7f03fSJed Brown 1570e2d7f03fSJed Brown /* Set up the local ISs */ 15719566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row)); 15729566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col)); 1573e2d7f03fSJed Brown for (i = 0, offset = 0; i < vs->nr; i++) { 1574e2d7f03fSJed Brown IS isloc; 15750298fd71SBarry Smith ISLocalToGlobalMapping rmap = NULL; 1576e2d7f03fSJed Brown PetscInt nlocal, bs; 15779566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 15789566063dSJacob Faibussowitsch if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL)); 1579207556f9SJed Brown if (rmap) { 15809566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 15819566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal)); 15829566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 15839566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(isloc, bs)); 1584207556f9SJed Brown } else { 1585207556f9SJed Brown nlocal = 0; 15860298fd71SBarry Smith isloc = NULL; 1587207556f9SJed Brown } 1588e2d7f03fSJed Brown vs->islocal.row[i] = isloc; 1589e2d7f03fSJed Brown offset += nlocal; 1590e2d7f03fSJed Brown } 15918188e55aSJed Brown for (i = 0, offset = 0; i < vs->nc; i++) { 1592e2d7f03fSJed Brown IS isloc; 15930298fd71SBarry Smith ISLocalToGlobalMapping cmap = NULL; 1594e2d7f03fSJed Brown PetscInt nlocal, bs; 15959566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 15969566063dSJacob Faibussowitsch if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap)); 1597207556f9SJed Brown if (cmap) { 15989566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 15999566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal)); 16009566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 16019566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(isloc, bs)); 1602207556f9SJed Brown } else { 1603207556f9SJed Brown nlocal = 0; 16040298fd71SBarry Smith isloc = NULL; 1605207556f9SJed Brown } 1606e2d7f03fSJed Brown vs->islocal.col[i] = isloc; 1607e2d7f03fSJed Brown offset += nlocal; 1608e2d7f03fSJed Brown } 16090189643fSJed Brown 161077019fcaSJed Brown /* Set up the aggregate ISLocalToGlobalMapping */ 161177019fcaSJed Brown { 161245b6f7e9SBarry Smith ISLocalToGlobalMapping rmap, cmap; 16139566063dSJacob Faibussowitsch PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap)); 16149566063dSJacob Faibussowitsch PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap)); 16159566063dSJacob Faibussowitsch if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap)); 16169566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingDestroy(&rmap)); 16179566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingDestroy(&cmap)); 161877019fcaSJed Brown } 161977019fcaSJed Brown 162076bd3646SJed Brown if (PetscDefined(USE_DEBUG)) { 16210189643fSJed Brown for (i = 0; i < vs->nr; i++) { 16220189643fSJed Brown for (j = 0; j < vs->nc; j++) { 16230189643fSJed Brown PetscInt m, n, M, N, mi, ni, Mi, Ni; 16240189643fSJed Brown Mat B = vs->m[i][j]; 16250189643fSJed Brown if (!B) continue; 16269566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, &M, &N)); 16279566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(B, &m, &n)); 16289566063dSJacob Faibussowitsch PetscCall(ISGetSize(vs->isglobal.row[i], &Mi)); 16299566063dSJacob Faibussowitsch PetscCall(ISGetSize(vs->isglobal.col[j], &Ni)); 16309566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi)); 16319566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni)); 1632aed4548fSBarry 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); 1633aed4548fSBarry 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); 16340189643fSJed Brown } 16350189643fSJed Brown } 163676bd3646SJed Brown } 1637a061e289SJed Brown 1638a061e289SJed Brown /* Set A->assembled if all non-null blocks are currently assembled */ 1639a061e289SJed Brown for (i = 0; i < vs->nr; i++) { 1640a061e289SJed Brown for (j = 0; j < vs->nc; j++) { 1641a061e289SJed Brown if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(0); 1642a061e289SJed Brown } 1643a061e289SJed Brown } 1644a061e289SJed Brown A->assembled = PETSC_TRUE; 1645d8588912SDave May PetscFunctionReturn(0); 1646d8588912SDave May } 1647d8588912SDave May 164845c38901SJed Brown /*@C 1649659c6bb0SJed Brown MatCreateNest - Creates a new matrix containing several nested submatrices, each stored separately 1650659c6bb0SJed Brown 1651659c6bb0SJed Brown Collective on Mat 1652659c6bb0SJed Brown 1653d8d19677SJose E. Roman Input Parameters: 1654659c6bb0SJed Brown + comm - Communicator for the new Mat 1655659c6bb0SJed Brown . nr - number of nested row blocks 16560298fd71SBarry Smith . is_row - index sets for each nested row block, or NULL to make contiguous 1657659c6bb0SJed Brown . nc - number of nested column blocks 16580298fd71SBarry Smith . is_col - index sets for each nested column block, or NULL to make contiguous 16590298fd71SBarry Smith - a - row-aligned array of nr*nc submatrices, empty submatrices can be passed using NULL 1660659c6bb0SJed Brown 1661659c6bb0SJed Brown Output Parameter: 1662659c6bb0SJed Brown . B - new matrix 1663659c6bb0SJed Brown 1664659c6bb0SJed Brown Level: advanced 1665659c6bb0SJed Brown 1666db781477SPatrick Sanan .seealso: `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MATNEST`, `MatNestSetSubMat()`, 1667db781477SPatrick Sanan `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`, 1668db781477SPatrick Sanan `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 1669659c6bb0SJed Brown @*/ 16709371c9d4SSatish Balay PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B) { 1671d8588912SDave May Mat A; 1672d8588912SDave May 1673d8588912SDave May PetscFunctionBegin; 1674f4259b30SLisandro Dalcin *B = NULL; 16759566063dSJacob Faibussowitsch PetscCall(MatCreate(comm, &A)); 16769566063dSJacob Faibussowitsch PetscCall(MatSetType(A, MATNEST)); 167791a28eb3SBarry Smith A->preallocated = PETSC_TRUE; 16789566063dSJacob Faibussowitsch PetscCall(MatNestSetSubMats(A, nr, is_row, nc, is_col, a)); 1679d8588912SDave May *B = A; 1680d8588912SDave May PetscFunctionReturn(0); 1681d8588912SDave May } 1682659c6bb0SJed Brown 16839371c9d4SSatish Balay PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) { 1684b68353e5Sstefano_zampini Mat_Nest *nest = (Mat_Nest *)A->data; 168523875855Sstefano_zampini Mat *trans; 1686b68353e5Sstefano_zampini PetscScalar **avv; 1687b68353e5Sstefano_zampini PetscScalar *vv; 1688b68353e5Sstefano_zampini PetscInt **aii, **ajj; 1689b68353e5Sstefano_zampini PetscInt *ii, *jj, *ci; 1690b68353e5Sstefano_zampini PetscInt nr, nc, nnz, i, j; 1691b68353e5Sstefano_zampini PetscBool done; 1692b68353e5Sstefano_zampini 1693b68353e5Sstefano_zampini PetscFunctionBegin; 16949566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &nr, &nc)); 1695b68353e5Sstefano_zampini if (reuse == MAT_REUSE_MATRIX) { 1696b68353e5Sstefano_zampini PetscInt rnr; 1697b68353e5Sstefano_zampini 16989566063dSJacob Faibussowitsch PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done)); 169928b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ"); 170008401ef6SPierre Jolivet PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows"); 17019566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArray(*newmat, &vv)); 1702b68353e5Sstefano_zampini } 1703b68353e5Sstefano_zampini /* extract CSR for nested SeqAIJ matrices */ 1704b68353e5Sstefano_zampini nnz = 0; 17059566063dSJacob Faibussowitsch PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans)); 1706b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1707b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1708b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1709b68353e5Sstefano_zampini if (B) { 1710b68353e5Sstefano_zampini PetscScalar *naa; 1711b68353e5Sstefano_zampini PetscInt *nii, *njj, nnr; 171223875855Sstefano_zampini PetscBool istrans; 1713b68353e5Sstefano_zampini 17149566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEMAT, &istrans)); 171523875855Sstefano_zampini if (istrans) { 171623875855Sstefano_zampini Mat Bt; 171723875855Sstefano_zampini 17189566063dSJacob Faibussowitsch PetscCall(MatTransposeGetMat(B, &Bt)); 17199566063dSJacob Faibussowitsch PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 172023875855Sstefano_zampini B = trans[i * nest->nc + j]; 172123875855Sstefano_zampini } 17229566063dSJacob Faibussowitsch PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done)); 172328b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ"); 17249566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArray(B, &naa)); 1725b68353e5Sstefano_zampini nnz += nii[nnr]; 1726b68353e5Sstefano_zampini 1727b68353e5Sstefano_zampini aii[i * nest->nc + j] = nii; 1728b68353e5Sstefano_zampini ajj[i * nest->nc + j] = njj; 1729b68353e5Sstefano_zampini avv[i * nest->nc + j] = naa; 1730b68353e5Sstefano_zampini } 1731b68353e5Sstefano_zampini } 1732b68353e5Sstefano_zampini } 1733b68353e5Sstefano_zampini if (reuse != MAT_REUSE_MATRIX) { 17349566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr + 1, &ii)); 17359566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &jj)); 17369566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &vv)); 1737b68353e5Sstefano_zampini } else { 173808401ef6SPierre Jolivet PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros"); 1739b68353e5Sstefano_zampini } 1740b68353e5Sstefano_zampini 1741b68353e5Sstefano_zampini /* new row pointer */ 17429566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(ii, nr + 1)); 1743b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1744b68353e5Sstefano_zampini PetscInt ncr, rst; 1745b68353e5Sstefano_zampini 17469566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 17479566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1748b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1749b68353e5Sstefano_zampini if (aii[i * nest->nc + j]) { 1750b68353e5Sstefano_zampini PetscInt *nii = aii[i * nest->nc + j]; 1751b68353e5Sstefano_zampini PetscInt ir; 1752b68353e5Sstefano_zampini 1753b68353e5Sstefano_zampini for (ir = rst; ir < ncr + rst; ++ir) { 1754b68353e5Sstefano_zampini ii[ir + 1] += nii[1] - nii[0]; 1755b68353e5Sstefano_zampini nii++; 1756b68353e5Sstefano_zampini } 1757b68353e5Sstefano_zampini } 1758b68353e5Sstefano_zampini } 1759b68353e5Sstefano_zampini } 1760b68353e5Sstefano_zampini for (i = 0; i < nr; i++) ii[i + 1] += ii[i]; 1761b68353e5Sstefano_zampini 1762b68353e5Sstefano_zampini /* construct CSR for the new matrix */ 17639566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr, &ci)); 1764b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1765b68353e5Sstefano_zampini PetscInt ncr, rst; 1766b68353e5Sstefano_zampini 17679566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 17689566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1769b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1770b68353e5Sstefano_zampini if (aii[i * nest->nc + j]) { 1771b68353e5Sstefano_zampini PetscScalar *nvv = avv[i * nest->nc + j]; 1772b68353e5Sstefano_zampini PetscInt *nii = aii[i * nest->nc + j]; 1773b68353e5Sstefano_zampini PetscInt *njj = ajj[i * nest->nc + j]; 1774b68353e5Sstefano_zampini PetscInt ir, cst; 1775b68353e5Sstefano_zampini 17769566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL)); 1777b68353e5Sstefano_zampini for (ir = rst; ir < ncr + rst; ++ir) { 1778b68353e5Sstefano_zampini PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir]; 1779b68353e5Sstefano_zampini 1780b68353e5Sstefano_zampini for (ij = 0; ij < rsize; ij++) { 1781b68353e5Sstefano_zampini jj[ist + ij] = *njj + cst; 1782b68353e5Sstefano_zampini vv[ist + ij] = *nvv; 1783b68353e5Sstefano_zampini njj++; 1784b68353e5Sstefano_zampini nvv++; 1785b68353e5Sstefano_zampini } 1786b68353e5Sstefano_zampini ci[ir] += rsize; 1787b68353e5Sstefano_zampini nii++; 1788b68353e5Sstefano_zampini } 1789b68353e5Sstefano_zampini } 1790b68353e5Sstefano_zampini } 1791b68353e5Sstefano_zampini } 17929566063dSJacob Faibussowitsch PetscCall(PetscFree(ci)); 1793b68353e5Sstefano_zampini 1794b68353e5Sstefano_zampini /* restore info */ 1795b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1796b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1797b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1798b68353e5Sstefano_zampini if (B) { 1799b68353e5Sstefano_zampini PetscInt nnr = 0, k = i * nest->nc + j; 180023875855Sstefano_zampini 180123875855Sstefano_zampini B = (trans[k] ? trans[k] : B); 18029566063dSJacob Faibussowitsch PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done)); 180328b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ"); 18049566063dSJacob Faibussowitsch PetscCall(MatSeqAIJRestoreArray(B, &avv[k])); 18059566063dSJacob Faibussowitsch PetscCall(MatDestroy(&trans[k])); 1806b68353e5Sstefano_zampini } 1807b68353e5Sstefano_zampini } 1808b68353e5Sstefano_zampini } 18099566063dSJacob Faibussowitsch PetscCall(PetscFree4(aii, ajj, avv, trans)); 1810b68353e5Sstefano_zampini 1811b68353e5Sstefano_zampini /* finalize newmat */ 1812b68353e5Sstefano_zampini if (reuse == MAT_INITIAL_MATRIX) { 18139566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat)); 1814b68353e5Sstefano_zampini } else if (reuse == MAT_INPLACE_MATRIX) { 1815b68353e5Sstefano_zampini Mat B; 1816b68353e5Sstefano_zampini 18179566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B)); 18189566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &B)); 1819b68353e5Sstefano_zampini } 18209566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY)); 18219566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY)); 1822b68353e5Sstefano_zampini { 1823b68353e5Sstefano_zampini Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data); 1824b68353e5Sstefano_zampini a->free_a = PETSC_TRUE; 1825b68353e5Sstefano_zampini a->free_ij = PETSC_TRUE; 1826b68353e5Sstefano_zampini } 1827b68353e5Sstefano_zampini PetscFunctionReturn(0); 1828b68353e5Sstefano_zampini } 1829b68353e5Sstefano_zampini 18309371c9d4SSatish Balay PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X) { 1831be705e3aSPierre Jolivet Mat_Nest *nest = (Mat_Nest *)X->data; 1832be705e3aSPierre Jolivet PetscInt i, j, k, rstart; 1833be705e3aSPierre Jolivet PetscBool flg; 1834be705e3aSPierre Jolivet 1835be705e3aSPierre Jolivet PetscFunctionBegin; 1836be705e3aSPierre Jolivet /* Fill by row */ 1837be705e3aSPierre Jolivet for (j = 0; j < nest->nc; ++j) { 1838be705e3aSPierre Jolivet /* Using global column indices and ISAllGather() is not scalable. */ 1839be705e3aSPierre Jolivet IS bNis; 1840be705e3aSPierre Jolivet PetscInt bN; 1841be705e3aSPierre Jolivet const PetscInt *bNindices; 18429566063dSJacob Faibussowitsch PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 18439566063dSJacob Faibussowitsch PetscCall(ISGetSize(bNis, &bN)); 18449566063dSJacob Faibussowitsch PetscCall(ISGetIndices(bNis, &bNindices)); 1845be705e3aSPierre Jolivet for (i = 0; i < nest->nr; ++i) { 1846fd8a7442SPierre Jolivet Mat B = nest->m[i][j], D = NULL; 1847be705e3aSPierre Jolivet PetscInt bm, br; 1848be705e3aSPierre Jolivet const PetscInt *bmindices; 1849be705e3aSPierre Jolivet if (!B) continue; 18509566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEMAT, &flg)); 1851be705e3aSPierre Jolivet if (flg) { 1852cac4c232SBarry Smith PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 1853cac4c232SBarry Smith PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 18549566063dSJacob Faibussowitsch PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 1855be705e3aSPierre Jolivet B = D; 1856be705e3aSPierre Jolivet } 18579566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 1858be705e3aSPierre Jolivet if (flg) { 1859fd8a7442SPierre Jolivet if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 1860fd8a7442SPierre Jolivet else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 1861be705e3aSPierre Jolivet B = D; 1862be705e3aSPierre Jolivet } 18639566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 18649566063dSJacob Faibussowitsch PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 18659566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 1866be705e3aSPierre Jolivet for (br = 0; br < bm; ++br) { 1867be705e3aSPierre Jolivet PetscInt row = bmindices[br], brncols, *cols; 1868be705e3aSPierre Jolivet const PetscInt *brcols; 1869be705e3aSPierre Jolivet const PetscScalar *brcoldata; 1870be705e3aSPierre Jolivet PetscScalar *vals = NULL; 18719566063dSJacob Faibussowitsch PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 18729566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(brncols, &cols)); 1873be705e3aSPierre Jolivet for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]]; 1874be705e3aSPierre Jolivet /* 1875be705e3aSPierre Jolivet Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match. 1876be705e3aSPierre Jolivet Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES. 1877be705e3aSPierre Jolivet */ 1878be705e3aSPierre Jolivet if (a != 1.0) { 18799566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(brncols, &vals)); 1880be705e3aSPierre Jolivet for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k]; 18819566063dSJacob Faibussowitsch PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES)); 18829566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 1883be705e3aSPierre Jolivet } else { 18849566063dSJacob Faibussowitsch PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES)); 1885be705e3aSPierre Jolivet } 18869566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 18879566063dSJacob Faibussowitsch PetscCall(PetscFree(cols)); 1888be705e3aSPierre Jolivet } 1889fd8a7442SPierre Jolivet if (D) PetscCall(MatDestroy(&D)); 18909566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 1891be705e3aSPierre Jolivet } 18929566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(bNis, &bNindices)); 18939566063dSJacob Faibussowitsch PetscCall(ISDestroy(&bNis)); 1894be705e3aSPierre Jolivet } 18959566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY)); 18969566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY)); 1897be705e3aSPierre Jolivet PetscFunctionReturn(0); 1898be705e3aSPierre Jolivet } 1899be705e3aSPierre Jolivet 19009371c9d4SSatish Balay PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) { 1901629c3df2SDmitry Karpeev Mat_Nest *nest = (Mat_Nest *)A->data; 1902be705e3aSPierre Jolivet PetscInt m, n, M, N, i, j, k, *dnnz, *onnz, rstart, cstart, cend; 1903b68353e5Sstefano_zampini PetscMPIInt size; 1904629c3df2SDmitry Karpeev Mat C; 1905629c3df2SDmitry Karpeev 1906629c3df2SDmitry Karpeev PetscFunctionBegin; 19079566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 1908b68353e5Sstefano_zampini if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */ 1909b68353e5Sstefano_zampini PetscInt nf; 1910b68353e5Sstefano_zampini PetscBool fast; 1911b68353e5Sstefano_zampini 19129566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(newtype, MATAIJ, &fast)); 1913*48a46eb9SPierre Jolivet if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast)); 1914b68353e5Sstefano_zampini for (i = 0; i < nest->nr && fast; ++i) { 1915b68353e5Sstefano_zampini for (j = 0; j < nest->nc && fast; ++j) { 1916b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1917b68353e5Sstefano_zampini if (B) { 19189566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast)); 191923875855Sstefano_zampini if (!fast) { 192023875855Sstefano_zampini PetscBool istrans; 192123875855Sstefano_zampini 19229566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEMAT, &istrans)); 192323875855Sstefano_zampini if (istrans) { 192423875855Sstefano_zampini Mat Bt; 192523875855Sstefano_zampini 19269566063dSJacob Faibussowitsch PetscCall(MatTransposeGetMat(B, &Bt)); 19279566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 192823875855Sstefano_zampini } 1929b68353e5Sstefano_zampini } 1930b68353e5Sstefano_zampini } 1931b68353e5Sstefano_zampini } 1932b68353e5Sstefano_zampini } 1933b68353e5Sstefano_zampini for (i = 0, nf = 0; i < nest->nr && fast; ++i) { 19349566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast)); 1935b68353e5Sstefano_zampini if (fast) { 1936b68353e5Sstefano_zampini PetscInt f, s; 1937b68353e5Sstefano_zampini 19389566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s)); 19399371c9d4SSatish Balay if (f != nf || s != 1) { 19409371c9d4SSatish Balay fast = PETSC_FALSE; 19419371c9d4SSatish Balay } else { 19429566063dSJacob Faibussowitsch PetscCall(ISGetSize(nest->isglobal.row[i], &f)); 1943b68353e5Sstefano_zampini nf += f; 1944b68353e5Sstefano_zampini } 1945b68353e5Sstefano_zampini } 1946b68353e5Sstefano_zampini } 1947b68353e5Sstefano_zampini for (i = 0, nf = 0; i < nest->nc && fast; ++i) { 19489566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast)); 1949b68353e5Sstefano_zampini if (fast) { 1950b68353e5Sstefano_zampini PetscInt f, s; 1951b68353e5Sstefano_zampini 19529566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s)); 19539371c9d4SSatish Balay if (f != nf || s != 1) { 19549371c9d4SSatish Balay fast = PETSC_FALSE; 19559371c9d4SSatish Balay } else { 19569566063dSJacob Faibussowitsch PetscCall(ISGetSize(nest->isglobal.col[i], &f)); 1957b68353e5Sstefano_zampini nf += f; 1958b68353e5Sstefano_zampini } 1959b68353e5Sstefano_zampini } 1960b68353e5Sstefano_zampini } 1961b68353e5Sstefano_zampini if (fast) { 19629566063dSJacob Faibussowitsch PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat)); 1963b68353e5Sstefano_zampini PetscFunctionReturn(0); 1964b68353e5Sstefano_zampini } 1965b68353e5Sstefano_zampini } 19669566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, &N)); 19679566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, &n)); 19689566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend)); 1969d1487292SPierre Jolivet if (reuse == MAT_REUSE_MATRIX) C = *newmat; 1970d1487292SPierre Jolivet else { 19719566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C)); 19729566063dSJacob Faibussowitsch PetscCall(MatSetType(C, newtype)); 19739566063dSJacob Faibussowitsch PetscCall(MatSetSizes(C, m, n, M, N)); 1974629c3df2SDmitry Karpeev } 19759566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(2 * m, &dnnz)); 1976629c3df2SDmitry Karpeev onnz = dnnz + m; 1977629c3df2SDmitry Karpeev for (k = 0; k < m; k++) { 1978629c3df2SDmitry Karpeev dnnz[k] = 0; 1979629c3df2SDmitry Karpeev onnz[k] = 0; 1980629c3df2SDmitry Karpeev } 1981629c3df2SDmitry Karpeev for (j = 0; j < nest->nc; ++j) { 1982629c3df2SDmitry Karpeev IS bNis; 1983629c3df2SDmitry Karpeev PetscInt bN; 1984629c3df2SDmitry Karpeev const PetscInt *bNindices; 1985fd8a7442SPierre Jolivet PetscBool flg; 1986629c3df2SDmitry Karpeev /* Using global column indices and ISAllGather() is not scalable. */ 19879566063dSJacob Faibussowitsch PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 19889566063dSJacob Faibussowitsch PetscCall(ISGetSize(bNis, &bN)); 19899566063dSJacob Faibussowitsch PetscCall(ISGetIndices(bNis, &bNindices)); 1990629c3df2SDmitry Karpeev for (i = 0; i < nest->nr; ++i) { 1991629c3df2SDmitry Karpeev PetscSF bmsf; 1992649b366bSFande Kong PetscSFNode *iremote; 1993fd8a7442SPierre Jolivet Mat B = nest->m[i][j], D = NULL; 1994649b366bSFande Kong PetscInt bm, *sub_dnnz, *sub_onnz, br; 1995629c3df2SDmitry Karpeev const PetscInt *bmindices; 1996629c3df2SDmitry Karpeev if (!B) continue; 19979566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 19989566063dSJacob Faibussowitsch PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 19999566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf)); 20009566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &iremote)); 20019566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &sub_dnnz)); 20029566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &sub_onnz)); 2003649b366bSFande Kong for (k = 0; k < bm; ++k) { 2004649b366bSFande Kong sub_dnnz[k] = 0; 2005649b366bSFande Kong sub_onnz[k] = 0; 2006649b366bSFande Kong } 2007fd8a7442SPierre Jolivet PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEMAT, &flg)); 2008fd8a7442SPierre Jolivet if (flg) { 2009fd8a7442SPierre Jolivet PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2010fd8a7442SPierre Jolivet PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2011fd8a7442SPierre Jolivet PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 2012fd8a7442SPierre Jolivet B = D; 2013fd8a7442SPierre Jolivet } 2014fd8a7442SPierre Jolivet PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 2015fd8a7442SPierre Jolivet if (flg) { 2016fd8a7442SPierre Jolivet if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 2017fd8a7442SPierre Jolivet else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 2018fd8a7442SPierre Jolivet B = D; 2019fd8a7442SPierre Jolivet } 2020629c3df2SDmitry Karpeev /* 2021629c3df2SDmitry Karpeev Locate the owners for all of the locally-owned global row indices for this row block. 2022629c3df2SDmitry Karpeev These determine the roots of PetscSF used to communicate preallocation data to row owners. 2023629c3df2SDmitry Karpeev The roots correspond to the dnnz and onnz entries; thus, there are two roots per row. 2024629c3df2SDmitry Karpeev */ 20259566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 2026629c3df2SDmitry Karpeev for (br = 0; br < bm; ++br) { 2027131c27b5Sprj- PetscInt row = bmindices[br], brncols, col; 2028629c3df2SDmitry Karpeev const PetscInt *brcols; 2029a4b3d3acSMatthew G Knepley PetscInt rowrel = 0; /* row's relative index on its owner rank */ 2030131c27b5Sprj- PetscMPIInt rowowner = 0; 20319566063dSJacob Faibussowitsch PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel)); 2032649b366bSFande Kong /* how many roots */ 20339371c9d4SSatish Balay iremote[br].rank = rowowner; 20349371c9d4SSatish Balay iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */ 2035649b366bSFande Kong /* get nonzero pattern */ 20369566063dSJacob Faibussowitsch PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL)); 2037629c3df2SDmitry Karpeev for (k = 0; k < brncols; k++) { 2038629c3df2SDmitry Karpeev col = bNindices[brcols[k]]; 2039649b366bSFande Kong if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) { 2040649b366bSFande Kong sub_dnnz[br]++; 2041649b366bSFande Kong } else { 2042649b366bSFande Kong sub_onnz[br]++; 2043649b366bSFande Kong } 2044629c3df2SDmitry Karpeev } 20459566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL)); 2046629c3df2SDmitry Karpeev } 2047fd8a7442SPierre Jolivet if (D) PetscCall(MatDestroy(&D)); 20489566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 2049629c3df2SDmitry Karpeev /* bsf will have to take care of disposing of bedges. */ 20509566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 20519566063dSJacob Faibussowitsch PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 20529566063dSJacob Faibussowitsch PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 20539566063dSJacob Faibussowitsch PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 20549566063dSJacob Faibussowitsch PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 20559566063dSJacob Faibussowitsch PetscCall(PetscFree(sub_dnnz)); 20569566063dSJacob Faibussowitsch PetscCall(PetscFree(sub_onnz)); 20579566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&bmsf)); 2058629c3df2SDmitry Karpeev } 20599566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(bNis, &bNindices)); 20609566063dSJacob Faibussowitsch PetscCall(ISDestroy(&bNis)); 206165a4a0a3Sstefano_zampini } 206265a4a0a3Sstefano_zampini /* Resize preallocation if overestimated */ 206365a4a0a3Sstefano_zampini for (i = 0; i < m; i++) { 206465a4a0a3Sstefano_zampini dnnz[i] = PetscMin(dnnz[i], A->cmap->n); 206565a4a0a3Sstefano_zampini onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n); 2066629c3df2SDmitry Karpeev } 20679566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz)); 20689566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz)); 20699566063dSJacob Faibussowitsch PetscCall(PetscFree(dnnz)); 20709566063dSJacob Faibussowitsch PetscCall(MatAXPY_Dense_Nest(C, 1.0, A)); 2071d1487292SPierre Jolivet if (reuse == MAT_INPLACE_MATRIX) { 20729566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &C)); 2073d1487292SPierre Jolivet } else *newmat = C; 2074be705e3aSPierre Jolivet PetscFunctionReturn(0); 2075be705e3aSPierre Jolivet } 2076629c3df2SDmitry Karpeev 20779371c9d4SSatish Balay PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) { 2078629c3df2SDmitry Karpeev Mat B; 2079be705e3aSPierre Jolivet PetscInt m, n, M, N; 2080be705e3aSPierre Jolivet 2081be705e3aSPierre Jolivet PetscFunctionBegin; 20829566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, &N)); 20839566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, &n)); 2084be705e3aSPierre Jolivet if (reuse == MAT_REUSE_MATRIX) { 2085be705e3aSPierre Jolivet B = *newmat; 20869566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(B)); 2087be705e3aSPierre Jolivet } else { 20889566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B)); 2089629c3df2SDmitry Karpeev } 20909566063dSJacob Faibussowitsch PetscCall(MatAXPY_Dense_Nest(B, 1.0, A)); 2091be705e3aSPierre Jolivet if (reuse == MAT_INPLACE_MATRIX) { 20929566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &B)); 2093be705e3aSPierre Jolivet } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B; 2094629c3df2SDmitry Karpeev PetscFunctionReturn(0); 2095629c3df2SDmitry Karpeev } 2096629c3df2SDmitry Karpeev 20979371c9d4SSatish Balay PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has) { 20988b7d3b4bSBarry Smith Mat_Nest *bA = (Mat_Nest *)mat->data; 20993c6db4c4SPierre Jolivet MatOperation opAdd; 21008b7d3b4bSBarry Smith PetscInt i, j, nr = bA->nr, nc = bA->nc; 21018b7d3b4bSBarry Smith PetscBool flg; 210252c5f739Sprj- PetscFunctionBegin; 21038b7d3b4bSBarry Smith 210452c5f739Sprj- *has = PETSC_FALSE; 21053c6db4c4SPierre Jolivet if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) { 21063c6db4c4SPierre Jolivet opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD); 21078b7d3b4bSBarry Smith for (j = 0; j < nc; j++) { 21088b7d3b4bSBarry Smith for (i = 0; i < nr; i++) { 21098b7d3b4bSBarry Smith if (!bA->m[i][j]) continue; 21109566063dSJacob Faibussowitsch PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg)); 21118b7d3b4bSBarry Smith if (!flg) PetscFunctionReturn(0); 21128b7d3b4bSBarry Smith } 21138b7d3b4bSBarry Smith } 21148b7d3b4bSBarry Smith } 21153c6db4c4SPierre Jolivet if (((void **)mat->ops)[op]) *has = PETSC_TRUE; 21168b7d3b4bSBarry Smith PetscFunctionReturn(0); 21178b7d3b4bSBarry Smith } 21188b7d3b4bSBarry Smith 2119659c6bb0SJed Brown /*MC 2120659c6bb0SJed Brown MATNEST - MATNEST = "nest" - Matrix type consisting of nested submatrices, each stored separately. 2121659c6bb0SJed Brown 2122659c6bb0SJed Brown Level: intermediate 2123659c6bb0SJed Brown 2124659c6bb0SJed Brown Notes: 2125659c6bb0SJed Brown This matrix type permits scalable use of PCFieldSplit and avoids the large memory costs of extracting submatrices. 2126659c6bb0SJed Brown It allows the use of symmetric and block formats for parts of multi-physics simulations. 2127950540a4SJed Brown It is usually used with DMComposite and DMCreateMatrix() 2128659c6bb0SJed Brown 21298b7d3b4bSBarry Smith Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero 21308b7d3b4bSBarry Smith rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes 21318b7d3b4bSBarry Smith than the nest matrix. 21328b7d3b4bSBarry Smith 2133db781477SPatrick Sanan .seealso: `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, 2134db781477SPatrick Sanan `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`, 2135db781477SPatrick Sanan `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 2136659c6bb0SJed Brown M*/ 21379371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A) { 2138c8883902SJed Brown Mat_Nest *s; 2139c8883902SJed Brown 2140c8883902SJed Brown PetscFunctionBegin; 21419566063dSJacob Faibussowitsch PetscCall(PetscNewLog(A, &s)); 2142c8883902SJed Brown A->data = (void *)s; 2143e7c19651SJed Brown 2144e7c19651SJed Brown s->nr = -1; 2145e7c19651SJed Brown s->nc = -1; 21460298fd71SBarry Smith s->m = NULL; 2147e7c19651SJed Brown s->splitassembly = PETSC_FALSE; 2148c8883902SJed Brown 21499566063dSJacob Faibussowitsch PetscCall(PetscMemzero(A->ops, sizeof(*A->ops))); 215026fbe8dcSKarl Rupp 2151c8883902SJed Brown A->ops->mult = MatMult_Nest; 21529194d70fSJed Brown A->ops->multadd = MatMultAdd_Nest; 2153c8883902SJed Brown A->ops->multtranspose = MatMultTranspose_Nest; 21549194d70fSJed Brown A->ops->multtransposeadd = MatMultTransposeAdd_Nest; 2155f8170845SAlex Fikl A->ops->transpose = MatTranspose_Nest; 2156c8883902SJed Brown A->ops->assemblybegin = MatAssemblyBegin_Nest; 2157c8883902SJed Brown A->ops->assemblyend = MatAssemblyEnd_Nest; 2158c8883902SJed Brown A->ops->zeroentries = MatZeroEntries_Nest; 2159c222c20dSDavid Ham A->ops->copy = MatCopy_Nest; 21606e76ffeaSPierre Jolivet A->ops->axpy = MatAXPY_Nest; 2161c8883902SJed Brown A->ops->duplicate = MatDuplicate_Nest; 21627dae84e0SHong Zhang A->ops->createsubmatrix = MatCreateSubMatrix_Nest; 2163c8883902SJed Brown A->ops->destroy = MatDestroy_Nest; 2164c8883902SJed Brown A->ops->view = MatView_Nest; 2165f4259b30SLisandro Dalcin A->ops->getvecs = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */ 2166c8883902SJed Brown A->ops->getlocalsubmatrix = MatGetLocalSubMatrix_Nest; 2167c8883902SJed Brown A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest; 2168429bac76SJed Brown A->ops->getdiagonal = MatGetDiagonal_Nest; 2169429bac76SJed Brown A->ops->diagonalscale = MatDiagonalScale_Nest; 2170a061e289SJed Brown A->ops->scale = MatScale_Nest; 2171a061e289SJed Brown A->ops->shift = MatShift_Nest; 217213135bc6SAlex Fikl A->ops->diagonalset = MatDiagonalSet_Nest; 2173f8170845SAlex Fikl A->ops->setrandom = MatSetRandom_Nest; 21748b7d3b4bSBarry Smith A->ops->hasoperation = MatHasOperation_Nest; 2175381b8e50SStefano Zampini A->ops->missingdiagonal = MatMissingDiagonal_Nest; 2176c8883902SJed Brown 2177f4259b30SLisandro Dalcin A->spptr = NULL; 2178c8883902SJed Brown A->assembled = PETSC_FALSE; 2179c8883902SJed Brown 2180c8883902SJed Brown /* expose Nest api's */ 21819566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest)); 21829566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest)); 21839566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest)); 21849566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest)); 21859566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest)); 21869566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest)); 21879566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest)); 21889566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest)); 21899566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ)); 21909566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ)); 21919566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ)); 21929566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS)); 21939566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense)); 21949566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense)); 21959566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense)); 21969566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense)); 21979566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_dense_C", MatProductSetFromOptions_Nest_Dense)); 2198c8883902SJed Brown 21999566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST)); 2200c8883902SJed Brown PetscFunctionReturn(0); 2201c8883902SJed Brown } 2202