1 #include <../src/mat/impls/nest/matnestimpl.h> /*I "petscmat.h" I*/ 2 #include <../src/mat/impls/aij/seq/aij.h> 3 #include <../src/mat/impls/shell/shell.h> 4 #include <petscsf.h> 5 6 static PetscErrorCode MatSetUp_NestIS_Private(Mat, PetscInt, const IS[], PetscInt, const IS[]); 7 static PetscErrorCode MatCreateVecs_Nest(Mat, Vec *, Vec *); 8 static PetscErrorCode MatReset_Nest(Mat); 9 10 PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat, MatType, MatReuse, Mat *); 11 12 /* private functions */ 13 static PetscErrorCode MatNestGetSizes_Private(Mat A, PetscInt *m, PetscInt *n, PetscInt *M, PetscInt *N) 14 { 15 Mat_Nest *bA = (Mat_Nest *)A->data; 16 PetscInt i, j; 17 18 PetscFunctionBegin; 19 *m = *n = *M = *N = 0; 20 for (i = 0; i < bA->nr; i++) { /* rows */ 21 PetscInt sm, sM; 22 PetscCall(ISGetLocalSize(bA->isglobal.row[i], &sm)); 23 PetscCall(ISGetSize(bA->isglobal.row[i], &sM)); 24 *m += sm; 25 *M += sM; 26 } 27 for (j = 0; j < bA->nc; j++) { /* cols */ 28 PetscInt sn, sN; 29 PetscCall(ISGetLocalSize(bA->isglobal.col[j], &sn)); 30 PetscCall(ISGetSize(bA->isglobal.col[j], &sN)); 31 *n += sn; 32 *N += sN; 33 } 34 PetscFunctionReturn(PETSC_SUCCESS); 35 } 36 37 /* operations */ 38 static PetscErrorCode MatMult_Nest(Mat A, Vec x, Vec y) 39 { 40 Mat_Nest *bA = (Mat_Nest *)A->data; 41 Vec *bx = bA->right, *by = bA->left; 42 PetscInt i, j, nr = bA->nr, nc = bA->nc; 43 44 PetscFunctionBegin; 45 for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by[i])); 46 for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i])); 47 for (i = 0; i < nr; i++) { 48 PetscCall(VecZeroEntries(by[i])); 49 for (j = 0; j < nc; j++) { 50 if (!bA->m[i][j]) continue; 51 /* y[i] <- y[i] + A[i][j] * x[j] */ 52 PetscCall(MatMultAdd(bA->m[i][j], bx[j], by[i], by[i])); 53 } 54 } 55 for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by[i])); 56 for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i])); 57 PetscFunctionReturn(PETSC_SUCCESS); 58 } 59 60 static PetscErrorCode MatMultAdd_Nest(Mat A, Vec x, Vec y, Vec z) 61 { 62 Mat_Nest *bA = (Mat_Nest *)A->data; 63 Vec *bx = bA->right, *bz = bA->left; 64 PetscInt i, j, nr = bA->nr, nc = bA->nc; 65 66 PetscFunctionBegin; 67 for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(z, bA->isglobal.row[i], &bz[i])); 68 for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(x, bA->isglobal.col[i], &bx[i])); 69 for (i = 0; i < nr; i++) { 70 if (y != z) { 71 Vec by; 72 PetscCall(VecGetSubVector(y, bA->isglobal.row[i], &by)); 73 PetscCall(VecCopy(by, bz[i])); 74 PetscCall(VecRestoreSubVector(y, bA->isglobal.row[i], &by)); 75 } 76 for (j = 0; j < nc; j++) { 77 if (!bA->m[i][j]) continue; 78 /* y[i] <- y[i] + A[i][j] * x[j] */ 79 PetscCall(MatMultAdd(bA->m[i][j], bx[j], bz[i], bz[i])); 80 } 81 } 82 for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.row[i], &bz[i])); 83 for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.col[i], &bx[i])); 84 PetscFunctionReturn(PETSC_SUCCESS); 85 } 86 87 typedef struct { 88 Mat *workC; /* array of Mat with specific containers depending on the underlying MatMatMult implementation */ 89 PetscScalar *tarray; /* buffer for storing all temporary products A[i][j] B[j] */ 90 PetscInt *dm, *dn, k; /* displacements and number of submatrices */ 91 } Nest_Dense; 92 93 static PetscErrorCode MatProductNumeric_Nest_Dense(Mat C) 94 { 95 Mat_Nest *bA; 96 Nest_Dense *contents; 97 Mat viewB, viewC, productB, workC; 98 const PetscScalar *barray; 99 PetscScalar *carray; 100 PetscInt i, j, M, N, nr, nc, ldb, ldc; 101 Mat A, B; 102 103 PetscFunctionBegin; 104 MatCheckProduct(C, 1); 105 A = C->product->A; 106 B = C->product->B; 107 PetscCall(MatGetSize(B, NULL, &N)); 108 if (!N) { 109 PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 110 PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 111 PetscFunctionReturn(PETSC_SUCCESS); 112 } 113 contents = (Nest_Dense *)C->product->data; 114 PetscCheck(contents, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data empty"); 115 bA = (Mat_Nest *)A->data; 116 nr = bA->nr; 117 nc = bA->nc; 118 PetscCall(MatDenseGetLDA(B, &ldb)); 119 PetscCall(MatDenseGetLDA(C, &ldc)); 120 PetscCall(MatZeroEntries(C)); 121 PetscCall(MatDenseGetArrayRead(B, &barray)); 122 PetscCall(MatDenseGetArray(C, &carray)); 123 for (i = 0; i < nr; i++) { 124 PetscCall(ISGetSize(bA->isglobal.row[i], &M)); 125 PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dm[i + 1] - contents->dm[i], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset(carray, contents->dm[i]), &viewC)); 126 PetscCall(MatDenseSetLDA(viewC, ldc)); 127 for (j = 0; j < nc; j++) { 128 if (!bA->m[i][j]) continue; 129 PetscCall(ISGetSize(bA->isglobal.col[j], &M)); 130 PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB)); 131 PetscCall(MatDenseSetLDA(viewB, ldb)); 132 133 /* MatMatMultNumeric(bA->m[i][j],viewB,contents->workC[i*nc + j]); */ 134 workC = contents->workC[i * nc + j]; 135 productB = workC->product->B; 136 workC->product->B = viewB; /* use newly created dense matrix viewB */ 137 PetscCall(MatProductNumeric(workC)); 138 PetscCall(MatDestroy(&viewB)); 139 workC->product->B = productB; /* resume original B */ 140 141 /* C[i] <- workC + C[i] */ 142 PetscCall(MatAXPY(viewC, 1.0, contents->workC[i * nc + j], SAME_NONZERO_PATTERN)); 143 } 144 PetscCall(MatDestroy(&viewC)); 145 } 146 PetscCall(MatDenseRestoreArray(C, &carray)); 147 PetscCall(MatDenseRestoreArrayRead(B, &barray)); 148 149 PetscCall(MatSetOption(C, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 150 PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 151 PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 152 PetscFunctionReturn(PETSC_SUCCESS); 153 } 154 155 static PetscErrorCode MatNest_DenseDestroy(void *ctx) 156 { 157 Nest_Dense *contents = (Nest_Dense *)ctx; 158 PetscInt i; 159 160 PetscFunctionBegin; 161 PetscCall(PetscFree(contents->tarray)); 162 for (i = 0; i < contents->k; i++) PetscCall(MatDestroy(contents->workC + i)); 163 PetscCall(PetscFree3(contents->dm, contents->dn, contents->workC)); 164 PetscCall(PetscFree(contents)); 165 PetscFunctionReturn(PETSC_SUCCESS); 166 } 167 168 static PetscErrorCode MatProductSymbolic_Nest_Dense(Mat C) 169 { 170 Mat_Nest *bA; 171 Mat viewB, workC; 172 const PetscScalar *barray; 173 PetscInt i, j, M, N, m, n, nr, nc, maxm = 0, ldb; 174 Nest_Dense *contents = NULL; 175 PetscBool cisdense; 176 Mat A, B; 177 PetscReal fill; 178 179 PetscFunctionBegin; 180 MatCheckProduct(C, 1); 181 PetscCheck(!C->product->data, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Product data not empty"); 182 A = C->product->A; 183 B = C->product->B; 184 fill = C->product->fill; 185 bA = (Mat_Nest *)A->data; 186 nr = bA->nr; 187 nc = bA->nc; 188 PetscCall(MatGetLocalSize(C, &m, &n)); 189 PetscCall(MatGetSize(C, &M, &N)); 190 if (m == PETSC_DECIDE || n == PETSC_DECIDE || M == PETSC_DECIDE || N == PETSC_DECIDE) { 191 PetscCall(MatGetLocalSize(B, NULL, &n)); 192 PetscCall(MatGetSize(B, NULL, &N)); 193 PetscCall(MatGetLocalSize(A, &m, NULL)); 194 PetscCall(MatGetSize(A, &M, NULL)); 195 PetscCall(MatSetSizes(C, m, n, M, N)); 196 } 197 PetscCall(PetscObjectTypeCompareAny((PetscObject)C, &cisdense, MATSEQDENSE, MATMPIDENSE, MATSEQDENSECUDA, MATMPIDENSECUDA, "")); 198 if (!cisdense) PetscCall(MatSetType(C, ((PetscObject)B)->type_name)); 199 PetscCall(MatSetUp(C)); 200 if (!N) { 201 C->ops->productnumeric = MatProductNumeric_Nest_Dense; 202 PetscFunctionReturn(PETSC_SUCCESS); 203 } 204 205 PetscCall(PetscNew(&contents)); 206 C->product->data = contents; 207 C->product->destroy = MatNest_DenseDestroy; 208 PetscCall(PetscCalloc3(nr + 1, &contents->dm, nc + 1, &contents->dn, nr * nc, &contents->workC)); 209 contents->k = nr * nc; 210 for (i = 0; i < nr; i++) { 211 PetscCall(ISGetLocalSize(bA->isglobal.row[i], contents->dm + i + 1)); 212 maxm = PetscMax(maxm, contents->dm[i + 1]); 213 contents->dm[i + 1] += contents->dm[i]; 214 } 215 for (i = 0; i < nc; i++) { 216 PetscCall(ISGetLocalSize(bA->isglobal.col[i], contents->dn + i + 1)); 217 contents->dn[i + 1] += contents->dn[i]; 218 } 219 PetscCall(PetscMalloc1(maxm * N, &contents->tarray)); 220 PetscCall(MatDenseGetLDA(B, &ldb)); 221 PetscCall(MatGetSize(B, NULL, &N)); 222 PetscCall(MatDenseGetArrayRead(B, &barray)); 223 /* loops are permuted compared to MatMatMultNumeric so that viewB is created only once per column of A */ 224 for (j = 0; j < nc; j++) { 225 PetscCall(ISGetSize(bA->isglobal.col[j], &M)); 226 PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), contents->dn[j + 1] - contents->dn[j], PETSC_DECIDE, M, N, PetscSafePointerPlusOffset((PetscScalar *)barray, contents->dn[j]), &viewB)); 227 PetscCall(MatDenseSetLDA(viewB, ldb)); 228 for (i = 0; i < nr; i++) { 229 if (!bA->m[i][j]) continue; 230 /* MatMatMultSymbolic may attach a specific container (depending on MatType of bA->m[i][j]) to workC[i][j] */ 231 232 PetscCall(MatProductCreate(bA->m[i][j], viewB, NULL, &contents->workC[i * nc + j])); 233 workC = contents->workC[i * nc + j]; 234 PetscCall(MatProductSetType(workC, MATPRODUCT_AB)); 235 PetscCall(MatProductSetAlgorithm(workC, "default")); 236 PetscCall(MatProductSetFill(workC, fill)); 237 PetscCall(MatProductSetFromOptions(workC)); 238 PetscCall(MatProductSymbolic(workC)); 239 240 /* since tarray will be shared by all Mat */ 241 PetscCall(MatSeqDenseSetPreallocation(workC, contents->tarray)); 242 PetscCall(MatMPIDenseSetPreallocation(workC, contents->tarray)); 243 } 244 PetscCall(MatDestroy(&viewB)); 245 } 246 PetscCall(MatDenseRestoreArrayRead(B, &barray)); 247 248 C->ops->productnumeric = MatProductNumeric_Nest_Dense; 249 PetscFunctionReturn(PETSC_SUCCESS); 250 } 251 252 static PetscErrorCode MatProductSetFromOptions_Nest_Dense(Mat C) 253 { 254 Mat_Product *product = C->product; 255 256 PetscFunctionBegin; 257 if (product->type == MATPRODUCT_AB) C->ops->productsymbolic = MatProductSymbolic_Nest_Dense; 258 PetscFunctionReturn(PETSC_SUCCESS); 259 } 260 261 static PetscErrorCode MatMultTransposeKernel_Nest(Mat A, Vec x, Vec y, PetscBool herm) 262 { 263 Mat_Nest *bA = (Mat_Nest *)A->data; 264 Vec *bx = bA->left, *by = bA->right; 265 PetscInt i, j, nr = bA->nr, nc = bA->nc; 266 267 PetscFunctionBegin; 268 for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 269 for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(y, bA->isglobal.col[i], &by[i])); 270 for (j = 0; j < nc; j++) { 271 PetscCall(VecZeroEntries(by[j])); 272 for (i = 0; i < nr; i++) { 273 if (!bA->m[i][j]) continue; 274 if (herm) PetscCall(MatMultHermitianTransposeAdd(bA->m[i][j], bx[i], by[j], by[j])); /* y[j] <- y[j] + (A[i][j])^H * x[i] */ 275 else PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], by[j], by[j])); /* y[j] <- y[j] + (A[i][j])^T * x[i] */ 276 } 277 } 278 for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 279 for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(y, bA->isglobal.col[i], &by[i])); 280 PetscFunctionReturn(PETSC_SUCCESS); 281 } 282 283 static PetscErrorCode MatMultTranspose_Nest(Mat A, Vec x, Vec y) 284 { 285 PetscFunctionBegin; 286 PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_FALSE)); 287 PetscFunctionReturn(PETSC_SUCCESS); 288 } 289 290 static PetscErrorCode MatMultHermitianTranspose_Nest(Mat A, Vec x, Vec y) 291 { 292 PetscFunctionBegin; 293 PetscCall(MatMultTransposeKernel_Nest(A, x, y, PETSC_TRUE)); 294 PetscFunctionReturn(PETSC_SUCCESS); 295 } 296 297 static PetscErrorCode MatMultTransposeAddKernel_Nest(Mat A, Vec x, Vec y, Vec z, PetscBool herm) 298 { 299 Mat_Nest *bA = (Mat_Nest *)A->data; 300 Vec *bx = bA->left, *bz = bA->right; 301 PetscInt i, j, nr = bA->nr, nc = bA->nc; 302 303 PetscFunctionBegin; 304 for (i = 0; i < nr; i++) PetscCall(VecGetSubVector(x, bA->isglobal.row[i], &bx[i])); 305 for (i = 0; i < nc; i++) PetscCall(VecGetSubVector(z, bA->isglobal.col[i], &bz[i])); 306 for (j = 0; j < nc; j++) { 307 if (y != z) { 308 Vec by; 309 PetscCall(VecGetSubVector(y, bA->isglobal.col[j], &by)); 310 PetscCall(VecCopy(by, bz[j])); 311 PetscCall(VecRestoreSubVector(y, bA->isglobal.col[j], &by)); 312 } 313 for (i = 0; i < nr; i++) { 314 if (!bA->m[i][j]) continue; 315 if (herm) PetscCall(MatMultHermitianTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j])); /* z[j] <- y[j] + (A[i][j])^H * x[i] */ 316 else PetscCall(MatMultTransposeAdd(bA->m[i][j], bx[i], bz[j], bz[j])); /* z[j] <- y[j] + (A[i][j])^T * x[i] */ 317 } 318 } 319 for (i = 0; i < nr; i++) PetscCall(VecRestoreSubVector(x, bA->isglobal.row[i], &bx[i])); 320 for (i = 0; i < nc; i++) PetscCall(VecRestoreSubVector(z, bA->isglobal.col[i], &bz[i])); 321 PetscFunctionReturn(PETSC_SUCCESS); 322 } 323 324 static PetscErrorCode MatMultTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z) 325 { 326 PetscFunctionBegin; 327 PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_FALSE)); 328 PetscFunctionReturn(PETSC_SUCCESS); 329 } 330 331 static PetscErrorCode MatMultHermitianTransposeAdd_Nest(Mat A, Vec x, Vec y, Vec z) 332 { 333 PetscFunctionBegin; 334 PetscCall(MatMultTransposeAddKernel_Nest(A, x, y, z, PETSC_TRUE)); 335 PetscFunctionReturn(PETSC_SUCCESS); 336 } 337 338 static PetscErrorCode MatTranspose_Nest(Mat A, MatReuse reuse, Mat *B) 339 { 340 Mat_Nest *bA = (Mat_Nest *)A->data, *bC; 341 Mat C; 342 PetscInt i, j, nr = bA->nr, nc = bA->nc; 343 344 PetscFunctionBegin; 345 if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B)); 346 PetscCheck(reuse != MAT_INPLACE_MATRIX || nr == nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Square nested matrix only for in-place"); 347 348 if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) { 349 Mat *subs; 350 IS *is_row, *is_col; 351 352 PetscCall(PetscCalloc1(nr * nc, &subs)); 353 PetscCall(PetscMalloc2(nr, &is_row, nc, &is_col)); 354 PetscCall(MatNestGetISs(A, is_row, is_col)); 355 if (reuse == MAT_INPLACE_MATRIX) { 356 for (i = 0; i < nr; i++) { 357 for (j = 0; j < nc; j++) subs[i + nr * j] = bA->m[i][j]; 358 } 359 } 360 361 PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nc, is_col, nr, is_row, subs, &C)); 362 PetscCall(PetscFree(subs)); 363 PetscCall(PetscFree2(is_row, is_col)); 364 } else { 365 C = *B; 366 } 367 368 bC = (Mat_Nest *)C->data; 369 for (i = 0; i < nr; i++) { 370 for (j = 0; j < nc; j++) { 371 if (bA->m[i][j]) { 372 PetscCall(MatTranspose(bA->m[i][j], reuse, &bC->m[j][i])); 373 } else { 374 bC->m[j][i] = NULL; 375 } 376 } 377 } 378 379 if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) { 380 *B = C; 381 } else { 382 PetscCall(MatHeaderMerge(A, &C)); 383 } 384 PetscFunctionReturn(PETSC_SUCCESS); 385 } 386 387 static PetscErrorCode MatNestDestroyISList(PetscInt n, IS **list) 388 { 389 IS *lst = *list; 390 PetscInt i; 391 392 PetscFunctionBegin; 393 if (!lst) PetscFunctionReturn(PETSC_SUCCESS); 394 for (i = 0; i < n; i++) 395 if (lst[i]) PetscCall(ISDestroy(&lst[i])); 396 PetscCall(PetscFree(lst)); 397 *list = NULL; 398 PetscFunctionReturn(PETSC_SUCCESS); 399 } 400 401 static PetscErrorCode MatReset_Nest(Mat A) 402 { 403 Mat_Nest *vs = (Mat_Nest *)A->data; 404 PetscInt i, j; 405 406 PetscFunctionBegin; 407 /* release the matrices and the place holders */ 408 PetscCall(MatNestDestroyISList(vs->nr, &vs->isglobal.row)); 409 PetscCall(MatNestDestroyISList(vs->nc, &vs->isglobal.col)); 410 PetscCall(MatNestDestroyISList(vs->nr, &vs->islocal.row)); 411 PetscCall(MatNestDestroyISList(vs->nc, &vs->islocal.col)); 412 413 PetscCall(PetscFree(vs->row_len)); 414 PetscCall(PetscFree(vs->col_len)); 415 PetscCall(PetscFree(vs->nnzstate)); 416 417 PetscCall(PetscFree2(vs->left, vs->right)); 418 419 /* release the matrices and the place holders */ 420 if (vs->m) { 421 for (i = 0; i < vs->nr; i++) { 422 for (j = 0; j < vs->nc; j++) PetscCall(MatDestroy(&vs->m[i][j])); 423 } 424 PetscCall(PetscFree(vs->m[0])); 425 PetscCall(PetscFree(vs->m)); 426 } 427 428 /* restore defaults */ 429 vs->nr = 0; 430 vs->nc = 0; 431 vs->splitassembly = PETSC_FALSE; 432 PetscFunctionReturn(PETSC_SUCCESS); 433 } 434 435 static PetscErrorCode MatDestroy_Nest(Mat A) 436 { 437 PetscFunctionBegin; 438 PetscCall(MatReset_Nest(A)); 439 PetscCall(PetscFree(A->data)); 440 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", NULL)); 441 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", NULL)); 442 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", NULL)); 443 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", NULL)); 444 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", NULL)); 445 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", NULL)); 446 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", NULL)); 447 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", NULL)); 448 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", NULL)); 449 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", NULL)); 450 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", NULL)); 451 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", NULL)); 452 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", NULL)); 453 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", NULL)); 454 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", NULL)); 455 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", NULL)); 456 PetscFunctionReturn(PETSC_SUCCESS); 457 } 458 459 static PetscErrorCode MatMissingDiagonal_Nest(Mat mat, PetscBool *missing, PetscInt *dd) 460 { 461 Mat_Nest *vs = (Mat_Nest *)mat->data; 462 PetscInt i; 463 464 PetscFunctionBegin; 465 if (dd) *dd = 0; 466 if (!vs->nr) { 467 *missing = PETSC_TRUE; 468 PetscFunctionReturn(PETSC_SUCCESS); 469 } 470 *missing = PETSC_FALSE; 471 for (i = 0; i < vs->nr && !*missing; i++) { 472 *missing = PETSC_TRUE; 473 if (vs->m[i][i]) { 474 PetscCall(MatMissingDiagonal(vs->m[i][i], missing, NULL)); 475 PetscCheck(!*missing || !dd, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "First missing entry not yet implemented"); 476 } 477 } 478 PetscFunctionReturn(PETSC_SUCCESS); 479 } 480 481 static PetscErrorCode MatAssemblyBegin_Nest(Mat A, MatAssemblyType type) 482 { 483 Mat_Nest *vs = (Mat_Nest *)A->data; 484 PetscInt i, j; 485 PetscBool nnzstate = PETSC_FALSE; 486 487 PetscFunctionBegin; 488 for (i = 0; i < vs->nr; i++) { 489 for (j = 0; j < vs->nc; j++) { 490 PetscObjectState subnnzstate = 0; 491 if (vs->m[i][j]) { 492 PetscCall(MatAssemblyBegin(vs->m[i][j], type)); 493 if (!vs->splitassembly) { 494 /* Note: split assembly will fail if the same block appears more than once (even indirectly through a nested 495 * sub-block). This could be fixed by adding a flag to Mat so that there was a way to check if a Mat was 496 * already performing an assembly, but the result would by more complicated and appears to offer less 497 * potential for diagnostics and correctness checking. Split assembly should be fixed once there is an 498 * interface for libraries to make asynchronous progress in "user-defined non-blocking collectives". 499 */ 500 PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 501 PetscCall(MatGetNonzeroState(vs->m[i][j], &subnnzstate)); 502 } 503 } 504 nnzstate = (PetscBool)(nnzstate || vs->nnzstate[i * vs->nc + j] != subnnzstate); 505 vs->nnzstate[i * vs->nc + j] = subnnzstate; 506 } 507 } 508 if (nnzstate) A->nonzerostate++; 509 PetscFunctionReturn(PETSC_SUCCESS); 510 } 511 512 static PetscErrorCode MatAssemblyEnd_Nest(Mat A, MatAssemblyType type) 513 { 514 Mat_Nest *vs = (Mat_Nest *)A->data; 515 PetscInt i, j; 516 517 PetscFunctionBegin; 518 for (i = 0; i < vs->nr; i++) { 519 for (j = 0; j < vs->nc; j++) { 520 if (vs->m[i][j]) { 521 if (vs->splitassembly) PetscCall(MatAssemblyEnd(vs->m[i][j], type)); 522 } 523 } 524 } 525 PetscFunctionReturn(PETSC_SUCCESS); 526 } 527 528 static PetscErrorCode MatNestFindNonzeroSubMatRow(Mat A, PetscInt row, Mat *B) 529 { 530 Mat_Nest *vs = (Mat_Nest *)A->data; 531 PetscInt j; 532 Mat sub; 533 534 PetscFunctionBegin; 535 sub = (row < vs->nc) ? vs->m[row][row] : (Mat)NULL; /* Prefer to find on the diagonal */ 536 for (j = 0; !sub && j < vs->nc; j++) sub = vs->m[row][j]; 537 if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 538 *B = sub; 539 PetscFunctionReturn(PETSC_SUCCESS); 540 } 541 542 static PetscErrorCode MatNestFindNonzeroSubMatCol(Mat A, PetscInt col, Mat *B) 543 { 544 Mat_Nest *vs = (Mat_Nest *)A->data; 545 PetscInt i; 546 Mat sub; 547 548 PetscFunctionBegin; 549 sub = (col < vs->nr) ? vs->m[col][col] : (Mat)NULL; /* Prefer to find on the diagonal */ 550 for (i = 0; !sub && i < vs->nr; i++) sub = vs->m[i][col]; 551 if (sub) PetscCall(MatSetUp(sub)); /* Ensure that the sizes are available */ 552 *B = sub; 553 PetscFunctionReturn(PETSC_SUCCESS); 554 } 555 556 static PetscErrorCode MatNestFindISRange(Mat A, PetscInt n, const IS list[], IS is, PetscInt *begin, PetscInt *end) 557 { 558 PetscInt i, j, size, m; 559 PetscBool flg; 560 IS out, concatenate[2]; 561 562 PetscFunctionBegin; 563 PetscAssertPointer(list, 3); 564 PetscValidHeaderSpecific(is, IS_CLASSID, 4); 565 if (begin) { 566 PetscAssertPointer(begin, 5); 567 *begin = -1; 568 } 569 if (end) { 570 PetscAssertPointer(end, 6); 571 *end = -1; 572 } 573 for (i = 0; i < n; i++) { 574 if (!list[i]) continue; 575 PetscCall(ISEqualUnsorted(list[i], is, &flg)); 576 if (flg) { 577 if (begin) *begin = i; 578 if (end) *end = i + 1; 579 PetscFunctionReturn(PETSC_SUCCESS); 580 } 581 } 582 PetscCall(ISGetSize(is, &size)); 583 for (i = 0; i < n - 1; i++) { 584 if (!list[i]) continue; 585 m = 0; 586 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, list + i, &out)); 587 PetscCall(ISGetSize(out, &m)); 588 for (j = i + 2; j < n && m < size; j++) { 589 if (list[j]) { 590 concatenate[0] = out; 591 concatenate[1] = list[j]; 592 PetscCall(ISConcatenate(PetscObjectComm((PetscObject)A), 2, concatenate, &out)); 593 PetscCall(ISDestroy(concatenate)); 594 PetscCall(ISGetSize(out, &m)); 595 } 596 } 597 if (m == size) { 598 PetscCall(ISEqualUnsorted(out, is, &flg)); 599 if (flg) { 600 if (begin) *begin = i; 601 if (end) *end = j; 602 PetscCall(ISDestroy(&out)); 603 PetscFunctionReturn(PETSC_SUCCESS); 604 } 605 } 606 PetscCall(ISDestroy(&out)); 607 } 608 PetscFunctionReturn(PETSC_SUCCESS); 609 } 610 611 static PetscErrorCode MatNestFillEmptyMat_Private(Mat A, PetscInt i, PetscInt j, Mat *B) 612 { 613 Mat_Nest *vs = (Mat_Nest *)A->data; 614 PetscInt lr, lc; 615 616 PetscFunctionBegin; 617 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), B)); 618 PetscCall(ISGetLocalSize(vs->isglobal.row[i], &lr)); 619 PetscCall(ISGetLocalSize(vs->isglobal.col[j], &lc)); 620 PetscCall(MatSetSizes(*B, lr, lc, PETSC_DECIDE, PETSC_DECIDE)); 621 PetscCall(MatSetType(*B, MATAIJ)); 622 PetscCall(MatSeqAIJSetPreallocation(*B, 0, NULL)); 623 PetscCall(MatMPIAIJSetPreallocation(*B, 0, NULL, 0, NULL)); 624 PetscCall(MatSetUp(*B)); 625 PetscCall(MatSetOption(*B, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 626 PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 627 PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 628 PetscFunctionReturn(PETSC_SUCCESS); 629 } 630 631 static PetscErrorCode MatNestGetBlock_Private(Mat A, PetscInt rbegin, PetscInt rend, PetscInt cbegin, PetscInt cend, Mat *B) 632 { 633 Mat_Nest *vs = (Mat_Nest *)A->data; 634 Mat *a; 635 PetscInt i, j, k, l, nr = rend - rbegin, nc = cend - cbegin; 636 char keyname[256]; 637 PetscBool *b; 638 PetscBool flg; 639 640 PetscFunctionBegin; 641 *B = NULL; 642 PetscCall(PetscSNPrintf(keyname, sizeof(keyname), "NestBlock_%" PetscInt_FMT "-%" PetscInt_FMT "x%" PetscInt_FMT "-%" PetscInt_FMT, rbegin, rend, cbegin, cend)); 643 PetscCall(PetscObjectQuery((PetscObject)A, keyname, (PetscObject *)B)); 644 if (*B) PetscFunctionReturn(PETSC_SUCCESS); 645 646 PetscCall(PetscMalloc2(nr * nc, &a, nr * nc, &b)); 647 for (i = 0; i < nr; i++) { 648 for (j = 0; j < nc; j++) { 649 a[i * nc + j] = vs->m[rbegin + i][cbegin + j]; 650 b[i * nc + j] = PETSC_FALSE; 651 } 652 } 653 if (nc != vs->nc && nr != vs->nr) { 654 for (i = 0; i < nr; i++) { 655 for (j = 0; j < nc; j++) { 656 flg = PETSC_FALSE; 657 for (k = 0; (k < nr && !flg); k++) { 658 if (a[j + k * nc]) flg = PETSC_TRUE; 659 } 660 if (flg) { 661 flg = PETSC_FALSE; 662 for (l = 0; (l < nc && !flg); l++) { 663 if (a[i * nc + l]) flg = PETSC_TRUE; 664 } 665 } 666 if (!flg) { 667 b[i * nc + j] = PETSC_TRUE; 668 PetscCall(MatNestFillEmptyMat_Private(A, rbegin + i, cbegin + j, a + i * nc + j)); 669 } 670 } 671 } 672 } 673 PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, nr != vs->nr ? NULL : vs->isglobal.row, nc, nc != vs->nc ? NULL : vs->isglobal.col, a, B)); 674 for (i = 0; i < nr; i++) { 675 for (j = 0; j < nc; j++) { 676 if (b[i * nc + j]) PetscCall(MatDestroy(a + i * nc + j)); 677 } 678 } 679 PetscCall(PetscFree2(a, b)); 680 (*B)->assembled = A->assembled; 681 PetscCall(PetscObjectCompose((PetscObject)A, keyname, (PetscObject)*B)); 682 PetscCall(PetscObjectDereference((PetscObject)*B)); /* Leave the only remaining reference in the composition */ 683 PetscFunctionReturn(PETSC_SUCCESS); 684 } 685 686 static PetscErrorCode MatNestFindSubMat(Mat A, struct MatNestISPair *is, IS isrow, IS iscol, Mat *B) 687 { 688 Mat_Nest *vs = (Mat_Nest *)A->data; 689 PetscInt rbegin, rend, cbegin, cend; 690 691 PetscFunctionBegin; 692 PetscCall(MatNestFindISRange(A, vs->nr, is->row, isrow, &rbegin, &rend)); 693 PetscCall(MatNestFindISRange(A, vs->nc, is->col, iscol, &cbegin, &cend)); 694 if (rend == rbegin + 1 && cend == cbegin + 1) { 695 if (!vs->m[rbegin][cbegin]) PetscCall(MatNestFillEmptyMat_Private(A, rbegin, cbegin, vs->m[rbegin] + cbegin)); 696 *B = vs->m[rbegin][cbegin]; 697 } else if (rbegin != -1 && cbegin != -1) { 698 PetscCall(MatNestGetBlock_Private(A, rbegin, rend, cbegin, cend, B)); 699 } else SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_INCOMP, "Could not find index set"); 700 PetscFunctionReturn(PETSC_SUCCESS); 701 } 702 703 /* 704 TODO: This does not actually returns a submatrix we can modify 705 */ 706 static PetscErrorCode MatCreateSubMatrix_Nest(Mat A, IS isrow, IS iscol, MatReuse reuse, Mat *B) 707 { 708 Mat_Nest *vs = (Mat_Nest *)A->data; 709 Mat sub; 710 711 PetscFunctionBegin; 712 PetscCall(MatNestFindSubMat(A, &vs->isglobal, isrow, iscol, &sub)); 713 switch (reuse) { 714 case MAT_INITIAL_MATRIX: 715 if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 716 *B = sub; 717 break; 718 case MAT_REUSE_MATRIX: 719 PetscCheck(sub == *B, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Submatrix was not used before in this call"); 720 break; 721 case MAT_IGNORE_MATRIX: /* Nothing to do */ 722 break; 723 case MAT_INPLACE_MATRIX: /* Nothing to do */ 724 SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "MAT_INPLACE_MATRIX is not supported yet"); 725 } 726 PetscFunctionReturn(PETSC_SUCCESS); 727 } 728 729 static PetscErrorCode MatGetLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) 730 { 731 Mat_Nest *vs = (Mat_Nest *)A->data; 732 Mat sub; 733 734 PetscFunctionBegin; 735 PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 736 /* We allow the submatrix to be NULL, perhaps it would be better for the user to return an empty matrix instead */ 737 if (sub) PetscCall(PetscObjectReference((PetscObject)sub)); 738 *B = sub; 739 PetscFunctionReturn(PETSC_SUCCESS); 740 } 741 742 static PetscErrorCode MatRestoreLocalSubMatrix_Nest(Mat A, IS isrow, IS iscol, Mat *B) 743 { 744 Mat_Nest *vs = (Mat_Nest *)A->data; 745 Mat sub; 746 747 PetscFunctionBegin; 748 PetscCall(MatNestFindSubMat(A, &vs->islocal, isrow, iscol, &sub)); 749 PetscCheck(*B == sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has not been gotten"); 750 if (sub) { 751 PetscCheck(((PetscObject)sub)->refct > 1, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Local submatrix has had reference count decremented too many times"); 752 PetscCall(MatDestroy(B)); 753 } 754 PetscFunctionReturn(PETSC_SUCCESS); 755 } 756 757 static PetscErrorCode MatGetDiagonal_Nest(Mat A, Vec v) 758 { 759 Mat_Nest *bA = (Mat_Nest *)A->data; 760 PetscInt i; 761 762 PetscFunctionBegin; 763 for (i = 0; i < bA->nr; i++) { 764 Vec bv; 765 PetscCall(VecGetSubVector(v, bA->isglobal.row[i], &bv)); 766 if (bA->m[i][i]) { 767 PetscCall(MatGetDiagonal(bA->m[i][i], bv)); 768 } else { 769 PetscCall(VecSet(bv, 0.0)); 770 } 771 PetscCall(VecRestoreSubVector(v, bA->isglobal.row[i], &bv)); 772 } 773 PetscFunctionReturn(PETSC_SUCCESS); 774 } 775 776 static PetscErrorCode MatDiagonalScale_Nest(Mat A, Vec l, Vec r) 777 { 778 Mat_Nest *bA = (Mat_Nest *)A->data; 779 Vec bl, *br; 780 PetscInt i, j; 781 782 PetscFunctionBegin; 783 PetscCall(PetscCalloc1(bA->nc, &br)); 784 if (r) { 785 for (j = 0; j < bA->nc; j++) PetscCall(VecGetSubVector(r, bA->isglobal.col[j], &br[j])); 786 } 787 bl = NULL; 788 for (i = 0; i < bA->nr; i++) { 789 if (l) PetscCall(VecGetSubVector(l, bA->isglobal.row[i], &bl)); 790 for (j = 0; j < bA->nc; j++) { 791 if (bA->m[i][j]) PetscCall(MatDiagonalScale(bA->m[i][j], bl, br[j])); 792 } 793 if (l) PetscCall(VecRestoreSubVector(l, bA->isglobal.row[i], &bl)); 794 } 795 if (r) { 796 for (j = 0; j < bA->nc; j++) PetscCall(VecRestoreSubVector(r, bA->isglobal.col[j], &br[j])); 797 } 798 PetscCall(PetscFree(br)); 799 PetscFunctionReturn(PETSC_SUCCESS); 800 } 801 802 static PetscErrorCode MatScale_Nest(Mat A, PetscScalar a) 803 { 804 Mat_Nest *bA = (Mat_Nest *)A->data; 805 PetscInt i, j; 806 807 PetscFunctionBegin; 808 for (i = 0; i < bA->nr; i++) { 809 for (j = 0; j < bA->nc; j++) { 810 if (bA->m[i][j]) PetscCall(MatScale(bA->m[i][j], a)); 811 } 812 } 813 PetscFunctionReturn(PETSC_SUCCESS); 814 } 815 816 static PetscErrorCode MatShift_Nest(Mat A, PetscScalar a) 817 { 818 Mat_Nest *bA = (Mat_Nest *)A->data; 819 PetscInt i; 820 PetscBool nnzstate = PETSC_FALSE; 821 822 PetscFunctionBegin; 823 for (i = 0; i < bA->nr; i++) { 824 PetscObjectState subnnzstate = 0; 825 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); 826 PetscCall(MatShift(bA->m[i][i], a)); 827 PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 828 nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 829 bA->nnzstate[i * bA->nc + i] = subnnzstate; 830 } 831 if (nnzstate) A->nonzerostate++; 832 PetscFunctionReturn(PETSC_SUCCESS); 833 } 834 835 static PetscErrorCode MatDiagonalSet_Nest(Mat A, Vec D, InsertMode is) 836 { 837 Mat_Nest *bA = (Mat_Nest *)A->data; 838 PetscInt i; 839 PetscBool nnzstate = PETSC_FALSE; 840 841 PetscFunctionBegin; 842 for (i = 0; i < bA->nr; i++) { 843 PetscObjectState subnnzstate = 0; 844 Vec bv; 845 PetscCall(VecGetSubVector(D, bA->isglobal.row[i], &bv)); 846 if (bA->m[i][i]) { 847 PetscCall(MatDiagonalSet(bA->m[i][i], bv, is)); 848 PetscCall(MatGetNonzeroState(bA->m[i][i], &subnnzstate)); 849 } 850 PetscCall(VecRestoreSubVector(D, bA->isglobal.row[i], &bv)); 851 nnzstate = (PetscBool)(nnzstate || bA->nnzstate[i * bA->nc + i] != subnnzstate); 852 bA->nnzstate[i * bA->nc + i] = subnnzstate; 853 } 854 if (nnzstate) A->nonzerostate++; 855 PetscFunctionReturn(PETSC_SUCCESS); 856 } 857 858 static PetscErrorCode MatSetRandom_Nest(Mat A, PetscRandom rctx) 859 { 860 Mat_Nest *bA = (Mat_Nest *)A->data; 861 PetscInt i, j; 862 863 PetscFunctionBegin; 864 for (i = 0; i < bA->nr; i++) { 865 for (j = 0; j < bA->nc; j++) { 866 if (bA->m[i][j]) PetscCall(MatSetRandom(bA->m[i][j], rctx)); 867 } 868 } 869 PetscFunctionReturn(PETSC_SUCCESS); 870 } 871 872 static PetscErrorCode MatCreateVecs_Nest(Mat A, Vec *right, Vec *left) 873 { 874 Mat_Nest *bA = (Mat_Nest *)A->data; 875 Vec *L, *R; 876 MPI_Comm comm; 877 PetscInt i, j; 878 879 PetscFunctionBegin; 880 PetscCall(PetscObjectGetComm((PetscObject)A, &comm)); 881 if (right) { 882 /* allocate R */ 883 PetscCall(PetscMalloc1(bA->nc, &R)); 884 /* Create the right vectors */ 885 for (j = 0; j < bA->nc; j++) { 886 for (i = 0; i < bA->nr; i++) { 887 if (bA->m[i][j]) { 888 PetscCall(MatCreateVecs(bA->m[i][j], &R[j], NULL)); 889 break; 890 } 891 } 892 PetscCheck(i != bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null column."); 893 } 894 PetscCall(VecCreateNest(comm, bA->nc, bA->isglobal.col, R, right)); 895 /* hand back control to the nest vector */ 896 for (j = 0; j < bA->nc; j++) PetscCall(VecDestroy(&R[j])); 897 PetscCall(PetscFree(R)); 898 } 899 900 if (left) { 901 /* allocate L */ 902 PetscCall(PetscMalloc1(bA->nr, &L)); 903 /* Create the left vectors */ 904 for (i = 0; i < bA->nr; i++) { 905 for (j = 0; j < bA->nc; j++) { 906 if (bA->m[i][j]) { 907 PetscCall(MatCreateVecs(bA->m[i][j], NULL, &L[i])); 908 break; 909 } 910 } 911 PetscCheck(j != bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Mat(Nest) contains a null row."); 912 } 913 914 PetscCall(VecCreateNest(comm, bA->nr, bA->isglobal.row, L, left)); 915 for (i = 0; i < bA->nr; i++) PetscCall(VecDestroy(&L[i])); 916 917 PetscCall(PetscFree(L)); 918 } 919 PetscFunctionReturn(PETSC_SUCCESS); 920 } 921 922 static PetscErrorCode MatView_Nest(Mat A, PetscViewer viewer) 923 { 924 Mat_Nest *bA = (Mat_Nest *)A->data; 925 PetscBool isascii, viewSub = PETSC_FALSE; 926 PetscInt i, j; 927 928 PetscFunctionBegin; 929 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 930 if (isascii) { 931 PetscCall(PetscOptionsGetBool(((PetscObject)A)->options, ((PetscObject)A)->prefix, "-mat_view_nest_sub", &viewSub, NULL)); 932 PetscCall(PetscViewerASCIIPrintf(viewer, "Matrix object:\n")); 933 PetscCall(PetscViewerASCIIPushTab(viewer)); 934 PetscCall(PetscViewerASCIIPrintf(viewer, "type=nest, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", bA->nr, bA->nc)); 935 936 PetscCall(PetscViewerASCIIPrintf(viewer, "MatNest structure:\n")); 937 for (i = 0; i < bA->nr; i++) { 938 for (j = 0; j < bA->nc; j++) { 939 MatType type; 940 char name[256] = "", prefix[256] = ""; 941 PetscInt NR, NC; 942 PetscBool isNest = PETSC_FALSE; 943 944 if (!bA->m[i][j]) { 945 PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : NULL\n", i, j)); 946 continue; 947 } 948 PetscCall(MatGetSize(bA->m[i][j], &NR, &NC)); 949 PetscCall(MatGetType(bA->m[i][j], &type)); 950 if (((PetscObject)bA->m[i][j])->name) PetscCall(PetscSNPrintf(name, sizeof(name), "name=\"%s\", ", ((PetscObject)bA->m[i][j])->name)); 951 if (((PetscObject)bA->m[i][j])->prefix) PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "prefix=\"%s\", ", ((PetscObject)bA->m[i][j])->prefix)); 952 PetscCall(PetscObjectTypeCompare((PetscObject)bA->m[i][j], MATNEST, &isNest)); 953 954 PetscCall(PetscViewerASCIIPrintf(viewer, "(%" PetscInt_FMT ",%" PetscInt_FMT ") : %s%stype=%s, rows=%" PetscInt_FMT ", cols=%" PetscInt_FMT "\n", i, j, name, prefix, type, NR, NC)); 955 956 if (isNest || viewSub) { 957 PetscCall(PetscViewerASCIIPushTab(viewer)); /* push1 */ 958 PetscCall(MatView(bA->m[i][j], viewer)); 959 PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop1 */ 960 } 961 } 962 } 963 PetscCall(PetscViewerASCIIPopTab(viewer)); /* pop0 */ 964 } 965 PetscFunctionReturn(PETSC_SUCCESS); 966 } 967 968 static PetscErrorCode MatZeroEntries_Nest(Mat A) 969 { 970 Mat_Nest *bA = (Mat_Nest *)A->data; 971 PetscInt i, j; 972 973 PetscFunctionBegin; 974 for (i = 0; i < bA->nr; i++) { 975 for (j = 0; j < bA->nc; j++) { 976 if (!bA->m[i][j]) continue; 977 PetscCall(MatZeroEntries(bA->m[i][j])); 978 } 979 } 980 PetscFunctionReturn(PETSC_SUCCESS); 981 } 982 983 static PetscErrorCode MatCopy_Nest(Mat A, Mat B, MatStructure str) 984 { 985 Mat_Nest *bA = (Mat_Nest *)A->data, *bB = (Mat_Nest *)B->data; 986 PetscInt i, j, nr = bA->nr, nc = bA->nc; 987 PetscBool nnzstate = PETSC_FALSE; 988 989 PetscFunctionBegin; 990 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); 991 for (i = 0; i < nr; i++) { 992 for (j = 0; j < nc; j++) { 993 PetscObjectState subnnzstate = 0; 994 if (bA->m[i][j] && bB->m[i][j]) { 995 PetscCall(MatCopy(bA->m[i][j], bB->m[i][j], str)); 996 PetscCall(MatGetNonzeroState(bB->m[i][j], &subnnzstate)); 997 nnzstate = (PetscBool)(nnzstate || bB->nnzstate[i * nc + j] != subnnzstate); 998 bB->nnzstate[i * nc + j] = subnnzstate; 999 } else if (bA->m[i][j]) { // bB->m[i][j] is NULL 1000 Mat M; 1001 1002 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); 1003 PetscCall(MatDuplicate(bA->m[i][j], MAT_COPY_VALUES, &M)); 1004 PetscCall(MatNestSetSubMat(B, i, j, M)); 1005 PetscCall(MatDestroy(&M)); 1006 } else if (bB->m[i][j]) { // bA->m[i][j] is NULL 1007 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); 1008 PetscCall(MatNestSetSubMat(B, i, j, NULL)); 1009 } 1010 } 1011 } 1012 if (nnzstate) B->nonzerostate++; 1013 PetscFunctionReturn(PETSC_SUCCESS); 1014 } 1015 1016 static PetscErrorCode MatAXPY_Nest(Mat Y, PetscScalar a, Mat X, MatStructure str) 1017 { 1018 Mat_Nest *bY = (Mat_Nest *)Y->data, *bX = (Mat_Nest *)X->data; 1019 PetscInt i, j, nr = bY->nr, nc = bY->nc; 1020 PetscBool nnzstate = PETSC_FALSE; 1021 1022 PetscFunctionBegin; 1023 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); 1024 for (i = 0; i < nr; i++) { 1025 for (j = 0; j < nc; j++) { 1026 PetscObjectState subnnzstate = 0; 1027 if (bY->m[i][j] && bX->m[i][j]) { 1028 PetscCall(MatAXPY(bY->m[i][j], a, bX->m[i][j], str)); 1029 } else if (bX->m[i][j]) { 1030 Mat M; 1031 1032 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); 1033 PetscCall(MatDuplicate(bX->m[i][j], MAT_COPY_VALUES, &M)); 1034 PetscCall(MatNestSetSubMat(Y, i, j, M)); 1035 PetscCall(MatDestroy(&M)); 1036 } 1037 if (bY->m[i][j]) PetscCall(MatGetNonzeroState(bY->m[i][j], &subnnzstate)); 1038 nnzstate = (PetscBool)(nnzstate || bY->nnzstate[i * nc + j] != subnnzstate); 1039 bY->nnzstate[i * nc + j] = subnnzstate; 1040 } 1041 } 1042 if (nnzstate) Y->nonzerostate++; 1043 PetscFunctionReturn(PETSC_SUCCESS); 1044 } 1045 1046 static PetscErrorCode MatDuplicate_Nest(Mat A, MatDuplicateOption op, Mat *B) 1047 { 1048 Mat_Nest *bA = (Mat_Nest *)A->data; 1049 Mat *b; 1050 PetscInt i, j, nr = bA->nr, nc = bA->nc; 1051 1052 PetscFunctionBegin; 1053 PetscCall(PetscMalloc1(nr * nc, &b)); 1054 for (i = 0; i < nr; i++) { 1055 for (j = 0; j < nc; j++) { 1056 if (bA->m[i][j]) { 1057 PetscCall(MatDuplicate(bA->m[i][j], op, &b[i * nc + j])); 1058 } else { 1059 b[i * nc + j] = NULL; 1060 } 1061 } 1062 } 1063 PetscCall(MatCreateNest(PetscObjectComm((PetscObject)A), nr, bA->isglobal.row, nc, bA->isglobal.col, b, B)); 1064 /* Give the new MatNest exclusive ownership */ 1065 for (i = 0; i < nr * nc; i++) PetscCall(MatDestroy(&b[i])); 1066 PetscCall(PetscFree(b)); 1067 1068 PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 1069 PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 1070 PetscFunctionReturn(PETSC_SUCCESS); 1071 } 1072 1073 /* nest api */ 1074 static PetscErrorCode MatNestGetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat *mat) 1075 { 1076 Mat_Nest *bA = (Mat_Nest *)A->data; 1077 1078 PetscFunctionBegin; 1079 PetscCheck(idxm < bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm, bA->nr - 1); 1080 PetscCheck(jdxm < bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT, jdxm, bA->nc - 1); 1081 *mat = bA->m[idxm][jdxm]; 1082 PetscFunctionReturn(PETSC_SUCCESS); 1083 } 1084 1085 /*@ 1086 MatNestGetSubMat - Returns a single, sub-matrix from a `MATNEST` 1087 1088 Not Collective 1089 1090 Input Parameters: 1091 + A - `MATNEST` matrix 1092 . idxm - index of the matrix within the nest matrix 1093 - jdxm - index of the matrix within the nest matrix 1094 1095 Output Parameter: 1096 . sub - matrix at index `idxm`, `jdxm` within the nest matrix 1097 1098 Level: developer 1099 1100 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestSetSubMat()`, 1101 `MatNestGetLocalISs()`, `MatNestGetISs()` 1102 @*/ 1103 PetscErrorCode MatNestGetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat *sub) 1104 { 1105 PetscFunctionBegin; 1106 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1107 PetscValidLogicalCollectiveInt(A, idxm, 2); 1108 PetscValidLogicalCollectiveInt(A, jdxm, 3); 1109 PetscAssertPointer(sub, 4); 1110 PetscUseMethod(A, "MatNestGetSubMat_C", (Mat, PetscInt, PetscInt, Mat *), (A, idxm, jdxm, sub)); 1111 PetscFunctionReturn(PETSC_SUCCESS); 1112 } 1113 1114 static PetscErrorCode MatNestSetSubMat_Nest(Mat A, PetscInt idxm, PetscInt jdxm, Mat mat) 1115 { 1116 Mat_Nest *bA = (Mat_Nest *)A->data; 1117 PetscInt m, n, M, N, mi, ni, Mi, Ni; 1118 1119 PetscFunctionBegin; 1120 PetscCheck(idxm < bA->nr, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Row too large: row %" PetscInt_FMT " max %" PetscInt_FMT, idxm, bA->nr - 1); 1121 PetscCheck(jdxm < bA->nc, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Col too large: row %" PetscInt_FMT " max %" PetscInt_FMT, jdxm, bA->nc - 1); 1122 if (mat) { 1123 PetscCall(MatGetLocalSize(mat, &m, &n)); 1124 PetscCall(MatGetSize(mat, &M, &N)); 1125 PetscCall(ISGetLocalSize(bA->isglobal.row[idxm], &mi)); 1126 PetscCall(ISGetSize(bA->isglobal.row[idxm], &Mi)); 1127 PetscCall(ISGetLocalSize(bA->isglobal.col[jdxm], &ni)); 1128 PetscCall(ISGetSize(bA->isglobal.col[jdxm], &Ni)); 1129 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); 1130 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); 1131 } 1132 1133 /* do not increase object state */ 1134 if (mat == bA->m[idxm][jdxm]) PetscFunctionReturn(PETSC_SUCCESS); 1135 1136 PetscCall(PetscObjectReference((PetscObject)mat)); 1137 PetscCall(MatDestroy(&bA->m[idxm][jdxm])); 1138 bA->m[idxm][jdxm] = mat; 1139 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 1140 if (mat) PetscCall(MatGetNonzeroState(mat, &bA->nnzstate[idxm * bA->nc + jdxm])); 1141 else bA->nnzstate[idxm * bA->nc + jdxm] = 0; 1142 A->nonzerostate++; 1143 PetscFunctionReturn(PETSC_SUCCESS); 1144 } 1145 1146 /*@ 1147 MatNestSetSubMat - Set a single submatrix in the `MATNEST` 1148 1149 Logically Collective 1150 1151 Input Parameters: 1152 + A - `MATNEST` matrix 1153 . idxm - index of the matrix within the nest matrix 1154 . jdxm - index of the matrix within the nest matrix 1155 - sub - matrix at index `idxm`, `jdxm` within the nest matrix 1156 1157 Level: developer 1158 1159 Notes: 1160 The new submatrix must have the same size and communicator as that block of the nest. 1161 1162 This increments the reference count of the submatrix. 1163 1164 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestSetSubMats()`, `MatNestGetSubMats()`, `MatNestGetLocalISs()`, `MatCreateNest()`, 1165 `MatNestGetSubMat()`, `MatNestGetISs()`, `MatNestGetSize()` 1166 @*/ 1167 PetscErrorCode MatNestSetSubMat(Mat A, PetscInt idxm, PetscInt jdxm, Mat sub) 1168 { 1169 PetscFunctionBegin; 1170 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1171 PetscValidLogicalCollectiveInt(A, idxm, 2); 1172 PetscValidLogicalCollectiveInt(A, jdxm, 3); 1173 if (sub) PetscValidHeaderSpecific(sub, MAT_CLASSID, 4); 1174 PetscTryMethod(A, "MatNestSetSubMat_C", (Mat, PetscInt, PetscInt, Mat), (A, idxm, jdxm, sub)); 1175 PetscFunctionReturn(PETSC_SUCCESS); 1176 } 1177 1178 static PetscErrorCode MatNestGetSubMats_Nest(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) 1179 { 1180 Mat_Nest *bA = (Mat_Nest *)A->data; 1181 1182 PetscFunctionBegin; 1183 if (M) *M = bA->nr; 1184 if (N) *N = bA->nc; 1185 if (mat) *mat = bA->m; 1186 PetscFunctionReturn(PETSC_SUCCESS); 1187 } 1188 1189 /*@C 1190 MatNestGetSubMats - Returns the entire two dimensional array of matrices defining a `MATNEST` matrix. 1191 1192 Not Collective 1193 1194 Input Parameter: 1195 . A - nest matrix 1196 1197 Output Parameters: 1198 + M - number of submatrix rows in the nest matrix 1199 . N - number of submatrix columns in the nest matrix 1200 - mat - array of matrices 1201 1202 Level: developer 1203 1204 Note: 1205 The user should not free the array `mat`. 1206 1207 Fortran Notes: 1208 This routine has a calling sequence `call MatNestGetSubMats(A, M, N, mat, ierr)` 1209 where the space allocated for the optional argument `mat` is assumed large enough (if provided). 1210 Matrices in `mat` are returned in row-major order, see `MatCreateNest()` for an example. 1211 1212 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSize()`, `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatCreateNest()`, 1213 `MatNestSetSubMats()`, `MatNestGetISs()`, `MatNestSetSubMat()` 1214 @*/ 1215 PetscErrorCode MatNestGetSubMats(Mat A, PetscInt *M, PetscInt *N, Mat ***mat) 1216 { 1217 PetscFunctionBegin; 1218 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1219 PetscUseMethod(A, "MatNestGetSubMats_C", (Mat, PetscInt *, PetscInt *, Mat ***), (A, M, N, mat)); 1220 PetscFunctionReturn(PETSC_SUCCESS); 1221 } 1222 1223 static PetscErrorCode MatNestGetSize_Nest(Mat A, PetscInt *M, PetscInt *N) 1224 { 1225 Mat_Nest *bA = (Mat_Nest *)A->data; 1226 1227 PetscFunctionBegin; 1228 if (M) *M = bA->nr; 1229 if (N) *N = bA->nc; 1230 PetscFunctionReturn(PETSC_SUCCESS); 1231 } 1232 1233 /*@ 1234 MatNestGetSize - Returns the size of the `MATNEST` matrix. 1235 1236 Not Collective 1237 1238 Input Parameter: 1239 . A - `MATNEST` matrix 1240 1241 Output Parameters: 1242 + M - number of rows in the nested mat 1243 - N - number of cols in the nested mat 1244 1245 Level: developer 1246 1247 Note: 1248 `size` refers to the number of submatrices in the row and column directions of the nested matrix 1249 1250 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatCreateNest()`, `MatNestGetLocalISs()`, 1251 `MatNestGetISs()` 1252 @*/ 1253 PetscErrorCode MatNestGetSize(Mat A, PetscInt *M, PetscInt *N) 1254 { 1255 PetscFunctionBegin; 1256 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1257 PetscUseMethod(A, "MatNestGetSize_C", (Mat, PetscInt *, PetscInt *), (A, M, N)); 1258 PetscFunctionReturn(PETSC_SUCCESS); 1259 } 1260 1261 static PetscErrorCode MatNestGetISs_Nest(Mat A, IS rows[], IS cols[]) 1262 { 1263 Mat_Nest *vs = (Mat_Nest *)A->data; 1264 PetscInt i; 1265 1266 PetscFunctionBegin; 1267 if (rows) 1268 for (i = 0; i < vs->nr; i++) rows[i] = vs->isglobal.row[i]; 1269 if (cols) 1270 for (i = 0; i < vs->nc; i++) cols[i] = vs->isglobal.col[i]; 1271 PetscFunctionReturn(PETSC_SUCCESS); 1272 } 1273 1274 /*@ 1275 MatNestGetISs - Returns the index sets partitioning the row and column spaces of a `MATNEST` 1276 1277 Not Collective 1278 1279 Input Parameter: 1280 . A - `MATNEST` matrix 1281 1282 Output Parameters: 1283 + rows - array of row index sets (pass `NULL` to ignore) 1284 - cols - array of column index sets (pass `NULL` to ignore) 1285 1286 Level: advanced 1287 1288 Note: 1289 The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s. 1290 1291 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetLocalISs()`, 1292 `MatCreateNest()`, `MatNestSetSubMats()` 1293 @*/ 1294 PetscErrorCode MatNestGetISs(Mat A, IS rows[], IS cols[]) 1295 { 1296 PetscFunctionBegin; 1297 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1298 PetscUseMethod(A, "MatNestGetISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 1299 PetscFunctionReturn(PETSC_SUCCESS); 1300 } 1301 1302 static PetscErrorCode MatNestGetLocalISs_Nest(Mat A, IS rows[], IS cols[]) 1303 { 1304 Mat_Nest *vs = (Mat_Nest *)A->data; 1305 PetscInt i; 1306 1307 PetscFunctionBegin; 1308 if (rows) 1309 for (i = 0; i < vs->nr; i++) rows[i] = vs->islocal.row[i]; 1310 if (cols) 1311 for (i = 0; i < vs->nc; i++) cols[i] = vs->islocal.col[i]; 1312 PetscFunctionReturn(PETSC_SUCCESS); 1313 } 1314 1315 /*@ 1316 MatNestGetLocalISs - Returns the index sets partitioning the row and column spaces of a `MATNEST` 1317 1318 Not Collective 1319 1320 Input Parameter: 1321 . A - `MATNEST` matrix 1322 1323 Output Parameters: 1324 + rows - array of row index sets (pass `NULL` to ignore) 1325 - cols - array of column index sets (pass `NULL` to ignore) 1326 1327 Level: advanced 1328 1329 Note: 1330 The user must have allocated arrays of the correct size. The reference count is not increased on the returned `IS`s. 1331 1332 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatNestGetSubMat()`, `MatNestGetSubMats()`, `MatNestGetSize()`, `MatNestGetISs()`, `MatCreateNest()`, 1333 `MatNestSetSubMats()`, `MatNestSetSubMat()` 1334 @*/ 1335 PetscErrorCode MatNestGetLocalISs(Mat A, IS rows[], IS cols[]) 1336 { 1337 PetscFunctionBegin; 1338 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1339 PetscUseMethod(A, "MatNestGetLocalISs_C", (Mat, IS[], IS[]), (A, rows, cols)); 1340 PetscFunctionReturn(PETSC_SUCCESS); 1341 } 1342 1343 static PetscErrorCode MatNestSetVecType_Nest(Mat A, VecType vtype) 1344 { 1345 PetscBool flg; 1346 1347 PetscFunctionBegin; 1348 PetscCall(PetscStrcmp(vtype, VECNEST, &flg)); 1349 /* In reality, this only distinguishes VECNEST and "other" */ 1350 if (flg) A->ops->getvecs = MatCreateVecs_Nest; 1351 else A->ops->getvecs = NULL; 1352 PetscFunctionReturn(PETSC_SUCCESS); 1353 } 1354 1355 /*@ 1356 MatNestSetVecType - Sets the type of `Vec` returned by `MatCreateVecs()` 1357 1358 Not Collective 1359 1360 Input Parameters: 1361 + A - `MATNEST` matrix 1362 - vtype - `VecType` to use for creating vectors 1363 1364 Level: developer 1365 1366 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateVecs()`, `MatCreateNest()`, `VecType` 1367 @*/ 1368 PetscErrorCode MatNestSetVecType(Mat A, VecType vtype) 1369 { 1370 PetscFunctionBegin; 1371 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1372 PetscTryMethod(A, "MatNestSetVecType_C", (Mat, VecType), (A, vtype)); 1373 PetscFunctionReturn(PETSC_SUCCESS); 1374 } 1375 1376 static PetscErrorCode MatNestSetSubMats_Nest(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) 1377 { 1378 Mat_Nest *s = (Mat_Nest *)A->data; 1379 PetscInt i, j, m, n, M, N; 1380 PetscBool cong, isstd, sametype = PETSC_FALSE; 1381 VecType vtype, type; 1382 1383 PetscFunctionBegin; 1384 PetscCall(MatReset_Nest(A)); 1385 1386 s->nr = nr; 1387 s->nc = nc; 1388 1389 /* Create space for submatrices */ 1390 PetscCall(PetscMalloc1(nr, &s->m)); 1391 PetscCall(PetscMalloc1(nr * nc, &s->m[0])); 1392 for (i = 0; i < nr; i++) { 1393 s->m[i] = s->m[0] + i * nc; 1394 for (j = 0; j < nc; j++) { 1395 s->m[i][j] = a ? a[i * nc + j] : NULL; 1396 PetscCall(PetscObjectReference((PetscObject)s->m[i][j])); 1397 } 1398 } 1399 PetscCall(MatGetVecType(A, &vtype)); 1400 PetscCall(PetscStrcmp(vtype, VECSTANDARD, &isstd)); 1401 if (isstd) { 1402 /* check if all blocks have the same vectype */ 1403 vtype = NULL; 1404 for (i = 0; i < nr; i++) { 1405 for (j = 0; j < nc; j++) { 1406 if (s->m[i][j]) { 1407 if (!vtype) { /* first visited block */ 1408 PetscCall(MatGetVecType(s->m[i][j], &vtype)); 1409 sametype = PETSC_TRUE; 1410 } else if (sametype) { 1411 PetscCall(MatGetVecType(s->m[i][j], &type)); 1412 PetscCall(PetscStrcmp(vtype, type, &sametype)); 1413 } 1414 } 1415 } 1416 } 1417 if (sametype) { /* propagate vectype */ 1418 PetscCall(MatSetVecType(A, vtype)); 1419 } 1420 } 1421 1422 PetscCall(MatSetUp_NestIS_Private(A, nr, is_row, nc, is_col)); 1423 1424 PetscCall(PetscMalloc1(nr, &s->row_len)); 1425 PetscCall(PetscMalloc1(nc, &s->col_len)); 1426 for (i = 0; i < nr; i++) s->row_len[i] = -1; 1427 for (j = 0; j < nc; j++) s->col_len[j] = -1; 1428 1429 PetscCall(PetscCalloc1(nr * nc, &s->nnzstate)); 1430 for (i = 0; i < nr; i++) { 1431 for (j = 0; j < nc; j++) { 1432 if (s->m[i][j]) PetscCall(MatGetNonzeroState(s->m[i][j], &s->nnzstate[i * nc + j])); 1433 } 1434 } 1435 1436 PetscCall(MatNestGetSizes_Private(A, &m, &n, &M, &N)); 1437 1438 PetscCall(PetscLayoutSetSize(A->rmap, M)); 1439 PetscCall(PetscLayoutSetLocalSize(A->rmap, m)); 1440 PetscCall(PetscLayoutSetSize(A->cmap, N)); 1441 PetscCall(PetscLayoutSetLocalSize(A->cmap, n)); 1442 1443 PetscCall(PetscLayoutSetUp(A->rmap)); 1444 PetscCall(PetscLayoutSetUp(A->cmap)); 1445 1446 /* disable operations that are not supported for non-square matrices, 1447 or matrices for which is_row != is_col */ 1448 PetscCall(MatHasCongruentLayouts(A, &cong)); 1449 if (cong && nr != nc) cong = PETSC_FALSE; 1450 if (cong) { 1451 for (i = 0; cong && i < nr; i++) PetscCall(ISEqualUnsorted(s->isglobal.row[i], s->isglobal.col[i], &cong)); 1452 } 1453 if (!cong) { 1454 A->ops->missingdiagonal = NULL; 1455 A->ops->getdiagonal = NULL; 1456 A->ops->shift = NULL; 1457 A->ops->diagonalset = NULL; 1458 } 1459 1460 PetscCall(PetscCalloc2(nr, &s->left, nc, &s->right)); 1461 PetscCall(PetscObjectStateIncrease((PetscObject)A)); 1462 A->nonzerostate++; 1463 PetscFunctionReturn(PETSC_SUCCESS); 1464 } 1465 1466 /*@ 1467 MatNestSetSubMats - Sets the nested submatrices in a `MATNEST` 1468 1469 Collective 1470 1471 Input Parameters: 1472 + A - `MATNEST` matrix 1473 . nr - number of nested row blocks 1474 . is_row - index sets for each nested row block, or `NULL` to make contiguous 1475 . nc - number of nested column blocks 1476 . is_col - index sets for each nested column block, or `NULL` to make contiguous 1477 - a - array of nr*nc submatrices, or `NULL` 1478 1479 Level: advanced 1480 1481 Notes: 1482 This always resets any block matrix information previously set. 1483 1484 Pass `NULL` in the corresponding entry of `a` for an empty block. 1485 1486 In both C and Fortran, `a` must be a row-major order array containing the matrices. See 1487 `MatCreateNest()` for an example. 1488 1489 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, `MatNestGetSubMats()` 1490 @*/ 1491 PetscErrorCode MatNestSetSubMats(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[]) 1492 { 1493 PetscFunctionBegin; 1494 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1495 PetscValidLogicalCollectiveInt(A, nr, 2); 1496 PetscCheck(nr >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of rows cannot be negative"); 1497 if (nr && is_row) { 1498 PetscAssertPointer(is_row, 3); 1499 for (PetscInt i = 0; i < nr; i++) PetscValidHeaderSpecific(is_row[i], IS_CLASSID, 3); 1500 } 1501 PetscValidLogicalCollectiveInt(A, nc, 4); 1502 PetscCheck(nc >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_OUTOFRANGE, "Number of columns cannot be negative"); 1503 if (nc && is_col) { 1504 PetscAssertPointer(is_col, 5); 1505 for (PetscInt i = 0; i < nc; i++) PetscValidHeaderSpecific(is_col[i], IS_CLASSID, 5); 1506 } 1507 PetscTryMethod(A, "MatNestSetSubMats_C", (Mat, PetscInt, const IS[], PetscInt, const IS[], const Mat[]), (A, nr, is_row, nc, is_col, a)); 1508 PetscFunctionReturn(PETSC_SUCCESS); 1509 } 1510 1511 static PetscErrorCode MatNestCreateAggregateL2G_Private(Mat A, PetscInt n, const IS islocal[], const IS isglobal[], PetscBool colflg, ISLocalToGlobalMapping *ltog) 1512 { 1513 PetscBool flg; 1514 PetscInt i, j, m, mi, *ix; 1515 1516 PetscFunctionBegin; 1517 *ltog = NULL; 1518 for (i = 0, m = 0, flg = PETSC_FALSE; i < n; i++) { 1519 if (islocal[i]) { 1520 PetscCall(ISGetLocalSize(islocal[i], &mi)); 1521 flg = PETSC_TRUE; /* We found a non-trivial entry */ 1522 } else { 1523 PetscCall(ISGetLocalSize(isglobal[i], &mi)); 1524 } 1525 m += mi; 1526 } 1527 if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 1528 1529 PetscCall(PetscMalloc1(m, &ix)); 1530 for (i = 0, m = 0; i < n; i++) { 1531 ISLocalToGlobalMapping smap = NULL; 1532 Mat sub = NULL; 1533 PetscSF sf; 1534 PetscLayout map; 1535 const PetscInt *ix2; 1536 1537 if (!colflg) { 1538 PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 1539 } else { 1540 PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 1541 } 1542 if (sub) { 1543 if (!colflg) { 1544 PetscCall(MatGetLocalToGlobalMapping(sub, &smap, NULL)); 1545 } else { 1546 PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &smap)); 1547 } 1548 } 1549 /* 1550 Now we need to extract the monolithic global indices that correspond to the given split global indices. 1551 In many/most cases, we only want MatGetLocalSubMatrix() to work, in which case we only need to know the size of the local spaces. 1552 */ 1553 PetscCall(ISGetIndices(isglobal[i], &ix2)); 1554 if (islocal[i]) { 1555 PetscInt *ilocal, *iremote; 1556 PetscInt mil, nleaves; 1557 1558 PetscCall(ISGetLocalSize(islocal[i], &mi)); 1559 PetscCheck(smap, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "Missing local to global map"); 1560 for (j = 0; j < mi; j++) ix[m + j] = j; 1561 PetscCall(ISLocalToGlobalMappingApply(smap, mi, ix + m, ix + m)); 1562 1563 /* PetscSFSetGraphLayout does not like negative indices */ 1564 PetscCall(PetscMalloc2(mi, &ilocal, mi, &iremote)); 1565 for (j = 0, nleaves = 0; j < mi; j++) { 1566 if (ix[m + j] < 0) continue; 1567 ilocal[nleaves] = j; 1568 iremote[nleaves] = ix[m + j]; 1569 nleaves++; 1570 } 1571 PetscCall(ISGetLocalSize(isglobal[i], &mil)); 1572 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &sf)); 1573 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)A), &map)); 1574 PetscCall(PetscLayoutSetLocalSize(map, mil)); 1575 PetscCall(PetscLayoutSetUp(map)); 1576 PetscCall(PetscSFSetGraphLayout(sf, map, nleaves, ilocal, PETSC_USE_POINTER, iremote)); 1577 PetscCall(PetscLayoutDestroy(&map)); 1578 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 1579 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, ix2, ix + m, MPI_REPLACE)); 1580 PetscCall(PetscSFDestroy(&sf)); 1581 PetscCall(PetscFree2(ilocal, iremote)); 1582 } else { 1583 PetscCall(ISGetLocalSize(isglobal[i], &mi)); 1584 for (j = 0; j < mi; j++) ix[m + j] = ix2[i]; 1585 } 1586 PetscCall(ISRestoreIndices(isglobal[i], &ix2)); 1587 m += mi; 1588 } 1589 PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, m, ix, PETSC_OWN_POINTER, ltog)); 1590 PetscFunctionReturn(PETSC_SUCCESS); 1591 } 1592 1593 /* If an IS was provided, there is nothing Nest needs to do, otherwise Nest will build a strided IS */ 1594 /* 1595 nprocessors = NP 1596 Nest x^T = ((g_0,g_1,...g_nprocs-1), (h_0,h_1,...h_NP-1)) 1597 proc 0: => (g_0,h_0,) 1598 proc 1: => (g_1,h_1,) 1599 ... 1600 proc nprocs-1: => (g_NP-1,h_NP-1,) 1601 1602 proc 0: proc 1: proc nprocs-1: 1603 is[0] = (0,1,2,...,nlocal(g_0)-1) (0,1,...,nlocal(g_1)-1) (0,1,...,nlocal(g_NP-1)) 1604 1605 proc 0: 1606 is[1] = (nlocal(g_0),nlocal(g_0)+1,...,nlocal(g_0)+nlocal(h_0)-1) 1607 proc 1: 1608 is[1] = (nlocal(g_1),nlocal(g_1)+1,...,nlocal(g_1)+nlocal(h_1)-1) 1609 1610 proc NP-1: 1611 is[1] = (nlocal(g_NP-1),nlocal(g_NP-1)+1,...,nlocal(g_NP-1)+nlocal(h_NP-1)-1) 1612 */ 1613 static PetscErrorCode MatSetUp_NestIS_Private(Mat A, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[]) 1614 { 1615 Mat_Nest *vs = (Mat_Nest *)A->data; 1616 PetscInt i, j, offset, n, nsum, bs; 1617 Mat sub = NULL; 1618 1619 PetscFunctionBegin; 1620 PetscCall(PetscMalloc1(nr, &vs->isglobal.row)); 1621 PetscCall(PetscMalloc1(nc, &vs->isglobal.col)); 1622 if (is_row) { /* valid IS is passed in */ 1623 /* refs on is[] are incremented */ 1624 for (i = 0; i < vs->nr; i++) { 1625 PetscCall(PetscObjectReference((PetscObject)is_row[i])); 1626 vs->isglobal.row[i] = is_row[i]; 1627 } 1628 } else { /* Create the ISs by inspecting sizes of a submatrix in each row */ 1629 nsum = 0; 1630 for (i = 0; i < vs->nr; i++) { /* Add up the local sizes to compute the aggregate offset */ 1631 PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 1632 PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in row %" PetscInt_FMT, i); 1633 PetscCall(MatGetLocalSize(sub, &n, NULL)); 1634 PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 1635 nsum += n; 1636 } 1637 PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 1638 offset -= nsum; 1639 for (i = 0; i < vs->nr; i++) { 1640 PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 1641 PetscCall(MatGetLocalSize(sub, &n, NULL)); 1642 PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 1643 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.row[i])); 1644 PetscCall(ISSetBlockSize(vs->isglobal.row[i], bs)); 1645 offset += n; 1646 } 1647 } 1648 1649 if (is_col) { /* valid IS is passed in */ 1650 /* refs on is[] are incremented */ 1651 for (j = 0; j < vs->nc; j++) { 1652 PetscCall(PetscObjectReference((PetscObject)is_col[j])); 1653 vs->isglobal.col[j] = is_col[j]; 1654 } 1655 } else { /* Create the ISs by inspecting sizes of a submatrix in each column */ 1656 offset = A->cmap->rstart; 1657 nsum = 0; 1658 for (j = 0; j < vs->nc; j++) { 1659 PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 1660 PetscCheck(sub, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "No nonzero submatrix in column %" PetscInt_FMT, i); 1661 PetscCall(MatGetLocalSize(sub, NULL, &n)); 1662 PetscCheck(n >= 0, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONGSTATE, "Sizes have not yet been set for submatrix"); 1663 nsum += n; 1664 } 1665 PetscCallMPI(MPI_Scan(&nsum, &offset, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)A))); 1666 offset -= nsum; 1667 for (j = 0; j < vs->nc; j++) { 1668 PetscCall(MatNestFindNonzeroSubMatCol(A, j, &sub)); 1669 PetscCall(MatGetLocalSize(sub, NULL, &n)); 1670 PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 1671 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)sub), n, offset, 1, &vs->isglobal.col[j])); 1672 PetscCall(ISSetBlockSize(vs->isglobal.col[j], bs)); 1673 offset += n; 1674 } 1675 } 1676 1677 /* Set up the local ISs */ 1678 PetscCall(PetscMalloc1(vs->nr, &vs->islocal.row)); 1679 PetscCall(PetscMalloc1(vs->nc, &vs->islocal.col)); 1680 for (i = 0, offset = 0; i < vs->nr; i++) { 1681 IS isloc; 1682 ISLocalToGlobalMapping rmap = NULL; 1683 PetscInt nlocal, bs; 1684 PetscCall(MatNestFindNonzeroSubMatRow(A, i, &sub)); 1685 if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, &rmap, NULL)); 1686 if (rmap) { 1687 PetscCall(MatGetBlockSizes(sub, &bs, NULL)); 1688 PetscCall(ISLocalToGlobalMappingGetSize(rmap, &nlocal)); 1689 PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 1690 PetscCall(ISSetBlockSize(isloc, bs)); 1691 } else { 1692 nlocal = 0; 1693 isloc = NULL; 1694 } 1695 vs->islocal.row[i] = isloc; 1696 offset += nlocal; 1697 } 1698 for (i = 0, offset = 0; i < vs->nc; i++) { 1699 IS isloc; 1700 ISLocalToGlobalMapping cmap = NULL; 1701 PetscInt nlocal, bs; 1702 PetscCall(MatNestFindNonzeroSubMatCol(A, i, &sub)); 1703 if (sub) PetscCall(MatGetLocalToGlobalMapping(sub, NULL, &cmap)); 1704 if (cmap) { 1705 PetscCall(MatGetBlockSizes(sub, NULL, &bs)); 1706 PetscCall(ISLocalToGlobalMappingGetSize(cmap, &nlocal)); 1707 PetscCall(ISCreateStride(PETSC_COMM_SELF, nlocal, offset, 1, &isloc)); 1708 PetscCall(ISSetBlockSize(isloc, bs)); 1709 } else { 1710 nlocal = 0; 1711 isloc = NULL; 1712 } 1713 vs->islocal.col[i] = isloc; 1714 offset += nlocal; 1715 } 1716 1717 /* Set up the aggregate ISLocalToGlobalMapping */ 1718 { 1719 ISLocalToGlobalMapping rmap, cmap; 1720 PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nr, vs->islocal.row, vs->isglobal.row, PETSC_FALSE, &rmap)); 1721 PetscCall(MatNestCreateAggregateL2G_Private(A, vs->nc, vs->islocal.col, vs->isglobal.col, PETSC_TRUE, &cmap)); 1722 if (rmap && cmap) PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap)); 1723 PetscCall(ISLocalToGlobalMappingDestroy(&rmap)); 1724 PetscCall(ISLocalToGlobalMappingDestroy(&cmap)); 1725 } 1726 1727 if (PetscDefined(USE_DEBUG)) { 1728 for (i = 0; i < vs->nr; i++) { 1729 for (j = 0; j < vs->nc; j++) { 1730 PetscInt m, n, M, N, mi, ni, Mi, Ni; 1731 Mat B = vs->m[i][j]; 1732 if (!B) continue; 1733 PetscCall(MatGetSize(B, &M, &N)); 1734 PetscCall(MatGetLocalSize(B, &m, &n)); 1735 PetscCall(ISGetSize(vs->isglobal.row[i], &Mi)); 1736 PetscCall(ISGetSize(vs->isglobal.col[j], &Ni)); 1737 PetscCall(ISGetLocalSize(vs->isglobal.row[i], &mi)); 1738 PetscCall(ISGetLocalSize(vs->isglobal.col[j], &ni)); 1739 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); 1740 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); 1741 } 1742 } 1743 } 1744 1745 /* Set A->assembled if all non-null blocks are currently assembled */ 1746 for (i = 0; i < vs->nr; i++) { 1747 for (j = 0; j < vs->nc; j++) { 1748 if (vs->m[i][j] && !vs->m[i][j]->assembled) PetscFunctionReturn(PETSC_SUCCESS); 1749 } 1750 } 1751 A->assembled = PETSC_TRUE; 1752 PetscFunctionReturn(PETSC_SUCCESS); 1753 } 1754 1755 /*@C 1756 MatCreateNest - Creates a new `MATNEST` matrix containing several nested submatrices, each stored separately 1757 1758 Collective 1759 1760 Input Parameters: 1761 + comm - Communicator for the new `MATNEST` 1762 . nr - number of nested row blocks 1763 . is_row - index sets for each nested row block, or `NULL` to make contiguous 1764 . nc - number of nested column blocks 1765 . is_col - index sets for each nested column block, or `NULL` to make contiguous 1766 - a - array of nr*nc submatrices, empty submatrices can be passed using `NULL` 1767 1768 Output Parameter: 1769 . B - new matrix 1770 1771 Note: 1772 In both C and Fortran, `a` must be a row-major order array holding references to the matrices. 1773 For instance, to represent the matrix 1774 $\begin{bmatrix} A_{11} & A_{12} \\ A_{21} & A_{22}\end{bmatrix}$ 1775 one should use `Mat a[4]={A11,A12,A21,A22}`. 1776 1777 Level: advanced 1778 1779 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `VecCreateNest()`, `DMCreateMatrix()`, `MatNestSetSubMat()`, 1780 `MatNestGetSubMat()`, `MatNestGetLocalISs()`, `MatNestGetSize()`, 1781 `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 1782 @*/ 1783 PetscErrorCode MatCreateNest(MPI_Comm comm, PetscInt nr, const IS is_row[], PetscInt nc, const IS is_col[], const Mat a[], Mat *B) PeNSS 1784 { 1785 PetscFunctionBegin; 1786 PetscCall(MatCreate(comm, B)); 1787 PetscCall(MatSetType(*B, MATNEST)); 1788 (*B)->preallocated = PETSC_TRUE; 1789 PetscCall(MatNestSetSubMats(*B, nr, is_row, nc, is_col, a)); 1790 PetscFunctionReturn(PETSC_SUCCESS); 1791 } 1792 1793 static PetscErrorCode MatConvert_Nest_SeqAIJ_fast(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 1794 { 1795 Mat_Nest *nest = (Mat_Nest *)A->data; 1796 Mat *trans; 1797 PetscScalar **avv; 1798 PetscScalar *vv; 1799 PetscInt **aii, **ajj; 1800 PetscInt *ii, *jj, *ci; 1801 PetscInt nr, nc, nnz, i, j; 1802 PetscBool done; 1803 1804 PetscFunctionBegin; 1805 PetscCall(MatGetSize(A, &nr, &nc)); 1806 if (reuse == MAT_REUSE_MATRIX) { 1807 PetscInt rnr; 1808 1809 PetscCall(MatGetRowIJ(*newmat, 0, PETSC_FALSE, PETSC_FALSE, &rnr, (const PetscInt **)&ii, (const PetscInt **)&jj, &done)); 1810 PetscCheck(done, PetscObjectComm((PetscObject)A), PETSC_ERR_PLIB, "MatGetRowIJ"); 1811 PetscCheck(rnr == nr, PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of rows"); 1812 PetscCall(MatSeqAIJGetArray(*newmat, &vv)); 1813 } 1814 /* extract CSR for nested SeqAIJ matrices */ 1815 nnz = 0; 1816 PetscCall(PetscCalloc4(nest->nr * nest->nc, &aii, nest->nr * nest->nc, &ajj, nest->nr * nest->nc, &avv, nest->nr * nest->nc, &trans)); 1817 for (i = 0; i < nest->nr; ++i) { 1818 for (j = 0; j < nest->nc; ++j) { 1819 Mat B = nest->m[i][j]; 1820 if (B) { 1821 PetscScalar *naa; 1822 PetscInt *nii, *njj, nnr; 1823 PetscBool istrans; 1824 1825 PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans)); 1826 if (istrans) { 1827 Mat Bt; 1828 1829 PetscCall(MatTransposeGetMat(B, &Bt)); 1830 PetscCall(MatTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 1831 B = trans[i * nest->nc + j]; 1832 } else { 1833 PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans)); 1834 if (istrans) { 1835 Mat Bt; 1836 1837 PetscCall(MatHermitianTransposeGetMat(B, &Bt)); 1838 PetscCall(MatHermitianTranspose(Bt, MAT_INITIAL_MATRIX, &trans[i * nest->nc + j])); 1839 B = trans[i * nest->nc + j]; 1840 } 1841 } 1842 PetscCall(MatGetRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&nii, (const PetscInt **)&njj, &done)); 1843 PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatGetRowIJ"); 1844 PetscCall(MatSeqAIJGetArray(B, &naa)); 1845 nnz += nii[nnr]; 1846 1847 aii[i * nest->nc + j] = nii; 1848 ajj[i * nest->nc + j] = njj; 1849 avv[i * nest->nc + j] = naa; 1850 } 1851 } 1852 } 1853 if (reuse != MAT_REUSE_MATRIX) { 1854 PetscCall(PetscMalloc1(nr + 1, &ii)); 1855 PetscCall(PetscMalloc1(nnz, &jj)); 1856 PetscCall(PetscMalloc1(nnz, &vv)); 1857 } else { 1858 PetscCheck(nnz == ii[nr], PetscObjectComm((PetscObject)A), PETSC_ERR_USER, "Cannot reuse matrix, wrong number of nonzeros"); 1859 } 1860 1861 /* new row pointer */ 1862 PetscCall(PetscArrayzero(ii, nr + 1)); 1863 for (i = 0; i < nest->nr; ++i) { 1864 PetscInt ncr, rst; 1865 1866 PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 1867 PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1868 for (j = 0; j < nest->nc; ++j) { 1869 if (aii[i * nest->nc + j]) { 1870 PetscInt *nii = aii[i * nest->nc + j]; 1871 PetscInt ir; 1872 1873 for (ir = rst; ir < ncr + rst; ++ir) { 1874 ii[ir + 1] += nii[1] - nii[0]; 1875 nii++; 1876 } 1877 } 1878 } 1879 } 1880 for (i = 0; i < nr; i++) ii[i + 1] += ii[i]; 1881 1882 /* construct CSR for the new matrix */ 1883 PetscCall(PetscCalloc1(nr, &ci)); 1884 for (i = 0; i < nest->nr; ++i) { 1885 PetscInt ncr, rst; 1886 1887 PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &rst, NULL)); 1888 PetscCall(ISGetLocalSize(nest->isglobal.row[i], &ncr)); 1889 for (j = 0; j < nest->nc; ++j) { 1890 if (aii[i * nest->nc + j]) { 1891 PetscScalar *nvv = avv[i * nest->nc + j], vscale = 1.0, vshift = 0.0; 1892 PetscInt *nii = aii[i * nest->nc + j]; 1893 PetscInt *njj = ajj[i * nest->nc + j]; 1894 PetscInt ir, cst; 1895 1896 if (trans[i * nest->nc + j]) { 1897 vscale = ((Mat_Shell *)nest->m[i][j]->data)->vscale; 1898 vshift = ((Mat_Shell *)nest->m[i][j]->data)->vshift; 1899 } 1900 PetscCall(ISStrideGetInfo(nest->isglobal.col[j], &cst, NULL)); 1901 for (ir = rst; ir < ncr + rst; ++ir) { 1902 PetscInt ij, rsize = nii[1] - nii[0], ist = ii[ir] + ci[ir]; 1903 1904 for (ij = 0; ij < rsize; ij++) { 1905 jj[ist + ij] = *njj + cst; 1906 vv[ist + ij] = vscale * *nvv; 1907 if (PetscUnlikely(vshift != 0.0 && *njj == ir - rst)) vv[ist + ij] += vshift; 1908 njj++; 1909 nvv++; 1910 } 1911 ci[ir] += rsize; 1912 nii++; 1913 } 1914 } 1915 } 1916 } 1917 PetscCall(PetscFree(ci)); 1918 1919 /* restore info */ 1920 for (i = 0; i < nest->nr; ++i) { 1921 for (j = 0; j < nest->nc; ++j) { 1922 Mat B = nest->m[i][j]; 1923 if (B) { 1924 PetscInt nnr = 0, k = i * nest->nc + j; 1925 1926 B = (trans[k] ? trans[k] : B); 1927 PetscCall(MatRestoreRowIJ(B, 0, PETSC_FALSE, PETSC_FALSE, &nnr, (const PetscInt **)&aii[k], (const PetscInt **)&ajj[k], &done)); 1928 PetscCheck(done, PetscObjectComm((PetscObject)B), PETSC_ERR_PLIB, "MatRestoreRowIJ"); 1929 PetscCall(MatSeqAIJRestoreArray(B, &avv[k])); 1930 PetscCall(MatDestroy(&trans[k])); 1931 } 1932 } 1933 } 1934 PetscCall(PetscFree4(aii, ajj, avv, trans)); 1935 1936 /* finalize newmat */ 1937 if (reuse == MAT_INITIAL_MATRIX) { 1938 PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, newmat)); 1939 } else if (reuse == MAT_INPLACE_MATRIX) { 1940 Mat B; 1941 1942 PetscCall(MatCreateSeqAIJWithArrays(PetscObjectComm((PetscObject)A), nr, nc, ii, jj, vv, &B)); 1943 PetscCall(MatHeaderReplace(A, &B)); 1944 } 1945 PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY)); 1946 PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY)); 1947 { 1948 Mat_SeqAIJ *a = (Mat_SeqAIJ *)((*newmat)->data); 1949 a->free_a = PETSC_TRUE; 1950 a->free_ij = PETSC_TRUE; 1951 } 1952 PetscFunctionReturn(PETSC_SUCCESS); 1953 } 1954 1955 PETSC_INTERN PetscErrorCode MatAXPY_Dense_Nest(Mat Y, PetscScalar a, Mat X) 1956 { 1957 Mat_Nest *nest = (Mat_Nest *)X->data; 1958 PetscInt i, j, k, rstart; 1959 PetscBool flg; 1960 1961 PetscFunctionBegin; 1962 /* Fill by row */ 1963 for (j = 0; j < nest->nc; ++j) { 1964 /* Using global column indices and ISAllGather() is not scalable. */ 1965 IS bNis; 1966 PetscInt bN; 1967 const PetscInt *bNindices; 1968 PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 1969 PetscCall(ISGetSize(bNis, &bN)); 1970 PetscCall(ISGetIndices(bNis, &bNindices)); 1971 for (i = 0; i < nest->nr; ++i) { 1972 Mat B = nest->m[i][j], D = NULL; 1973 PetscInt bm, br; 1974 const PetscInt *bmindices; 1975 if (!B) continue; 1976 PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 1977 if (flg) { 1978 PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 1979 PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 1980 PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 1981 B = D; 1982 } 1983 PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 1984 if (flg) { 1985 if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 1986 else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 1987 B = D; 1988 } 1989 PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 1990 PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 1991 PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 1992 for (br = 0; br < bm; ++br) { 1993 PetscInt row = bmindices[br], brncols, *cols; 1994 const PetscInt *brcols; 1995 const PetscScalar *brcoldata; 1996 PetscScalar *vals = NULL; 1997 PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 1998 PetscCall(PetscMalloc1(brncols, &cols)); 1999 for (k = 0; k < brncols; k++) cols[k] = bNindices[brcols[k]]; 2000 /* 2001 Nest blocks are required to be nonoverlapping -- otherwise nest and monolithic index layouts wouldn't match. 2002 Thus, we could use INSERT_VALUES, but I prefer ADD_VALUES. 2003 */ 2004 if (a != 1.0) { 2005 PetscCall(PetscMalloc1(brncols, &vals)); 2006 for (k = 0; k < brncols; k++) vals[k] = a * brcoldata[k]; 2007 PetscCall(MatSetValues(Y, 1, &row, brncols, cols, vals, ADD_VALUES)); 2008 PetscCall(PetscFree(vals)); 2009 } else { 2010 PetscCall(MatSetValues(Y, 1, &row, brncols, cols, brcoldata, ADD_VALUES)); 2011 } 2012 PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, &brcoldata)); 2013 PetscCall(PetscFree(cols)); 2014 } 2015 if (D) PetscCall(MatDestroy(&D)); 2016 PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 2017 } 2018 PetscCall(ISRestoreIndices(bNis, &bNindices)); 2019 PetscCall(ISDestroy(&bNis)); 2020 } 2021 PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY)); 2022 PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY)); 2023 PetscFunctionReturn(PETSC_SUCCESS); 2024 } 2025 2026 static PetscErrorCode MatConvert_Nest_AIJ(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 2027 { 2028 Mat_Nest *nest = (Mat_Nest *)A->data; 2029 PetscInt m, n, M, N, i, j, k, *dnnz, *onnz = NULL, rstart, cstart, cend; 2030 PetscMPIInt size; 2031 Mat C; 2032 2033 PetscFunctionBegin; 2034 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 2035 if (size == 1) { /* look for a special case with SeqAIJ matrices and strided-1, contiguous, blocks */ 2036 PetscInt nf; 2037 PetscBool fast; 2038 2039 PetscCall(PetscStrcmp(newtype, MATAIJ, &fast)); 2040 if (!fast) PetscCall(PetscStrcmp(newtype, MATSEQAIJ, &fast)); 2041 for (i = 0; i < nest->nr && fast; ++i) { 2042 for (j = 0; j < nest->nc && fast; ++j) { 2043 Mat B = nest->m[i][j]; 2044 if (B) { 2045 PetscCall(PetscObjectTypeCompare((PetscObject)B, MATSEQAIJ, &fast)); 2046 if (!fast) { 2047 PetscBool istrans; 2048 2049 PetscCall(PetscObjectTypeCompare((PetscObject)B, MATTRANSPOSEVIRTUAL, &istrans)); 2050 if (istrans) { 2051 Mat Bt; 2052 2053 PetscCall(MatTransposeGetMat(B, &Bt)); 2054 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 2055 } else { 2056 PetscCall(PetscObjectTypeCompare((PetscObject)B, MATHERMITIANTRANSPOSEVIRTUAL, &istrans)); 2057 if (istrans) { 2058 Mat Bt; 2059 2060 PetscCall(MatHermitianTransposeGetMat(B, &Bt)); 2061 PetscCall(PetscObjectTypeCompare((PetscObject)Bt, MATSEQAIJ, &fast)); 2062 } 2063 } 2064 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); 2065 } 2066 } 2067 } 2068 } 2069 for (i = 0, nf = 0; i < nest->nr && fast; ++i) { 2070 PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.row[i], ISSTRIDE, &fast)); 2071 if (fast) { 2072 PetscInt f, s; 2073 2074 PetscCall(ISStrideGetInfo(nest->isglobal.row[i], &f, &s)); 2075 if (f != nf || s != 1) { 2076 fast = PETSC_FALSE; 2077 } else { 2078 PetscCall(ISGetSize(nest->isglobal.row[i], &f)); 2079 nf += f; 2080 } 2081 } 2082 } 2083 for (i = 0, nf = 0; i < nest->nc && fast; ++i) { 2084 PetscCall(PetscObjectTypeCompare((PetscObject)nest->isglobal.col[i], ISSTRIDE, &fast)); 2085 if (fast) { 2086 PetscInt f, s; 2087 2088 PetscCall(ISStrideGetInfo(nest->isglobal.col[i], &f, &s)); 2089 if (f != nf || s != 1) { 2090 fast = PETSC_FALSE; 2091 } else { 2092 PetscCall(ISGetSize(nest->isglobal.col[i], &f)); 2093 nf += f; 2094 } 2095 } 2096 } 2097 if (fast) { 2098 PetscCall(MatConvert_Nest_SeqAIJ_fast(A, newtype, reuse, newmat)); 2099 PetscFunctionReturn(PETSC_SUCCESS); 2100 } 2101 } 2102 PetscCall(MatGetSize(A, &M, &N)); 2103 PetscCall(MatGetLocalSize(A, &m, &n)); 2104 PetscCall(MatGetOwnershipRangeColumn(A, &cstart, &cend)); 2105 if (reuse == MAT_REUSE_MATRIX) C = *newmat; 2106 else { 2107 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C)); 2108 PetscCall(MatSetType(C, newtype)); 2109 PetscCall(MatSetSizes(C, m, n, M, N)); 2110 } 2111 PetscCall(PetscMalloc1(2 * m, &dnnz)); 2112 if (m) { 2113 onnz = dnnz + m; 2114 for (k = 0; k < m; k++) { 2115 dnnz[k] = 0; 2116 onnz[k] = 0; 2117 } 2118 } 2119 for (j = 0; j < nest->nc; ++j) { 2120 IS bNis; 2121 PetscInt bN; 2122 const PetscInt *bNindices; 2123 PetscBool flg; 2124 /* Using global column indices and ISAllGather() is not scalable. */ 2125 PetscCall(ISAllGather(nest->isglobal.col[j], &bNis)); 2126 PetscCall(ISGetSize(bNis, &bN)); 2127 PetscCall(ISGetIndices(bNis, &bNindices)); 2128 for (i = 0; i < nest->nr; ++i) { 2129 PetscSF bmsf; 2130 PetscSFNode *iremote; 2131 Mat B = nest->m[i][j], D = NULL; 2132 PetscInt bm, *sub_dnnz, *sub_onnz, br; 2133 const PetscInt *bmindices; 2134 if (!B) continue; 2135 PetscCall(ISGetLocalSize(nest->isglobal.row[i], &bm)); 2136 PetscCall(ISGetIndices(nest->isglobal.row[i], &bmindices)); 2137 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)A), &bmsf)); 2138 PetscCall(PetscMalloc1(bm, &iremote)); 2139 PetscCall(PetscMalloc1(bm, &sub_dnnz)); 2140 PetscCall(PetscMalloc1(bm, &sub_onnz)); 2141 for (k = 0; k < bm; ++k) { 2142 sub_dnnz[k] = 0; 2143 sub_onnz[k] = 0; 2144 } 2145 PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATTRANSPOSEVIRTUAL, MATHERMITIANTRANSPOSEVIRTUAL, "")); 2146 if (flg) { 2147 PetscTryMethod(B, "MatTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2148 PetscTryMethod(B, "MatHermitianTransposeGetMat_C", (Mat, Mat *), (B, &D)); 2149 PetscCall(MatConvert(B, ((PetscObject)D)->type_name, MAT_INITIAL_MATRIX, &D)); 2150 B = D; 2151 } 2152 PetscCall(PetscObjectTypeCompareAny((PetscObject)B, &flg, MATSEQSBAIJ, MATMPISBAIJ, "")); 2153 if (flg) { 2154 if (D) PetscCall(MatConvert(D, MATBAIJ, MAT_INPLACE_MATRIX, &D)); 2155 else PetscCall(MatConvert(B, MATBAIJ, MAT_INITIAL_MATRIX, &D)); 2156 B = D; 2157 } 2158 /* 2159 Locate the owners for all of the locally-owned global row indices for this row block. 2160 These determine the roots of PetscSF used to communicate preallocation data to row owners. 2161 The roots correspond to the dnnz and onnz entries; thus, there are two roots per row. 2162 */ 2163 PetscCall(MatGetOwnershipRange(B, &rstart, NULL)); 2164 for (br = 0; br < bm; ++br) { 2165 PetscInt row = bmindices[br], brncols, col; 2166 const PetscInt *brcols; 2167 PetscInt rowrel = 0; /* row's relative index on its owner rank */ 2168 PetscMPIInt rowowner = 0; 2169 PetscCall(PetscLayoutFindOwnerIndex(A->rmap, row, &rowowner, &rowrel)); 2170 /* how many roots */ 2171 iremote[br].rank = rowowner; 2172 iremote[br].index = rowrel; /* edge from bmdnnz to dnnz */ 2173 /* get nonzero pattern */ 2174 PetscCall(MatGetRow(B, br + rstart, &brncols, &brcols, NULL)); 2175 for (k = 0; k < brncols; k++) { 2176 col = bNindices[brcols[k]]; 2177 if (col >= A->cmap->range[rowowner] && col < A->cmap->range[rowowner + 1]) { 2178 sub_dnnz[br]++; 2179 } else { 2180 sub_onnz[br]++; 2181 } 2182 } 2183 PetscCall(MatRestoreRow(B, br + rstart, &brncols, &brcols, NULL)); 2184 } 2185 if (D) PetscCall(MatDestroy(&D)); 2186 PetscCall(ISRestoreIndices(nest->isglobal.row[i], &bmindices)); 2187 /* bsf will have to take care of disposing of bedges. */ 2188 PetscCall(PetscSFSetGraph(bmsf, m, bm, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 2189 PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 2190 PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_dnnz, dnnz, MPI_SUM)); 2191 PetscCall(PetscSFReduceBegin(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 2192 PetscCall(PetscSFReduceEnd(bmsf, MPIU_INT, sub_onnz, onnz, MPI_SUM)); 2193 PetscCall(PetscFree(sub_dnnz)); 2194 PetscCall(PetscFree(sub_onnz)); 2195 PetscCall(PetscSFDestroy(&bmsf)); 2196 } 2197 PetscCall(ISRestoreIndices(bNis, &bNindices)); 2198 PetscCall(ISDestroy(&bNis)); 2199 } 2200 /* Resize preallocation if overestimated */ 2201 for (i = 0; i < m; i++) { 2202 dnnz[i] = PetscMin(dnnz[i], A->cmap->n); 2203 onnz[i] = PetscMin(onnz[i], A->cmap->N - A->cmap->n); 2204 } 2205 PetscCall(MatSeqAIJSetPreallocation(C, 0, dnnz)); 2206 PetscCall(MatMPIAIJSetPreallocation(C, 0, dnnz, 0, onnz)); 2207 PetscCall(PetscFree(dnnz)); 2208 PetscCall(MatAXPY_Dense_Nest(C, 1.0, A)); 2209 if (reuse == MAT_INPLACE_MATRIX) { 2210 PetscCall(MatHeaderReplace(A, &C)); 2211 } else *newmat = C; 2212 PetscFunctionReturn(PETSC_SUCCESS); 2213 } 2214 2215 static PetscErrorCode MatConvert_Nest_Dense(Mat A, MatType newtype, MatReuse reuse, Mat *newmat) 2216 { 2217 Mat B; 2218 PetscInt m, n, M, N; 2219 2220 PetscFunctionBegin; 2221 PetscCall(MatGetSize(A, &M, &N)); 2222 PetscCall(MatGetLocalSize(A, &m, &n)); 2223 if (reuse == MAT_REUSE_MATRIX) { 2224 B = *newmat; 2225 PetscCall(MatZeroEntries(B)); 2226 } else { 2227 PetscCall(MatCreateDense(PetscObjectComm((PetscObject)A), m, PETSC_DECIDE, M, N, NULL, &B)); 2228 } 2229 PetscCall(MatAXPY_Dense_Nest(B, 1.0, A)); 2230 if (reuse == MAT_INPLACE_MATRIX) { 2231 PetscCall(MatHeaderReplace(A, &B)); 2232 } else if (reuse == MAT_INITIAL_MATRIX) *newmat = B; 2233 PetscFunctionReturn(PETSC_SUCCESS); 2234 } 2235 2236 static PetscErrorCode MatHasOperation_Nest(Mat mat, MatOperation op, PetscBool *has) 2237 { 2238 Mat_Nest *bA = (Mat_Nest *)mat->data; 2239 MatOperation opAdd; 2240 PetscInt i, j, nr = bA->nr, nc = bA->nc; 2241 PetscBool flg; 2242 2243 PetscFunctionBegin; 2244 *has = PETSC_FALSE; 2245 if (op == MATOP_MULT || op == MATOP_MULT_ADD || op == MATOP_MULT_TRANSPOSE || op == MATOP_MULT_TRANSPOSE_ADD) { 2246 opAdd = (op == MATOP_MULT || op == MATOP_MULT_ADD ? MATOP_MULT_ADD : MATOP_MULT_TRANSPOSE_ADD); 2247 for (j = 0; j < nc; j++) { 2248 for (i = 0; i < nr; i++) { 2249 if (!bA->m[i][j]) continue; 2250 PetscCall(MatHasOperation(bA->m[i][j], opAdd, &flg)); 2251 if (!flg) PetscFunctionReturn(PETSC_SUCCESS); 2252 } 2253 } 2254 } 2255 if (((void **)mat->ops)[op]) *has = PETSC_TRUE; 2256 PetscFunctionReturn(PETSC_SUCCESS); 2257 } 2258 2259 /*MC 2260 MATNEST - "nest" - Matrix type consisting of nested submatrices, each stored separately. 2261 2262 Level: intermediate 2263 2264 Notes: 2265 This matrix type permits scalable use of `PCFIELDSPLIT` and avoids the large memory costs of extracting submatrices. 2266 It allows the use of symmetric and block formats for parts of multi-physics simulations. 2267 It is usually used with `DMCOMPOSITE` and `DMCreateMatrix()` 2268 2269 Each of the submatrices lives on the same MPI communicator as the original nest matrix (though they can have zero 2270 rows/columns on some processes.) Thus this is not meant for cases where the submatrices live on far fewer processes 2271 than the nest matrix. 2272 2273 .seealso: [](ch_matrices), `Mat`, `MATNEST`, `MatCreate()`, `MatType`, `MatCreateNest()`, `MatNestSetSubMat()`, `MatNestGetSubMat()`, 2274 `VecCreateNest()`, `DMCreateMatrix()`, `DMCOMPOSITE`, `MatNestSetVecType()`, `MatNestGetLocalISs()`, 2275 `MatNestGetISs()`, `MatNestSetSubMats()`, `MatNestGetSubMats()` 2276 M*/ 2277 PETSC_EXTERN PetscErrorCode MatCreate_Nest(Mat A) 2278 { 2279 Mat_Nest *s; 2280 2281 PetscFunctionBegin; 2282 PetscCall(PetscNew(&s)); 2283 A->data = (void *)s; 2284 2285 s->nr = -1; 2286 s->nc = -1; 2287 s->m = NULL; 2288 s->splitassembly = PETSC_FALSE; 2289 2290 PetscCall(PetscMemzero(A->ops, sizeof(*A->ops))); 2291 2292 A->ops->mult = MatMult_Nest; 2293 A->ops->multadd = MatMultAdd_Nest; 2294 A->ops->multtranspose = MatMultTranspose_Nest; 2295 A->ops->multtransposeadd = MatMultTransposeAdd_Nest; 2296 A->ops->transpose = MatTranspose_Nest; 2297 A->ops->multhermitiantranspose = MatMultHermitianTranspose_Nest; 2298 A->ops->multhermitiantransposeadd = MatMultHermitianTransposeAdd_Nest; 2299 A->ops->assemblybegin = MatAssemblyBegin_Nest; 2300 A->ops->assemblyend = MatAssemblyEnd_Nest; 2301 A->ops->zeroentries = MatZeroEntries_Nest; 2302 A->ops->copy = MatCopy_Nest; 2303 A->ops->axpy = MatAXPY_Nest; 2304 A->ops->duplicate = MatDuplicate_Nest; 2305 A->ops->createsubmatrix = MatCreateSubMatrix_Nest; 2306 A->ops->destroy = MatDestroy_Nest; 2307 A->ops->view = MatView_Nest; 2308 A->ops->getvecs = NULL; /* Use VECNEST by calling MatNestSetVecType(A,VECNEST) */ 2309 A->ops->getlocalsubmatrix = MatGetLocalSubMatrix_Nest; 2310 A->ops->restorelocalsubmatrix = MatRestoreLocalSubMatrix_Nest; 2311 A->ops->getdiagonal = MatGetDiagonal_Nest; 2312 A->ops->diagonalscale = MatDiagonalScale_Nest; 2313 A->ops->scale = MatScale_Nest; 2314 A->ops->shift = MatShift_Nest; 2315 A->ops->diagonalset = MatDiagonalSet_Nest; 2316 A->ops->setrandom = MatSetRandom_Nest; 2317 A->ops->hasoperation = MatHasOperation_Nest; 2318 A->ops->missingdiagonal = MatMissingDiagonal_Nest; 2319 2320 A->spptr = NULL; 2321 A->assembled = PETSC_FALSE; 2322 2323 /* expose Nest api's */ 2324 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMat_C", MatNestGetSubMat_Nest)); 2325 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMat_C", MatNestSetSubMat_Nest)); 2326 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSubMats_C", MatNestGetSubMats_Nest)); 2327 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetSize_C", MatNestGetSize_Nest)); 2328 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetISs_C", MatNestGetISs_Nest)); 2329 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestGetLocalISs_C", MatNestGetLocalISs_Nest)); 2330 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetVecType_C", MatNestSetVecType_Nest)); 2331 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatNestSetSubMats_C", MatNestSetSubMats_Nest)); 2332 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpiaij_C", MatConvert_Nest_AIJ)); 2333 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqaij_C", MatConvert_Nest_AIJ)); 2334 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_aij_C", MatConvert_Nest_AIJ)); 2335 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_is_C", MatConvert_Nest_IS)); 2336 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_mpidense_C", MatConvert_Nest_Dense)); 2337 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_nest_seqdense_C", MatConvert_Nest_Dense)); 2338 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_seqdense_C", MatProductSetFromOptions_Nest_Dense)); 2339 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatProductSetFromOptions_nest_mpidense_C", MatProductSetFromOptions_Nest_Dense)); 2340 2341 PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATNEST)); 2342 PetscFunctionReturn(PETSC_SUCCESS); 2343 } 2344