1aaa7dc30SBarry Smith #include <../src/mat/impls/nest/matnestimpl.h> /*I "petscmat.h" I*/ 2b68353e5Sstefano_zampini #include <../src/mat/impls/aij/seq/aij.h> 3b22c5e46SPierre Jolivet #include <../src/mat/impls/shell/shell.h> 40c312b8eSJed Brown #include <petscsf.h> 5d8588912SDave May 6c8883902SJed Brown static PetscErrorCode MatSetUp_NestIS_Private(Mat, PetscInt, const IS[], PetscInt, const IS[]); 706a1af2fSStefano Zampini static PetscErrorCode MatCreateVecs_Nest(Mat, Vec *, Vec *); 806a1af2fSStefano Zampini static PetscErrorCode MatReset_Nest(Mat); 906a1af2fSStefano Zampini 105e3038f0Sstefano_zampini PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat, MatType, MatReuse, Mat *); 11c8883902SJed Brown 12d8588912SDave May /* private functions */ 13d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetSizes_Private(Mat A, PetscInt *m, PetscInt *n, PetscInt *M, PetscInt *N) 14d71ae5a4SJacob Faibussowitsch { 15d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 168188e55aSJed Brown PetscInt i, j; 17d8588912SDave May 18d8588912SDave May PetscFunctionBegin; 198188e55aSJed Brown *m = *n = *M = *N = 0; 208188e55aSJed Brown for (i = 0; i < bA->nr; i++) { /* rows */ 218188e55aSJed Brown PetscInt sm, sM; 229566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[i], &sm)); 239566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.row[i], &sM)); 248188e55aSJed Brown *m += sm; 258188e55aSJed Brown *M += sM; 26d8588912SDave May } 278188e55aSJed Brown for (j = 0; j < bA->nc; j++) { /* cols */ 288188e55aSJed Brown PetscInt sn, sN; 299566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[j], &sn)); 309566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[j], &sN)); 318188e55aSJed Brown *n += sn; 328188e55aSJed Brown *N += sN; 33d8588912SDave May } 343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 35d8588912SDave May } 36d8588912SDave May 37d8588912SDave May /* operations */ 38d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMult_Nest(Mat A, Vec x, Vec y) 39d71ae5a4SJacob Faibussowitsch { 40d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 41207556f9SJed Brown Vec *bx = bA->right, *by = bA->left; 42207556f9SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 43d8588912SDave May 44d8588912SDave May PetscFunctionBegin; 459566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by[i])); 469566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i])); 47207556f9SJed Brown for (i = 0; i < nr; i++) { 489566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(by[i])); 49207556f9SJed Brown for (j = 0; j < nc; j++) { 50207556f9SJed Brown if (!bA->m[i][j]) continue; 51d8588912SDave May /* y[i] <- y[i] + A[i][j] * x[j] */ 529566063dSJacob Faibussowitsch PetscCall(MatMultAdd(bA->m[i][j], bx[j], by[i], by[i])); 53d8588912SDave May } 54d8588912SDave May } 559566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by[i])); 569566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i])); 573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 58d8588912SDave May } 59d8588912SDave May 60d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMultAdd_Nest(Mat A, Vec x, Vec y, Vec z) 61d71ae5a4SJacob Faibussowitsch { 629194d70fSJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 639194d70fSJed Brown Vec *bx = bA->right, *bz = bA->left; 649194d70fSJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 659194d70fSJed Brown 669194d70fSJed Brown PetscFunctionBegin; 679566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(z, bA->isglobal.row[i], &bz[i])); 689566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i])); 699194d70fSJed Brown for (i = 0; i < nr; i++) { 709194d70fSJed Brown if (y != z) { 719194d70fSJed Brown Vec by; 729566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by)); 739566063dSJacob Faibussowitsch PetscCall(VecCopy(by, bz[i])); 749566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by)); 759194d70fSJed Brown } 769194d70fSJed Brown for (j = 0; j < nc; j++) { 779194d70fSJed Brown if (!bA->m[i][j]) continue; 789194d70fSJed Brown /* y[i] <- y[i] + A[i][j] * x[j] */ 799566063dSJacob Faibussowitsch PetscCall(MatMultAdd(bA->m[i][j], bx[j], bz[i], bz[i])); 809194d70fSJed Brown } 819194d70fSJed Brown } 829566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.row[i], &bz[i])); 839566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i])); 843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 859194d70fSJed Brown } 869194d70fSJed Brown 8752c5f739Sprj- typedef struct { 8852c5f739Sprj- Mat *workC; /* array of Mat with specific containers depending on the underlying MatMatMult implementation */ 8952c5f739Sprj- PetscScalar *tarray; /* buffer for storing all temporary products A[i][j] B[j] */ 9052c5f739Sprj- PetscInt *dm, *dn, k; /* displacements and number of submatrices */ 9152c5f739Sprj- } Nest_Dense; 9252c5f739Sprj- 93a678f235SPierre Jolivet static PetscErrorCode MatProductNumeric_Nest_Dense(Mat C) 94d71ae5a4SJacob Faibussowitsch { 956718818eSStefano Zampini Mat_Nest *bA; 9652c5f739Sprj- Nest_Dense *contents; 976718818eSStefano Zampini Mat viewB, viewC, productB, workC; 9852c5f739Sprj- const PetscScalar *barray; 9952c5f739Sprj- PetscScalar *carray; 1006718818eSStefano Zampini PetscInt i, j, M, N, nr, nc, ldb, ldc; 1016718818eSStefano Zampini Mat A, B; 10252c5f739Sprj- 10352c5f739Sprj- PetscFunctionBegin; 1040d6f747bSJacob Faibussowitsch MatCheckProduct(C, 1); 1056718818eSStefano Zampini A = C->product->A; 1066718818eSStefano Zampini B = C->product->B; 1079566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 1086718818eSStefano Zampini if (!N) { 1099566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 1109566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 1113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1126718818eSStefano Zampini } 1136718818eSStefano Zampini contents = (Nest_Dense *)C->product->data; 11428b400f6SJacob Faibussowitsch PetscCheck(contents, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty"); 1156718818eSStefano Zampini bA = (Mat_Nest *)A->data; 1166718818eSStefano Zampini nr = bA->nr; 1176718818eSStefano Zampini nc = bA->nc; 1189566063dSJacob Faibussowitsch PetscCall(MatDenseGetLDA(B, &ldb)); 1199566063dSJacob Faibussowitsch PetscCall(MatDenseGetLDA(C, &ldc)); 1209566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(C)); 1219566063dSJacob Faibussowitsch PetscCall(MatDenseGetArrayRead(B, &barray)); 1229566063dSJacob Faibussowitsch PetscCall(MatDenseGetArray(C, &carray)); 12352c5f739Sprj- for (i = 0; i < nr; i++) { 1249566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.row[i], &M)); 1258e3a54c0SPierre Jolivet PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dm[i + 1] - contents->dm[i], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset(carray, contents->dm[i]), &viewC)); 1269566063dSJacob Faibussowitsch PetscCall(MatDenseSetLDA(viewC, ldc)); 12752c5f739Sprj- for (j = 0; j < nc; j++) { 12852c5f739Sprj- if (!bA->m[i][j]) continue; 1299566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[j], &M)); 1308e3a54c0SPierre Jolivet PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB)); 1319566063dSJacob Faibussowitsch PetscCall(MatDenseSetLDA(viewB, ldb)); 1324222ddf1SHong Zhang 1334222ddf1SHong Zhang /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */ 1344222ddf1SHong Zhang workC = contents->workC[i * nc + j]; 1354222ddf1SHong Zhang productB = workC->product->B; 1364222ddf1SHong Zhang workC->product->B = viewB; /* use newly created dense matrix viewB */ 1379566063dSJacob Faibussowitsch PetscCall(MatProductNumeric(workC)); 1389566063dSJacob Faibussowitsch PetscCall(MatDestroy(&viewB)); 1394222ddf1SHong Zhang workC->product->B = productB; /* resume original B */ 1404222ddf1SHong Zhang 14152c5f739Sprj- /* C[i] <- workC + C[i] */ 1429566063dSJacob Faibussowitsch PetscCall(MatAXPY(viewC, 1.0, contents->workC[i * nc + j], SAME_NONZERO_PATTERN)); 14352c5f739Sprj- } 1449566063dSJacob Faibussowitsch PetscCall(MatDestroy(&viewC)); 14552c5f739Sprj- } 1469566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArray(C, &carray)); 1479566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArrayRead(B, &barray)); 1484222ddf1SHong Zhang 14967af85e8SPierre Jolivet PetscCall(MatSetOption(C, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 1509566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 1519566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 1523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15352c5f739Sprj- } 15452c5f739Sprj- 15566976f2fSJacob Faibussowitsch static PetscErrorCode MatNest_DenseDestroy(void *ctx) 156d71ae5a4SJacob Faibussowitsch { 15752c5f739Sprj- Nest_Dense *contents = (Nest_Dense *)ctx; 15852c5f739Sprj- PetscInt i; 15952c5f739Sprj- 16052c5f739Sprj- PetscFunctionBegin; 1619566063dSJacob Faibussowitsch PetscCall(PetscFree(contents->tarray)); 16248a46eb9SPierre Jolivet for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i)); 1639566063dSJacob Faibussowitsch PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC)); 1649566063dSJacob Faibussowitsch PetscCall(PetscFree(contents)); 1653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16652c5f739Sprj- } 16752c5f739Sprj- 168a678f235SPierre Jolivet static PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C) 169d71ae5a4SJacob Faibussowitsch { 1706718818eSStefano Zampini Mat_Nest *bA; 1716718818eSStefano Zampini Mat viewB, workC; 17252c5f739Sprj- const PetscScalar *barray; 1736718818eSStefano Zampini PetscInt i, j, M, N, m, n, nr, nc, maxm = 0, ldb; 1744222ddf1SHong Zhang Nest_Dense *contents = NULL; 1756718818eSStefano Zampini PetscBool cisdense; 1766718818eSStefano Zampini Mat A, B; 1776718818eSStefano Zampini PetscReal fill; 17852c5f739Sprj- 17952c5f739Sprj- PetscFunctionBegin; 1800d6f747bSJacob Faibussowitsch MatCheckProduct(C, 1); 18128b400f6SJacob Faibussowitsch PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty"); 1826718818eSStefano Zampini A = C->product->A; 1836718818eSStefano Zampini B = C->product->B; 1846718818eSStefano Zampini fill = C->product->fill; 1856718818eSStefano Zampini bA = (Mat_Nest *)A->data; 1866718818eSStefano Zampini nr = bA->nr; 1876718818eSStefano Zampini nc = bA->nc; 1889566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(C, &m, &n)); 1899566063dSJacob Faibussowitsch PetscCall(MatGetSize(C, &M, &N)); 1900572eedcSPierre Jolivet if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) { 1919566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(B, NULL, &n)); 1929566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 1939566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, NULL)); 1949566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, NULL)); 1959566063dSJacob Faibussowitsch PetscCall(MatSetSizes(C, m, n, M, N)); 1960572eedcSPierre Jolivet } 1979566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, "")); 19848a46eb9SPierre Jolivet if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name)); 1999566063dSJacob Faibussowitsch PetscCall(MatSetUp(C)); 2006718818eSStefano Zampini if (!N) { 2016718818eSStefano Zampini C->ops->productnumeric = MatProductNumeric_Nest_Dense; 2023ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 20352c5f739Sprj- } 20452c5f739Sprj- 2059566063dSJacob Faibussowitsch PetscCall(PetscNew(&contents)); 2066718818eSStefano Zampini C->product->data = contents; 2076718818eSStefano Zampini C->product->destroy = MatNest_DenseDestroy; 2089566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC)); 20952c5f739Sprj- contents->k = nr * nc; 21052c5f739Sprj- for (i = 0; i < nr; i++) { 2119566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1)); 21252c5f739Sprj- maxm = PetscMax(maxm, contents->dm[i + 1]); 21352c5f739Sprj- contents->dm[i + 1] += contents->dm[i]; 21452c5f739Sprj- } 21552c5f739Sprj- for (i = 0; i < nc; i++) { 2169566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1)); 21752c5f739Sprj- contents->dn[i + 1] += contents->dn[i]; 21852c5f739Sprj- } 2199566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(maxm * N, &contents->tarray)); 2209566063dSJacob Faibussowitsch PetscCall(MatDenseGetLDA(B, &ldb)); 2219566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, NULL, &N)); 2229566063dSJacob Faibussowitsch PetscCall(MatDenseGetArrayRead(B, &barray)); 22352c5f739Sprj- /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */ 22452c5f739Sprj- for (j = 0; j < nc; j++) { 2259566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[j], &M)); 2268e3a54c0SPierre Jolivet PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB)); 2279566063dSJacob Faibussowitsch PetscCall(MatDenseSetLDA(viewB, ldb)); 22852c5f739Sprj- for (i = 0; i < nr; i++) { 22952c5f739Sprj- if (!bA->m[i][j]) continue; 23052c5f739Sprj- /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */ 2314222ddf1SHong Zhang 2329566063dSJacob Faibussowitsch PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j])); 2334222ddf1SHong Zhang workC = contents->workC[i * nc + j]; 2349566063dSJacob Faibussowitsch PetscCall(MatProductSetType(workC, MATPRODUCT_AB)); 2359566063dSJacob Faibussowitsch PetscCall(MatProductSetAlgorithm(workC, "default")); 2369566063dSJacob Faibussowitsch PetscCall(MatProductSetFill(workC, fill)); 2379566063dSJacob Faibussowitsch PetscCall(MatProductSetFromOptions(workC)); 2389566063dSJacob Faibussowitsch PetscCall(MatProductSymbolic(workC)); 2394222ddf1SHong Zhang 2406718818eSStefano Zampini /* since tarray will be shared by all Mat */ 2419566063dSJacob Faibussowitsch PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray)); 2429566063dSJacob Faibussowitsch PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray)); 24352c5f739Sprj- } 2449566063dSJacob Faibussowitsch PetscCall(MatDestroy(&viewB)); 24552c5f739Sprj- } 2469566063dSJacob Faibussowitsch PetscCall(MatDenseRestoreArrayRead(B, &barray)); 24752c5f739Sprj- 2486718818eSStefano Zampini C->ops->productnumeric = MatProductNumeric_Nest_Dense; 2493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 25052c5f739Sprj- } 25152c5f739Sprj- 252a678f235SPierre Jolivet static PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C) 253d71ae5a4SJacob Faibussowitsch { 2544222ddf1SHong Zhang Mat_Product *product = C->product; 25552c5f739Sprj- 25652c5f739Sprj- PetscFunctionBegin; 257c57d7d18SPierre Jolivet if (product->type == MATPRODUCT_AB) C->ops->productsymbolic = MatProductSymbolic_Nest_Dense; 2583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 25952c5f739Sprj- } 26052c5f739Sprj- 2610998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeKernel_Nest(Mat A, Vec x, Vec y, PetscBool herm) 262d71ae5a4SJacob Faibussowitsch { 263d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 264207556f9SJed Brown Vec *bx = bA->left, *by = bA->right; 265207556f9SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 266d8588912SDave May 267d8588912SDave May PetscFunctionBegin; 2689566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 2699566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i])); 270207556f9SJed Brown for (j = 0; j < nc; j++) { 2719566063dSJacob Faibussowitsch PetscCall(VecZeroEntries(by[j])); 272609e31cbSJed Brown for (i = 0; i < nr; i++) { 2736c75ac25SJed Brown if (!bA->m[i][j]) continue; 2740998551bSBlanca Mellado Pinto if (herm) PetscCall(MatMultHermitianTransposeAdd(bA->m[i][j], bx[i], by[j], by[j])); /* y[j] <- y[j] + (A[i][j])^H * x[i] */ 2750998551bSBlanca Mellado Pinto else PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j])); /* y[j] <- y[j] + (A[i][j])^T * x[i] */ 276d8588912SDave May } 277d8588912SDave May } 2789566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 2799566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i])); 2803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 281d8588912SDave May } 282d8588912SDave May 2830998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y) 2840998551bSBlanca Mellado Pinto { 2850998551bSBlanca Mellado Pinto PetscFunctionBegin; 2860998551bSBlanca Mellado Pinto PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_FALSE)); 2870998551bSBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 2880998551bSBlanca Mellado Pinto } 2890998551bSBlanca Mellado Pinto 2900998551bSBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTranspose_Nest(Mat A, Vec x, Vec y) 2910998551bSBlanca Mellado Pinto { 2920998551bSBlanca Mellado Pinto PetscFunctionBegin; 2930998551bSBlanca Mellado Pinto PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_TRUE)); 2940998551bSBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 2950998551bSBlanca Mellado Pinto } 2960998551bSBlanca Mellado Pinto 2970998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeAddKernel_Nest(Mat A, Vec x, Vec y, Vec z, PetscBool herm) 298d71ae5a4SJacob Faibussowitsch { 2999194d70fSJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 3009194d70fSJed Brown Vec *bx = bA->left, *bz = bA->right; 3019194d70fSJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 3029194d70fSJed Brown 3039194d70fSJed Brown PetscFunctionBegin; 3049566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 3059566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i])); 3069194d70fSJed Brown for (j = 0; j < nc; j++) { 3079194d70fSJed Brown if (y != z) { 3089194d70fSJed Brown Vec by; 3099566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by)); 3109566063dSJacob Faibussowitsch PetscCall(VecCopy(by, bz[j])); 3119566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by)); 3129194d70fSJed Brown } 3139194d70fSJed Brown for (i = 0; i < nr; i++) { 3146c75ac25SJed Brown if (!bA->m[i][j]) continue; 3150998551bSBlanca Mellado Pinto if (herm) PetscCall(MatMultHermitianTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j])); /* z[j] <- y[j] + (A[i][j])^H * x[i] */ 3160998551bSBlanca Mellado Pinto else PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j])); /* z[j] <- y[j] + (A[i][j])^T * x[i] */ 3179194d70fSJed Brown } 3189194d70fSJed Brown } 3199566063dSJacob Faibussowitsch for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 3209566063dSJacob Faibussowitsch for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i])); 3213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 3229194d70fSJed Brown } 3239194d70fSJed Brown 3240998551bSBlanca Mellado Pinto static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z) 3250998551bSBlanca Mellado Pinto { 3260998551bSBlanca Mellado Pinto PetscFunctionBegin; 3270998551bSBlanca Mellado Pinto PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_FALSE)); 3280998551bSBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 3290998551bSBlanca Mellado Pinto } 3300998551bSBlanca Mellado Pinto 3310998551bSBlanca Mellado Pinto static PetscErrorCode MatMultHermitianTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z) 3320998551bSBlanca Mellado Pinto { 3330998551bSBlanca Mellado Pinto PetscFunctionBegin; 3340998551bSBlanca Mellado Pinto PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_TRUE)); 3350998551bSBlanca Mellado Pinto PetscFunctionReturn(PETSC_SUCCESS); 3360998551bSBlanca Mellado Pinto } 3370998551bSBlanca Mellado Pinto 338d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B) 339d71ae5a4SJacob Faibussowitsch { 340f8170845SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data, *bC; 341f8170845SAlex Fikl Mat C; 342f8170845SAlex Fikl PetscInt i, j, nr = bA->nr, nc = bA->nc; 343f8170845SAlex Fikl 344f8170845SAlex Fikl PetscFunctionBegin; 3457fb60732SBarry Smith if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B)); 346aed4548fSBarry Smith PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place"); 347f8170845SAlex Fikl 348cf37664fSBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) { 349f8170845SAlex Fikl Mat *subs; 350f8170845SAlex Fikl IS *is_row, *is_col; 351f8170845SAlex Fikl 3529566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr * nc, &subs)); 3539566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col)); 3549566063dSJacob Faibussowitsch PetscCall(MatNestGetISs(A, is_row, is_col)); 355cf37664fSBarry Smith if (reuse == MAT_INPLACE_MATRIX) { 356ddeb9bd8SAlex Fikl for (i = 0; i < nr; i++) { 357ad540459SPierre Jolivet for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j]; 358ddeb9bd8SAlex Fikl } 359ddeb9bd8SAlex Fikl } 360ddeb9bd8SAlex Fikl 3619566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C)); 3629566063dSJacob Faibussowitsch PetscCall(PetscFree(subs)); 3639566063dSJacob Faibussowitsch PetscCall(PetscFree2(is_row, is_col)); 364f8170845SAlex Fikl } else { 365f8170845SAlex Fikl C = *B; 366f8170845SAlex Fikl } 367f8170845SAlex Fikl 368f8170845SAlex Fikl bC = (Mat_Nest *)C->data; 369f8170845SAlex Fikl for (i = 0; i < nr; i++) { 370f8170845SAlex Fikl for (j = 0; j < nc; j++) { 371f8170845SAlex Fikl if (bA->m[i][j]) { 372f4f49eeaSPierre Jolivet PetscCall(MatTranspose(bA->m[i][j], reuse, &bC->m[j][i])); 373f8170845SAlex Fikl } else { 374f8170845SAlex Fikl bC->m[j][i] = NULL; 375f8170845SAlex Fikl } 376f8170845SAlex Fikl } 377f8170845SAlex Fikl } 378f8170845SAlex Fikl 379cf37664fSBarry Smith if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) { 380f8170845SAlex Fikl *B = C; 381f8170845SAlex Fikl } else { 3829566063dSJacob Faibussowitsch PetscCall(MatHeaderMerge(A, &C)); 383f8170845SAlex Fikl } 3843ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 385f8170845SAlex Fikl } 386f8170845SAlex Fikl 387d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list) 388d71ae5a4SJacob Faibussowitsch { 389e2d7f03fSJed Brown IS *lst = *list; 390e2d7f03fSJed Brown PetscInt i; 391e2d7f03fSJed Brown 392e2d7f03fSJed Brown PetscFunctionBegin; 3933ba16761SJacob Faibussowitsch if (!lst) PetscFunctionReturn(PETSC_SUCCESS); 3949371c9d4SSatish Balay for (i = 0; i < n; i++) 3959371c9d4SSatish Balay if (lst[i]) PetscCall(ISDestroy(&lst[i])); 3969566063dSJacob Faibussowitsch PetscCall(PetscFree(lst)); 3970298fd71SBarry Smith *list = NULL; 3983ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 399e2d7f03fSJed Brown } 400e2d7f03fSJed Brown 401d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatReset_Nest(Mat A) 402d71ae5a4SJacob Faibussowitsch { 403d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 404d8588912SDave May PetscInt i, j; 405d8588912SDave May 406d8588912SDave May PetscFunctionBegin; 407d8588912SDave May /* release the matrices and the place holders */ 4089566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row)); 4099566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col)); 4109566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row)); 4119566063dSJacob Faibussowitsch PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col)); 412d8588912SDave May 4139566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->row_len)); 4149566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->col_len)); 4159566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->nnzstate)); 416d8588912SDave May 4179566063dSJacob Faibussowitsch PetscCall(PetscFree2(vs->left, vs->right)); 418207556f9SJed Brown 419d8588912SDave May /* release the matrices and the place holders */ 420d8588912SDave May if (vs->m) { 421d8588912SDave May for (i = 0; i < vs->nr; i++) { 42248a46eb9SPierre Jolivet for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j])); 423d8588912SDave May } 4248068ee9dSPierre Jolivet PetscCall(PetscFree(vs->m[0])); 4259566063dSJacob Faibussowitsch PetscCall(PetscFree(vs->m)); 426d8588912SDave May } 42706a1af2fSStefano Zampini 42806a1af2fSStefano Zampini /* restore defaults */ 42906a1af2fSStefano Zampini vs->nr = 0; 43006a1af2fSStefano Zampini vs->nc = 0; 43106a1af2fSStefano Zampini vs->splitassembly = PETSC_FALSE; 4323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 43306a1af2fSStefano Zampini } 43406a1af2fSStefano Zampini 435d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDestroy_Nest(Mat A) 436d71ae5a4SJacob Faibussowitsch { 437362febeeSStefano Zampini PetscFunctionBegin; 4389566063dSJacob Faibussowitsch PetscCall(MatReset_Nest(A)); 4399566063dSJacob Faibussowitsch PetscCall(PetscFree(A->data)); 4409566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL)); 4419566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL)); 4429566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL)); 4439566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL)); 4449566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL)); 4459566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL)); 4469566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL)); 4479566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL)); 4489566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL)); 4499566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL)); 4509566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL)); 4519566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL)); 4529566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL)); 4539566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL)); 4549566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL)); 4559566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL)); 4563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 457d8588912SDave May } 458d8588912SDave May 459d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd) 460d71ae5a4SJacob Faibussowitsch { 461381b8e50SStefano Zampini Mat_Nest *vs = (Mat_Nest *)mat->data; 462381b8e50SStefano Zampini PetscInt i; 463381b8e50SStefano Zampini 464381b8e50SStefano Zampini PetscFunctionBegin; 465381b8e50SStefano Zampini if (dd) *dd = 0; 466381b8e50SStefano Zampini if (!vs->nr) { 467381b8e50SStefano Zampini *missing = PETSC_TRUE; 4683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 469381b8e50SStefano Zampini } 470381b8e50SStefano Zampini *missing = PETSC_FALSE; 47157508eceSPierre Jolivet for (i = 0; i < vs->nr && !*missing; i++) { 472381b8e50SStefano Zampini *missing = PETSC_TRUE; 473381b8e50SStefano Zampini if (vs->m[i][i]) { 4749566063dSJacob Faibussowitsch PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL)); 47508401ef6SPierre Jolivet PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented"); 476381b8e50SStefano Zampini } 477381b8e50SStefano Zampini } 4783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 479381b8e50SStefano Zampini } 480381b8e50SStefano Zampini 481d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type) 482d71ae5a4SJacob Faibussowitsch { 483d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 484d8588912SDave May PetscInt i, j; 48506a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 486d8588912SDave May 487d8588912SDave May PetscFunctionBegin; 488d8588912SDave May for (i = 0; i < vs->nr; i++) { 489d8588912SDave May for (j = 0; j < vs->nc; j++) { 49006a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 491e7c19651SJed Brown if (vs->m[i][j]) { 4929566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(vs->m[i][j], type)); 493e7c19651SJed Brown if (!vs->splitassembly) { 494e7c19651SJed Brown /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested 495e7c19651SJed 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 496e7c19651SJed Brown * already performing an assembly, but the result would by more complicated and appears to offer less 497e7c19651SJed Brown * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an 498e7c19651SJed Brown * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives". 499e7c19651SJed Brown */ 5009566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 5019566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate)); 502e7c19651SJed Brown } 503e7c19651SJed Brown } 50406a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate); 50506a1af2fSStefano Zampini vs->nnzstate[i * vs->nc + j] = subnnzstate; 506d8588912SDave May } 507d8588912SDave May } 50806a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 5093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 510d8588912SDave May } 511d8588912SDave May 512d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type) 513d71ae5a4SJacob Faibussowitsch { 514d8588912SDave May Mat_Nest *vs = (Mat_Nest *)A->data; 515d8588912SDave May PetscInt i, j; 516d8588912SDave May 517d8588912SDave May PetscFunctionBegin; 518d8588912SDave May for (i = 0; i < vs->nr; i++) { 519d8588912SDave May for (j = 0; j < vs->nc; j++) { 520e7c19651SJed Brown if (vs->m[i][j]) { 52148a46eb9SPierre Jolivet if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 522e7c19651SJed Brown } 523d8588912SDave May } 524d8588912SDave May } 5253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 526d8588912SDave May } 527d8588912SDave May 528d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B) 529d71ae5a4SJacob Faibussowitsch { 530f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 531f349c1fdSJed Brown PetscInt j; 532f349c1fdSJed Brown Mat sub; 533d8588912SDave May 534d8588912SDave May PetscFunctionBegin; 5350298fd71SBarry Smith sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */ 536f349c1fdSJed Brown for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j]; 5379566063dSJacob Faibussowitsch if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 538f349c1fdSJed Brown *B = sub; 5393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 540d8588912SDave May } 541d8588912SDave May 542d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B) 543d71ae5a4SJacob Faibussowitsch { 544f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 545f349c1fdSJed Brown PetscInt i; 546f349c1fdSJed Brown Mat sub; 547f349c1fdSJed Brown 548f349c1fdSJed Brown PetscFunctionBegin; 5490298fd71SBarry Smith sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */ 550f349c1fdSJed Brown for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col]; 5519566063dSJacob Faibussowitsch if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 552f349c1fdSJed Brown *B = sub; 5533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 554d8588912SDave May } 555d8588912SDave May 556d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end) 557d71ae5a4SJacob Faibussowitsch { 55818d228c0SPierre Jolivet PetscInt i, j, size, m; 559f349c1fdSJed Brown PetscBool flg; 56018d228c0SPierre Jolivet IS out, concatenate[2]; 561f349c1fdSJed Brown 562f349c1fdSJed Brown PetscFunctionBegin; 5634f572ea9SToby Isaac PetscAssertPointer(list, 3); 564f349c1fdSJed Brown PetscValidHeaderSpecific(is, IS_CLASSID, 4); 56518d228c0SPierre Jolivet if (begin) { 5664f572ea9SToby Isaac PetscAssertPointer(begin, 5); 56718d228c0SPierre Jolivet *begin = -1; 56818d228c0SPierre Jolivet } 56918d228c0SPierre Jolivet if (end) { 5704f572ea9SToby Isaac PetscAssertPointer(end, 6); 57118d228c0SPierre Jolivet *end = -1; 57218d228c0SPierre Jolivet } 573f349c1fdSJed Brown for (i = 0; i < n; i++) { 574207556f9SJed Brown if (!list[i]) continue; 5759566063dSJacob Faibussowitsch PetscCall(ISEqualUnsorted(list[i], is, &flg)); 576f349c1fdSJed Brown if (flg) { 57718d228c0SPierre Jolivet if (begin) *begin = i; 57818d228c0SPierre Jolivet if (end) *end = i + 1; 5793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 580f349c1fdSJed Brown } 581f349c1fdSJed Brown } 5829566063dSJacob Faibussowitsch PetscCall(ISGetSize(is, &size)); 58318d228c0SPierre Jolivet for (i = 0; i < n - 1; i++) { 58418d228c0SPierre Jolivet if (!list[i]) continue; 58518d228c0SPierre Jolivet m = 0; 5869566063dSJacob Faibussowitsch PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out)); 5879566063dSJacob Faibussowitsch PetscCall(ISGetSize(out, &m)); 58818d228c0SPierre Jolivet for (j = i + 2; j < n && m < size; j++) { 58918d228c0SPierre Jolivet if (list[j]) { 59018d228c0SPierre Jolivet concatenate[0] = out; 59118d228c0SPierre Jolivet concatenate[1] = list[j]; 5929566063dSJacob Faibussowitsch PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out)); 5939566063dSJacob Faibussowitsch PetscCall(ISDestroy(concatenate)); 5949566063dSJacob Faibussowitsch PetscCall(ISGetSize(out, &m)); 59518d228c0SPierre Jolivet } 59618d228c0SPierre Jolivet } 59718d228c0SPierre Jolivet if (m == size) { 5989566063dSJacob Faibussowitsch PetscCall(ISEqualUnsorted(out, is, &flg)); 59918d228c0SPierre Jolivet if (flg) { 60018d228c0SPierre Jolivet if (begin) *begin = i; 60118d228c0SPierre Jolivet if (end) *end = j; 6029566063dSJacob Faibussowitsch PetscCall(ISDestroy(&out)); 6033ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 60418d228c0SPierre Jolivet } 60518d228c0SPierre Jolivet } 6069566063dSJacob Faibussowitsch PetscCall(ISDestroy(&out)); 60718d228c0SPierre Jolivet } 6083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 609f349c1fdSJed Brown } 610f349c1fdSJed Brown 611d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B) 612d71ae5a4SJacob Faibussowitsch { 6138188e55aSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 61418d228c0SPierre Jolivet PetscInt lr, lc; 61518d228c0SPierre Jolivet 61618d228c0SPierre Jolivet PetscFunctionBegin; 6179566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 6189566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr)); 6199566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc)); 6209566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE)); 6219566063dSJacob Faibussowitsch PetscCall(MatSetType(*B, MATAIJ)); 6229566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL)); 6239566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL)); 6249566063dSJacob Faibussowitsch PetscCall(MatSetUp(*B)); 6259566063dSJacob Faibussowitsch PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 6269566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 6279566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 6283ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 62918d228c0SPierre Jolivet } 63018d228c0SPierre Jolivet 631d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B) 632d71ae5a4SJacob Faibussowitsch { 63318d228c0SPierre Jolivet Mat_Nest *vs = (Mat_Nest *)A->data; 63418d228c0SPierre Jolivet Mat *a; 63518d228c0SPierre Jolivet PetscInt i, j, k, l, nr = rend - rbegin, nc = cend - cbegin; 6368188e55aSJed Brown char keyname[256]; 63718d228c0SPierre Jolivet PetscBool *b; 63818d228c0SPierre Jolivet PetscBool flg; 6398188e55aSJed Brown 6408188e55aSJed Brown PetscFunctionBegin; 6410298fd71SBarry Smith *B = NULL; 6429566063dSJacob Faibussowitsch PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend)); 6439566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B)); 6443ba16761SJacob Faibussowitsch if (*B) PetscFunctionReturn(PETSC_SUCCESS); 6458188e55aSJed Brown 6469566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b)); 64718d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 64818d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 64918d228c0SPierre Jolivet a[i * nc + j] = vs->m[rbegin + i][cbegin + j]; 65018d228c0SPierre Jolivet b[i * nc + j] = PETSC_FALSE; 65118d228c0SPierre Jolivet } 65218d228c0SPierre Jolivet } 65318d228c0SPierre Jolivet if (nc != vs->nc && nr != vs->nr) { 65418d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 65518d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 65618d228c0SPierre Jolivet flg = PETSC_FALSE; 65718d228c0SPierre Jolivet for (k = 0; (k < nr && !flg); k++) { 65818d228c0SPierre Jolivet if (a[j + k * nc]) flg = PETSC_TRUE; 65918d228c0SPierre Jolivet } 66018d228c0SPierre Jolivet if (flg) { 66118d228c0SPierre Jolivet flg = PETSC_FALSE; 66218d228c0SPierre Jolivet for (l = 0; (l < nc && !flg); l++) { 66318d228c0SPierre Jolivet if (a[i * nc + l]) flg = PETSC_TRUE; 66418d228c0SPierre Jolivet } 66518d228c0SPierre Jolivet } 66618d228c0SPierre Jolivet if (!flg) { 66718d228c0SPierre Jolivet b[i * nc + j] = PETSC_TRUE; 6689566063dSJacob Faibussowitsch PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j)); 66918d228c0SPierre Jolivet } 67018d228c0SPierre Jolivet } 67118d228c0SPierre Jolivet } 67218d228c0SPierre Jolivet } 6739566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B)); 67418d228c0SPierre Jolivet for (i = 0; i < nr; i++) { 67518d228c0SPierre Jolivet for (j = 0; j < nc; j++) { 67648a46eb9SPierre Jolivet if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j)); 67718d228c0SPierre Jolivet } 67818d228c0SPierre Jolivet } 6799566063dSJacob Faibussowitsch PetscCall(PetscFree2(a, b)); 6808188e55aSJed Brown (*B)->assembled = A->assembled; 6819566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B)); 6829566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */ 6833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6848188e55aSJed Brown } 6858188e55aSJed Brown 686d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B) 687d71ae5a4SJacob Faibussowitsch { 688f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 68918d228c0SPierre Jolivet PetscInt rbegin, rend, cbegin, cend; 690f349c1fdSJed Brown 691f349c1fdSJed Brown PetscFunctionBegin; 6929566063dSJacob Faibussowitsch PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend)); 6939566063dSJacob Faibussowitsch PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend)); 69418d228c0SPierre Jolivet if (rend == rbegin + 1 && cend == cbegin + 1) { 69548a46eb9SPierre Jolivet if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin)); 69618d228c0SPierre Jolivet *B = vs->m[rbegin][cbegin]; 69718d228c0SPierre Jolivet } else if (rbegin != -1 && cbegin != -1) { 6989566063dSJacob Faibussowitsch PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B)); 69918d228c0SPierre Jolivet } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set"); 7003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 701f349c1fdSJed Brown } 702f349c1fdSJed Brown 70306a1af2fSStefano Zampini /* 70406a1af2fSStefano Zampini TODO: This does not actually returns a submatrix we can modify 70506a1af2fSStefano Zampini */ 706d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B) 707d71ae5a4SJacob Faibussowitsch { 708f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 709f349c1fdSJed Brown Mat sub; 710f349c1fdSJed Brown 711f349c1fdSJed Brown PetscFunctionBegin; 7129566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub)); 713f349c1fdSJed Brown switch (reuse) { 714f349c1fdSJed Brown case MAT_INITIAL_MATRIX: 7159566063dSJacob Faibussowitsch if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 716f349c1fdSJed Brown *B = sub; 717f349c1fdSJed Brown break; 718d71ae5a4SJacob Faibussowitsch case MAT_REUSE_MATRIX: 719d71ae5a4SJacob Faibussowitsch PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call"); 720d71ae5a4SJacob Faibussowitsch break; 721d71ae5a4SJacob Faibussowitsch case MAT_IGNORE_MATRIX: /* Nothing to do */ 722d71ae5a4SJacob Faibussowitsch break; 723d71ae5a4SJacob Faibussowitsch case MAT_INPLACE_MATRIX: /* Nothing to do */ 724d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet"); 725f349c1fdSJed Brown } 7263ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 727f349c1fdSJed Brown } 728f349c1fdSJed Brown 72966976f2fSJacob Faibussowitsch static PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) 730d71ae5a4SJacob Faibussowitsch { 731f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 732f349c1fdSJed Brown Mat sub; 733f349c1fdSJed Brown 734f349c1fdSJed Brown PetscFunctionBegin; 7359566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 736f349c1fdSJed Brown /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */ 7379566063dSJacob Faibussowitsch if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 738f349c1fdSJed Brown *B = sub; 7393ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 740d8588912SDave May } 741d8588912SDave May 742d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) 743d71ae5a4SJacob Faibussowitsch { 744f349c1fdSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 745f349c1fdSJed Brown Mat sub; 746d8588912SDave May 747d8588912SDave May PetscFunctionBegin; 7489566063dSJacob Faibussowitsch PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 74908401ef6SPierre Jolivet PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten"); 750f349c1fdSJed Brown if (sub) { 751aed4548fSBarry Smith PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times"); 7529566063dSJacob Faibussowitsch PetscCall(MatDestroy(B)); 753d8588912SDave May } 7543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 755d8588912SDave May } 756d8588912SDave May 757d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v) 758d71ae5a4SJacob Faibussowitsch { 7597874fa86SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 7607874fa86SDave May PetscInt i; 7617874fa86SDave May 7627874fa86SDave May PetscFunctionBegin; 7637874fa86SDave May for (i = 0; i < bA->nr; i++) { 764429bac76SJed Brown Vec bv; 7659566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv)); 7667874fa86SDave May if (bA->m[i][i]) { 7679566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(bA->m[i][i], bv)); 7687874fa86SDave May } else { 7699566063dSJacob Faibussowitsch PetscCall(VecSet(bv, 0.0)); 7707874fa86SDave May } 7719566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv)); 7727874fa86SDave May } 7733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 7747874fa86SDave May } 7757874fa86SDave May 776d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r) 777d71ae5a4SJacob Faibussowitsch { 7787874fa86SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 779429bac76SJed Brown Vec bl, *br; 7807874fa86SDave May PetscInt i, j; 7817874fa86SDave May 7827874fa86SDave May PetscFunctionBegin; 7839566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(bA->nc, &br)); 7842e6472ebSElliott Sales de Andrade if (r) { 7859566063dSJacob Faibussowitsch for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j])); 7862e6472ebSElliott Sales de Andrade } 7872e6472ebSElliott Sales de Andrade bl = NULL; 7887874fa86SDave May for (i = 0; i < bA->nr; i++) { 78948a46eb9SPierre Jolivet if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl)); 7907874fa86SDave May for (j = 0; j < bA->nc; j++) { 79148a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j])); 7927874fa86SDave May } 79348a46eb9SPierre Jolivet if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl)); 7942e6472ebSElliott Sales de Andrade } 7952e6472ebSElliott Sales de Andrade if (r) { 7969566063dSJacob Faibussowitsch for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j])); 7972e6472ebSElliott Sales de Andrade } 7989566063dSJacob Faibussowitsch PetscCall(PetscFree(br)); 7993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 8007874fa86SDave May } 8017874fa86SDave May 802d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a) 803d71ae5a4SJacob Faibussowitsch { 804a061e289SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 805a061e289SJed Brown PetscInt i, j; 806a061e289SJed Brown 807a061e289SJed Brown PetscFunctionBegin; 808a061e289SJed Brown for (i = 0; i < bA->nr; i++) { 809a061e289SJed Brown for (j = 0; j < bA->nc; j++) { 81048a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a)); 811a061e289SJed Brown } 812a061e289SJed Brown } 8133ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 814a061e289SJed Brown } 815a061e289SJed Brown 816d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a) 817d71ae5a4SJacob Faibussowitsch { 818a061e289SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 819a061e289SJed Brown PetscInt i; 82006a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 821a061e289SJed Brown 822a061e289SJed Brown PetscFunctionBegin; 823a061e289SJed Brown for (i = 0; i < bA->nr; i++) { 82406a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 82508401ef6SPierre 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); 8269566063dSJacob Faibussowitsch PetscCall(MatShift(bA->m[i][i], a)); 8279566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 82806a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 82906a1af2fSStefano Zampini bA->nnzstate[i * bA->nc + i] = subnnzstate; 830a061e289SJed Brown } 83106a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 8323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 833a061e289SJed Brown } 834a061e289SJed Brown 835d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is) 836d71ae5a4SJacob Faibussowitsch { 83713135bc6SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data; 83813135bc6SAlex Fikl PetscInt i; 83906a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 84013135bc6SAlex Fikl 84113135bc6SAlex Fikl PetscFunctionBegin; 84213135bc6SAlex Fikl for (i = 0; i < bA->nr; i++) { 84306a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 84413135bc6SAlex Fikl Vec bv; 8459566063dSJacob Faibussowitsch PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv)); 84613135bc6SAlex Fikl if (bA->m[i][i]) { 8479566063dSJacob Faibussowitsch PetscCall(MatDiagonalSet(bA->m[i][i], bv, is)); 8489566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 84913135bc6SAlex Fikl } 8509566063dSJacob Faibussowitsch PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv)); 85106a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 85206a1af2fSStefano Zampini bA->nnzstate[i * bA->nc + i] = subnnzstate; 85313135bc6SAlex Fikl } 85406a1af2fSStefano Zampini if (nnzstate) A->nonzerostate++; 8553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 85613135bc6SAlex Fikl } 85713135bc6SAlex Fikl 858d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx) 859d71ae5a4SJacob Faibussowitsch { 860f8170845SAlex Fikl Mat_Nest *bA = (Mat_Nest *)A->data; 861f8170845SAlex Fikl PetscInt i, j; 862f8170845SAlex Fikl 863f8170845SAlex Fikl PetscFunctionBegin; 864f8170845SAlex Fikl for (i = 0; i < bA->nr; i++) { 865f8170845SAlex Fikl for (j = 0; j < bA->nc; j++) { 86648a46eb9SPierre Jolivet if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx)); 867f8170845SAlex Fikl } 868f8170845SAlex Fikl } 8693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 870f8170845SAlex Fikl } 871f8170845SAlex Fikl 872d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left) 873d71ae5a4SJacob Faibussowitsch { 874d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 875d8588912SDave May Vec *L, *R; 876d8588912SDave May MPI_Comm comm; 877d8588912SDave May PetscInt i, j; 878d8588912SDave May 879d8588912SDave May PetscFunctionBegin; 8809566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)A, &comm)); 881d8588912SDave May if (right) { 882d8588912SDave May /* allocate R */ 8839566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bA->nc, &R)); 884d8588912SDave May /* Create the right vectors */ 885d8588912SDave May for (j = 0; j < bA->nc; j++) { 886d8588912SDave May for (i = 0; i < bA->nr; i++) { 887d8588912SDave May if (bA->m[i][j]) { 8889566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL)); 889d8588912SDave May break; 890d8588912SDave May } 891d8588912SDave May } 89208401ef6SPierre Jolivet PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column."); 893d8588912SDave May } 8949566063dSJacob Faibussowitsch PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right)); 895d8588912SDave May /* hand back control to the nest vector */ 89648a46eb9SPierre Jolivet for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j])); 8979566063dSJacob Faibussowitsch PetscCall(PetscFree(R)); 898d8588912SDave May } 899d8588912SDave May 900d8588912SDave May if (left) { 901d8588912SDave May /* allocate L */ 9029566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bA->nr, &L)); 903d8588912SDave May /* Create the left vectors */ 904d8588912SDave May for (i = 0; i < bA->nr; i++) { 905d8588912SDave May for (j = 0; j < bA->nc; j++) { 906d8588912SDave May if (bA->m[i][j]) { 9079566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i])); 908d8588912SDave May break; 909d8588912SDave May } 910d8588912SDave May } 91108401ef6SPierre Jolivet PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row."); 912d8588912SDave May } 913d8588912SDave May 9149566063dSJacob Faibussowitsch PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left)); 91548a46eb9SPierre Jolivet for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i])); 916d8588912SDave May 9179566063dSJacob Faibussowitsch PetscCall(PetscFree(L)); 918d8588912SDave May } 9193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 920d8588912SDave May } 921d8588912SDave May 922d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer) 923d71ae5a4SJacob Faibussowitsch { 924d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 92529e60adbSStefano Zampini PetscBool isascii, viewSub = PETSC_FALSE; 926d8588912SDave May PetscInt i, j; 927d8588912SDave May 928d8588912SDave May PetscFunctionBegin; 9299566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 930d8588912SDave May if (isascii) { 93130924786SStefano Zampini PetscViewerFormat format; 93230924786SStefano Zampini 93330924786SStefano Zampini PetscCall(PetscViewerGetFormat(viewer, &format)); 93430924786SStefano Zampini if (format == PETSC_VIEWER_ASCII_MATLAB) { 93530924786SStefano Zampini Mat T; 93630924786SStefano Zampini 93730924786SStefano Zampini PetscCall(MatConvert(A, MATAIJ, MAT_INITIAL_MATRIX, &T)); 93830924786SStefano Zampini PetscCall(MatView(T, viewer)); 93930924786SStefano Zampini PetscCall(MatDestroy(&T)); 94030924786SStefano Zampini PetscFunctionReturn(PETSC_SUCCESS); 94130924786SStefano Zampini } 9429566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL)); 9439566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 944*7e1a0bbeSBarry Smith PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT ", structure:\n", bA->nr, bA->nc)); 945d8588912SDave May for (i = 0; i < bA->nr; i++) { 946d8588912SDave May for (j = 0; j < bA->nc; j++) { 94719fd82e9SBarry Smith MatType type; 948270f95d7SJed Brown char name[256] = "", prefix[256] = ""; 949d8588912SDave May PetscInt NR, NC; 950d8588912SDave May PetscBool isNest = PETSC_FALSE; 951d8588912SDave May 952d8588912SDave May if (!bA->m[i][j]) { 9539566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j)); 954d8588912SDave May continue; 955d8588912SDave May } 9569566063dSJacob Faibussowitsch PetscCall(MatGetSize(bA->m[i][j], &NR, &NC)); 9579566063dSJacob Faibussowitsch PetscCall(MatGetType(bA->m[i][j], &type)); 9589566063dSJacob Faibussowitsch if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name)); 9599566063dSJacob Faibussowitsch if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix)); 9609566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest)); 961d8588912SDave May 9629566063dSJacob 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)); 963d8588912SDave May 96429e60adbSStefano Zampini if (isNest || viewSub) { 9659566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */ 9669566063dSJacob Faibussowitsch PetscCall(MatView(bA->m[i][j], viewer)); 9679566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */ 968d8588912SDave May } 969d8588912SDave May } 970d8588912SDave May } 9719566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */ 972d8588912SDave May } 9733ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 974d8588912SDave May } 975d8588912SDave May 976d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatZeroEntries_Nest(Mat A) 977d71ae5a4SJacob Faibussowitsch { 978d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 979d8588912SDave May PetscInt i, j; 980d8588912SDave May 981d8588912SDave May PetscFunctionBegin; 982d8588912SDave May for (i = 0; i < bA->nr; i++) { 983d8588912SDave May for (j = 0; j < bA->nc; j++) { 984d8588912SDave May if (!bA->m[i][j]) continue; 9859566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(bA->m[i][j])); 986d8588912SDave May } 987d8588912SDave May } 9883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 989d8588912SDave May } 990d8588912SDave May 991d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str) 992d71ae5a4SJacob Faibussowitsch { 993c222c20dSDavid Ham Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data; 994c222c20dSDavid Ham PetscInt i, j, nr = bA->nr, nc = bA->nc; 99506a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 996c222c20dSDavid Ham 997c222c20dSDavid Ham PetscFunctionBegin; 998aed4548fSBarry 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); 999c222c20dSDavid Ham for (i = 0; i < nr; i++) { 1000c222c20dSDavid Ham for (j = 0; j < nc; j++) { 100106a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 100246a2b97cSJed Brown if (bA->m[i][j] && bB->m[i][j]) { 10039566063dSJacob Faibussowitsch PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str)); 10049566063dSJacob Faibussowitsch PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate)); 100506a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate); 100606a1af2fSStefano Zampini bB->nnzstate[i * nc + j] = subnnzstate; 1007ea6db252SJose E. Roman } else if (bA->m[i][j]) { // bB->m[i][j] is NULL 1008ea6db252SJose E. Roman Mat M; 1009ea6db252SJose E. Roman 1010ea6db252SJose E. Roman PetscCheck(str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN or UNKNOWN_NONZERO_PATTERN", i, j); 1011ea6db252SJose E. Roman PetscCall(MatDuplicate(bA->m[i][j], MAT_COPY_VALUES, &M)); 1012ea6db252SJose E. Roman PetscCall(MatNestSetSubMat(B, i, j, M)); 1013ea6db252SJose E. Roman PetscCall(MatDestroy(&M)); 1014ea6db252SJose E. Roman } else if (bB->m[i][j]) { // bA->m[i][j] is NULL 1015ea6db252SJose E. Roman PetscCheck(str == DIFFERENT_NONZERO_PATTERN || str == SUBSET_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN, SUBSET_NONZERO_PATTERN or UNKNOWN_NONZERO_PATTERN", i, j); 1016ea6db252SJose E. Roman PetscCall(MatNestSetSubMat(B, i, j, NULL)); 1017ea6db252SJose E. Roman } 1018c222c20dSDavid Ham } 1019c222c20dSDavid Ham } 102006a1af2fSStefano Zampini if (nnzstate) B->nonzerostate++; 10213ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1022c222c20dSDavid Ham } 1023c222c20dSDavid Ham 1024d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str) 1025d71ae5a4SJacob Faibussowitsch { 10266e76ffeaSPierre Jolivet Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data; 10276e76ffeaSPierre Jolivet PetscInt i, j, nr = bY->nr, nc = bY->nc; 102806a1af2fSStefano Zampini PetscBool nnzstate = PETSC_FALSE; 10296e76ffeaSPierre Jolivet 10306e76ffeaSPierre Jolivet PetscFunctionBegin; 1031aed4548fSBarry 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); 10326e76ffeaSPierre Jolivet for (i = 0; i < nr; i++) { 10336e76ffeaSPierre Jolivet for (j = 0; j < nc; j++) { 103406a1af2fSStefano Zampini PetscObjectState subnnzstate = 0; 10356e76ffeaSPierre Jolivet if (bY->m[i][j] && bX->m[i][j]) { 10369566063dSJacob Faibussowitsch PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str)); 1037c066aebcSStefano Zampini } else if (bX->m[i][j]) { 1038c066aebcSStefano Zampini Mat M; 1039c066aebcSStefano Zampini 1040e75569e9SPierre Jolivet PetscCheck(str == DIFFERENT_NONZERO_PATTERN || str == UNKNOWN_NONZERO_PATTERN, PetscObjectComm((PetscObject)Y), PETSC_ERR_ARG_INCOMP, "Matrix block does not exist at %" PetscInt_FMT ",%" PetscInt_FMT ". Use DIFFERENT_NONZERO_PATTERN or UNKNOWN_NONZERO_PATTERN", i, j); 10419566063dSJacob Faibussowitsch PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M)); 10429566063dSJacob Faibussowitsch PetscCall(MatNestSetSubMat(Y, i, j, M)); 10439566063dSJacob Faibussowitsch PetscCall(MatDestroy(&M)); 1044c066aebcSStefano Zampini } 10459566063dSJacob Faibussowitsch if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate)); 104606a1af2fSStefano Zampini nnzstate = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate); 104706a1af2fSStefano Zampini bY->nnzstate[i * nc + j] = subnnzstate; 10486e76ffeaSPierre Jolivet } 10496e76ffeaSPierre Jolivet } 105006a1af2fSStefano Zampini if (nnzstate) Y->nonzerostate++; 10513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 10526e76ffeaSPierre Jolivet } 10536e76ffeaSPierre Jolivet 1054d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B) 1055d71ae5a4SJacob Faibussowitsch { 1056d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 1057841e96a3SJed Brown Mat *b; 1058841e96a3SJed Brown PetscInt i, j, nr = bA->nr, nc = bA->nc; 1059d8588912SDave May 1060d8588912SDave May PetscFunctionBegin; 10619566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr * nc, &b)); 1062841e96a3SJed Brown for (i = 0; i < nr; i++) { 1063841e96a3SJed Brown for (j = 0; j < nc; j++) { 1064841e96a3SJed Brown if (bA->m[i][j]) { 10659566063dSJacob Faibussowitsch PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j])); 1066841e96a3SJed Brown } else { 10670298fd71SBarry Smith b[i * nc + j] = NULL; 1068d8588912SDave May } 1069d8588912SDave May } 1070d8588912SDave May } 10719566063dSJacob Faibussowitsch PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B)); 1072841e96a3SJed Brown /* Give the new MatNest exclusive ownership */ 107348a46eb9SPierre Jolivet for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i])); 10749566063dSJacob Faibussowitsch PetscCall(PetscFree(b)); 1075d8588912SDave May 10769566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 10779566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 10783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1079d8588912SDave May } 1080d8588912SDave May 1081d8588912SDave May /* nest api */ 108266976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat) 1083d71ae5a4SJacob Faibussowitsch { 1084d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 10855fd66863SKarl Rupp 1086d8588912SDave May PetscFunctionBegin; 108708401ef6SPierre 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); 108808401ef6SPierre 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); 1089d8588912SDave May *mat = bA->m[idxm][jdxm]; 10903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1091d8588912SDave May } 1092d8588912SDave May 10939ba0d327SJed Brown /*@ 109411a5261eSBarry Smith MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST` 1095d8588912SDave May 10962ef1f0ffSBarry Smith Not Collective 1097d8588912SDave May 1098d8588912SDave May Input Parameters: 109911a5261eSBarry Smith + A - `MATNEST` matrix 1100d8588912SDave May . idxm - index of the matrix within the nest matrix 1101629881c0SJed Brown - jdxm - index of the matrix within the nest matrix 1102d8588912SDave May 1103d8588912SDave May Output Parameter: 11042ef1f0ffSBarry Smith . sub - matrix at index `idxm`, `jdxm` within the nest matrix 1105d8588912SDave May 1106d8588912SDave May Level: developer 1107d8588912SDave May 1108fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`, 1109db781477SPatrick Sanan `MatNestGetLocalISs()`, `MatNestGetISs()` 1110d8588912SDave May @*/ 1111d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub) 1112d71ae5a4SJacob Faibussowitsch { 1113d8588912SDave May PetscFunctionBegin; 11143536838dSStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 11153536838dSStefano Zampini PetscValidLogicalCollectiveInt(A, idxm, 2); 11163536838dSStefano Zampini PetscValidLogicalCollectiveInt(A, jdxm, 3); 11173536838dSStefano Zampini PetscAssertPointer(sub, 4); 1118cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub)); 11193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1120d8588912SDave May } 1121d8588912SDave May 112266976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat) 1123d71ae5a4SJacob Faibussowitsch { 11240782ca92SJed Brown Mat_Nest *bA = (Mat_Nest *)A->data; 11250782ca92SJed Brown PetscInt m, n, M, N, mi, ni, Mi, Ni; 11260782ca92SJed Brown 11270782ca92SJed Brown PetscFunctionBegin; 112808401ef6SPierre 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); 112908401ef6SPierre 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); 11303536838dSStefano Zampini if (mat) { 11319566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(mat, &m, &n)); 11329566063dSJacob Faibussowitsch PetscCall(MatGetSize(mat, &M, &N)); 11339566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi)); 11349566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi)); 11359566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni)); 11369566063dSJacob Faibussowitsch PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni)); 1137aed4548fSBarry 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); 1138aed4548fSBarry 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); 11393536838dSStefano Zampini } 114026fbe8dcSKarl Rupp 114106a1af2fSStefano Zampini /* do not increase object state */ 11423ba16761SJacob Faibussowitsch if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS); 114306a1af2fSStefano Zampini 11449566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)mat)); 11459566063dSJacob Faibussowitsch PetscCall(MatDestroy(&bA->m[idxm][jdxm])); 11460782ca92SJed Brown bA->m[idxm][jdxm] = mat; 11479566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)A)); 11483536838dSStefano Zampini if (mat) PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm])); 11493536838dSStefano Zampini else bA->nnzstate[idxm * bA->nc + jdxm] = 0; 115006a1af2fSStefano Zampini A->nonzerostate++; 11513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11520782ca92SJed Brown } 11530782ca92SJed Brown 11549ba0d327SJed Brown /*@ 115511a5261eSBarry Smith MatNestSetSubMat - Set a single submatrix in the `MATNEST` 11560782ca92SJed Brown 11572ef1f0ffSBarry Smith Logically Collective 11580782ca92SJed Brown 11590782ca92SJed Brown Input Parameters: 116011a5261eSBarry Smith + A - `MATNEST` matrix 11610782ca92SJed Brown . idxm - index of the matrix within the nest matrix 11620782ca92SJed Brown . jdxm - index of the matrix within the nest matrix 11632ef1f0ffSBarry Smith - sub - matrix at index `idxm`, `jdxm` within the nest matrix 11642ef1f0ffSBarry Smith 11652ef1f0ffSBarry Smith Level: developer 11660782ca92SJed Brown 11670782ca92SJed Brown Notes: 11680782ca92SJed Brown The new submatrix must have the same size and communicator as that block of the nest. 11690782ca92SJed Brown 11700782ca92SJed Brown This increments the reference count of the submatrix. 11710782ca92SJed Brown 1172fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`, 1173db781477SPatrick Sanan `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()` 11740782ca92SJed Brown @*/ 1175d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub) 1176d71ae5a4SJacob Faibussowitsch { 11770782ca92SJed Brown PetscFunctionBegin; 11783536838dSStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 11793536838dSStefano Zampini PetscValidLogicalCollectiveInt(A, idxm, 2); 11803536838dSStefano Zampini PetscValidLogicalCollectiveInt(A, jdxm, 3); 11813536838dSStefano Zampini if (sub) PetscValidHeaderSpecific(sub, MAT_CLASSID, 4); 11823536838dSStefano Zampini PetscTryMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub)); 11833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 11840782ca92SJed Brown } 11850782ca92SJed Brown 118666976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) 1187d71ae5a4SJacob Faibussowitsch { 1188d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 11895fd66863SKarl Rupp 1190d8588912SDave May PetscFunctionBegin; 119126fbe8dcSKarl Rupp if (M) *M = bA->nr; 119226fbe8dcSKarl Rupp if (N) *N = bA->nc; 119326fbe8dcSKarl Rupp if (mat) *mat = bA->m; 11943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1195d8588912SDave May } 1196d8588912SDave May 1197d8588912SDave May /*@C 119811a5261eSBarry Smith MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix. 1199d8588912SDave May 12002ef1f0ffSBarry Smith Not Collective 1201d8588912SDave May 1202f899ff85SJose E. Roman Input Parameter: 1203629881c0SJed Brown . A - nest matrix 1204d8588912SDave May 1205d8d19677SJose E. Roman Output Parameters: 1206a3b724e8SBarry Smith + M - number of submatrix rows in the nest matrix 1207a3b724e8SBarry Smith . N - number of submatrix columns in the nest matrix 1208e9d3347aSJose E. Roman - mat - array of matrices 1209d8588912SDave May 12102ef1f0ffSBarry Smith Level: developer 12112ef1f0ffSBarry Smith 121211a5261eSBarry Smith Note: 12132ef1f0ffSBarry Smith The user should not free the array `mat`. 1214d8588912SDave May 1215fe59aa6dSJacob Faibussowitsch Fortran Notes: 1216a3b724e8SBarry Smith This routine has a calling sequence `call MatNestGetSubMats(A, M, N, mat, ierr)` 121720f4b53cSBarry Smith where the space allocated for the optional argument `mat` is assumed large enough (if provided). 1218e9d3347aSJose E. Roman Matrices in `mat` are returned in row-major order, see `MatCreateNest()` for an example. 1219351962e3SVincent Le Chenadec 1220fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`, 1221db781477SPatrick Sanan `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()` 1222d8588912SDave May @*/ 1223d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) 1224d71ae5a4SJacob Faibussowitsch { 1225d8588912SDave May PetscFunctionBegin; 12263536838dSStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1227cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat)); 12283ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1229d8588912SDave May } 1230d8588912SDave May 123166976f2fSJacob Faibussowitsch static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N) 1232d71ae5a4SJacob Faibussowitsch { 1233d8588912SDave May Mat_Nest *bA = (Mat_Nest *)A->data; 1234d8588912SDave May 1235d8588912SDave May PetscFunctionBegin; 123626fbe8dcSKarl Rupp if (M) *M = bA->nr; 123726fbe8dcSKarl Rupp if (N) *N = bA->nc; 12383ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1239d8588912SDave May } 1240d8588912SDave May 12419ba0d327SJed Brown /*@ 124211a5261eSBarry Smith MatNestGetSize - Returns the size of the `MATNEST` matrix. 1243d8588912SDave May 12442ef1f0ffSBarry Smith Not Collective 1245d8588912SDave May 1246f899ff85SJose E. Roman Input Parameter: 124711a5261eSBarry Smith . A - `MATNEST` matrix 1248d8588912SDave May 1249d8d19677SJose E. Roman Output Parameters: 1250629881c0SJed Brown + M - number of rows in the nested mat 1251629881c0SJed Brown - N - number of cols in the nested mat 1252d8588912SDave May 1253d8588912SDave May Level: developer 1254d8588912SDave May 125580670ca5SBarry Smith Note: 125680670ca5SBarry Smith `size` refers to the number of submatrices in the row and column directions of the nested matrix 125780670ca5SBarry Smith 1258fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`, 1259db781477SPatrick Sanan `MatNestGetISs()` 1260d8588912SDave May @*/ 1261d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N) 1262d71ae5a4SJacob Faibussowitsch { 1263d8588912SDave May PetscFunctionBegin; 12643536838dSStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1265cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N)); 12663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1267d8588912SDave May } 1268d8588912SDave May 1269d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[]) 1270d71ae5a4SJacob Faibussowitsch { 1271900e7ff2SJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 1272900e7ff2SJed Brown PetscInt i; 1273900e7ff2SJed Brown 1274900e7ff2SJed Brown PetscFunctionBegin; 12759371c9d4SSatish Balay if (rows) 12769371c9d4SSatish Balay for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i]; 12779371c9d4SSatish Balay if (cols) 12789371c9d4SSatish Balay for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i]; 12793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1280900e7ff2SJed Brown } 1281900e7ff2SJed Brown 1282664df05cSJose E. Roman /*@ 128311a5261eSBarry Smith MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST` 1284900e7ff2SJed Brown 12852ef1f0ffSBarry Smith Not Collective 1286900e7ff2SJed Brown 1287f899ff85SJose E. Roman Input Parameter: 128811a5261eSBarry Smith . A - `MATNEST` matrix 1289900e7ff2SJed Brown 1290d8d19677SJose E. Roman Output Parameters: 1291a3b724e8SBarry Smith + rows - array of row index sets (pass `NULL` to ignore) 1292a3b724e8SBarry Smith - cols - array of column index sets (pass `NULL` to ignore) 1293900e7ff2SJed Brown 1294900e7ff2SJed Brown Level: advanced 1295900e7ff2SJed Brown 129611a5261eSBarry Smith Note: 12972ef1f0ffSBarry Smith The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s. 1298900e7ff2SJed Brown 1299fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`, 1300fe59aa6dSJacob Faibussowitsch `MatCreateNest()`, `MatNestSetSubMats()` 1301900e7ff2SJed Brown @*/ 1302d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[]) 1303d71ae5a4SJacob Faibussowitsch { 1304900e7ff2SJed Brown PetscFunctionBegin; 1305900e7ff2SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1306cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 13073ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1308900e7ff2SJed Brown } 1309900e7ff2SJed Brown 1310d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[]) 1311d71ae5a4SJacob Faibussowitsch { 1312900e7ff2SJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 1313900e7ff2SJed Brown PetscInt i; 1314900e7ff2SJed Brown 1315900e7ff2SJed Brown PetscFunctionBegin; 13169371c9d4SSatish Balay if (rows) 13179371c9d4SSatish Balay for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i]; 13189371c9d4SSatish Balay if (cols) 13199371c9d4SSatish Balay for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i]; 13203ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1321900e7ff2SJed Brown } 1322900e7ff2SJed Brown 13235d83a8b1SBarry Smith /*@ 132411a5261eSBarry Smith MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST` 1325900e7ff2SJed Brown 13262ef1f0ffSBarry Smith Not Collective 1327900e7ff2SJed Brown 1328f899ff85SJose E. Roman Input Parameter: 132911a5261eSBarry Smith . A - `MATNEST` matrix 1330900e7ff2SJed Brown 1331d8d19677SJose E. Roman Output Parameters: 1332a3b724e8SBarry Smith + rows - array of row index sets (pass `NULL` to ignore) 1333a3b724e8SBarry Smith - cols - array of column index sets (pass `NULL` to ignore) 1334900e7ff2SJed Brown 1335900e7ff2SJed Brown Level: advanced 1336900e7ff2SJed Brown 133711a5261eSBarry Smith Note: 13382ef1f0ffSBarry Smith The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s. 1339900e7ff2SJed Brown 13401cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`, 1341fe59aa6dSJacob Faibussowitsch `MatNestSetSubMats()`, `MatNestSetSubMat()` 1342900e7ff2SJed Brown @*/ 1343d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[]) 1344d71ae5a4SJacob Faibussowitsch { 1345900e7ff2SJed Brown PetscFunctionBegin; 1346900e7ff2SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1347cac4c232SBarry Smith PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 13483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1349900e7ff2SJed Brown } 1350900e7ff2SJed Brown 135166976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype) 1352d71ae5a4SJacob Faibussowitsch { 1353207556f9SJed Brown PetscBool flg; 1354207556f9SJed Brown 1355207556f9SJed Brown PetscFunctionBegin; 13569566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, VECNEST, &flg)); 1357207556f9SJed Brown /* In reality, this only distinguishes VECNEST and "other" */ 13582a7a6963SBarry Smith if (flg) A->ops->getvecs = MatCreateVecs_Nest; 13590d5ef98aSSatish Balay else A->ops->getvecs = NULL; 13603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1361207556f9SJed Brown } 1362207556f9SJed Brown 13635d83a8b1SBarry Smith /*@ 136411a5261eSBarry Smith MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()` 1365207556f9SJed Brown 13662ef1f0ffSBarry Smith Not Collective 1367207556f9SJed Brown 1368207556f9SJed Brown Input Parameters: 136911a5261eSBarry Smith + A - `MATNEST` matrix 137011a5261eSBarry Smith - vtype - `VecType` to use for creating vectors 1371207556f9SJed Brown 1372207556f9SJed Brown Level: developer 1373207556f9SJed Brown 1374fe59aa6dSJacob Faibussowitsch .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType` 1375207556f9SJed Brown @*/ 1376d71ae5a4SJacob Faibussowitsch PetscErrorCode MatNestSetVecType(Mat A, VecType vtype) 1377d71ae5a4SJacob Faibussowitsch { 1378207556f9SJed Brown PetscFunctionBegin; 13793536838dSStefano Zampini PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1380cac4c232SBarry Smith PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype)); 13813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1382207556f9SJed Brown } 1383207556f9SJed Brown 138466976f2fSJacob Faibussowitsch static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) 1385d71ae5a4SJacob Faibussowitsch { 1386c8883902SJed Brown Mat_Nest *s = (Mat_Nest *)A->data; 1387c8883902SJed Brown PetscInt i, j, m, n, M, N; 138888ffe2e8SJose E. Roman PetscBool cong, isstd, sametype = PETSC_FALSE; 138988ffe2e8SJose E. Roman VecType vtype, type; 1390d8588912SDave May 1391d8588912SDave May PetscFunctionBegin; 13929566063dSJacob Faibussowitsch PetscCall(MatReset_Nest(A)); 139306a1af2fSStefano Zampini 1394c8883902SJed Brown s->nr = nr; 1395c8883902SJed Brown s->nc = nc; 1396d8588912SDave May 1397c8883902SJed Brown /* Create space for submatrices */ 13989566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &s->m)); 13998068ee9dSPierre Jolivet PetscCall(PetscMalloc1(nr * nc, &s->m[0])); 1400c8883902SJed Brown for (i = 0; i < nr; i++) { 14018068ee9dSPierre Jolivet s->m[i] = s->m[0] + i * nc; 1402c8883902SJed Brown for (j = 0; j < nc; j++) { 14033536838dSStefano Zampini s->m[i][j] = a ? a[i * nc + j] : NULL; 14043536838dSStefano Zampini PetscCall(PetscObjectReference((PetscObject)s->m[i][j])); 1405d8588912SDave May } 1406d8588912SDave May } 14079566063dSJacob Faibussowitsch PetscCall(MatGetVecType(A, &vtype)); 14089566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd)); 140988ffe2e8SJose E. Roman if (isstd) { 141088ffe2e8SJose E. Roman /* check if all blocks have the same vectype */ 141188ffe2e8SJose E. Roman vtype = NULL; 141288ffe2e8SJose E. Roman for (i = 0; i < nr; i++) { 141388ffe2e8SJose E. Roman for (j = 0; j < nc; j++) { 14143536838dSStefano Zampini if (s->m[i][j]) { 141588ffe2e8SJose E. Roman if (!vtype) { /* first visited block */ 14163536838dSStefano Zampini PetscCall(MatGetVecType(s->m[i][j], &vtype)); 141788ffe2e8SJose E. Roman sametype = PETSC_TRUE; 141888ffe2e8SJose E. Roman } else if (sametype) { 14193536838dSStefano Zampini PetscCall(MatGetVecType(s->m[i][j], &type)); 14209566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(vtype, type, &sametype)); 142188ffe2e8SJose E. Roman } 142288ffe2e8SJose E. Roman } 142388ffe2e8SJose E. Roman } 142488ffe2e8SJose E. Roman } 142588ffe2e8SJose E. Roman if (sametype) { /* propagate vectype */ 14269566063dSJacob Faibussowitsch PetscCall(MatSetVecType(A, vtype)); 142788ffe2e8SJose E. Roman } 142888ffe2e8SJose E. Roman } 1429d8588912SDave May 14309566063dSJacob Faibussowitsch PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col)); 1431d8588912SDave May 14329566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &s->row_len)); 14339566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &s->col_len)); 1434c8883902SJed Brown for (i = 0; i < nr; i++) s->row_len[i] = -1; 1435c8883902SJed Brown for (j = 0; j < nc; j++) s->col_len[j] = -1; 1436d8588912SDave May 14379566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr * nc, &s->nnzstate)); 143806a1af2fSStefano Zampini for (i = 0; i < nr; i++) { 143906a1af2fSStefano Zampini for (j = 0; j < nc; j++) { 144048a46eb9SPierre Jolivet if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j])); 144106a1af2fSStefano Zampini } 144206a1af2fSStefano Zampini } 144306a1af2fSStefano Zampini 14449566063dSJacob Faibussowitsch PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N)); 1445d8588912SDave May 14469566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(A->rmap, M)); 14479566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(A->rmap, m)); 14489566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(A->cmap, N)); 14499566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(A->cmap, n)); 1450c8883902SJed Brown 14519566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->rmap)); 14529566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(A->cmap)); 1453c8883902SJed Brown 145406a1af2fSStefano Zampini /* disable operations that are not supported for non-square matrices, 145506a1af2fSStefano Zampini or matrices for which is_row != is_col */ 14569566063dSJacob Faibussowitsch PetscCall(MatHasCongruentLayouts(A, &cong)); 145706a1af2fSStefano Zampini if (cong && nr != nc) cong = PETSC_FALSE; 145806a1af2fSStefano Zampini if (cong) { 145948a46eb9SPierre Jolivet for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong)); 146006a1af2fSStefano Zampini } 146106a1af2fSStefano Zampini if (!cong) { 1462381b8e50SStefano Zampini A->ops->missingdiagonal = NULL; 146306a1af2fSStefano Zampini A->ops->getdiagonal = NULL; 146406a1af2fSStefano Zampini A->ops->shift = NULL; 146506a1af2fSStefano Zampini A->ops->diagonalset = NULL; 146606a1af2fSStefano Zampini } 146706a1af2fSStefano Zampini 14689566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right)); 14699566063dSJacob Faibussowitsch PetscCall(PetscObjectStateIncrease((PetscObject)A)); 147006a1af2fSStefano Zampini A->nonzerostate++; 14713ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1472d8588912SDave May } 1473d8588912SDave May 1474c8883902SJed Brown /*@ 147511a5261eSBarry Smith MatNestSetSubMats - Sets the nested submatrices in a `MATNEST` 1476c8883902SJed Brown 1477c3339decSBarry Smith Collective 1478c8883902SJed Brown 1479d8d19677SJose E. Roman Input Parameters: 148011a5261eSBarry Smith + A - `MATNEST` matrix 1481c8883902SJed Brown . nr - number of nested row blocks 14822ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous 1483c8883902SJed Brown . nc - number of nested column blocks 14842ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous 148558ad77e8SBarry Smith - a - array of $ nr \times nc$ submatrices, or `NULL` 14862ef1f0ffSBarry Smith 14872ef1f0ffSBarry Smith Level: advanced 1488c8883902SJed Brown 1489e9d3347aSJose E. Roman Notes: 14903536838dSStefano Zampini This always resets any block matrix information previously set. 1491ce78bad3SBarry Smith 1492d8b4a066SPierre Jolivet Pass `NULL` in the corresponding entry of `a` for an empty block. 149306a1af2fSStefano Zampini 149458ad77e8SBarry Smith In both C and Fortran, `a` must be a one-dimensional array representing a two-dimensional row-major order array containing the matrices. See 1495e9d3347aSJose E. Roman `MatCreateNest()` for an example. 1496e9d3347aSJose E. Roman 149758ad77e8SBarry Smith Fortran Note: 149858ad77e8SBarry Smith Pass `PETSC_NULL_MAT` in the corresponding entry of `a` for an empty block 149958ad77e8SBarry Smith 15001cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()` 1501c8883902SJed Brown @*/ 150258ad77e8SBarry Smith PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) PeNSS 1503d71ae5a4SJacob Faibussowitsch { 1504c8883902SJed Brown PetscFunctionBegin; 1505c8883902SJed Brown PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 15063536838dSStefano Zampini PetscValidLogicalCollectiveInt(A, nr, 2); 150708401ef6SPierre Jolivet PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative"); 1508c8883902SJed Brown if (nr && is_row) { 15094f572ea9SToby Isaac PetscAssertPointer(is_row, 3); 15103536838dSStefano Zampini for (PetscInt i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3); 1511c8883902SJed Brown } 15123536838dSStefano Zampini PetscValidLogicalCollectiveInt(A, nc, 4); 151308401ef6SPierre Jolivet PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative"); 15141664e352SJed Brown if (nc && is_col) { 15154f572ea9SToby Isaac PetscAssertPointer(is_col, 5); 15163536838dSStefano Zampini for (PetscInt i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5); 1517c8883902SJed Brown } 15183536838dSStefano Zampini PetscTryMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a)); 15193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1520c8883902SJed Brown } 1521d8588912SDave May 1522d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog) 1523d71ae5a4SJacob Faibussowitsch { 152477019fcaSJed Brown PetscBool flg; 152577019fcaSJed Brown PetscInt i, j, m, mi, *ix; 152677019fcaSJed Brown 152777019fcaSJed Brown PetscFunctionBegin; 1528aea6d515SStefano Zampini *ltog = NULL; 152977019fcaSJed Brown for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) { 153077019fcaSJed Brown if (islocal[i]) { 15319566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(islocal[i], &mi)); 153277019fcaSJed Brown flg = PETSC_TRUE; /* We found a non-trivial entry */ 153377019fcaSJed Brown } else { 15349566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mi)); 153577019fcaSJed Brown } 153677019fcaSJed Brown m += mi; 153777019fcaSJed Brown } 15383ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 1539aea6d515SStefano Zampini 15409566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m, &ix)); 1541165cd838SBarry Smith for (i = 0, m = 0; i < n; i++) { 15420298fd71SBarry Smith ISLocalToGlobalMapping smap = NULL; 1543e108cb99SStefano Zampini Mat sub = NULL; 1544f6d38dbbSStefano Zampini PetscSF sf; 1545f6d38dbbSStefano Zampini PetscLayout map; 1546aea6d515SStefano Zampini const PetscInt *ix2; 154777019fcaSJed Brown 1548165cd838SBarry Smith if (!colflg) { 15499566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 155077019fcaSJed Brown } else { 15519566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 155277019fcaSJed Brown } 1553191fd14bSBarry Smith if (sub) { 1554191fd14bSBarry Smith if (!colflg) { 15559566063dSJacob Faibussowitsch PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL)); 1556191fd14bSBarry Smith } else { 15579566063dSJacob Faibussowitsch PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap)); 1558191fd14bSBarry Smith } 1559191fd14bSBarry Smith } 156077019fcaSJed Brown /* 156177019fcaSJed Brown Now we need to extract the monolithic global indices that correspond to the given split global indices. 156277019fcaSJed 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. 156377019fcaSJed Brown */ 15649566063dSJacob Faibussowitsch PetscCall(ISGetIndices(isglobal[i], &ix2)); 1565aea6d515SStefano Zampini if (islocal[i]) { 1566aea6d515SStefano Zampini PetscInt *ilocal, *iremote; 1567aea6d515SStefano Zampini PetscInt mil, nleaves; 1568aea6d515SStefano Zampini 15699566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(islocal[i], &mi)); 157028b400f6SJacob Faibussowitsch PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map"); 1571aea6d515SStefano Zampini for (j = 0; j < mi; j++) ix[m + j] = j; 15729566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m)); 1573aea6d515SStefano Zampini 1574aea6d515SStefano Zampini /* PetscSFSetGraphLayout does not like negative indices */ 15759566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote)); 1576aea6d515SStefano Zampini for (j = 0, nleaves = 0; j < mi; j++) { 1577aea6d515SStefano Zampini if (ix[m + j] < 0) continue; 1578aea6d515SStefano Zampini ilocal[nleaves] = j; 1579aea6d515SStefano Zampini iremote[nleaves] = ix[m + j]; 1580aea6d515SStefano Zampini nleaves++; 1581aea6d515SStefano Zampini } 15829566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mil)); 15839566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf)); 15849566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map)); 15859566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(map, mil)); 15869566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(map)); 15879566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote)); 15889566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&map)); 15899566063dSJacob Faibussowitsch PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 15909566063dSJacob Faibussowitsch PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 15919566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&sf)); 15929566063dSJacob Faibussowitsch PetscCall(PetscFree2(ilocal, iremote)); 1593aea6d515SStefano Zampini } else { 15949566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(isglobal[i], &mi)); 1595aea6d515SStefano Zampini for (j = 0; j < mi; j++) ix[m + j] = ix2[i]; 1596aea6d515SStefano Zampini } 15979566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(isglobal[i], &ix2)); 159877019fcaSJed Brown m += mi; 159977019fcaSJed Brown } 16009566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog)); 16013ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 160277019fcaSJed Brown } 160377019fcaSJed Brown 1604d8588912SDave May /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */ 1605d8588912SDave May /* 1606d8588912SDave May nprocessors = NP 1607d8588912SDave May Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1)) 1608d8588912SDave May proc 0: => (g_0,h_0,) 1609d8588912SDave May proc 1: => (g_1,h_1,) 1610d8588912SDave May ... 1611d8588912SDave May proc nprocs-1: => (g_NP-1,h_NP-1,) 1612d8588912SDave May 1613d8588912SDave May proc 0: proc 1: proc nprocs-1: 1614d8588912SDave May is[0] = (0,1,2,...,nlocal(g_0)-1) (0,1,...,nlocal(g_1)-1) (0,1,...,nlocal(g_NP-1)) 1615d8588912SDave May 1616d8588912SDave May proc 0: 1617d8588912SDave May is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1) 1618d8588912SDave May proc 1: 1619d8588912SDave May is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1) 1620d8588912SDave May 1621d8588912SDave May proc NP-1: 1622d8588912SDave May is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1) 1623d8588912SDave May */ 1624d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[]) 1625d71ae5a4SJacob Faibussowitsch { 1626e2d7f03fSJed Brown Mat_Nest *vs = (Mat_Nest *)A->data; 16278188e55aSJed Brown PetscInt i, j, offset, n, nsum, bs; 16280298fd71SBarry Smith Mat sub = NULL; 1629d8588912SDave May 1630d8588912SDave May PetscFunctionBegin; 16319566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr, &vs->isglobal.row)); 16329566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nc, &vs->isglobal.col)); 1633d8588912SDave May if (is_row) { /* valid IS is passed in */ 1634a5b23f4aSJose E. Roman /* refs on is[] are incremented */ 1635e2d7f03fSJed Brown for (i = 0; i < vs->nr; i++) { 16369566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is_row[i])); 1637e2d7f03fSJed Brown vs->isglobal.row[i] = is_row[i]; 1638d8588912SDave May } 16392ae74bdbSJed Brown } else { /* Create the ISs by inspecting sizes of a submatrix in each row */ 16408188e55aSJed Brown nsum = 0; 16418188e55aSJed Brown for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */ 16429566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 164328b400f6SJacob Faibussowitsch PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i); 16449566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, &n, NULL)); 164508401ef6SPierre Jolivet PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 16468188e55aSJed Brown nsum += n; 16478188e55aSJed Brown } 16489566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 164930bc264bSJed Brown offset -= nsum; 1650e2d7f03fSJed Brown for (i = 0; i < vs->nr; i++) { 16519566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 16529566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, &n, NULL)); 16539566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 16549566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i])); 16559566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs)); 16562ae74bdbSJed Brown offset += n; 1657d8588912SDave May } 1658d8588912SDave May } 1659d8588912SDave May 1660d8588912SDave May if (is_col) { /* valid IS is passed in */ 1661a5b23f4aSJose E. Roman /* refs on is[] are incremented */ 1662e2d7f03fSJed Brown for (j = 0; j < vs->nc; j++) { 16639566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)is_col[j])); 1664e2d7f03fSJed Brown vs->isglobal.col[j] = is_col[j]; 1665d8588912SDave May } 16662ae74bdbSJed Brown } else { /* Create the ISs by inspecting sizes of a submatrix in each column */ 16672ae74bdbSJed Brown offset = A->cmap->rstart; 16688188e55aSJed Brown nsum = 0; 16698188e55aSJed Brown for (j = 0; j < vs->nc; j++) { 16709566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 167128b400f6SJacob Faibussowitsch PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i); 16729566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, NULL, &n)); 167308401ef6SPierre Jolivet PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 16748188e55aSJed Brown nsum += n; 16758188e55aSJed Brown } 16769566063dSJacob Faibussowitsch PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 167730bc264bSJed Brown offset -= nsum; 1678e2d7f03fSJed Brown for (j = 0; j < vs->nc; j++) { 16799566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 16809566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(sub, NULL, &n)); 16819566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 16829566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j])); 16839566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs)); 16842ae74bdbSJed Brown offset += n; 1685d8588912SDave May } 1686d8588912SDave May } 1687e2d7f03fSJed Brown 1688e2d7f03fSJed Brown /* Set up the local ISs */ 16899566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row)); 16909566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col)); 1691e2d7f03fSJed Brown for (i = 0, offset = 0; i < vs->nr; i++) { 1692e2d7f03fSJed Brown IS isloc; 16930298fd71SBarry Smith ISLocalToGlobalMapping rmap = NULL; 1694e2d7f03fSJed Brown PetscInt nlocal, bs; 16959566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 16969566063dSJacob Faibussowitsch if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL)); 1697207556f9SJed Brown if (rmap) { 16989566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 16999566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal)); 17009566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 17019566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(isloc, bs)); 1702207556f9SJed Brown } else { 1703207556f9SJed Brown nlocal = 0; 17040298fd71SBarry Smith isloc = NULL; 1705207556f9SJed Brown } 1706e2d7f03fSJed Brown vs->islocal.row[i] = isloc; 1707e2d7f03fSJed Brown offset += nlocal; 1708e2d7f03fSJed Brown } 17098188e55aSJed Brown for (i = 0, offset = 0; i < vs->nc; i++) { 1710e2d7f03fSJed Brown IS isloc; 17110298fd71SBarry Smith ISLocalToGlobalMapping cmap = NULL; 1712e2d7f03fSJed Brown PetscInt nlocal, bs; 17139566063dSJacob Faibussowitsch PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 17149566063dSJacob Faibussowitsch if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap)); 1715207556f9SJed Brown if (cmap) { 17169566063dSJacob Faibussowitsch PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 17179566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal)); 17189566063dSJacob Faibussowitsch PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 17199566063dSJacob Faibussowitsch PetscCall(ISSetBlockSize(isloc, bs)); 1720207556f9SJed Brown } else { 1721207556f9SJed Brown nlocal = 0; 17220298fd71SBarry Smith isloc = NULL; 1723207556f9SJed Brown } 1724e2d7f03fSJed Brown vs->islocal.col[i] = isloc; 1725e2d7f03fSJed Brown offset += nlocal; 1726e2d7f03fSJed Brown } 17270189643fSJed Brown 172877019fcaSJed Brown /* Set up the aggregate ISLocalToGlobalMapping */ 172977019fcaSJed Brown { 173045b6f7e9SBarry Smith ISLocalToGlobalMapping rmap, cmap; 17319566063dSJacob Faibussowitsch PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap)); 17329566063dSJacob Faibussowitsch PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap)); 17339566063dSJacob Faibussowitsch if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap)); 17349566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingDestroy(&rmap)); 17359566063dSJacob Faibussowitsch PetscCall(ISLocalToGlobalMappingDestroy(&cmap)); 173677019fcaSJed Brown } 173777019fcaSJed Brown 173876bd3646SJed Brown if (PetscDefined(USE_DEBUG)) { 17390189643fSJed Brown for (i = 0; i < vs->nr; i++) { 17400189643fSJed Brown for (j = 0; j < vs->nc; j++) { 17410189643fSJed Brown PetscInt m, n, M, N, mi, ni, Mi, Ni; 17420189643fSJed Brown Mat B = vs->m[i][j]; 17430189643fSJed Brown if (!B) continue; 17449566063dSJacob Faibussowitsch PetscCall(MatGetSize(B, &M, &N)); 17459566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(B, &m, &n)); 17469566063dSJacob Faibussowitsch PetscCall(ISGetSize(vs->isglobal.row[i], &Mi)); 17479566063dSJacob Faibussowitsch PetscCall(ISGetSize(vs->isglobal.col[j], &Ni)); 17489566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi)); 17499566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni)); 1750aed4548fSBarry 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); 1751aed4548fSBarry 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); 17520189643fSJed Brown } 17530189643fSJed Brown } 175476bd3646SJed Brown } 1755a061e289SJed Brown 1756a061e289SJed Brown /* Set A->assembled if all non-null blocks are currently assembled */ 1757a061e289SJed Brown for (i = 0; i < vs->nr; i++) { 1758a061e289SJed Brown for (j = 0; j < vs->nc; j++) { 17593ba16761SJacob Faibussowitsch if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS); 1760a061e289SJed Brown } 1761a061e289SJed Brown } 1762a061e289SJed Brown A->assembled = PETSC_TRUE; 17633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1764d8588912SDave May } 1765d8588912SDave May 176645c38901SJed Brown /*@C 176711a5261eSBarry Smith MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately 1768659c6bb0SJed Brown 176911a5261eSBarry Smith Collective 1770659c6bb0SJed Brown 1771d8d19677SJose E. Roman Input Parameters: 177211a5261eSBarry Smith + comm - Communicator for the new `MATNEST` 1773659c6bb0SJed Brown . nr - number of nested row blocks 17742ef1f0ffSBarry Smith . is_row - index sets for each nested row block, or `NULL` to make contiguous 1775659c6bb0SJed Brown . nc - number of nested column blocks 17762ef1f0ffSBarry Smith . is_col - index sets for each nested column block, or `NULL` to make contiguous 177758ad77e8SBarry Smith - a - array of $nr \times nc$ submatrices, empty submatrices can be passed using `NULL` 1778659c6bb0SJed Brown 1779659c6bb0SJed Brown Output Parameter: 1780659c6bb0SJed Brown . B - new matrix 1781659c6bb0SJed Brown 178258ad77e8SBarry Smith Level: advanced 178358ad77e8SBarry Smith 1784e9d3347aSJose E. Roman Note: 178558ad77e8SBarry Smith In both C and Fortran, `a` must be a one-dimensional array representing a two-dimensional row-major order array holding references to the matrices. 1786e9d3347aSJose E. Roman For instance, to represent the matrix 1787e9d3347aSJose E. Roman $\begin{bmatrix} A_{11} & A_{12} \\ A_{21} & A_{22}\end{bmatrix}$ 1788e9d3347aSJose E. Roman one should use `Mat a[4]={A11,A12,A21,A22}`. 1789e9d3347aSJose E. Roman 179058ad77e8SBarry Smith Fortran Note: 179158ad77e8SBarry Smith Pass `PETSC_NULL_MAT` in the corresponding entry of `a` for an empty block 1792659c6bb0SJed Brown 17931cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`, 1794db781477SPatrick Sanan `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`, 1795db781477SPatrick Sanan `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 1796659c6bb0SJed Brown @*/ 1797030363d8SJose E. Roman PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B) PeNSS 1798d71ae5a4SJacob Faibussowitsch { 1799d8588912SDave May PetscFunctionBegin; 18003536838dSStefano Zampini PetscCall(MatCreate(comm, B)); 18013536838dSStefano Zampini PetscCall(MatSetType(*B, MATNEST)); 18023536838dSStefano Zampini (*B)->preallocated = PETSC_TRUE; 18033536838dSStefano Zampini PetscCall(MatNestSetSubMats(*B, nr, is_row, nc, is_col, a)); 18043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1805d8588912SDave May } 1806659c6bb0SJed Brown 180766976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 1808d71ae5a4SJacob Faibussowitsch { 1809b68353e5Sstefano_zampini Mat_Nest *nest = (Mat_Nest *)A->data; 181023875855Sstefano_zampini Mat *trans; 1811b68353e5Sstefano_zampini PetscScalar **avv; 1812b68353e5Sstefano_zampini PetscScalar *vv; 1813b68353e5Sstefano_zampini PetscInt **aii, **ajj; 1814b68353e5Sstefano_zampini PetscInt *ii, *jj, *ci; 1815b68353e5Sstefano_zampini PetscInt nr, nc, nnz, i, j; 1816b68353e5Sstefano_zampini PetscBool done; 1817b68353e5Sstefano_zampini 1818b68353e5Sstefano_zampini PetscFunctionBegin; 18199566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &nr, &nc)); 1820b68353e5Sstefano_zampini if (reuse == MAT_REUSE_MATRIX) { 1821b68353e5Sstefano_zampini PetscInt rnr; 1822b68353e5Sstefano_zampini 18239566063dSJacob Faibussowitsch PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done)); 182428b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ"); 182508401ef6SPierre Jolivet PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows"); 18269566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArray(*newmat, &vv)); 1827b68353e5Sstefano_zampini } 1828b68353e5Sstefano_zampini /* extract CSR for nested SeqAIJ matrices */ 1829b68353e5Sstefano_zampini nnz = 0; 18309566063dSJacob Faibussowitsch PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans)); 1831b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1832b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1833b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1834b68353e5Sstefano_zampini if (B) { 1835b68353e5Sstefano_zampini PetscScalar *naa; 1836b68353e5Sstefano_zampini PetscInt *nii, *njj, nnr; 183723875855Sstefano_zampini PetscBool istrans; 1838b68353e5Sstefano_zampini 1839013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans)); 184023875855Sstefano_zampini if (istrans) { 184123875855Sstefano_zampini Mat Bt; 184223875855Sstefano_zampini 18439566063dSJacob Faibussowitsch PetscCall(MatTransposeGetMat(B, &Bt)); 18449566063dSJacob Faibussowitsch PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 184523875855Sstefano_zampini B = trans[i * nest->nc + j]; 1846013e2dc7SBarry Smith } else { 1847013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans)); 1848013e2dc7SBarry Smith if (istrans) { 1849013e2dc7SBarry Smith Mat Bt; 1850013e2dc7SBarry Smith 1851013e2dc7SBarry Smith PetscCall(MatHermitianTransposeGetMat(B, &Bt)); 1852013e2dc7SBarry Smith PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 1853013e2dc7SBarry Smith B = trans[i * nest->nc + j]; 1854013e2dc7SBarry Smith } 185523875855Sstefano_zampini } 18569566063dSJacob Faibussowitsch PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done)); 185728b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ"); 18589566063dSJacob Faibussowitsch PetscCall(MatSeqAIJGetArray(B, &naa)); 1859b68353e5Sstefano_zampini nnz += nii[nnr]; 1860b68353e5Sstefano_zampini 1861b68353e5Sstefano_zampini aii[i * nest->nc + j] = nii; 1862b68353e5Sstefano_zampini ajj[i * nest->nc + j] = njj; 1863b68353e5Sstefano_zampini avv[i * nest->nc + j] = naa; 1864b68353e5Sstefano_zampini } 1865b68353e5Sstefano_zampini } 1866b68353e5Sstefano_zampini } 1867b68353e5Sstefano_zampini if (reuse != MAT_REUSE_MATRIX) { 18689566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nr + 1, &ii)); 18699566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &jj)); 18709566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nnz, &vv)); 1871b68353e5Sstefano_zampini } else { 187208401ef6SPierre Jolivet PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros"); 1873b68353e5Sstefano_zampini } 1874b68353e5Sstefano_zampini 1875b68353e5Sstefano_zampini /* new row pointer */ 18769566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(ii, nr + 1)); 1877b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1878b68353e5Sstefano_zampini PetscInt ncr, rst; 1879b68353e5Sstefano_zampini 18809566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 18819566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1882b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1883b68353e5Sstefano_zampini if (aii[i * nest->nc + j]) { 1884b68353e5Sstefano_zampini PetscInt *nii = aii[i * nest->nc + j]; 1885b68353e5Sstefano_zampini PetscInt ir; 1886b68353e5Sstefano_zampini 1887b68353e5Sstefano_zampini for (ir = rst; ir < ncr + rst; ++ir) { 1888b68353e5Sstefano_zampini ii[ir + 1] += nii[1] - nii[0]; 1889b68353e5Sstefano_zampini nii++; 1890b68353e5Sstefano_zampini } 1891b68353e5Sstefano_zampini } 1892b68353e5Sstefano_zampini } 1893b68353e5Sstefano_zampini } 1894b68353e5Sstefano_zampini for (i = 0; i < nr; i++) ii[i + 1] += ii[i]; 1895b68353e5Sstefano_zampini 1896b68353e5Sstefano_zampini /* construct CSR for the new matrix */ 18979566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(nr, &ci)); 1898b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1899b68353e5Sstefano_zampini PetscInt ncr, rst; 1900b68353e5Sstefano_zampini 19019566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 19029566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1903b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1904b68353e5Sstefano_zampini if (aii[i * nest->nc + j]) { 1905b22c5e46SPierre Jolivet PetscScalar *nvv = avv[i * nest->nc + j], vscale = 1.0, vshift = 0.0; 1906b68353e5Sstefano_zampini PetscInt *nii = aii[i * nest->nc + j]; 1907b68353e5Sstefano_zampini PetscInt *njj = ajj[i * nest->nc + j]; 1908b68353e5Sstefano_zampini PetscInt ir, cst; 1909b68353e5Sstefano_zampini 1910b22c5e46SPierre Jolivet if (trans[i * nest->nc + j]) { 1911b22c5e46SPierre Jolivet vscale = ((Mat_Shell *)nest->m[i][j]->data)->vscale; 1912b22c5e46SPierre Jolivet vshift = ((Mat_Shell *)nest->m[i][j]->data)->vshift; 1913b22c5e46SPierre Jolivet } 19149566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL)); 1915b68353e5Sstefano_zampini for (ir = rst; ir < ncr + rst; ++ir) { 1916b68353e5Sstefano_zampini PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir]; 1917b68353e5Sstefano_zampini 1918b68353e5Sstefano_zampini for (ij = 0; ij < rsize; ij++) { 1919b68353e5Sstefano_zampini jj[ist + ij] = *njj + cst; 1920b22c5e46SPierre Jolivet vv[ist + ij] = vscale * *nvv; 1921b22c5e46SPierre Jolivet if (PetscUnlikely(vshift != 0.0 && *njj == ir - rst)) vv[ist + ij] += vshift; 1922b68353e5Sstefano_zampini njj++; 1923b68353e5Sstefano_zampini nvv++; 1924b68353e5Sstefano_zampini } 1925b68353e5Sstefano_zampini ci[ir] += rsize; 1926b68353e5Sstefano_zampini nii++; 1927b68353e5Sstefano_zampini } 1928b68353e5Sstefano_zampini } 1929b68353e5Sstefano_zampini } 1930b68353e5Sstefano_zampini } 19319566063dSJacob Faibussowitsch PetscCall(PetscFree(ci)); 1932b68353e5Sstefano_zampini 1933b68353e5Sstefano_zampini /* restore info */ 1934b68353e5Sstefano_zampini for (i = 0; i < nest->nr; ++i) { 1935b68353e5Sstefano_zampini for (j = 0; j < nest->nc; ++j) { 1936b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 1937b68353e5Sstefano_zampini if (B) { 1938b68353e5Sstefano_zampini PetscInt nnr = 0, k = i * nest->nc + j; 193923875855Sstefano_zampini 194023875855Sstefano_zampini B = (trans[k] ? trans[k] : B); 19419566063dSJacob Faibussowitsch PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done)); 194228b400f6SJacob Faibussowitsch PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ"); 19439566063dSJacob Faibussowitsch PetscCall(MatSeqAIJRestoreArray(B, &avv[k])); 19449566063dSJacob Faibussowitsch PetscCall(MatDestroy(&trans[k])); 1945b68353e5Sstefano_zampini } 1946b68353e5Sstefano_zampini } 1947b68353e5Sstefano_zampini } 19489566063dSJacob Faibussowitsch PetscCall(PetscFree4(aii, ajj, avv, trans)); 1949b68353e5Sstefano_zampini 1950b68353e5Sstefano_zampini /* finalize newmat */ 1951b68353e5Sstefano_zampini if (reuse == MAT_INITIAL_MATRIX) { 19529566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat)); 1953b68353e5Sstefano_zampini } else if (reuse == MAT_INPLACE_MATRIX) { 1954b68353e5Sstefano_zampini Mat B; 1955b68353e5Sstefano_zampini 19569566063dSJacob Faibussowitsch PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B)); 19579566063dSJacob Faibussowitsch PetscCall(MatHeaderReplace(A, &B)); 1958b68353e5Sstefano_zampini } 19599566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY)); 19609566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY)); 1961b68353e5Sstefano_zampini { 1962b68353e5Sstefano_zampini Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data); 1963b68353e5Sstefano_zampini a->free_a = PETSC_TRUE; 1964b68353e5Sstefano_zampini a->free_ij = PETSC_TRUE; 1965b68353e5Sstefano_zampini } 19663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1967b68353e5Sstefano_zampini } 1968b68353e5Sstefano_zampini 1969d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X) 1970d71ae5a4SJacob Faibussowitsch { 1971be705e3aSPierre Jolivet Mat_Nest *nest = (Mat_Nest *)X->data; 1972be705e3aSPierre Jolivet PetscInt i, j, k, rstart; 1973be705e3aSPierre Jolivet PetscBool flg; 1974be705e3aSPierre Jolivet 1975be705e3aSPierre Jolivet PetscFunctionBegin; 1976be705e3aSPierre Jolivet /* Fill by row */ 1977be705e3aSPierre Jolivet for (j = 0; j < nest->nc; ++j) { 1978be705e3aSPierre Jolivet /* Using global column indices and ISAllGather() is not scalable. */ 1979be705e3aSPierre Jolivet IS bNis; 1980be705e3aSPierre Jolivet PetscInt bN; 1981be705e3aSPierre Jolivet const PetscInt *bNindices; 19829566063dSJacob Faibussowitsch PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 19839566063dSJacob Faibussowitsch PetscCall(ISGetSize(bNis, &bN)); 19849566063dSJacob Faibussowitsch PetscCall(ISGetIndices(bNis, &bNindices)); 1985be705e3aSPierre Jolivet for (i = 0; i < nest->nr; ++i) { 1986fd8a7442SPierre Jolivet Mat B = nest->m[i][j], D = NULL; 1987be705e3aSPierre Jolivet PetscInt bm, br; 1988be705e3aSPierre Jolivet const PetscInt *bmindices; 1989be705e3aSPierre Jolivet if (!B) continue; 1990013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 1991be705e3aSPierre Jolivet if (flg) { 1992cac4c232SBarry Smith PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 1993cac4c232SBarry Smith PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 19949566063dSJacob Faibussowitsch PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 1995be705e3aSPierre Jolivet B = D; 1996be705e3aSPierre Jolivet } 19979566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 1998be705e3aSPierre Jolivet if (flg) { 1999fd8a7442SPierre Jolivet if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 2000fd8a7442SPierre Jolivet else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 2001be705e3aSPierre Jolivet B = D; 2002be705e3aSPierre Jolivet } 20039566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 20049566063dSJacob Faibussowitsch PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 20059566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 2006be705e3aSPierre Jolivet for (br = 0; br < bm; ++br) { 2007be705e3aSPierre Jolivet PetscInt row = bmindices[br], brncols, *cols; 2008be705e3aSPierre Jolivet const PetscInt *brcols; 2009be705e3aSPierre Jolivet const PetscScalar *brcoldata; 2010be705e3aSPierre Jolivet PetscScalar *vals = NULL; 20119566063dSJacob Faibussowitsch PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 20129566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(brncols, &cols)); 2013be705e3aSPierre Jolivet for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]]; 2014be705e3aSPierre Jolivet /* 2015be705e3aSPierre Jolivet Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match. 2016be705e3aSPierre Jolivet Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES. 2017be705e3aSPierre Jolivet */ 2018be705e3aSPierre Jolivet if (a != 1.0) { 20199566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(brncols, &vals)); 2020be705e3aSPierre Jolivet for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k]; 20219566063dSJacob Faibussowitsch PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES)); 20229566063dSJacob Faibussowitsch PetscCall(PetscFree(vals)); 2023be705e3aSPierre Jolivet } else { 20249566063dSJacob Faibussowitsch PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES)); 2025be705e3aSPierre Jolivet } 20269566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 20279566063dSJacob Faibussowitsch PetscCall(PetscFree(cols)); 2028be705e3aSPierre Jolivet } 2029fd8a7442SPierre Jolivet if (D) PetscCall(MatDestroy(&D)); 20309566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 2031be705e3aSPierre Jolivet } 20329566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(bNis, &bNindices)); 20339566063dSJacob Faibussowitsch PetscCall(ISDestroy(&bNis)); 2034be705e3aSPierre Jolivet } 20359566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY)); 20369566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY)); 20373ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2038be705e3aSPierre Jolivet } 2039be705e3aSPierre Jolivet 204066976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 2041d71ae5a4SJacob Faibussowitsch { 2042629c3df2SDmitry Karpeev Mat_Nest *nest = (Mat_Nest *)A->data; 2043e30678d3SPierre Jolivet PetscInt m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend; 2044b68353e5Sstefano_zampini PetscMPIInt size; 2045629c3df2SDmitry Karpeev Mat C; 2046629c3df2SDmitry Karpeev 2047629c3df2SDmitry Karpeev PetscFunctionBegin; 20489566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 2049b68353e5Sstefano_zampini if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */ 2050b68353e5Sstefano_zampini PetscInt nf; 2051b68353e5Sstefano_zampini PetscBool fast; 2052b68353e5Sstefano_zampini 20539566063dSJacob Faibussowitsch PetscCall(PetscStrcmp(newtype, MATAIJ, &fast)); 205448a46eb9SPierre Jolivet if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast)); 2055b68353e5Sstefano_zampini for (i = 0; i < nest->nr && fast; ++i) { 2056b68353e5Sstefano_zampini for (j = 0; j < nest->nc && fast; ++j) { 2057b68353e5Sstefano_zampini Mat B = nest->m[i][j]; 2058b68353e5Sstefano_zampini if (B) { 20599566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast)); 206023875855Sstefano_zampini if (!fast) { 206123875855Sstefano_zampini PetscBool istrans; 206223875855Sstefano_zampini 2063013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans)); 206423875855Sstefano_zampini if (istrans) { 206523875855Sstefano_zampini Mat Bt; 206623875855Sstefano_zampini 20679566063dSJacob Faibussowitsch PetscCall(MatTransposeGetMat(B, &Bt)); 20689566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 2069013e2dc7SBarry Smith } else { 2070013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans)); 2071013e2dc7SBarry Smith if (istrans) { 2072013e2dc7SBarry Smith Mat Bt; 2073013e2dc7SBarry Smith 2074013e2dc7SBarry Smith PetscCall(MatHermitianTransposeGetMat(B, &Bt)); 2075013e2dc7SBarry Smith PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 2076013e2dc7SBarry Smith } 207723875855Sstefano_zampini } 2078b22c5e46SPierre Jolivet if (fast) fast = (PetscBool)(!((Mat_Shell *)B->data)->zrows && !((Mat_Shell *)B->data)->zcols && !((Mat_Shell *)B->data)->axpy && !((Mat_Shell *)B->data)->left && !((Mat_Shell *)B->data)->right && !((Mat_Shell *)B->data)->dshift); 2079b68353e5Sstefano_zampini } 2080b68353e5Sstefano_zampini } 2081b68353e5Sstefano_zampini } 2082b68353e5Sstefano_zampini } 2083b68353e5Sstefano_zampini for (i = 0, nf = 0; i < nest->nr && fast; ++i) { 20849566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast)); 2085b68353e5Sstefano_zampini if (fast) { 2086b68353e5Sstefano_zampini PetscInt f, s; 2087b68353e5Sstefano_zampini 20889566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s)); 20899371c9d4SSatish Balay if (f != nf || s != 1) { 20909371c9d4SSatish Balay fast = PETSC_FALSE; 20919371c9d4SSatish Balay } else { 20929566063dSJacob Faibussowitsch PetscCall(ISGetSize(nest->isglobal.row[i], &f)); 2093b68353e5Sstefano_zampini nf += f; 2094b68353e5Sstefano_zampini } 2095b68353e5Sstefano_zampini } 2096b68353e5Sstefano_zampini } 2097b68353e5Sstefano_zampini for (i = 0, nf = 0; i < nest->nc && fast; ++i) { 20989566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast)); 2099b68353e5Sstefano_zampini if (fast) { 2100b68353e5Sstefano_zampini PetscInt f, s; 2101b68353e5Sstefano_zampini 21029566063dSJacob Faibussowitsch PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s)); 21039371c9d4SSatish Balay if (f != nf || s != 1) { 21049371c9d4SSatish Balay fast = PETSC_FALSE; 21059371c9d4SSatish Balay } else { 21069566063dSJacob Faibussowitsch PetscCall(ISGetSize(nest->isglobal.col[i], &f)); 2107b68353e5Sstefano_zampini nf += f; 2108b68353e5Sstefano_zampini } 2109b68353e5Sstefano_zampini } 2110b68353e5Sstefano_zampini } 2111b68353e5Sstefano_zampini if (fast) { 21129566063dSJacob Faibussowitsch PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat)); 21133ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2114b68353e5Sstefano_zampini } 2115b68353e5Sstefano_zampini } 21169566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, &N)); 21179566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, &n)); 21189566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend)); 2119d1487292SPierre Jolivet if (reuse == MAT_REUSE_MATRIX) C = *newmat; 2120d1487292SPierre Jolivet else { 21219566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C)); 21229566063dSJacob Faibussowitsch PetscCall(MatSetType(C, newtype)); 21239566063dSJacob Faibussowitsch PetscCall(MatSetSizes(C, m, n, M, N)); 2124629c3df2SDmitry Karpeev } 21259566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(2 * m, &dnnz)); 2126e30678d3SPierre Jolivet if (m) { 2127629c3df2SDmitry Karpeev onnz = dnnz + m; 2128629c3df2SDmitry Karpeev for (k = 0; k < m; k++) { 2129629c3df2SDmitry Karpeev dnnz[k] = 0; 2130629c3df2SDmitry Karpeev onnz[k] = 0; 2131629c3df2SDmitry Karpeev } 2132e30678d3SPierre Jolivet } 2133629c3df2SDmitry Karpeev for (j = 0; j < nest->nc; ++j) { 2134629c3df2SDmitry Karpeev IS bNis; 2135629c3df2SDmitry Karpeev PetscInt bN; 2136629c3df2SDmitry Karpeev const PetscInt *bNindices; 2137fd8a7442SPierre Jolivet PetscBool flg; 2138629c3df2SDmitry Karpeev /* Using global column indices and ISAllGather() is not scalable. */ 21399566063dSJacob Faibussowitsch PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 21409566063dSJacob Faibussowitsch PetscCall(ISGetSize(bNis, &bN)); 21419566063dSJacob Faibussowitsch PetscCall(ISGetIndices(bNis, &bNindices)); 2142629c3df2SDmitry Karpeev for (i = 0; i < nest->nr; ++i) { 2143629c3df2SDmitry Karpeev PetscSF bmsf; 2144649b366bSFande Kong PetscSFNode *iremote; 2145fd8a7442SPierre Jolivet Mat B = nest->m[i][j], D = NULL; 2146649b366bSFande Kong PetscInt bm, *sub_dnnz, *sub_onnz, br; 2147629c3df2SDmitry Karpeev const PetscInt *bmindices; 2148629c3df2SDmitry Karpeev if (!B) continue; 21499566063dSJacob Faibussowitsch PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 21509566063dSJacob Faibussowitsch PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 21519566063dSJacob Faibussowitsch PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf)); 21529566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &iremote)); 21539566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &sub_dnnz)); 21549566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(bm, &sub_onnz)); 2155649b366bSFande Kong for (k = 0; k < bm; ++k) { 2156649b366bSFande Kong sub_dnnz[k] = 0; 2157649b366bSFande Kong sub_onnz[k] = 0; 2158649b366bSFande Kong } 2159dead4d76SPierre Jolivet PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 2160fd8a7442SPierre Jolivet if (flg) { 2161fd8a7442SPierre Jolivet PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2162fd8a7442SPierre Jolivet PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2163fd8a7442SPierre Jolivet PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 2164fd8a7442SPierre Jolivet B = D; 2165fd8a7442SPierre Jolivet } 2166fd8a7442SPierre Jolivet PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 2167fd8a7442SPierre Jolivet if (flg) { 2168fd8a7442SPierre Jolivet if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 2169fd8a7442SPierre Jolivet else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 2170fd8a7442SPierre Jolivet B = D; 2171fd8a7442SPierre Jolivet } 2172629c3df2SDmitry Karpeev /* 2173629c3df2SDmitry Karpeev Locate the owners for all of the locally-owned global row indices for this row block. 2174629c3df2SDmitry Karpeev These determine the roots of PetscSF used to communicate preallocation data to row owners. 2175629c3df2SDmitry Karpeev The roots correspond to the dnnz and onnz entries; thus, there are two roots per row. 2176629c3df2SDmitry Karpeev */ 21779566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 2178629c3df2SDmitry Karpeev for (br = 0; br < bm; ++br) { 2179131c27b5Sprj- PetscInt row = bmindices[br], brncols, col; 2180629c3df2SDmitry Karpeev const PetscInt *brcols; 2181a4b3d3acSMatthew G Knepley PetscInt rowrel = 0; /* row's relative index on its owner rank */ 2182131c27b5Sprj- PetscMPIInt rowowner = 0; 21839566063dSJacob Faibussowitsch PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel)); 2184649b366bSFande Kong /* how many roots */ 21859371c9d4SSatish Balay iremote[br].rank = rowowner; 21869371c9d4SSatish Balay iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */ 2187649b366bSFande Kong /* get nonzero pattern */ 21889566063dSJacob Faibussowitsch PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL)); 2189629c3df2SDmitry Karpeev for (k = 0; k < brncols; k++) { 2190629c3df2SDmitry Karpeev col = bNindices[brcols[k]]; 2191649b366bSFande Kong if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) { 2192649b366bSFande Kong sub_dnnz[br]++; 2193649b366bSFande Kong } else { 2194649b366bSFande Kong sub_onnz[br]++; 2195649b366bSFande Kong } 2196629c3df2SDmitry Karpeev } 21979566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL)); 2198629c3df2SDmitry Karpeev } 2199fd8a7442SPierre Jolivet if (D) PetscCall(MatDestroy(&D)); 22009566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 2201629c3df2SDmitry Karpeev /* bsf will have to take care of disposing of bedges. */ 22029566063dSJacob Faibussowitsch PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 22039566063dSJacob Faibussowitsch PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 22049566063dSJacob Faibussowitsch PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 22059566063dSJacob Faibussowitsch PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 22069566063dSJacob Faibussowitsch PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 22079566063dSJacob Faibussowitsch PetscCall(PetscFree(sub_dnnz)); 22089566063dSJacob Faibussowitsch PetscCall(PetscFree(sub_onnz)); 22099566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&bmsf)); 2210629c3df2SDmitry Karpeev } 22119566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(bNis, &bNindices)); 22129566063dSJacob Faibussowitsch PetscCall(ISDestroy(&bNis)); 221365a4a0a3Sstefano_zampini } 221465a4a0a3Sstefano_zampini /* Resize preallocation if overestimated */ 221565a4a0a3Sstefano_zampini for (i = 0; i < m; i++) { 221665a4a0a3Sstefano_zampini dnnz[i] = PetscMin(dnnz[i], A->cmap->n); 221765a4a0a3Sstefano_zampini onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n); 2218629c3df2SDmitry Karpeev } 22199566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz)); 22209566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz)); 22219566063dSJacob Faibussowitsch PetscCall(PetscFree(dnnz)); 22229566063dSJacob Faibussowitsch PetscCall(MatAXPY_Dense_Nest(C, 1.0, A)); 2223ac530a7eSPierre Jolivet if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &C)); 2224ac530a7eSPierre Jolivet else *newmat = C; 22253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2226be705e3aSPierre Jolivet } 2227629c3df2SDmitry Karpeev 222866976f2fSJacob Faibussowitsch static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 2229d71ae5a4SJacob Faibussowitsch { 2230629c3df2SDmitry Karpeev Mat B; 2231be705e3aSPierre Jolivet PetscInt m, n, M, N; 2232be705e3aSPierre Jolivet 2233be705e3aSPierre Jolivet PetscFunctionBegin; 22349566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &M, &N)); 22359566063dSJacob Faibussowitsch PetscCall(MatGetLocalSize(A, &m, &n)); 2236be705e3aSPierre Jolivet if (reuse == MAT_REUSE_MATRIX) { 2237be705e3aSPierre Jolivet B = *newmat; 22389566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(B)); 2239be705e3aSPierre Jolivet } else { 22409566063dSJacob Faibussowitsch PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B)); 2241629c3df2SDmitry Karpeev } 22429566063dSJacob Faibussowitsch PetscCall(MatAXPY_Dense_Nest(B, 1.0, A)); 2243ac530a7eSPierre Jolivet if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B)); 2244ac530a7eSPierre Jolivet else if (reuse == MAT_INITIAL_MATRIX) *newmat = B; 22453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2246629c3df2SDmitry Karpeev } 2247629c3df2SDmitry Karpeev 224866976f2fSJacob Faibussowitsch static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has) 2249d71ae5a4SJacob Faibussowitsch { 22508b7d3b4bSBarry Smith Mat_Nest *bA = (Mat_Nest *)mat->data; 22513c6db4c4SPierre Jolivet MatOperation opAdd; 22528b7d3b4bSBarry Smith PetscInt i, j, nr = bA->nr, nc = bA->nc; 22538b7d3b4bSBarry Smith PetscBool flg; 22548b7d3b4bSBarry Smith 22554d86920dSPierre Jolivet PetscFunctionBegin; 225652c5f739Sprj- *has = PETSC_FALSE; 22573c6db4c4SPierre Jolivet if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) { 22583c6db4c4SPierre Jolivet opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD); 22598b7d3b4bSBarry Smith for (j = 0; j < nc; j++) { 22608b7d3b4bSBarry Smith for (i = 0; i < nr; i++) { 22618b7d3b4bSBarry Smith if (!bA->m[i][j]) continue; 22629566063dSJacob Faibussowitsch PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg)); 22633ba16761SJacob Faibussowitsch if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 22648b7d3b4bSBarry Smith } 22658b7d3b4bSBarry Smith } 22668b7d3b4bSBarry Smith } 22673c6db4c4SPierre Jolivet if (((void **)mat->ops)[op]) *has = PETSC_TRUE; 22683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 22698b7d3b4bSBarry Smith } 22708b7d3b4bSBarry Smith 2271659c6bb0SJed Brown /*MC 22722ef1f0ffSBarry Smith MATNEST - "nest" - Matrix type consisting of nested submatrices, each stored separately. 2273659c6bb0SJed Brown 2274659c6bb0SJed Brown Level: intermediate 2275659c6bb0SJed Brown 2276659c6bb0SJed Brown Notes: 227711a5261eSBarry Smith This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices. 2278659c6bb0SJed Brown It allows the use of symmetric and block formats for parts of multi-physics simulations. 227911a5261eSBarry Smith It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()` 2280659c6bb0SJed Brown 22818b7d3b4bSBarry Smith Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero 22828b7d3b4bSBarry Smith rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes 22838b7d3b4bSBarry Smith than the nest matrix. 22848b7d3b4bSBarry Smith 22851cc06b55SBarry Smith .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, 2286db781477SPatrick Sanan `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`, 2287db781477SPatrick Sanan `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 2288659c6bb0SJed Brown M*/ 2289d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A) 2290d71ae5a4SJacob Faibussowitsch { 2291c8883902SJed Brown Mat_Nest *s; 2292c8883902SJed Brown 2293c8883902SJed Brown PetscFunctionBegin; 22944dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&s)); 2295c8883902SJed Brown A->data = (void *)s; 2296e7c19651SJed Brown 2297e7c19651SJed Brown s->nr = -1; 2298e7c19651SJed Brown s->nc = -1; 22990298fd71SBarry Smith s->m = NULL; 2300e7c19651SJed Brown s->splitassembly = PETSC_FALSE; 2301c8883902SJed Brown 23029566063dSJacob Faibussowitsch PetscCall(PetscMemzero(A->ops, sizeof(*A->ops))); 230326fbe8dcSKarl Rupp 2304c8883902SJed Brown A->ops->mult = MatMult_Nest; 23059194d70fSJed Brown A->ops->multadd = MatMultAdd_Nest; 2306c8883902SJed Brown A->ops->multtranspose = MatMultTranspose_Nest; 23079194d70fSJed Brown A->ops->multtransposeadd = MatMultTransposeAdd_Nest; 2308f8170845SAlex Fikl A->ops->transpose = MatTranspose_Nest; 23090998551bSBlanca Mellado Pinto A->ops->multhermitiantranspose = MatMultHermitianTranspose_Nest; 23100998551bSBlanca Mellado Pinto A->ops->multhermitiantransposeadd = MatMultHermitianTransposeAdd_Nest; 2311c8883902SJed Brown A->ops->assemblybegin = MatAssemblyBegin_Nest; 2312c8883902SJed Brown A->ops->assemblyend = MatAssemblyEnd_Nest; 2313c8883902SJed Brown A->ops->zeroentries = MatZeroEntries_Nest; 2314c222c20dSDavid Ham A->ops->copy = MatCopy_Nest; 23156e76ffeaSPierre Jolivet A->ops->axpy = MatAXPY_Nest; 2316c8883902SJed Brown A->ops->duplicate = MatDuplicate_Nest; 23177dae84e0SHong Zhang A->ops->createsubmatrix = MatCreateSubMatrix_Nest; 2318c8883902SJed Brown A->ops->destroy = MatDestroy_Nest; 2319c8883902SJed Brown A->ops->view = MatView_Nest; 2320f4259b30SLisandro Dalcin A->ops->getvecs = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */ 2321c8883902SJed Brown A->ops->getlocalsubmatrix = MatGetLocalSubMatrix_Nest; 2322c8883902SJed Brown A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest; 2323429bac76SJed Brown A->ops->getdiagonal = MatGetDiagonal_Nest; 2324429bac76SJed Brown A->ops->diagonalscale = MatDiagonalScale_Nest; 2325a061e289SJed Brown A->ops->scale = MatScale_Nest; 2326a061e289SJed Brown A->ops->shift = MatShift_Nest; 232713135bc6SAlex Fikl A->ops->diagonalset = MatDiagonalSet_Nest; 2328f8170845SAlex Fikl A->ops->setrandom = MatSetRandom_Nest; 23298b7d3b4bSBarry Smith A->ops->hasoperation = MatHasOperation_Nest; 2330381b8e50SStefano Zampini A->ops->missingdiagonal = MatMissingDiagonal_Nest; 2331c8883902SJed Brown 2332f4259b30SLisandro Dalcin A->spptr = NULL; 2333c8883902SJed Brown A->assembled = PETSC_FALSE; 2334c8883902SJed Brown 2335c8883902SJed Brown /* expose Nest api's */ 23369566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest)); 23379566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest)); 23389566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest)); 23399566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest)); 23409566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest)); 23419566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest)); 23429566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest)); 23439566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest)); 23449566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ)); 23459566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ)); 23469566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ)); 23479566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS)); 23489566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense)); 23499566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense)); 23509566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense)); 23519566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense)); 2352c8883902SJed Brown 23539566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST)); 23543ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 2355c8883902SJed Brown } 2356