1 /* 2 Creates a matrix class for using the Neumann-Neumann type preconditioners. 3 This stores the matrices in globally unassembled form. Each processor 4 assembles only its local Neumann problem and the parallel matrix vector 5 product is handled "implicitly". 6 7 Currently this allows for only one subdomain per processor. 8 */ 9 10 #include <petsc/private/matisimpl.h> /*I "petscmat.h" I*/ 11 #include <../src/mat/impls/aij/mpi/mpiaij.h> 12 #include <petsc/private/sfimpl.h> 13 #include <petsc/private/vecimpl.h> 14 #include <petsc/private/hashseti.h> 15 16 #define MATIS_MAX_ENTRIES_INSERTION 2048 17 18 /* copied from src/mat/impls/localref/mlocalref.c */ 19 #define IndexSpaceGet(buf, nrow, ncol, irowm, icolm) \ 20 do { \ 21 if (nrow + ncol > (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) { \ 22 PetscCall(PetscMalloc2(nrow, &irowm, ncol, &icolm)); \ 23 } else { \ 24 irowm = &buf[0]; \ 25 icolm = &buf[nrow]; \ 26 } \ 27 } while (0) 28 29 #define IndexSpaceRestore(buf, nrow, ncol, irowm, icolm) \ 30 do { \ 31 if (nrow + ncol > (PetscInt)PETSC_STATIC_ARRAY_LENGTH(buf)) PetscCall(PetscFree2(irowm, icolm)); \ 32 } while (0) 33 34 static void BlockIndicesExpand(PetscInt n, const PetscInt idx[], PetscInt bs, PetscInt idxm[]) 35 { 36 for (PetscInt i = 0; i < n; i++) { 37 for (PetscInt j = 0; j < bs; j++) idxm[i * bs + j] = idx[i] * bs + j; 38 } 39 } 40 41 static PetscErrorCode MatSetValuesLocal_IS(Mat, PetscInt, const PetscInt *, PetscInt, const PetscInt *, const PetscScalar *, InsertMode); 42 static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat, PetscInt, const PetscInt *, PetscInt, const PetscInt *, const PetscScalar *, InsertMode); 43 static PetscErrorCode MatISSetUpScatters_Private(Mat); 44 45 static PetscErrorCode MatISContainerDestroyPtAP_Private(void **ptr) 46 { 47 MatISPtAP ptap = (MatISPtAP)*ptr; 48 49 PetscFunctionBegin; 50 PetscCall(MatDestroySubMatrices(ptap->ris1 ? 2 : 1, &ptap->lP)); 51 PetscCall(ISDestroy(&ptap->cis0)); 52 PetscCall(ISDestroy(&ptap->cis1)); 53 PetscCall(ISDestroy(&ptap->ris0)); 54 PetscCall(ISDestroy(&ptap->ris1)); 55 PetscCall(PetscFree(ptap)); 56 PetscFunctionReturn(PETSC_SUCCESS); 57 } 58 59 static PetscErrorCode MatPtAPNumeric_IS_XAIJ(Mat A, Mat P, Mat C) 60 { 61 MatISPtAP ptap; 62 Mat_IS *matis = (Mat_IS *)A->data; 63 Mat lA, lC; 64 MatReuse reuse; 65 IS ris[2], cis[2]; 66 PetscContainer c; 67 PetscInt n; 68 69 PetscFunctionBegin; 70 PetscCall(PetscObjectQuery((PetscObject)C, "_MatIS_PtAP", (PetscObject *)&c)); 71 PetscCheck(c, PetscObjectComm((PetscObject)C), PETSC_ERR_PLIB, "Missing PtAP information"); 72 PetscCall(PetscContainerGetPointer(c, (void **)&ptap)); 73 ris[0] = ptap->ris0; 74 ris[1] = ptap->ris1; 75 cis[0] = ptap->cis0; 76 cis[1] = ptap->cis1; 77 n = ptap->ris1 ? 2 : 1; 78 reuse = ptap->lP ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX; 79 PetscCall(MatCreateSubMatrices(P, n, ris, cis, reuse, &ptap->lP)); 80 81 PetscCall(MatISGetLocalMat(A, &lA)); 82 PetscCall(MatISGetLocalMat(C, &lC)); 83 if (ptap->ris1) { /* unsymmetric A mapping */ 84 Mat lPt; 85 86 PetscCall(MatTranspose(ptap->lP[1], MAT_INITIAL_MATRIX, &lPt)); 87 PetscCall(MatMatMatMult(lPt, lA, ptap->lP[0], reuse, ptap->fill, &lC)); 88 if (matis->storel2l) PetscCall(PetscObjectCompose((PetscObject)A, "_MatIS_PtAP_l2l", (PetscObject)lPt)); 89 PetscCall(MatDestroy(&lPt)); 90 } else { 91 PetscCall(MatPtAP(lA, ptap->lP[0], reuse, ptap->fill, &lC)); 92 if (matis->storel2l) PetscCall(PetscObjectCompose((PetscObject)C, "_MatIS_PtAP_l2l", (PetscObject)ptap->lP[0])); 93 } 94 if (reuse == MAT_INITIAL_MATRIX) { 95 PetscCall(MatISSetLocalMat(C, lC)); 96 PetscCall(MatDestroy(&lC)); 97 } 98 PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); 99 PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); 100 PetscFunctionReturn(PETSC_SUCCESS); 101 } 102 103 static PetscErrorCode MatGetNonzeroColumnsLocal_Private(Mat PT, IS *cis) 104 { 105 Mat Po, Pd; 106 IS zd, zo; 107 const PetscInt *garray; 108 PetscInt *aux, i, bs; 109 PetscInt dc, stc, oc, ctd, cto; 110 PetscBool ismpiaij, ismpibaij, isseqaij, isseqbaij; 111 MPI_Comm comm; 112 113 PetscFunctionBegin; 114 PetscValidHeaderSpecific(PT, MAT_CLASSID, 1); 115 PetscAssertPointer(cis, 2); 116 PetscCall(PetscObjectGetComm((PetscObject)PT, &comm)); 117 bs = 1; 118 PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATMPIAIJ, &ismpiaij)); 119 PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATMPIBAIJ, &ismpibaij)); 120 PetscCall(PetscObjectBaseTypeCompare((PetscObject)PT, MATSEQAIJ, &isseqaij)); 121 PetscCall(PetscObjectTypeCompare((PetscObject)PT, MATSEQBAIJ, &isseqbaij)); 122 if (isseqaij || isseqbaij) { 123 Pd = PT; 124 Po = NULL; 125 garray = NULL; 126 } else if (ismpiaij) { 127 PetscCall(MatMPIAIJGetSeqAIJ(PT, &Pd, &Po, &garray)); 128 } else if (ismpibaij) { 129 PetscCall(MatMPIBAIJGetSeqBAIJ(PT, &Pd, &Po, &garray)); 130 PetscCall(MatGetBlockSize(PT, &bs)); 131 } else SETERRQ(comm, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)PT)->type_name); 132 133 /* identify any null columns in Pd or Po */ 134 /* We use a tolerance comparison since it may happen that, with geometric multigrid, 135 some of the columns are not really zero, but very close to */ 136 zo = zd = NULL; 137 if (Po) PetscCall(MatFindNonzeroRowsOrCols_Basic(Po, PETSC_TRUE, PETSC_SMALL, &zo)); 138 PetscCall(MatFindNonzeroRowsOrCols_Basic(Pd, PETSC_TRUE, PETSC_SMALL, &zd)); 139 140 PetscCall(MatGetLocalSize(PT, NULL, &dc)); 141 PetscCall(MatGetOwnershipRangeColumn(PT, &stc, NULL)); 142 if (Po) PetscCall(MatGetLocalSize(Po, NULL, &oc)); 143 else oc = 0; 144 PetscCall(PetscMalloc1((dc + oc) / bs, &aux)); 145 if (zd) { 146 const PetscInt *idxs; 147 PetscInt nz; 148 149 /* this will throw an error if bs is not valid */ 150 PetscCall(ISSetBlockSize(zd, bs)); 151 PetscCall(ISGetLocalSize(zd, &nz)); 152 PetscCall(ISGetIndices(zd, &idxs)); 153 ctd = nz / bs; 154 for (i = 0; i < ctd; i++) aux[i] = (idxs[bs * i] + stc) / bs; 155 PetscCall(ISRestoreIndices(zd, &idxs)); 156 } else { 157 ctd = dc / bs; 158 for (i = 0; i < ctd; i++) aux[i] = i + stc / bs; 159 } 160 if (zo) { 161 const PetscInt *idxs; 162 PetscInt nz; 163 164 /* this will throw an error if bs is not valid */ 165 PetscCall(ISSetBlockSize(zo, bs)); 166 PetscCall(ISGetLocalSize(zo, &nz)); 167 PetscCall(ISGetIndices(zo, &idxs)); 168 cto = nz / bs; 169 for (i = 0; i < cto; i++) aux[i + ctd] = garray[idxs[bs * i] / bs]; 170 PetscCall(ISRestoreIndices(zo, &idxs)); 171 } else { 172 cto = oc / bs; 173 for (i = 0; i < cto; i++) aux[i + ctd] = garray[i]; 174 } 175 PetscCall(ISCreateBlock(comm, bs, ctd + cto, aux, PETSC_OWN_POINTER, cis)); 176 PetscCall(ISDestroy(&zd)); 177 PetscCall(ISDestroy(&zo)); 178 PetscFunctionReturn(PETSC_SUCCESS); 179 } 180 181 static PetscErrorCode MatPtAPSymbolic_IS_XAIJ(Mat A, Mat P, PetscReal fill, Mat C) 182 { 183 Mat PT, lA; 184 MatISPtAP ptap; 185 ISLocalToGlobalMapping Crl2g, Ccl2g, rl2g, cl2g; 186 PetscContainer c; 187 MatType lmtype; 188 const PetscInt *garray; 189 PetscInt ibs, N, dc; 190 MPI_Comm comm; 191 192 PetscFunctionBegin; 193 PetscCall(PetscObjectGetComm((PetscObject)A, &comm)); 194 PetscCall(MatSetType(C, MATIS)); 195 PetscCall(MatISGetLocalMat(A, &lA)); 196 PetscCall(MatGetType(lA, &lmtype)); 197 PetscCall(MatISSetLocalMatType(C, lmtype)); 198 PetscCall(MatGetSize(P, NULL, &N)); 199 PetscCall(MatGetLocalSize(P, NULL, &dc)); 200 PetscCall(MatSetSizes(C, dc, dc, N, N)); 201 /* Not sure about this 202 PetscCall(MatGetBlockSizes(P,NULL,&ibs)); 203 PetscCall(MatSetBlockSize(*C,ibs)); 204 */ 205 206 PetscCall(PetscNew(&ptap)); 207 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &c)); 208 PetscCall(PetscContainerSetPointer(c, ptap)); 209 PetscCall(PetscContainerSetCtxDestroy(c, MatISContainerDestroyPtAP_Private)); 210 PetscCall(PetscObjectCompose((PetscObject)C, "_MatIS_PtAP", (PetscObject)c)); 211 PetscCall(PetscContainerDestroy(&c)); 212 ptap->fill = fill; 213 214 PetscCall(MatISGetLocalToGlobalMapping(A, &rl2g, &cl2g)); 215 216 PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &ibs)); 217 PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &N)); 218 PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &garray)); 219 PetscCall(ISCreateBlock(comm, ibs, N / ibs, garray, PETSC_COPY_VALUES, &ptap->ris0)); 220 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &garray)); 221 222 PetscCall(MatCreateSubMatrix(P, ptap->ris0, NULL, MAT_INITIAL_MATRIX, &PT)); 223 PetscCall(MatGetNonzeroColumnsLocal_Private(PT, &ptap->cis0)); 224 PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis0, &Ccl2g)); 225 PetscCall(MatDestroy(&PT)); 226 227 Crl2g = NULL; 228 if (rl2g != cl2g) { /* unsymmetric A mapping */ 229 PetscBool same, lsame = PETSC_FALSE; 230 PetscInt N1, ibs1; 231 232 PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &N1)); 233 PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &ibs1)); 234 PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &garray)); 235 PetscCall(ISCreateBlock(comm, ibs, N1 / ibs, garray, PETSC_COPY_VALUES, &ptap->ris1)); 236 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &garray)); 237 if (ibs1 == ibs && N1 == N) { /* check if the l2gmaps are the same */ 238 const PetscInt *i1, *i2; 239 240 PetscCall(ISBlockGetIndices(ptap->ris0, &i1)); 241 PetscCall(ISBlockGetIndices(ptap->ris1, &i2)); 242 PetscCall(PetscArraycmp(i1, i2, N, &lsame)); 243 } 244 PetscCallMPI(MPIU_Allreduce(&lsame, &same, 1, MPI_C_BOOL, MPI_LAND, comm)); 245 if (same) { 246 PetscCall(ISDestroy(&ptap->ris1)); 247 } else { 248 PetscCall(MatCreateSubMatrix(P, ptap->ris1, NULL, MAT_INITIAL_MATRIX, &PT)); 249 PetscCall(MatGetNonzeroColumnsLocal_Private(PT, &ptap->cis1)); 250 PetscCall(ISLocalToGlobalMappingCreateIS(ptap->cis1, &Crl2g)); 251 PetscCall(MatDestroy(&PT)); 252 } 253 } 254 /* Not sure about this 255 if (!Crl2g) { 256 PetscCall(MatGetBlockSize(C,&ibs)); 257 PetscCall(ISLocalToGlobalMappingSetBlockSize(Ccl2g,ibs)); 258 } 259 */ 260 PetscCall(MatSetLocalToGlobalMapping(C, Crl2g ? Crl2g : Ccl2g, Ccl2g)); 261 PetscCall(ISLocalToGlobalMappingDestroy(&Crl2g)); 262 PetscCall(ISLocalToGlobalMappingDestroy(&Ccl2g)); 263 264 C->ops->ptapnumeric = MatPtAPNumeric_IS_XAIJ; 265 PetscFunctionReturn(PETSC_SUCCESS); 266 } 267 268 static PetscErrorCode MatProductSymbolic_PtAP_IS_XAIJ(Mat C) 269 { 270 Mat_Product *product = C->product; 271 Mat A = product->A, P = product->B; 272 PetscReal fill = product->fill; 273 274 PetscFunctionBegin; 275 PetscCall(MatPtAPSymbolic_IS_XAIJ(A, P, fill, C)); 276 C->ops->productnumeric = MatProductNumeric_PtAP; 277 PetscFunctionReturn(PETSC_SUCCESS); 278 } 279 280 static PetscErrorCode MatProductSetFromOptions_IS_XAIJ_PtAP(Mat C) 281 { 282 PetscFunctionBegin; 283 C->ops->productsymbolic = MatProductSymbolic_PtAP_IS_XAIJ; 284 PetscFunctionReturn(PETSC_SUCCESS); 285 } 286 287 PETSC_INTERN PetscErrorCode MatProductSetFromOptions_IS_XAIJ(Mat C) 288 { 289 Mat_Product *product = C->product; 290 291 PetscFunctionBegin; 292 if (product->type == MATPRODUCT_PtAP) PetscCall(MatProductSetFromOptions_IS_XAIJ_PtAP(C)); 293 PetscFunctionReturn(PETSC_SUCCESS); 294 } 295 296 static PetscErrorCode MatISContainerDestroyFields_Private(void **ptr) 297 { 298 MatISLocalFields lf = (MatISLocalFields)*ptr; 299 PetscInt i; 300 301 PetscFunctionBegin; 302 for (i = 0; i < lf->nr; i++) PetscCall(ISDestroy(&lf->rf[i])); 303 for (i = 0; i < lf->nc; i++) PetscCall(ISDestroy(&lf->cf[i])); 304 PetscCall(PetscFree2(lf->rf, lf->cf)); 305 PetscCall(PetscFree(lf)); 306 PetscFunctionReturn(PETSC_SUCCESS); 307 } 308 309 static PetscErrorCode MatConvert_SeqXAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat) 310 { 311 Mat B, lB; 312 313 PetscFunctionBegin; 314 if (reuse != MAT_REUSE_MATRIX) { 315 ISLocalToGlobalMapping rl2g, cl2g; 316 PetscInt bs; 317 IS is; 318 319 PetscCall(MatGetBlockSize(A, &bs)); 320 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->n / bs, 0, 1, &is)); 321 if (bs > 1) { 322 IS is2; 323 PetscInt i, *aux; 324 325 PetscCall(ISGetLocalSize(is, &i)); 326 PetscCall(ISGetIndices(is, (const PetscInt **)&aux)); 327 PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2)); 328 PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux)); 329 PetscCall(ISDestroy(&is)); 330 is = is2; 331 } 332 PetscCall(ISSetIdentity(is)); 333 PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g)); 334 PetscCall(ISDestroy(&is)); 335 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->n / bs, 0, 1, &is)); 336 if (bs > 1) { 337 IS is2; 338 PetscInt i, *aux; 339 340 PetscCall(ISGetLocalSize(is, &i)); 341 PetscCall(ISGetIndices(is, (const PetscInt **)&aux)); 342 PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, i, aux, PETSC_COPY_VALUES, &is2)); 343 PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux)); 344 PetscCall(ISDestroy(&is)); 345 is = is2; 346 } 347 PetscCall(ISSetIdentity(is)); 348 PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g)); 349 PetscCall(ISDestroy(&is)); 350 PetscCall(MatCreateIS(PetscObjectComm((PetscObject)A), bs, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N, rl2g, cl2g, &B)); 351 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 352 PetscCall(ISLocalToGlobalMappingDestroy(&cl2g)); 353 PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &lB)); 354 if (reuse == MAT_INITIAL_MATRIX) *newmat = B; 355 } else { 356 B = *newmat; 357 PetscCall(PetscObjectReference((PetscObject)A)); 358 lB = A; 359 } 360 PetscCall(MatISSetLocalMat(B, lB)); 361 PetscCall(MatDestroy(&lB)); 362 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 363 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 364 if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B)); 365 PetscFunctionReturn(PETSC_SUCCESS); 366 } 367 368 static PetscErrorCode MatISScaleDisassembling_Private(Mat A) 369 { 370 Mat_IS *matis = (Mat_IS *)A->data; 371 PetscScalar *aa; 372 const PetscInt *ii, *jj; 373 PetscInt i, n, m; 374 PetscInt *ecount, **eneighs; 375 PetscBool flg; 376 377 PetscFunctionBegin; 378 PetscCall(MatGetRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg)); 379 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure"); 380 PetscCall(ISLocalToGlobalMappingGetNodeInfo(matis->rmapping, &n, &ecount, &eneighs)); 381 PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %" PetscInt_FMT " != %" PetscInt_FMT, m, n); 382 PetscCall(MatSeqAIJGetArray(matis->A, &aa)); 383 for (i = 0; i < n; i++) { 384 if (ecount[i] > 1) { 385 PetscInt j; 386 387 for (j = ii[i]; j < ii[i + 1]; j++) { 388 PetscInt i2 = jj[j], p, p2; 389 PetscReal scal = 0.0; 390 391 for (p = 0; p < ecount[i]; p++) { 392 for (p2 = 0; p2 < ecount[i2]; p2++) { 393 if (eneighs[i][p] == eneighs[i2][p2]) { 394 scal += 1.0; 395 break; 396 } 397 } 398 } 399 if (scal) aa[j] /= scal; 400 } 401 } 402 } 403 PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(matis->rmapping, &n, &ecount, &eneighs)); 404 PetscCall(MatSeqAIJRestoreArray(matis->A, &aa)); 405 PetscCall(MatRestoreRowIJ(matis->A, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg)); 406 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure"); 407 PetscFunctionReturn(PETSC_SUCCESS); 408 } 409 410 typedef enum { 411 MAT_IS_DISASSEMBLE_L2G_NATURAL, 412 MAT_IS_DISASSEMBLE_L2G_MAT, 413 MAT_IS_DISASSEMBLE_L2G_ND 414 } MatISDisassemblel2gType; 415 416 static PetscErrorCode MatMPIXAIJComputeLocalToGlobalMapping_Private(Mat A, ISLocalToGlobalMapping *l2g) 417 { 418 Mat Ad, Ao; 419 IS is, ndmap, ndsub; 420 MPI_Comm comm; 421 const PetscInt *garray, *ndmapi; 422 PetscInt bs, i, cnt, nl, *ncount, *ndmapc; 423 PetscBool ismpiaij, ismpibaij; 424 const char *const MatISDisassemblel2gTypes[] = {"NATURAL", "MAT", "ND", "MatISDisassemblel2gType", "MAT_IS_DISASSEMBLE_L2G_", NULL}; 425 MatISDisassemblel2gType mode = MAT_IS_DISASSEMBLE_L2G_NATURAL; 426 MatPartitioning part; 427 PetscSF sf; 428 PetscObject dm; 429 430 PetscFunctionBegin; 431 PetscOptionsBegin(PetscObjectComm((PetscObject)A), ((PetscObject)A)->prefix, "MatIS l2g disassembling options", "Mat"); 432 PetscCall(PetscOptionsEnum("-mat_is_disassemble_l2g_type", "Type of local-to-global mapping to be used for disassembling", "MatISDisassemblel2gType", MatISDisassemblel2gTypes, (PetscEnum)mode, (PetscEnum *)&mode, NULL)); 433 PetscOptionsEnd(); 434 if (mode == MAT_IS_DISASSEMBLE_L2G_MAT) { 435 PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL)); 436 PetscFunctionReturn(PETSC_SUCCESS); 437 } 438 PetscCall(PetscObjectGetComm((PetscObject)A, &comm)); 439 PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij)); 440 PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij)); 441 PetscCall(MatGetBlockSize(A, &bs)); 442 switch (mode) { 443 case MAT_IS_DISASSEMBLE_L2G_ND: 444 PetscCall(MatPartitioningCreate(comm, &part)); 445 PetscCall(MatPartitioningSetAdjacency(part, A)); 446 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)part, ((PetscObject)A)->prefix)); 447 PetscCall(MatPartitioningSetFromOptions(part)); 448 PetscCall(MatPartitioningApplyND(part, &ndmap)); 449 PetscCall(MatPartitioningDestroy(&part)); 450 PetscCall(ISBuildTwoSided(ndmap, NULL, &ndsub)); 451 PetscCall(MatMPIAIJSetUseScalableIncreaseOverlap(A, PETSC_TRUE)); 452 PetscCall(MatIncreaseOverlap(A, 1, &ndsub, 1)); 453 PetscCall(ISLocalToGlobalMappingCreateIS(ndsub, l2g)); 454 455 /* it may happen that a separator node is not properly shared */ 456 PetscCall(ISLocalToGlobalMappingGetNodeInfo(*l2g, &nl, &ncount, NULL)); 457 PetscCall(PetscSFCreate(comm, &sf)); 458 PetscCall(ISLocalToGlobalMappingGetIndices(*l2g, &garray)); 459 PetscCall(PetscSFSetGraphLayout(sf, A->rmap, nl, NULL, PETSC_OWN_POINTER, garray)); 460 PetscCall(ISLocalToGlobalMappingRestoreIndices(*l2g, &garray)); 461 PetscCall(PetscCalloc1(A->rmap->n, &ndmapc)); 462 PetscCall(PetscSFReduceBegin(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE)); 463 PetscCall(PetscSFReduceEnd(sf, MPIU_INT, ncount, ndmapc, MPI_REPLACE)); 464 PetscCall(ISLocalToGlobalMappingRestoreNodeInfo(*l2g, NULL, &ncount, NULL)); 465 PetscCall(ISGetIndices(ndmap, &ndmapi)); 466 for (i = 0, cnt = 0; i < A->rmap->n; i++) 467 if (ndmapi[i] < 0 && ndmapc[i] < 2) cnt++; 468 469 PetscCallMPI(MPIU_Allreduce(&cnt, &i, 1, MPIU_INT, MPI_MAX, comm)); 470 if (i) { /* we detected isolated separator nodes */ 471 Mat A2, A3; 472 IS *workis, is2; 473 PetscScalar *vals; 474 PetscInt gcnt = i, *dnz, *onz, j, *lndmapi; 475 ISLocalToGlobalMapping ll2g; 476 PetscBool flg; 477 const PetscInt *ii, *jj; 478 479 /* communicate global id of separators */ 480 MatPreallocateBegin(comm, A->rmap->n, A->cmap->n, dnz, onz); 481 for (i = 0, cnt = 0; i < A->rmap->n; i++) dnz[i] = ndmapi[i] < 0 ? i + A->rmap->rstart : -1; 482 483 PetscCall(PetscMalloc1(nl, &lndmapi)); 484 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE)); 485 486 /* compute adjacency of isolated separators node */ 487 PetscCall(PetscMalloc1(gcnt, &workis)); 488 for (i = 0, cnt = 0; i < A->rmap->n; i++) { 489 if (ndmapi[i] < 0 && ndmapc[i] < 2) PetscCall(ISCreateStride(comm, 1, i + A->rmap->rstart, 1, &workis[cnt++])); 490 } 491 for (i = cnt; i < gcnt; i++) PetscCall(ISCreateStride(comm, 0, 0, 1, &workis[i])); 492 for (i = 0; i < gcnt; i++) { 493 PetscCall(PetscObjectSetName((PetscObject)workis[i], "ISOLATED")); 494 PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators")); 495 } 496 497 /* no communications since all the ISes correspond to locally owned rows */ 498 PetscCall(MatIncreaseOverlap(A, gcnt, workis, 1)); 499 500 /* end communicate global id of separators */ 501 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, dnz, lndmapi, MPI_REPLACE)); 502 503 /* communicate new layers : create a matrix and transpose it */ 504 PetscCall(PetscArrayzero(dnz, A->rmap->n)); 505 PetscCall(PetscArrayzero(onz, A->rmap->n)); 506 for (i = 0, j = 0; i < A->rmap->n; i++) { 507 if (ndmapi[i] < 0 && ndmapc[i] < 2) { 508 const PetscInt *idxs; 509 PetscInt s; 510 511 PetscCall(ISGetLocalSize(workis[j], &s)); 512 PetscCall(ISGetIndices(workis[j], &idxs)); 513 PetscCall(MatPreallocateSet(i + A->rmap->rstart, s, idxs, dnz, onz)); 514 j++; 515 } 516 } 517 PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt); 518 519 for (i = 0; i < gcnt; i++) { 520 PetscCall(PetscObjectSetName((PetscObject)workis[i], "EXTENDED")); 521 PetscCall(ISViewFromOptions(workis[i], NULL, "-view_isolated_separators")); 522 } 523 524 for (i = 0, j = 0; i < A->rmap->n; i++) j = PetscMax(j, dnz[i] + onz[i]); 525 PetscCall(PetscMalloc1(j, &vals)); 526 for (i = 0; i < j; i++) vals[i] = 1.0; 527 528 PetscCall(MatCreate(comm, &A2)); 529 PetscCall(MatSetType(A2, MATMPIAIJ)); 530 PetscCall(MatSetSizes(A2, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N)); 531 PetscCall(MatMPIAIJSetPreallocation(A2, 0, dnz, 0, onz)); 532 PetscCall(MatSetOption(A2, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); 533 for (i = 0, j = 0; i < A2->rmap->n; i++) { 534 PetscInt row = i + A2->rmap->rstart, s = dnz[i] + onz[i]; 535 const PetscInt *idxs; 536 537 if (s) { 538 PetscCall(ISGetIndices(workis[j], &idxs)); 539 PetscCall(MatSetValues(A2, 1, &row, s, idxs, vals, INSERT_VALUES)); 540 PetscCall(ISRestoreIndices(workis[j], &idxs)); 541 j++; 542 } 543 } 544 PetscCheck(j == cnt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected local count %" PetscInt_FMT " != %" PetscInt_FMT, j, cnt); 545 PetscCall(PetscFree(vals)); 546 PetscCall(MatAssemblyBegin(A2, MAT_FINAL_ASSEMBLY)); 547 PetscCall(MatAssemblyEnd(A2, MAT_FINAL_ASSEMBLY)); 548 PetscCall(MatTranspose(A2, MAT_INPLACE_MATRIX, &A2)); 549 550 /* extract submatrix corresponding to the coupling "owned separators" x "isolated separators" */ 551 for (i = 0, j = 0; i < nl; i++) 552 if (lndmapi[i] >= 0) lndmapi[j++] = lndmapi[i]; 553 PetscCall(ISCreateGeneral(comm, j, lndmapi, PETSC_USE_POINTER, &is)); 554 PetscCall(MatMPIAIJGetLocalMatCondensed(A2, MAT_INITIAL_MATRIX, &is, NULL, &A3)); 555 PetscCall(ISDestroy(&is)); 556 PetscCall(MatDestroy(&A2)); 557 558 /* extend local to global map to include connected isolated separators */ 559 PetscCall(PetscObjectQuery((PetscObject)A3, "_petsc_GetLocalMatCondensed_iscol", (PetscObject *)&is)); 560 PetscCheck(is, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing column map"); 561 PetscCall(ISLocalToGlobalMappingCreateIS(is, &ll2g)); 562 PetscCall(MatGetRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg)); 563 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure"); 564 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ii[i], jj, PETSC_COPY_VALUES, &is)); 565 PetscCall(MatRestoreRowIJ(A3, 0, PETSC_FALSE, PETSC_FALSE, &i, &ii, &jj, &flg)); 566 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure"); 567 PetscCall(ISLocalToGlobalMappingApplyIS(ll2g, is, &is2)); 568 PetscCall(ISDestroy(&is)); 569 PetscCall(ISLocalToGlobalMappingDestroy(&ll2g)); 570 571 /* add new nodes to the local-to-global map */ 572 PetscCall(ISLocalToGlobalMappingDestroy(l2g)); 573 PetscCall(ISExpand(ndsub, is2, &is)); 574 PetscCall(ISDestroy(&is2)); 575 PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g)); 576 PetscCall(ISDestroy(&is)); 577 578 PetscCall(MatDestroy(&A3)); 579 PetscCall(PetscFree(lndmapi)); 580 MatPreallocateEnd(dnz, onz); 581 for (i = 0; i < gcnt; i++) PetscCall(ISDestroy(&workis[i])); 582 PetscCall(PetscFree(workis)); 583 } 584 PetscCall(ISRestoreIndices(ndmap, &ndmapi)); 585 PetscCall(PetscSFDestroy(&sf)); 586 PetscCall(PetscFree(ndmapc)); 587 PetscCall(ISDestroy(&ndmap)); 588 PetscCall(ISDestroy(&ndsub)); 589 PetscCall(ISLocalToGlobalMappingSetBlockSize(*l2g, bs)); 590 PetscCall(ISLocalToGlobalMappingViewFromOptions(*l2g, NULL, "-mat_is_nd_l2g_view")); 591 break; 592 case MAT_IS_DISASSEMBLE_L2G_NATURAL: 593 PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", &dm)); 594 if (dm) { /* if a matrix comes from a DM, most likely we can use the l2gmap if any */ 595 PetscCall(MatGetLocalToGlobalMapping(A, l2g, NULL)); 596 PetscCall(PetscObjectReference((PetscObject)*l2g)); 597 if (*l2g) PetscFunctionReturn(PETSC_SUCCESS); 598 } 599 if (ismpiaij) { 600 PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray)); 601 } else if (ismpibaij) { 602 PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray)); 603 } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name); 604 if (A->rmap->n) { 605 PetscInt dc, oc, stc, *aux; 606 607 PetscCall(MatGetLocalSize(Ad, NULL, &dc)); 608 PetscCall(MatGetLocalSize(Ao, NULL, &oc)); 609 PetscCheck(!oc || garray, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "garray not present"); 610 PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL)); 611 PetscCall(PetscMalloc1((dc + oc) / bs, &aux)); 612 for (i = 0; i < dc / bs; i++) aux[i] = i + stc / bs; 613 for (i = 0; i < oc / bs; i++) aux[i + dc / bs] = (ismpiaij ? garray[i * bs] / bs : garray[i]); 614 PetscCall(ISCreateBlock(comm, bs, (dc + oc) / bs, aux, PETSC_OWN_POINTER, &is)); 615 } else { 616 PetscCall(ISCreateBlock(comm, 1, 0, NULL, PETSC_OWN_POINTER, &is)); 617 } 618 PetscCall(ISLocalToGlobalMappingCreateIS(is, l2g)); 619 PetscCall(ISDestroy(&is)); 620 break; 621 default: 622 SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unsupported l2g disassembling type %d", mode); 623 } 624 PetscFunctionReturn(PETSC_SUCCESS); 625 } 626 627 PETSC_INTERN PetscErrorCode MatConvert_XAIJ_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat) 628 { 629 Mat lA, Ad, Ao, B = NULL; 630 ISLocalToGlobalMapping rl2g, cl2g; 631 IS is; 632 MPI_Comm comm; 633 void *ptrs[2]; 634 const char *names[2] = {"_convert_csr_aux", "_convert_csr_data"}; 635 const PetscInt *garray; 636 PetscScalar *dd, *od, *aa, *data; 637 const PetscInt *di, *dj, *oi, *oj; 638 const PetscInt *odi, *odj, *ooi, *ooj; 639 PetscInt *aux, *ii, *jj; 640 PetscInt rbs, cbs, lc, dr, dc, oc, str, stc, nnz, i, jd, jo, cum; 641 PetscBool flg, ismpiaij, ismpibaij, was_inplace = PETSC_FALSE, cong; 642 PetscMPIInt size; 643 644 PetscFunctionBegin; 645 PetscCall(PetscObjectGetComm((PetscObject)A, &comm)); 646 PetscCallMPI(MPI_Comm_size(comm, &size)); 647 if (size == 1) { 648 PetscCall(MatConvert_SeqXAIJ_IS(A, type, reuse, newmat)); 649 PetscFunctionReturn(PETSC_SUCCESS); 650 } 651 PetscCall(MatGetBlockSizes(A, &rbs, &cbs)); 652 PetscCall(MatHasCongruentLayouts(A, &cong)); 653 if (reuse != MAT_REUSE_MATRIX && cong && rbs == cbs) { 654 PetscCall(MatMPIXAIJComputeLocalToGlobalMapping_Private(A, &rl2g)); 655 PetscCall(MatCreate(comm, &B)); 656 PetscCall(MatSetType(B, MATIS)); 657 PetscCall(MatSetSizes(B, A->rmap->n, A->rmap->n, A->rmap->N, A->rmap->N)); 658 PetscCall(MatSetLocalToGlobalMapping(B, rl2g, rl2g)); 659 PetscCall(MatSetBlockSizes(B, rbs, rbs)); 660 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 661 if (reuse == MAT_INPLACE_MATRIX) was_inplace = PETSC_TRUE; 662 reuse = MAT_REUSE_MATRIX; 663 } 664 if (reuse == MAT_REUSE_MATRIX) { 665 Mat *newlA, lA; 666 IS rows, cols; 667 const PetscInt *ridx, *cidx; 668 PetscInt nr, nc; 669 670 if (!B) B = *newmat; 671 PetscCall(MatISGetLocalToGlobalMapping(B, &rl2g, &cl2g)); 672 PetscCall(ISLocalToGlobalMappingGetBlockIndices(rl2g, &ridx)); 673 PetscCall(ISLocalToGlobalMappingGetBlockIndices(cl2g, &cidx)); 674 PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &nr)); 675 PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &nc)); 676 PetscCall(ISLocalToGlobalMappingGetBlockSize(rl2g, &rbs)); 677 PetscCall(ISLocalToGlobalMappingGetBlockSize(cl2g, &cbs)); 678 PetscCall(ISCreateBlock(comm, rbs, nr / rbs, ridx, PETSC_USE_POINTER, &rows)); 679 if (rl2g != cl2g) { 680 PetscCall(ISCreateBlock(comm, cbs, nc / cbs, cidx, PETSC_USE_POINTER, &cols)); 681 } else { 682 PetscCall(PetscObjectReference((PetscObject)rows)); 683 cols = rows; 684 } 685 PetscCall(MatISGetLocalMat(B, &lA)); 686 PetscCall(MatCreateSubMatrices(A, 1, &rows, &cols, MAT_INITIAL_MATRIX, &newlA)); 687 PetscCall(MatConvert(newlA[0], MATSEQAIJ, MAT_INPLACE_MATRIX, &newlA[0])); 688 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(rl2g, &ridx)); 689 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(cl2g, &cidx)); 690 PetscCall(ISDestroy(&rows)); 691 PetscCall(ISDestroy(&cols)); 692 if (!lA->preallocated) { /* first time */ 693 PetscCall(MatDuplicate(newlA[0], MAT_COPY_VALUES, &lA)); 694 PetscCall(MatISSetLocalMat(B, lA)); 695 PetscCall(PetscObjectDereference((PetscObject)lA)); 696 } 697 PetscCall(MatCopy(newlA[0], lA, SAME_NONZERO_PATTERN)); 698 PetscCall(MatDestroySubMatrices(1, &newlA)); 699 PetscCall(MatISScaleDisassembling_Private(B)); 700 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 701 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 702 if (was_inplace) PetscCall(MatHeaderReplace(A, &B)); 703 else *newmat = B; 704 PetscFunctionReturn(PETSC_SUCCESS); 705 } 706 /* general case, just compress out the column space */ 707 PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIAIJ, &ismpiaij)); 708 PetscCall(PetscObjectBaseTypeCompare((PetscObject)A, MATMPIBAIJ, &ismpibaij)); 709 if (ismpiaij) { 710 cbs = 1; /* We cannot guarantee the off-process matrix will respect the column block size */ 711 PetscCall(MatMPIAIJGetSeqAIJ(A, &Ad, &Ao, &garray)); 712 } else if (ismpibaij) { 713 PetscCall(MatMPIBAIJGetSeqBAIJ(A, &Ad, &Ao, &garray)); 714 PetscCall(MatConvert(Ad, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ad)); 715 PetscCall(MatConvert(Ao, MATSEQAIJ, MAT_INITIAL_MATRIX, &Ao)); 716 } else SETERRQ(comm, PETSC_ERR_SUP, "Type %s", ((PetscObject)A)->type_name); 717 PetscCall(MatSeqAIJGetArray(Ad, &dd)); 718 PetscCall(MatSeqAIJGetArray(Ao, &od)); 719 720 /* access relevant information from MPIAIJ */ 721 PetscCall(MatGetOwnershipRange(A, &str, NULL)); 722 PetscCall(MatGetOwnershipRangeColumn(A, &stc, NULL)); 723 PetscCall(MatGetLocalSize(Ad, &dr, &dc)); 724 PetscCall(MatGetLocalSize(Ao, NULL, &oc)); 725 PetscCheck(!oc || garray, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "garray not present"); 726 727 PetscCall(MatGetRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &di, &dj, &flg)); 728 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure"); 729 PetscCall(MatGetRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &oi, &oj, &flg)); 730 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot get IJ structure"); 731 nnz = di[dr] + oi[dr]; 732 /* store original pointers to be restored later */ 733 odi = di; 734 odj = dj; 735 ooi = oi; 736 ooj = oj; 737 738 /* generate l2g maps for rows and cols */ 739 PetscCall(ISCreateStride(comm, dr / rbs, str / rbs, 1, &is)); 740 if (rbs > 1) { 741 IS is2; 742 743 PetscCall(ISGetLocalSize(is, &i)); 744 PetscCall(ISGetIndices(is, (const PetscInt **)&aux)); 745 PetscCall(ISCreateBlock(comm, rbs, i, aux, PETSC_COPY_VALUES, &is2)); 746 PetscCall(ISRestoreIndices(is, (const PetscInt **)&aux)); 747 PetscCall(ISDestroy(&is)); 748 is = is2; 749 } 750 PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g)); 751 PetscCall(ISDestroy(&is)); 752 if (dr) { 753 PetscCall(PetscMalloc1((dc + oc) / cbs, &aux)); 754 for (i = 0; i < dc / cbs; i++) aux[i] = i + stc / cbs; 755 for (i = 0; i < oc / cbs; i++) aux[i + dc / cbs] = garray[i]; 756 PetscCall(ISCreateBlock(comm, cbs, (dc + oc) / cbs, aux, PETSC_OWN_POINTER, &is)); 757 lc = dc + oc; 758 } else { 759 PetscCall(ISCreateBlock(comm, cbs, 0, NULL, PETSC_OWN_POINTER, &is)); 760 lc = 0; 761 } 762 PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g)); 763 PetscCall(ISDestroy(&is)); 764 765 /* create MATIS object */ 766 PetscCall(MatCreate(comm, &B)); 767 PetscCall(MatSetSizes(B, dr, dc, PETSC_DECIDE, PETSC_DECIDE)); 768 PetscCall(MatSetType(B, MATIS)); 769 PetscCall(MatSetBlockSizes(B, rbs, cbs)); 770 PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g)); 771 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 772 PetscCall(ISLocalToGlobalMappingDestroy(&cl2g)); 773 774 /* merge local matrices */ 775 PetscCall(PetscMalloc1(nnz + dr + 1, &aux)); 776 PetscCall(PetscMalloc1(nnz, &data)); 777 ii = aux; 778 jj = aux + dr + 1; 779 aa = data; 780 *ii = *(di++) + *(oi++); 781 for (jd = 0, jo = 0, cum = 0; *ii < nnz; cum++) { 782 for (; jd < *di; jd++) { 783 *jj++ = *dj++; 784 *aa++ = *dd++; 785 } 786 for (; jo < *oi; jo++) { 787 *jj++ = *oj++ + dc; 788 *aa++ = *od++; 789 } 790 *(++ii) = *(di++) + *(oi++); 791 } 792 for (; cum < dr; cum++) *(++ii) = nnz; 793 794 PetscCall(MatRestoreRowIJ(Ad, 0, PETSC_FALSE, PETSC_FALSE, &i, &odi, &odj, &flg)); 795 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure"); 796 PetscCall(MatRestoreRowIJ(Ao, 0, PETSC_FALSE, PETSC_FALSE, &i, &ooi, &ooj, &flg)); 797 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot restore IJ structure"); 798 PetscCall(MatSeqAIJRestoreArray(Ad, &dd)); 799 PetscCall(MatSeqAIJRestoreArray(Ao, &od)); 800 801 ii = aux; 802 jj = aux + dr + 1; 803 aa = data; 804 PetscCall(MatCreateSeqAIJWithArrays(PETSC_COMM_SELF, dr, lc, ii, jj, aa, &lA)); 805 806 /* create containers to destroy the data */ 807 ptrs[0] = aux; 808 ptrs[1] = data; 809 for (i = 0; i < 2; i++) PetscCall(PetscObjectContainerCompose((PetscObject)lA, names[i], ptrs[i], PetscCtxDestroyDefault)); 810 if (ismpibaij) { /* destroy converted local matrices */ 811 PetscCall(MatDestroy(&Ad)); 812 PetscCall(MatDestroy(&Ao)); 813 } 814 815 /* finalize matrix */ 816 PetscCall(MatISSetLocalMat(B, lA)); 817 PetscCall(MatDestroy(&lA)); 818 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 819 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 820 if (reuse == MAT_INPLACE_MATRIX) PetscCall(MatHeaderReplace(A, &B)); 821 else *newmat = B; 822 PetscFunctionReturn(PETSC_SUCCESS); 823 } 824 825 PETSC_INTERN PetscErrorCode MatConvert_Nest_IS(Mat A, MatType type, MatReuse reuse, Mat *newmat) 826 { 827 Mat **nest, *snest, **rnest, lA, B; 828 IS *iscol, *isrow, *islrow, *islcol; 829 ISLocalToGlobalMapping rl2g, cl2g; 830 MPI_Comm comm; 831 PetscInt *lr, *lc, *l2gidxs; 832 PetscInt i, j, nr, nc, rbs, cbs; 833 PetscBool convert, lreuse, *istrans; 834 PetscBool3 allow_repeated = PETSC_BOOL3_UNKNOWN; 835 836 PetscFunctionBegin; 837 PetscCall(MatNestGetSubMats(A, &nr, &nc, &nest)); 838 lreuse = PETSC_FALSE; 839 rnest = NULL; 840 if (reuse == MAT_REUSE_MATRIX) { 841 PetscBool ismatis, isnest; 842 843 PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis)); 844 PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_USER, "Cannot reuse matrix of type %s", ((PetscObject)*newmat)->type_name); 845 PetscCall(MatISGetLocalMat(*newmat, &lA)); 846 PetscCall(PetscObjectTypeCompare((PetscObject)lA, MATNEST, &isnest)); 847 if (isnest) { 848 PetscCall(MatNestGetSubMats(lA, &i, &j, &rnest)); 849 lreuse = (PetscBool)(i == nr && j == nc); 850 if (!lreuse) rnest = NULL; 851 } 852 } 853 PetscCall(PetscObjectGetComm((PetscObject)A, &comm)); 854 PetscCall(PetscCalloc2(nr, &lr, nc, &lc)); 855 PetscCall(PetscCalloc6(nr, &isrow, nc, &iscol, nr, &islrow, nc, &islcol, nr * nc, &snest, nr * nc, &istrans)); 856 PetscCall(MatNestGetISs(A, isrow, iscol)); 857 for (i = 0; i < nr; i++) { 858 for (j = 0; j < nc; j++) { 859 PetscBool ismatis, sallow; 860 PetscInt l1, l2, lb1, lb2, ij = i * nc + j; 861 862 /* Null matrix pointers are allowed in MATNEST */ 863 if (!nest[i][j]) continue; 864 865 /* Nested matrices should be of type MATIS */ 866 PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATTRANSPOSEVIRTUAL, &istrans[ij])); 867 if (istrans[ij]) { 868 Mat T, lT; 869 PetscCall(MatTransposeGetMat(nest[i][j], &T)); 870 PetscCall(PetscObjectTypeCompare((PetscObject)T, MATIS, &ismatis)); 871 PetscCheck(ismatis, comm, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") (transposed) is not of type MATIS", i, j); 872 PetscCall(MatISGetAllowRepeated(T, &sallow)); 873 PetscCall(MatISGetLocalMat(T, &lT)); 874 PetscCall(MatCreateTranspose(lT, &snest[ij])); 875 } else { 876 PetscCall(PetscObjectTypeCompare((PetscObject)nest[i][j], MATIS, &ismatis)); 877 PetscCheck(ismatis, comm, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") is not of type MATIS", i, j); 878 PetscCall(MatISGetAllowRepeated(nest[i][j], &sallow)); 879 PetscCall(MatISGetLocalMat(nest[i][j], &snest[ij])); 880 } 881 if (allow_repeated == PETSC_BOOL3_UNKNOWN) allow_repeated = PetscBoolToBool3(sallow); 882 PetscCheck(sallow == PetscBool3ToBool(allow_repeated), comm, PETSC_ERR_SUP, "Cannot mix repeated and non repeated maps"); 883 884 /* Check compatibility of local sizes */ 885 PetscCall(MatGetSize(snest[ij], &l1, &l2)); 886 PetscCall(MatGetBlockSizes(snest[ij], &lb1, &lb2)); 887 if (!l1 || !l2) continue; 888 PetscCheck(!lr[i] || l1 == lr[i], PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid local size %" PetscInt_FMT " != %" PetscInt_FMT, i, j, lr[i], l1); 889 PetscCheck(!lc[j] || l2 == lc[j], PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid local size %" PetscInt_FMT " != %" PetscInt_FMT, i, j, lc[j], l2); 890 lr[i] = l1; 891 lc[j] = l2; 892 893 /* check compatibility for local matrix reusage */ 894 if (rnest && !rnest[i][j] != !snest[ij]) lreuse = PETSC_FALSE; 895 } 896 } 897 898 if (PetscDefined(USE_DEBUG)) { 899 /* Check compatibility of l2g maps for rows */ 900 for (i = 0; i < nr; i++) { 901 rl2g = NULL; 902 for (j = 0; j < nc; j++) { 903 PetscInt n1, n2; 904 905 if (!nest[i][j]) continue; 906 if (istrans[i * nc + j]) { 907 Mat T; 908 909 PetscCall(MatTransposeGetMat(nest[i][j], &T)); 910 PetscCall(MatISGetLocalToGlobalMapping(T, NULL, &cl2g)); 911 } else { 912 PetscCall(MatISGetLocalToGlobalMapping(nest[i][j], &cl2g, NULL)); 913 } 914 PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1)); 915 if (!n1) continue; 916 if (!rl2g) { 917 rl2g = cl2g; 918 } else { 919 const PetscInt *idxs1, *idxs2; 920 PetscBool same; 921 922 PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2)); 923 PetscCheck(n1 == n2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid row l2gmap size %" PetscInt_FMT " != %" PetscInt_FMT, i, j, n1, n2); 924 PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1)); 925 PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2)); 926 PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same)); 927 PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1)); 928 PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2)); 929 PetscCheck(same, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid row l2gmap", i, j); 930 } 931 } 932 } 933 /* Check compatibility of l2g maps for columns */ 934 for (i = 0; i < nc; i++) { 935 rl2g = NULL; 936 for (j = 0; j < nr; j++) { 937 PetscInt n1, n2; 938 939 if (!nest[j][i]) continue; 940 if (istrans[j * nc + i]) { 941 Mat T; 942 943 PetscCall(MatTransposeGetMat(nest[j][i], &T)); 944 PetscCall(MatISGetLocalToGlobalMapping(T, &cl2g, NULL)); 945 } else { 946 PetscCall(MatISGetLocalToGlobalMapping(nest[j][i], NULL, &cl2g)); 947 } 948 PetscCall(ISLocalToGlobalMappingGetSize(cl2g, &n1)); 949 if (!n1) continue; 950 if (!rl2g) { 951 rl2g = cl2g; 952 } else { 953 const PetscInt *idxs1, *idxs2; 954 PetscBool same; 955 956 PetscCall(ISLocalToGlobalMappingGetSize(rl2g, &n2)); 957 PetscCheck(n1 == n2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid column l2gmap size %" PetscInt_FMT " != %" PetscInt_FMT, j, i, n1, n2); 958 PetscCall(ISLocalToGlobalMappingGetIndices(cl2g, &idxs1)); 959 PetscCall(ISLocalToGlobalMappingGetIndices(rl2g, &idxs2)); 960 PetscCall(PetscArraycmp(idxs1, idxs2, n1, &same)); 961 PetscCall(ISLocalToGlobalMappingRestoreIndices(cl2g, &idxs1)); 962 PetscCall(ISLocalToGlobalMappingRestoreIndices(rl2g, &idxs2)); 963 PetscCheck(same, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot convert from MATNEST to MATIS! Matrix block (%" PetscInt_FMT ",%" PetscInt_FMT ") has invalid column l2gmap", j, i); 964 } 965 } 966 } 967 } 968 969 B = NULL; 970 if (reuse != MAT_REUSE_MATRIX) { 971 PetscInt stl; 972 973 /* Create l2g map for the rows of the new matrix and index sets for the local MATNEST */ 974 for (i = 0, stl = 0; i < nr; i++) stl += lr[i]; 975 PetscCall(PetscMalloc1(stl, &l2gidxs)); 976 for (i = 0, stl = 0; i < nr; i++) { 977 Mat usedmat; 978 Mat_IS *matis; 979 const PetscInt *idxs; 980 981 /* local IS for local NEST */ 982 PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i])); 983 984 /* l2gmap */ 985 j = 0; 986 usedmat = nest[i][j]; 987 while (!usedmat && j < nc - 1) usedmat = nest[i][++j]; 988 PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid row mat"); 989 990 if (istrans[i * nc + j]) { 991 Mat T; 992 PetscCall(MatTransposeGetMat(usedmat, &T)); 993 usedmat = T; 994 } 995 matis = (Mat_IS *)usedmat->data; 996 PetscCall(ISGetIndices(isrow[i], &idxs)); 997 if (istrans[i * nc + j]) { 998 PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE)); 999 PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE)); 1000 } else { 1001 PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE)); 1002 PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE)); 1003 } 1004 PetscCall(ISRestoreIndices(isrow[i], &idxs)); 1005 stl += lr[i]; 1006 } 1007 PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &rl2g)); 1008 1009 /* Create l2g map for columns of the new matrix and index sets for the local MATNEST */ 1010 for (i = 0, stl = 0; i < nc; i++) stl += lc[i]; 1011 PetscCall(PetscMalloc1(stl, &l2gidxs)); 1012 for (i = 0, stl = 0; i < nc; i++) { 1013 Mat usedmat; 1014 Mat_IS *matis; 1015 const PetscInt *idxs; 1016 1017 /* local IS for local NEST */ 1018 PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i])); 1019 1020 /* l2gmap */ 1021 j = 0; 1022 usedmat = nest[j][i]; 1023 while (!usedmat && j < nr - 1) usedmat = nest[++j][i]; 1024 PetscCheck(usedmat, comm, PETSC_ERR_SUP, "Cannot find valid column mat"); 1025 if (istrans[j * nc + i]) { 1026 Mat T; 1027 PetscCall(MatTransposeGetMat(usedmat, &T)); 1028 usedmat = T; 1029 } 1030 matis = (Mat_IS *)usedmat->data; 1031 PetscCall(ISGetIndices(iscol[i], &idxs)); 1032 if (istrans[j * nc + i]) { 1033 PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE)); 1034 PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE)); 1035 } else { 1036 PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE)); 1037 PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, idxs, l2gidxs + stl, MPI_REPLACE)); 1038 } 1039 PetscCall(ISRestoreIndices(iscol[i], &idxs)); 1040 stl += lc[i]; 1041 } 1042 PetscCall(ISLocalToGlobalMappingCreate(comm, 1, stl, l2gidxs, PETSC_OWN_POINTER, &cl2g)); 1043 1044 /* Create MATIS */ 1045 PetscCall(MatCreate(comm, &B)); 1046 PetscCall(MatSetSizes(B, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N)); 1047 PetscCall(MatGetBlockSizes(A, &rbs, &cbs)); 1048 PetscCall(MatSetBlockSizes(B, rbs, cbs)); 1049 PetscCall(MatSetType(B, MATIS)); 1050 PetscCall(MatISSetLocalMatType(B, MATNEST)); 1051 PetscCall(MatISSetAllowRepeated(B, PetscBool3ToBool(allow_repeated))); 1052 { /* hack : avoid setup of scatters */ 1053 Mat_IS *matis = (Mat_IS *)B->data; 1054 matis->islocalref = B; 1055 } 1056 PetscCall(MatSetLocalToGlobalMapping(B, rl2g, cl2g)); 1057 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 1058 PetscCall(ISLocalToGlobalMappingDestroy(&cl2g)); 1059 PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA)); 1060 PetscCall(MatNestSetVecType(lA, VECNEST)); 1061 for (i = 0; i < nr * nc; i++) { 1062 if (istrans[i]) PetscCall(MatDestroy(&snest[i])); 1063 } 1064 PetscCall(MatISSetLocalMat(B, lA)); 1065 PetscCall(MatDestroy(&lA)); 1066 { /* hack : setup of scatters done here */ 1067 Mat_IS *matis = (Mat_IS *)B->data; 1068 1069 matis->islocalref = NULL; 1070 PetscCall(MatISSetUpScatters_Private(B)); 1071 } 1072 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 1073 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 1074 if (reuse == MAT_INPLACE_MATRIX) { 1075 PetscCall(MatHeaderReplace(A, &B)); 1076 } else { 1077 *newmat = B; 1078 } 1079 } else { 1080 if (lreuse) { 1081 PetscCall(MatISGetLocalMat(*newmat, &lA)); 1082 for (i = 0; i < nr; i++) { 1083 for (j = 0; j < nc; j++) { 1084 if (snest[i * nc + j]) { 1085 PetscCall(MatNestSetSubMat(lA, i, j, snest[i * nc + j])); 1086 if (istrans[i * nc + j]) PetscCall(MatDestroy(&snest[i * nc + j])); 1087 } 1088 } 1089 } 1090 } else { 1091 PetscInt stl; 1092 for (i = 0, stl = 0; i < nr; i++) { 1093 PetscCall(ISCreateStride(PETSC_COMM_SELF, lr[i], stl, 1, &islrow[i])); 1094 stl += lr[i]; 1095 } 1096 for (i = 0, stl = 0; i < nc; i++) { 1097 PetscCall(ISCreateStride(PETSC_COMM_SELF, lc[i], stl, 1, &islcol[i])); 1098 stl += lc[i]; 1099 } 1100 PetscCall(MatCreateNest(PETSC_COMM_SELF, nr, islrow, nc, islcol, snest, &lA)); 1101 for (i = 0; i < nr * nc; i++) { 1102 if (istrans[i]) PetscCall(MatDestroy(&snest[i])); 1103 } 1104 PetscCall(MatISSetLocalMat(*newmat, lA)); 1105 PetscCall(MatDestroy(&lA)); 1106 } 1107 PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY)); 1108 PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY)); 1109 } 1110 1111 /* Create local matrix in MATNEST format */ 1112 convert = PETSC_FALSE; 1113 PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_convert_local_nest", &convert, NULL)); 1114 if (convert) { 1115 Mat M; 1116 MatISLocalFields lf; 1117 1118 PetscCall(MatISGetLocalMat(*newmat, &lA)); 1119 PetscCall(MatConvert(lA, MATAIJ, MAT_INITIAL_MATRIX, &M)); 1120 PetscCall(MatISSetLocalMat(*newmat, M)); 1121 PetscCall(MatDestroy(&M)); 1122 1123 /* attach local fields to the matrix */ 1124 PetscCall(PetscNew(&lf)); 1125 PetscCall(PetscMalloc2(nr, &lf->rf, nc, &lf->cf)); 1126 for (i = 0; i < nr; i++) { 1127 PetscInt n, st; 1128 1129 PetscCall(ISGetLocalSize(islrow[i], &n)); 1130 PetscCall(ISStrideGetInfo(islrow[i], &st, NULL)); 1131 PetscCall(ISCreateStride(comm, n, st, 1, &lf->rf[i])); 1132 } 1133 for (i = 0; i < nc; i++) { 1134 PetscInt n, st; 1135 1136 PetscCall(ISGetLocalSize(islcol[i], &n)); 1137 PetscCall(ISStrideGetInfo(islcol[i], &st, NULL)); 1138 PetscCall(ISCreateStride(comm, n, st, 1, &lf->cf[i])); 1139 } 1140 lf->nr = nr; 1141 lf->nc = nc; 1142 PetscCall(PetscObjectContainerCompose((PetscObject)*newmat, "_convert_nest_lfields", lf, MatISContainerDestroyFields_Private)); 1143 } 1144 1145 /* Free workspace */ 1146 for (i = 0; i < nr; i++) PetscCall(ISDestroy(&islrow[i])); 1147 for (i = 0; i < nc; i++) PetscCall(ISDestroy(&islcol[i])); 1148 PetscCall(PetscFree6(isrow, iscol, islrow, islcol, snest, istrans)); 1149 PetscCall(PetscFree2(lr, lc)); 1150 PetscFunctionReturn(PETSC_SUCCESS); 1151 } 1152 1153 static PetscErrorCode MatDiagonalScale_IS(Mat A, Vec l, Vec r) 1154 { 1155 Mat_IS *matis = (Mat_IS *)A->data; 1156 Vec ll, rr; 1157 const PetscScalar *Y, *X; 1158 PetscScalar *x, *y; 1159 1160 PetscFunctionBegin; 1161 if (l) { 1162 ll = matis->y; 1163 PetscCall(VecGetArrayRead(l, &Y)); 1164 PetscCall(VecGetArray(ll, &y)); 1165 PetscCall(PetscSFBcastBegin(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE)); 1166 } else { 1167 ll = NULL; 1168 } 1169 if (r) { 1170 rr = matis->x; 1171 PetscCall(VecGetArrayRead(r, &X)); 1172 PetscCall(VecGetArray(rr, &x)); 1173 PetscCall(PetscSFBcastBegin(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE)); 1174 } else { 1175 rr = NULL; 1176 } 1177 if (ll) { 1178 PetscCall(PetscSFBcastEnd(matis->sf, MPIU_SCALAR, Y, y, MPI_REPLACE)); 1179 PetscCall(VecRestoreArrayRead(l, &Y)); 1180 PetscCall(VecRestoreArray(ll, &y)); 1181 } 1182 if (rr) { 1183 PetscCall(PetscSFBcastEnd(matis->csf, MPIU_SCALAR, X, x, MPI_REPLACE)); 1184 PetscCall(VecRestoreArrayRead(r, &X)); 1185 PetscCall(VecRestoreArray(rr, &x)); 1186 } 1187 PetscCall(MatDiagonalScale(matis->A, ll, rr)); 1188 PetscFunctionReturn(PETSC_SUCCESS); 1189 } 1190 1191 static PetscErrorCode MatGetInfo_IS(Mat A, MatInfoType flag, MatInfo *ginfo) 1192 { 1193 Mat_IS *matis = (Mat_IS *)A->data; 1194 MatInfo info; 1195 PetscLogDouble isend[6], irecv[6]; 1196 PetscInt bs; 1197 1198 PetscFunctionBegin; 1199 PetscCall(MatGetBlockSize(A, &bs)); 1200 if (matis->A->ops->getinfo) { 1201 PetscCall(MatGetInfo(matis->A, MAT_LOCAL, &info)); 1202 isend[0] = info.nz_used; 1203 isend[1] = info.nz_allocated; 1204 isend[2] = info.nz_unneeded; 1205 isend[3] = info.memory; 1206 isend[4] = info.mallocs; 1207 } else { 1208 isend[0] = 0.; 1209 isend[1] = 0.; 1210 isend[2] = 0.; 1211 isend[3] = 0.; 1212 isend[4] = 0.; 1213 } 1214 isend[5] = matis->A->num_ass; 1215 if (flag == MAT_LOCAL) { 1216 ginfo->nz_used = isend[0]; 1217 ginfo->nz_allocated = isend[1]; 1218 ginfo->nz_unneeded = isend[2]; 1219 ginfo->memory = isend[3]; 1220 ginfo->mallocs = isend[4]; 1221 ginfo->assemblies = isend[5]; 1222 } else if (flag == MAT_GLOBAL_MAX) { 1223 PetscCallMPI(MPIU_Allreduce(isend, irecv, 6, MPIU_PETSCLOGDOUBLE, MPI_MAX, PetscObjectComm((PetscObject)A))); 1224 1225 ginfo->nz_used = irecv[0]; 1226 ginfo->nz_allocated = irecv[1]; 1227 ginfo->nz_unneeded = irecv[2]; 1228 ginfo->memory = irecv[3]; 1229 ginfo->mallocs = irecv[4]; 1230 ginfo->assemblies = irecv[5]; 1231 } else if (flag == MAT_GLOBAL_SUM) { 1232 PetscCallMPI(MPIU_Allreduce(isend, irecv, 5, MPIU_PETSCLOGDOUBLE, MPI_SUM, PetscObjectComm((PetscObject)A))); 1233 1234 ginfo->nz_used = irecv[0]; 1235 ginfo->nz_allocated = irecv[1]; 1236 ginfo->nz_unneeded = irecv[2]; 1237 ginfo->memory = irecv[3]; 1238 ginfo->mallocs = irecv[4]; 1239 ginfo->assemblies = A->num_ass; 1240 } 1241 ginfo->block_size = bs; 1242 ginfo->fill_ratio_given = 0; 1243 ginfo->fill_ratio_needed = 0; 1244 ginfo->factor_mallocs = 0; 1245 PetscFunctionReturn(PETSC_SUCCESS); 1246 } 1247 1248 static PetscErrorCode MatTranspose_IS(Mat A, MatReuse reuse, Mat *B) 1249 { 1250 Mat C, lC, lA; 1251 1252 PetscFunctionBegin; 1253 if (reuse == MAT_REUSE_MATRIX) PetscCall(MatTransposeCheckNonzeroState_Private(A, *B)); 1254 if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_INPLACE_MATRIX) { 1255 ISLocalToGlobalMapping rl2g, cl2g; 1256 PetscBool allow_repeated; 1257 1258 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &C)); 1259 PetscCall(MatSetSizes(C, A->cmap->n, A->rmap->n, A->cmap->N, A->rmap->N)); 1260 PetscCall(MatSetBlockSizes(C, A->cmap->bs, A->rmap->bs)); 1261 PetscCall(MatSetType(C, MATIS)); 1262 PetscCall(MatISGetAllowRepeated(A, &allow_repeated)); 1263 PetscCall(MatISSetAllowRepeated(C, allow_repeated)); 1264 PetscCall(MatGetLocalToGlobalMapping(A, &rl2g, &cl2g)); 1265 PetscCall(MatSetLocalToGlobalMapping(C, cl2g, rl2g)); 1266 } else C = *B; 1267 1268 /* perform local transposition */ 1269 PetscCall(MatISGetLocalMat(A, &lA)); 1270 PetscCall(MatTranspose(lA, MAT_INITIAL_MATRIX, &lC)); 1271 PetscCall(MatSetLocalToGlobalMapping(lC, lA->cmap->mapping, lA->rmap->mapping)); 1272 PetscCall(MatISSetLocalMat(C, lC)); 1273 PetscCall(MatDestroy(&lC)); 1274 1275 if (reuse == MAT_INITIAL_MATRIX || reuse == MAT_REUSE_MATRIX) { 1276 *B = C; 1277 } else { 1278 PetscCall(MatHeaderMerge(A, &C)); 1279 } 1280 PetscCall(MatAssemblyBegin(*B, MAT_FINAL_ASSEMBLY)); 1281 PetscCall(MatAssemblyEnd(*B, MAT_FINAL_ASSEMBLY)); 1282 PetscFunctionReturn(PETSC_SUCCESS); 1283 } 1284 1285 static PetscErrorCode MatDiagonalSet_IS(Mat A, Vec D, InsertMode insmode) 1286 { 1287 Mat_IS *is = (Mat_IS *)A->data; 1288 1289 PetscFunctionBegin; 1290 PetscCheck(!is->allow_repeated || insmode == ADD_VALUES, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "INSERT_VALUES with repeated entries not supported"); 1291 if (D) { /* MatShift_IS pass D = NULL */ 1292 PetscCall(VecScatterBegin(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD)); 1293 PetscCall(VecScatterEnd(is->rctx, D, is->y, INSERT_VALUES, SCATTER_FORWARD)); 1294 } 1295 PetscCall(VecPointwiseDivide(is->y, is->y, is->counter)); 1296 PetscCall(MatDiagonalSet(is->A, is->y, insmode)); 1297 PetscFunctionReturn(PETSC_SUCCESS); 1298 } 1299 1300 static PetscErrorCode MatShift_IS(Mat A, PetscScalar a) 1301 { 1302 Mat_IS *is = (Mat_IS *)A->data; 1303 1304 PetscFunctionBegin; 1305 PetscCall(VecSet(is->y, a)); 1306 PetscCall(MatDiagonalSet_IS(A, NULL, ADD_VALUES)); 1307 PetscFunctionReturn(PETSC_SUCCESS); 1308 } 1309 1310 static PetscErrorCode MatSetValuesLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) 1311 { 1312 PetscInt buf[2 * MATIS_MAX_ENTRIES_INSERTION], *rows_l = NULL, *cols_l = NULL; 1313 1314 PetscFunctionBegin; 1315 IndexSpaceGet(buf, m, n, rows_l, cols_l); 1316 PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m, rows, rows_l)); 1317 PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n, cols, cols_l)); 1318 PetscCall(MatSetValuesLocal_IS(A, m, rows_l, n, cols_l, values, addv)); 1319 IndexSpaceRestore(buf, m, n, rows_l, cols_l); 1320 PetscFunctionReturn(PETSC_SUCCESS); 1321 } 1322 1323 static PetscErrorCode MatSetValuesBlockedLocal_SubMat_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) 1324 { 1325 PetscInt buf[2 * MATIS_MAX_ENTRIES_INSERTION], *rows_l = NULL, *cols_l = NULL, rbs, cbs; 1326 1327 PetscFunctionBegin; 1328 /* We cannot guarantee the local matrix will have the same block size of the original matrix */ 1329 PetscCall(ISLocalToGlobalMappingGetBlockSize(A->rmap->mapping, &rbs)); 1330 PetscCall(ISLocalToGlobalMappingGetBlockSize(A->cmap->mapping, &cbs)); 1331 IndexSpaceGet(buf, m * rbs, n * cbs, rows_l, cols_l); 1332 BlockIndicesExpand(m, rows, rbs, rows_l); 1333 BlockIndicesExpand(n, cols, cbs, cols_l); 1334 PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, m * rbs, rows_l, rows_l)); 1335 PetscCall(ISLocalToGlobalMappingApply(A->cmap->mapping, n * cbs, cols_l, cols_l)); 1336 PetscCall(MatSetValuesLocal_IS(A, m * rbs, rows_l, n * cbs, cols_l, values, addv)); 1337 IndexSpaceRestore(buf, m * rbs, n * cbs, rows_l, cols_l); 1338 PetscFunctionReturn(PETSC_SUCCESS); 1339 } 1340 1341 static PetscErrorCode MatZeroRowsLocal_SubMat_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 1342 { 1343 PetscInt *rows_l; 1344 Mat_IS *is = (Mat_IS *)A->data; 1345 1346 PetscFunctionBegin; 1347 PetscCall(PetscMalloc1(n, &rows_l)); 1348 PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, n, rows, rows_l)); 1349 PetscCall(MatZeroRowsLocal(is->islocalref, n, rows_l, diag, x, b)); 1350 PetscCall(PetscFree(rows_l)); 1351 PetscFunctionReturn(PETSC_SUCCESS); 1352 } 1353 1354 static PetscErrorCode MatZeroRowsColumnsLocal_SubMat_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 1355 { 1356 PetscInt *rows_l; 1357 Mat_IS *is = (Mat_IS *)A->data; 1358 1359 PetscFunctionBegin; 1360 PetscCall(PetscMalloc1(n, &rows_l)); 1361 PetscCall(ISLocalToGlobalMappingApply(A->rmap->mapping, n, rows, rows_l)); 1362 PetscCall(MatZeroRowsColumnsLocal(is->islocalref, n, rows_l, diag, x, b)); 1363 PetscCall(PetscFree(rows_l)); 1364 PetscFunctionReturn(PETSC_SUCCESS); 1365 } 1366 1367 static PetscErrorCode MatCreateSubMatrix_IS(Mat mat, IS irow, IS icol, MatReuse scall, Mat *newmat) 1368 { 1369 Mat locmat, newlocmat; 1370 Mat_IS *newmatis; 1371 const PetscInt *idxs; 1372 PetscInt i, m, n; 1373 1374 PetscFunctionBegin; 1375 if (scall == MAT_REUSE_MATRIX) { 1376 PetscBool ismatis; 1377 1378 PetscCall(PetscObjectTypeCompare((PetscObject)*newmat, MATIS, &ismatis)); 1379 PetscCheck(ismatis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Not of MATIS type"); 1380 newmatis = (Mat_IS *)(*newmat)->data; 1381 PetscCheck(newmatis->getsub_ris, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local row IS"); 1382 PetscCheck(newmatis->getsub_cis, PetscObjectComm((PetscObject)*newmat), PETSC_ERR_ARG_WRONG, "Cannot reuse matrix! Misses local col IS"); 1383 } 1384 /* irow and icol may not have duplicate entries */ 1385 if (PetscDefined(USE_DEBUG)) { 1386 Vec rtest, ltest; 1387 const PetscScalar *array; 1388 1389 PetscCall(MatCreateVecs(mat, <est, &rtest)); 1390 PetscCall(ISGetLocalSize(irow, &n)); 1391 PetscCall(ISGetIndices(irow, &idxs)); 1392 for (i = 0; i < n; i++) PetscCall(VecSetValue(rtest, idxs[i], 1.0, ADD_VALUES)); 1393 PetscCall(VecAssemblyBegin(rtest)); 1394 PetscCall(VecAssemblyEnd(rtest)); 1395 PetscCall(VecGetLocalSize(rtest, &n)); 1396 PetscCall(VecGetOwnershipRange(rtest, &m, NULL)); 1397 PetscCall(VecGetArrayRead(rtest, &array)); 1398 for (i = 0; i < n; i++) PetscCheck(array[i] == 0. || array[i] == 1., PETSC_COMM_SELF, PETSC_ERR_SUP, "Index %" PetscInt_FMT " counted %" PetscInt_FMT " times! Irow may not have duplicate entries", i + m, (PetscInt)PetscRealPart(array[i])); 1399 PetscCall(VecRestoreArrayRead(rtest, &array)); 1400 PetscCall(ISRestoreIndices(irow, &idxs)); 1401 PetscCall(ISGetLocalSize(icol, &n)); 1402 PetscCall(ISGetIndices(icol, &idxs)); 1403 for (i = 0; i < n; i++) PetscCall(VecSetValue(ltest, idxs[i], 1.0, ADD_VALUES)); 1404 PetscCall(VecAssemblyBegin(ltest)); 1405 PetscCall(VecAssemblyEnd(ltest)); 1406 PetscCall(VecGetLocalSize(ltest, &n)); 1407 PetscCall(VecGetOwnershipRange(ltest, &m, NULL)); 1408 PetscCall(VecGetArrayRead(ltest, &array)); 1409 for (i = 0; i < n; i++) PetscCheck(array[i] == 0. || array[i] == 1., PETSC_COMM_SELF, PETSC_ERR_SUP, "Index %" PetscInt_FMT " counted %" PetscInt_FMT " times! Icol may not have duplicate entries", i + m, (PetscInt)PetscRealPart(array[i])); 1410 PetscCall(VecRestoreArrayRead(ltest, &array)); 1411 PetscCall(ISRestoreIndices(icol, &idxs)); 1412 PetscCall(VecDestroy(&rtest)); 1413 PetscCall(VecDestroy(<est)); 1414 } 1415 if (scall == MAT_INITIAL_MATRIX) { 1416 Mat_IS *matis = (Mat_IS *)mat->data; 1417 ISLocalToGlobalMapping rl2g; 1418 IS is; 1419 PetscInt *lidxs, *lgidxs, *newgidxs; 1420 PetscInt ll, newloc, irbs, icbs, arbs, acbs, rbs, cbs; 1421 PetscBool cong; 1422 MPI_Comm comm; 1423 1424 PetscCall(PetscObjectGetComm((PetscObject)mat, &comm)); 1425 PetscCall(MatGetBlockSizes(mat, &arbs, &acbs)); 1426 PetscCall(ISGetBlockSize(irow, &irbs)); 1427 PetscCall(ISGetBlockSize(icol, &icbs)); 1428 rbs = arbs == irbs ? irbs : 1; 1429 cbs = acbs == icbs ? icbs : 1; 1430 PetscCall(ISGetLocalSize(irow, &m)); 1431 PetscCall(ISGetLocalSize(icol, &n)); 1432 PetscCall(MatCreate(comm, newmat)); 1433 PetscCall(MatSetType(*newmat, MATIS)); 1434 PetscCall(MatISSetAllowRepeated(*newmat, matis->allow_repeated)); 1435 PetscCall(MatSetSizes(*newmat, m, n, PETSC_DECIDE, PETSC_DECIDE)); 1436 PetscCall(MatSetBlockSizes(*newmat, rbs, cbs)); 1437 /* communicate irow to their owners in the layout */ 1438 PetscCall(ISGetIndices(irow, &idxs)); 1439 PetscCall(PetscLayoutMapLocal(mat->rmap, m, idxs, &ll, &lidxs, &lgidxs)); 1440 PetscCall(ISRestoreIndices(irow, &idxs)); 1441 PetscCall(PetscArrayzero(matis->sf_rootdata, matis->sf->nroots)); 1442 for (i = 0; i < ll; i++) matis->sf_rootdata[lidxs[i]] = lgidxs[i] + 1; 1443 PetscCall(PetscFree(lidxs)); 1444 PetscCall(PetscFree(lgidxs)); 1445 PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE)); 1446 PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE)); 1447 for (i = 0, newloc = 0; i < matis->sf->nleaves; i++) 1448 if (matis->sf_leafdata[i]) newloc++; 1449 PetscCall(PetscMalloc1(newloc, &newgidxs)); 1450 PetscCall(PetscMalloc1(newloc, &lidxs)); 1451 for (i = 0, newloc = 0; i < matis->sf->nleaves; i++) 1452 if (matis->sf_leafdata[i]) { 1453 lidxs[newloc] = i; 1454 newgidxs[newloc++] = matis->sf_leafdata[i] - 1; 1455 } 1456 PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is)); 1457 PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g)); 1458 PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs)); 1459 PetscCall(ISDestroy(&is)); 1460 /* local is to extract local submatrix */ 1461 newmatis = (Mat_IS *)(*newmat)->data; 1462 PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_ris)); 1463 PetscCall(MatHasCongruentLayouts(mat, &cong)); 1464 if (cong && irow == icol && matis->csf == matis->sf) { 1465 PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, rl2g)); 1466 PetscCall(PetscObjectReference((PetscObject)newmatis->getsub_ris)); 1467 newmatis->getsub_cis = newmatis->getsub_ris; 1468 } else { 1469 ISLocalToGlobalMapping cl2g; 1470 1471 /* communicate icol to their owners in the layout */ 1472 PetscCall(ISGetIndices(icol, &idxs)); 1473 PetscCall(PetscLayoutMapLocal(mat->cmap, n, idxs, &ll, &lidxs, &lgidxs)); 1474 PetscCall(ISRestoreIndices(icol, &idxs)); 1475 PetscCall(PetscArrayzero(matis->csf_rootdata, matis->csf->nroots)); 1476 for (i = 0; i < ll; i++) matis->csf_rootdata[lidxs[i]] = lgidxs[i] + 1; 1477 PetscCall(PetscFree(lidxs)); 1478 PetscCall(PetscFree(lgidxs)); 1479 PetscCall(PetscSFBcastBegin(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE)); 1480 PetscCall(PetscSFBcastEnd(matis->csf, MPIU_INT, matis->csf_rootdata, matis->csf_leafdata, MPI_REPLACE)); 1481 for (i = 0, newloc = 0; i < matis->csf->nleaves; i++) 1482 if (matis->csf_leafdata[i]) newloc++; 1483 PetscCall(PetscMalloc1(newloc, &newgidxs)); 1484 PetscCall(PetscMalloc1(newloc, &lidxs)); 1485 for (i = 0, newloc = 0; i < matis->csf->nleaves; i++) 1486 if (matis->csf_leafdata[i]) { 1487 lidxs[newloc] = i; 1488 newgidxs[newloc++] = matis->csf_leafdata[i] - 1; 1489 } 1490 PetscCall(ISCreateGeneral(comm, newloc, newgidxs, PETSC_OWN_POINTER, &is)); 1491 PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g)); 1492 PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs)); 1493 PetscCall(ISDestroy(&is)); 1494 /* local is to extract local submatrix */ 1495 PetscCall(ISCreateGeneral(comm, newloc, lidxs, PETSC_OWN_POINTER, &newmatis->getsub_cis)); 1496 PetscCall(MatSetLocalToGlobalMapping(*newmat, rl2g, cl2g)); 1497 PetscCall(ISLocalToGlobalMappingDestroy(&cl2g)); 1498 } 1499 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 1500 } else { 1501 PetscCall(MatISGetLocalMat(*newmat, &newlocmat)); 1502 } 1503 PetscCall(MatISGetLocalMat(mat, &locmat)); 1504 newmatis = (Mat_IS *)(*newmat)->data; 1505 PetscCall(MatCreateSubMatrix(locmat, newmatis->getsub_ris, newmatis->getsub_cis, scall, &newlocmat)); 1506 if (scall == MAT_INITIAL_MATRIX) { 1507 PetscCall(MatISSetLocalMat(*newmat, newlocmat)); 1508 PetscCall(MatDestroy(&newlocmat)); 1509 } 1510 PetscCall(MatAssemblyBegin(*newmat, MAT_FINAL_ASSEMBLY)); 1511 PetscCall(MatAssemblyEnd(*newmat, MAT_FINAL_ASSEMBLY)); 1512 PetscFunctionReturn(PETSC_SUCCESS); 1513 } 1514 1515 static PetscErrorCode MatCopy_IS(Mat A, Mat B, MatStructure str) 1516 { 1517 Mat_IS *a = (Mat_IS *)A->data, *b; 1518 PetscBool ismatis; 1519 1520 PetscFunctionBegin; 1521 PetscCall(PetscObjectTypeCompare((PetscObject)B, MATIS, &ismatis)); 1522 PetscCheck(ismatis, PetscObjectComm((PetscObject)B), PETSC_ERR_SUP, "Need to be implemented"); 1523 b = (Mat_IS *)B->data; 1524 PetscCall(MatCopy(a->A, b->A, str)); 1525 PetscCall(PetscObjectStateIncrease((PetscObject)B)); 1526 PetscFunctionReturn(PETSC_SUCCESS); 1527 } 1528 1529 static PetscErrorCode MatMissingDiagonal_IS(Mat A, PetscBool *missing, PetscInt *d) 1530 { 1531 Vec v; 1532 const PetscScalar *array; 1533 PetscInt i, n; 1534 1535 PetscFunctionBegin; 1536 *missing = PETSC_FALSE; 1537 PetscCall(MatCreateVecs(A, NULL, &v)); 1538 PetscCall(MatGetDiagonal(A, v)); 1539 PetscCall(VecGetLocalSize(v, &n)); 1540 PetscCall(VecGetArrayRead(v, &array)); 1541 for (i = 0; i < n; i++) 1542 if (array[i] == 0.) break; 1543 PetscCall(VecRestoreArrayRead(v, &array)); 1544 PetscCall(VecDestroy(&v)); 1545 if (i != n) *missing = PETSC_TRUE; 1546 if (d) { 1547 *d = -1; 1548 if (*missing) { 1549 PetscInt rstart; 1550 PetscCall(MatGetOwnershipRange(A, &rstart, NULL)); 1551 *d = i + rstart; 1552 } 1553 } 1554 PetscFunctionReturn(PETSC_SUCCESS); 1555 } 1556 1557 static PetscErrorCode MatISSetUpSF_IS(Mat B) 1558 { 1559 Mat_IS *matis = (Mat_IS *)B->data; 1560 const PetscInt *gidxs; 1561 PetscInt nleaves; 1562 1563 PetscFunctionBegin; 1564 if (matis->sf) PetscFunctionReturn(PETSC_SUCCESS); 1565 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->sf)); 1566 PetscCall(ISLocalToGlobalMappingGetIndices(matis->rmapping, &gidxs)); 1567 PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nleaves)); 1568 PetscCall(PetscSFSetGraphLayout(matis->sf, B->rmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs)); 1569 PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->rmapping, &gidxs)); 1570 PetscCall(PetscMalloc2(matis->sf->nroots, &matis->sf_rootdata, matis->sf->nleaves, &matis->sf_leafdata)); 1571 if (matis->rmapping != matis->cmapping) { /* setup SF for columns */ 1572 PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nleaves)); 1573 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)B), &matis->csf)); 1574 PetscCall(ISLocalToGlobalMappingGetIndices(matis->cmapping, &gidxs)); 1575 PetscCall(PetscSFSetGraphLayout(matis->csf, B->cmap, nleaves, NULL, PETSC_OWN_POINTER, gidxs)); 1576 PetscCall(ISLocalToGlobalMappingRestoreIndices(matis->cmapping, &gidxs)); 1577 PetscCall(PetscMalloc2(matis->csf->nroots, &matis->csf_rootdata, matis->csf->nleaves, &matis->csf_leafdata)); 1578 } else { 1579 matis->csf = matis->sf; 1580 matis->csf_leafdata = matis->sf_leafdata; 1581 matis->csf_rootdata = matis->sf_rootdata; 1582 } 1583 PetscFunctionReturn(PETSC_SUCCESS); 1584 } 1585 1586 /*@ 1587 MatISGetAllowRepeated - Get the flag to allow repeated entries in the local to global map 1588 1589 Not Collective 1590 1591 Input Parameter: 1592 . A - the matrix 1593 1594 Output Parameter: 1595 . flg - the boolean flag 1596 1597 Level: intermediate 1598 1599 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISSetAllowRepeated()` 1600 @*/ 1601 PetscErrorCode MatISGetAllowRepeated(Mat A, PetscBool *flg) 1602 { 1603 PetscBool ismatis; 1604 1605 PetscFunctionBegin; 1606 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1607 PetscAssertPointer(flg, 2); 1608 PetscCall(PetscObjectTypeCompare((PetscObject)A, MATIS, &ismatis)); 1609 PetscCheck(ismatis, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)A)->type_name); 1610 *flg = ((Mat_IS *)A->data)->allow_repeated; 1611 PetscFunctionReturn(PETSC_SUCCESS); 1612 } 1613 1614 /*@ 1615 MatISSetAllowRepeated - Set the flag to allow repeated entries in the local to global map 1616 1617 Logically Collective 1618 1619 Input Parameters: 1620 + A - the matrix 1621 - flg - the boolean flag 1622 1623 Level: intermediate 1624 1625 Notes: 1626 The default value is `PETSC_FALSE`. 1627 When called AFTER calling `MatSetLocalToGlobalMapping()` it will recreate the local matrices 1628 if `flg` is different from the previously set value. 1629 Specifically, when `flg` is true it will just recreate the local matrices, while if 1630 `flg` is false will assemble the local matrices summing up repeated entries. 1631 1632 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatSetLocalToGlobalMapping()`, `MatISGetAllowRepeated()` 1633 @*/ 1634 PetscErrorCode MatISSetAllowRepeated(Mat A, PetscBool flg) 1635 { 1636 PetscFunctionBegin; 1637 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1638 PetscValidType(A, 1); 1639 PetscValidLogicalCollectiveBool(A, flg, 2); 1640 PetscTryMethod(A, "MatISSetAllowRepeated_C", (Mat, PetscBool), (A, flg)); 1641 PetscFunctionReturn(PETSC_SUCCESS); 1642 } 1643 1644 static PetscErrorCode MatISSetAllowRepeated_IS(Mat A, PetscBool flg) 1645 { 1646 Mat_IS *matis = (Mat_IS *)A->data; 1647 Mat lA = NULL; 1648 ISLocalToGlobalMapping lrmap, lcmap; 1649 1650 PetscFunctionBegin; 1651 if (flg == matis->allow_repeated) PetscFunctionReturn(PETSC_SUCCESS); 1652 if (!matis->A) { /* matrix has not been preallocated yet */ 1653 matis->allow_repeated = flg; 1654 PetscFunctionReturn(PETSC_SUCCESS); 1655 } 1656 PetscCheck(!matis->islocalref, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Not implemented for local references"); 1657 if (matis->allow_repeated) { /* we will assemble the old local matrix if needed */ 1658 lA = matis->A; 1659 PetscCall(PetscObjectReference((PetscObject)lA)); 1660 } 1661 /* In case flg is True, we only recreate the local matrix */ 1662 matis->allow_repeated = flg; 1663 PetscCall(MatSetLocalToGlobalMapping(A, A->rmap->mapping, A->cmap->mapping)); 1664 if (lA) { /* assemble previous local matrix if needed */ 1665 Mat nA = matis->A; 1666 1667 PetscCall(MatGetLocalToGlobalMapping(nA, &lrmap, &lcmap)); 1668 if (!lrmap && !lcmap) { 1669 PetscCall(MatISSetLocalMat(A, lA)); 1670 } else { 1671 Mat P = NULL, R = NULL; 1672 MatProductType ptype; 1673 1674 if (lrmap == lcmap) { 1675 ptype = MATPRODUCT_PtAP; 1676 PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P)); 1677 PetscCall(MatProductCreate(lA, P, NULL, &nA)); 1678 } else { 1679 if (lcmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lcmap, nA, PETSC_TRUE, PETSC_FALSE, NULL, &P)); 1680 if (lrmap) PetscCall(MatCreateFromISLocalToGlobalMapping(lrmap, nA, PETSC_FALSE, PETSC_TRUE, NULL, &R)); 1681 if (R && P) { 1682 ptype = MATPRODUCT_ABC; 1683 PetscCall(MatProductCreate(R, lA, P, &nA)); 1684 } else if (R) { 1685 ptype = MATPRODUCT_AB; 1686 PetscCall(MatProductCreate(R, lA, NULL, &nA)); 1687 } else { 1688 ptype = MATPRODUCT_AB; 1689 PetscCall(MatProductCreate(lA, P, NULL, &nA)); 1690 } 1691 } 1692 PetscCall(MatProductSetType(nA, ptype)); 1693 PetscCall(MatProductSetFromOptions(nA)); 1694 PetscCall(MatProductSymbolic(nA)); 1695 PetscCall(MatProductNumeric(nA)); 1696 PetscCall(MatProductClear(nA)); 1697 PetscCall(MatConvert(nA, matis->lmattype, MAT_INPLACE_MATRIX, &nA)); 1698 PetscCall(MatISSetLocalMat(A, nA)); 1699 PetscCall(MatDestroy(&nA)); 1700 PetscCall(MatDestroy(&P)); 1701 PetscCall(MatDestroy(&R)); 1702 } 1703 } 1704 PetscCall(MatDestroy(&lA)); 1705 PetscFunctionReturn(PETSC_SUCCESS); 1706 } 1707 1708 /*@ 1709 MatISStoreL2L - Store local-to-local operators during the Galerkin process of computing `MatPtAP()` 1710 1711 Logically Collective 1712 1713 Input Parameters: 1714 + A - the matrix 1715 - store - the boolean flag 1716 1717 Level: advanced 1718 1719 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatPtAP()` 1720 @*/ 1721 PetscErrorCode MatISStoreL2L(Mat A, PetscBool store) 1722 { 1723 PetscFunctionBegin; 1724 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1725 PetscValidType(A, 1); 1726 PetscValidLogicalCollectiveBool(A, store, 2); 1727 PetscTryMethod(A, "MatISStoreL2L_C", (Mat, PetscBool), (A, store)); 1728 PetscFunctionReturn(PETSC_SUCCESS); 1729 } 1730 1731 static PetscErrorCode MatISStoreL2L_IS(Mat A, PetscBool store) 1732 { 1733 Mat_IS *matis = (Mat_IS *)A->data; 1734 1735 PetscFunctionBegin; 1736 matis->storel2l = store; 1737 if (!store) PetscCall(PetscObjectCompose((PetscObject)A, "_MatIS_PtAP_l2l", NULL)); 1738 PetscFunctionReturn(PETSC_SUCCESS); 1739 } 1740 1741 /*@ 1742 MatISFixLocalEmpty - Compress out zero local rows from the local matrices 1743 1744 Logically Collective 1745 1746 Input Parameters: 1747 + A - the matrix 1748 - fix - the boolean flag 1749 1750 Level: advanced 1751 1752 Note: 1753 When `fix` is `PETSC_TRUE`, new local matrices and l2g maps are generated during the final assembly process. 1754 1755 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatCreate()`, `MatCreateIS()`, `MatISSetPreallocation()`, `MatAssemblyEnd()`, `MAT_FINAL_ASSEMBLY` 1756 @*/ 1757 PetscErrorCode MatISFixLocalEmpty(Mat A, PetscBool fix) 1758 { 1759 PetscFunctionBegin; 1760 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 1761 PetscValidType(A, 1); 1762 PetscValidLogicalCollectiveBool(A, fix, 2); 1763 PetscTryMethod(A, "MatISFixLocalEmpty_C", (Mat, PetscBool), (A, fix)); 1764 PetscFunctionReturn(PETSC_SUCCESS); 1765 } 1766 1767 static PetscErrorCode MatISFixLocalEmpty_IS(Mat A, PetscBool fix) 1768 { 1769 Mat_IS *matis = (Mat_IS *)A->data; 1770 1771 PetscFunctionBegin; 1772 matis->locempty = fix; 1773 PetscFunctionReturn(PETSC_SUCCESS); 1774 } 1775 1776 /*@ 1777 MatISSetPreallocation - Preallocates memory for a `MATIS` parallel matrix. 1778 1779 Collective 1780 1781 Input Parameters: 1782 + B - the matrix 1783 . d_nz - number of nonzeros per row in DIAGONAL portion of local submatrix 1784 (same value is used for all local rows) 1785 . d_nnz - array containing the number of nonzeros in the various rows of the 1786 DIAGONAL portion of the local submatrix (possibly different for each row) 1787 or `NULL`, if `d_nz` is used to specify the nonzero structure. 1788 The size of this array is equal to the number of local rows, i.e `m`. 1789 For matrices that will be factored, you must leave room for (and set) 1790 the diagonal entry even if it is zero. 1791 . o_nz - number of nonzeros per row in the OFF-DIAGONAL portion of local 1792 submatrix (same value is used for all local rows). 1793 - o_nnz - array containing the number of nonzeros in the various rows of the 1794 OFF-DIAGONAL portion of the local submatrix (possibly different for 1795 each row) or `NULL`, if `o_nz` is used to specify the nonzero 1796 structure. The size of this array is equal to the number 1797 of local rows, i.e `m`. 1798 1799 If the *_nnz parameter is given then the *_nz parameter is ignored 1800 1801 Level: intermediate 1802 1803 Note: 1804 This function has the same interface as the `MATMPIAIJ` preallocation routine in order to simplify the transition 1805 from the asssembled format to the unassembled one. It overestimates the preallocation of `MATIS` local 1806 matrices; for exact preallocation, the user should set the preallocation directly on local matrix objects. 1807 1808 .seealso: [](ch_matrices), `Mat`, `MatCreate()`, `MatCreateIS()`, `MatMPIAIJSetPreallocation()`, `MatISGetLocalMat()`, `MATIS` 1809 @*/ 1810 PetscErrorCode MatISSetPreallocation(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[]) 1811 { 1812 PetscFunctionBegin; 1813 PetscValidHeaderSpecific(B, MAT_CLASSID, 1); 1814 PetscValidType(B, 1); 1815 PetscTryMethod(B, "MatISSetPreallocation_C", (Mat, PetscInt, const PetscInt[], PetscInt, const PetscInt[]), (B, d_nz, d_nnz, o_nz, o_nnz)); 1816 PetscFunctionReturn(PETSC_SUCCESS); 1817 } 1818 1819 static PetscErrorCode MatISSetPreallocation_IS(Mat B, PetscInt d_nz, const PetscInt d_nnz[], PetscInt o_nz, const PetscInt o_nnz[]) 1820 { 1821 Mat_IS *matis = (Mat_IS *)B->data; 1822 PetscInt bs, i, nlocalcols; 1823 1824 PetscFunctionBegin; 1825 PetscCall(MatSetUp(B)); 1826 if (!d_nnz) 1827 for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nz; 1828 else 1829 for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] = d_nnz[i]; 1830 1831 if (!o_nnz) 1832 for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nz; 1833 else 1834 for (i = 0; i < matis->sf->nroots; i++) matis->sf_rootdata[i] += o_nnz[i]; 1835 1836 PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE)); 1837 PetscCall(MatGetSize(matis->A, NULL, &nlocalcols)); 1838 PetscCall(MatGetBlockSize(matis->A, &bs)); 1839 PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE)); 1840 1841 for (i = 0; i < matis->sf->nleaves; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols); 1842 PetscCall(MatSeqAIJSetPreallocation(matis->A, 0, matis->sf_leafdata)); 1843 #if defined(PETSC_HAVE_HYPRE) 1844 PetscCall(MatHYPRESetPreallocation(matis->A, 0, matis->sf_leafdata, 0, NULL)); 1845 #endif 1846 1847 for (i = 0; i < matis->sf->nleaves / bs; i++) { 1848 PetscInt b; 1849 1850 matis->sf_leafdata[i] = matis->sf_leafdata[i * bs] / bs; 1851 for (b = 1; b < bs; b++) matis->sf_leafdata[i] = PetscMax(matis->sf_leafdata[i], matis->sf_leafdata[i * bs + b] / bs); 1852 } 1853 PetscCall(MatSeqBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata)); 1854 1855 nlocalcols /= bs; 1856 for (i = 0; i < matis->sf->nleaves / bs; i++) matis->sf_leafdata[i] = PetscMin(matis->sf_leafdata[i], nlocalcols - i); 1857 PetscCall(MatSeqSBAIJSetPreallocation(matis->A, bs, 0, matis->sf_leafdata)); 1858 1859 /* for other matrix types */ 1860 PetscCall(MatSetUp(matis->A)); 1861 PetscFunctionReturn(PETSC_SUCCESS); 1862 } 1863 1864 PETSC_INTERN PetscErrorCode MatConvert_IS_XAIJ(Mat mat, MatType mtype, MatReuse reuse, Mat *M) 1865 { 1866 Mat_IS *matis = (Mat_IS *)mat->data; 1867 Mat local_mat = NULL, MT; 1868 PetscInt rbs, cbs, rows, cols, lrows, lcols; 1869 PetscInt local_rows, local_cols; 1870 PetscBool isseqdense, isseqsbaij, isseqaij, isseqbaij; 1871 PetscMPIInt size; 1872 const PetscScalar *array; 1873 1874 PetscFunctionBegin; 1875 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)mat), &size)); 1876 if (size == 1 && mat->rmap->N == matis->A->rmap->N && mat->cmap->N == matis->A->cmap->N && !matis->allow_repeated) { 1877 Mat B; 1878 IS irows = NULL, icols = NULL; 1879 PetscInt rbs, cbs; 1880 1881 PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs)); 1882 PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs)); 1883 if (reuse != MAT_REUSE_MATRIX) { /* check if l2g maps are one-to-one */ 1884 IS rows, cols; 1885 const PetscInt *ridxs, *cidxs; 1886 PetscInt i, nw; 1887 PetscBT work; 1888 1889 PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->rmapping, &ridxs)); 1890 PetscCall(ISLocalToGlobalMappingGetSize(matis->rmapping, &nw)); 1891 nw = nw / rbs; 1892 PetscCall(PetscBTCreate(nw, &work)); 1893 for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, ridxs[i])); 1894 for (i = 0; i < nw; i++) 1895 if (!PetscBTLookup(work, i)) break; 1896 if (i == nw) { 1897 PetscCall(ISCreateBlock(PETSC_COMM_SELF, rbs, nw, ridxs, PETSC_USE_POINTER, &rows)); 1898 PetscCall(ISSetPermutation(rows)); 1899 PetscCall(ISInvertPermutation(rows, PETSC_DECIDE, &irows)); 1900 PetscCall(ISDestroy(&rows)); 1901 } 1902 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->rmapping, &ridxs)); 1903 PetscCall(PetscBTDestroy(&work)); 1904 if (irows && matis->rmapping != matis->cmapping) { 1905 PetscCall(ISLocalToGlobalMappingGetBlockIndices(matis->cmapping, &cidxs)); 1906 PetscCall(ISLocalToGlobalMappingGetSize(matis->cmapping, &nw)); 1907 nw = nw / cbs; 1908 PetscCall(PetscBTCreate(nw, &work)); 1909 for (i = 0; i < nw; i++) PetscCall(PetscBTSet(work, cidxs[i])); 1910 for (i = 0; i < nw; i++) 1911 if (!PetscBTLookup(work, i)) break; 1912 if (i == nw) { 1913 PetscCall(ISCreateBlock(PETSC_COMM_SELF, cbs, nw, cidxs, PETSC_USE_POINTER, &cols)); 1914 PetscCall(ISSetPermutation(cols)); 1915 PetscCall(ISInvertPermutation(cols, PETSC_DECIDE, &icols)); 1916 PetscCall(ISDestroy(&cols)); 1917 } 1918 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(matis->cmapping, &cidxs)); 1919 PetscCall(PetscBTDestroy(&work)); 1920 } else if (irows) { 1921 PetscCall(PetscObjectReference((PetscObject)irows)); 1922 icols = irows; 1923 } 1924 } else { 1925 PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject *)&irows)); 1926 PetscCall(PetscObjectQuery((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject *)&icols)); 1927 if (irows) PetscCall(PetscObjectReference((PetscObject)irows)); 1928 if (icols) PetscCall(PetscObjectReference((PetscObject)icols)); 1929 } 1930 if (!irows || !icols) { 1931 PetscCall(ISDestroy(&icols)); 1932 PetscCall(ISDestroy(&irows)); 1933 goto general_assembly; 1934 } 1935 PetscCall(MatConvert(matis->A, mtype, MAT_INITIAL_MATRIX, &B)); 1936 if (reuse != MAT_INPLACE_MATRIX) { 1937 PetscCall(MatCreateSubMatrix(B, irows, icols, reuse, M)); 1938 PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_irows", (PetscObject)irows)); 1939 PetscCall(PetscObjectCompose((PetscObject)*M, "_MatIS_IS_XAIJ_icols", (PetscObject)icols)); 1940 } else { 1941 Mat C; 1942 1943 PetscCall(MatCreateSubMatrix(B, irows, icols, MAT_INITIAL_MATRIX, &C)); 1944 PetscCall(MatHeaderReplace(mat, &C)); 1945 } 1946 PetscCall(MatDestroy(&B)); 1947 PetscCall(ISDestroy(&icols)); 1948 PetscCall(ISDestroy(&irows)); 1949 PetscFunctionReturn(PETSC_SUCCESS); 1950 } 1951 general_assembly: 1952 PetscCall(MatGetSize(mat, &rows, &cols)); 1953 PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->rmapping, &rbs)); 1954 PetscCall(ISLocalToGlobalMappingGetBlockSize(matis->cmapping, &cbs)); 1955 PetscCall(MatGetLocalSize(mat, &lrows, &lcols)); 1956 PetscCall(MatGetSize(matis->A, &local_rows, &local_cols)); 1957 PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQDENSE, &isseqdense)); 1958 PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQAIJ, &isseqaij)); 1959 PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQBAIJ, &isseqbaij)); 1960 PetscCall(PetscObjectBaseTypeCompare((PetscObject)matis->A, MATSEQSBAIJ, &isseqsbaij)); 1961 PetscCheck(isseqdense || isseqaij || isseqbaij || isseqsbaij, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for matrix type %s", ((PetscObject)matis->A)->type_name); 1962 if (PetscDefined(USE_DEBUG)) { 1963 PetscBool lb[4], bb[4]; 1964 1965 lb[0] = isseqdense; 1966 lb[1] = isseqaij; 1967 lb[2] = isseqbaij; 1968 lb[3] = isseqsbaij; 1969 PetscCallMPI(MPIU_Allreduce(lb, bb, 4, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)mat))); 1970 PetscCheck(bb[0] || bb[1] || bb[2] || bb[3], PETSC_COMM_SELF, PETSC_ERR_SUP, "Local matrices must have the same type"); 1971 } 1972 1973 if (reuse != MAT_REUSE_MATRIX) { 1974 PetscCount ncoo; 1975 PetscInt *coo_i, *coo_j; 1976 1977 PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &MT)); 1978 PetscCall(MatSetSizes(MT, lrows, lcols, rows, cols)); 1979 PetscCall(MatSetType(MT, mtype)); 1980 PetscCall(MatSetBlockSizes(MT, rbs, cbs)); 1981 if (!isseqaij && !isseqdense) { 1982 PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat)); 1983 } else { 1984 PetscCall(PetscObjectReference((PetscObject)matis->A)); 1985 local_mat = matis->A; 1986 } 1987 PetscCall(MatSetLocalToGlobalMapping(MT, matis->rmapping, matis->cmapping)); 1988 if (isseqdense) { 1989 PetscInt nr, nc; 1990 1991 PetscCall(MatGetSize(local_mat, &nr, &nc)); 1992 ncoo = nr * nc; 1993 PetscCall(PetscMalloc2(ncoo, &coo_i, ncoo, &coo_j)); 1994 for (PetscInt j = 0; j < nc; j++) { 1995 for (PetscInt i = 0; i < nr; i++) { 1996 coo_i[j * nr + i] = i; 1997 coo_j[j * nr + i] = j; 1998 } 1999 } 2000 } else { 2001 const PetscInt *ii, *jj; 2002 PetscInt nr; 2003 PetscBool done; 2004 2005 PetscCall(MatGetRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nr, &ii, &jj, &done)); 2006 PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatGetRowIJ"); 2007 ncoo = ii[nr]; 2008 PetscCall(PetscMalloc2(ncoo, &coo_i, ncoo, &coo_j)); 2009 PetscCall(PetscArraycpy(coo_j, jj, ncoo)); 2010 for (PetscInt i = 0; i < nr; i++) { 2011 for (PetscInt j = ii[i]; j < ii[i + 1]; j++) coo_i[j] = i; 2012 } 2013 PetscCall(MatRestoreRowIJ(local_mat, 0, PETSC_FALSE, PETSC_FALSE, &nr, &ii, &jj, &done)); 2014 PetscCheck(done, PetscObjectComm((PetscObject)local_mat), PETSC_ERR_PLIB, "Error in MatRestoreRowIJ"); 2015 } 2016 PetscCall(MatSetPreallocationCOOLocal(MT, ncoo, coo_i, coo_j)); 2017 PetscCall(PetscFree2(coo_i, coo_j)); 2018 } else { 2019 PetscInt mrbs, mcbs, mrows, mcols, mlrows, mlcols; 2020 2021 /* some checks */ 2022 MT = *M; 2023 PetscCall(MatGetBlockSizes(MT, &mrbs, &mcbs)); 2024 PetscCall(MatGetSize(MT, &mrows, &mcols)); 2025 PetscCall(MatGetLocalSize(MT, &mlrows, &mlcols)); 2026 PetscCheck(mrows == rows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", rows, mrows); 2027 PetscCheck(mcols == cols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", cols, mcols); 2028 PetscCheck(mlrows == lrows, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local rows (%" PetscInt_FMT " != %" PetscInt_FMT ")", lrows, mlrows); 2029 PetscCheck(mlcols == lcols, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong number of local cols (%" PetscInt_FMT " != %" PetscInt_FMT ")", lcols, mlcols); 2030 PetscCheck(mrbs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong row block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", rbs, mrbs); 2031 PetscCheck(mcbs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot reuse matrix. Wrong col block size (%" PetscInt_FMT " != %" PetscInt_FMT ")", cbs, mcbs); 2032 PetscCall(MatZeroEntries(MT)); 2033 if (!isseqaij && !isseqdense) { 2034 PetscCall(MatConvert(matis->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &local_mat)); 2035 } else { 2036 PetscCall(PetscObjectReference((PetscObject)matis->A)); 2037 local_mat = matis->A; 2038 } 2039 } 2040 2041 /* Set values */ 2042 if (isseqdense) { 2043 PetscCall(MatDenseGetArrayRead(local_mat, &array)); 2044 PetscCall(MatSetValuesCOO(MT, array, INSERT_VALUES)); 2045 PetscCall(MatDenseRestoreArrayRead(local_mat, &array)); 2046 } else { 2047 PetscCall(MatSeqAIJGetArrayRead(local_mat, &array)); 2048 PetscCall(MatSetValuesCOO(MT, array, INSERT_VALUES)); 2049 PetscCall(MatSeqAIJRestoreArrayRead(local_mat, &array)); 2050 } 2051 PetscCall(MatDestroy(&local_mat)); 2052 PetscCall(MatAssemblyBegin(MT, MAT_FINAL_ASSEMBLY)); 2053 PetscCall(MatAssemblyEnd(MT, MAT_FINAL_ASSEMBLY)); 2054 if (reuse == MAT_INPLACE_MATRIX) { 2055 PetscCall(MatHeaderReplace(mat, &MT)); 2056 } else if (reuse == MAT_INITIAL_MATRIX) { 2057 *M = MT; 2058 } 2059 PetscFunctionReturn(PETSC_SUCCESS); 2060 } 2061 2062 static PetscErrorCode MatDuplicate_IS(Mat mat, MatDuplicateOption op, Mat *newmat) 2063 { 2064 Mat_IS *matis = (Mat_IS *)mat->data; 2065 PetscInt rbs, cbs, m, n, M, N; 2066 Mat B, localmat; 2067 2068 PetscFunctionBegin; 2069 PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->rmap->mapping, &rbs)); 2070 PetscCall(ISLocalToGlobalMappingGetBlockSize(mat->cmap->mapping, &cbs)); 2071 PetscCall(MatGetSize(mat, &M, &N)); 2072 PetscCall(MatGetLocalSize(mat, &m, &n)); 2073 PetscCall(MatCreate(PetscObjectComm((PetscObject)mat), &B)); 2074 PetscCall(MatSetSizes(B, m, n, M, N)); 2075 PetscCall(MatSetBlockSize(B, rbs == cbs ? rbs : 1)); 2076 PetscCall(MatSetType(B, MATIS)); 2077 PetscCall(MatISSetLocalMatType(B, matis->lmattype)); 2078 PetscCall(MatISSetAllowRepeated(B, matis->allow_repeated)); 2079 PetscCall(MatSetLocalToGlobalMapping(B, mat->rmap->mapping, mat->cmap->mapping)); 2080 PetscCall(MatDuplicate(matis->A, op, &localmat)); 2081 PetscCall(MatSetLocalToGlobalMapping(localmat, matis->A->rmap->mapping, matis->A->cmap->mapping)); 2082 PetscCall(MatISSetLocalMat(B, localmat)); 2083 PetscCall(MatDestroy(&localmat)); 2084 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 2085 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 2086 *newmat = B; 2087 PetscFunctionReturn(PETSC_SUCCESS); 2088 } 2089 2090 static PetscErrorCode MatIsHermitian_IS(Mat A, PetscReal tol, PetscBool *flg) 2091 { 2092 Mat_IS *matis = (Mat_IS *)A->data; 2093 PetscBool local_sym; 2094 2095 PetscFunctionBegin; 2096 PetscCall(MatIsHermitian(matis->A, tol, &local_sym)); 2097 PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A))); 2098 PetscFunctionReturn(PETSC_SUCCESS); 2099 } 2100 2101 static PetscErrorCode MatIsSymmetric_IS(Mat A, PetscReal tol, PetscBool *flg) 2102 { 2103 Mat_IS *matis = (Mat_IS *)A->data; 2104 PetscBool local_sym; 2105 2106 PetscFunctionBegin; 2107 if (matis->rmapping != matis->cmapping) { 2108 *flg = PETSC_FALSE; 2109 PetscFunctionReturn(PETSC_SUCCESS); 2110 } 2111 PetscCall(MatIsSymmetric(matis->A, tol, &local_sym)); 2112 PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A))); 2113 PetscFunctionReturn(PETSC_SUCCESS); 2114 } 2115 2116 static PetscErrorCode MatIsStructurallySymmetric_IS(Mat A, PetscBool *flg) 2117 { 2118 Mat_IS *matis = (Mat_IS *)A->data; 2119 PetscBool local_sym; 2120 2121 PetscFunctionBegin; 2122 if (matis->rmapping != matis->cmapping) { 2123 *flg = PETSC_FALSE; 2124 PetscFunctionReturn(PETSC_SUCCESS); 2125 } 2126 PetscCall(MatIsStructurallySymmetric(matis->A, &local_sym)); 2127 PetscCallMPI(MPIU_Allreduce(&local_sym, flg, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A))); 2128 PetscFunctionReturn(PETSC_SUCCESS); 2129 } 2130 2131 static PetscErrorCode MatDestroy_IS(Mat A) 2132 { 2133 Mat_IS *b = (Mat_IS *)A->data; 2134 2135 PetscFunctionBegin; 2136 PetscCall(PetscFree(b->bdiag)); 2137 PetscCall(PetscFree(b->lmattype)); 2138 PetscCall(MatDestroy(&b->A)); 2139 PetscCall(VecScatterDestroy(&b->cctx)); 2140 PetscCall(VecScatterDestroy(&b->rctx)); 2141 PetscCall(VecDestroy(&b->x)); 2142 PetscCall(VecDestroy(&b->y)); 2143 PetscCall(VecDestroy(&b->counter)); 2144 PetscCall(ISDestroy(&b->getsub_ris)); 2145 PetscCall(ISDestroy(&b->getsub_cis)); 2146 if (b->sf != b->csf) { 2147 PetscCall(PetscSFDestroy(&b->csf)); 2148 PetscCall(PetscFree2(b->csf_rootdata, b->csf_leafdata)); 2149 } else b->csf = NULL; 2150 PetscCall(PetscSFDestroy(&b->sf)); 2151 PetscCall(PetscFree2(b->sf_rootdata, b->sf_leafdata)); 2152 PetscCall(ISLocalToGlobalMappingDestroy(&b->rmapping)); 2153 PetscCall(ISLocalToGlobalMappingDestroy(&b->cmapping)); 2154 PetscCall(MatDestroy(&b->dA)); 2155 PetscCall(MatDestroy(&b->assembledA)); 2156 PetscCall(PetscFree(A->data)); 2157 PetscCall(PetscObjectChangeTypeName((PetscObject)A, NULL)); 2158 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", NULL)); 2159 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", NULL)); 2160 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", NULL)); 2161 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", NULL)); 2162 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", NULL)); 2163 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", NULL)); 2164 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", NULL)); 2165 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", NULL)); 2166 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", NULL)); 2167 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", NULL)); 2168 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", NULL)); 2169 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", NULL)); 2170 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", NULL)); 2171 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", NULL)); 2172 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", NULL)); 2173 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", NULL)); 2174 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", NULL)); 2175 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", NULL)); 2176 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", NULL)); 2177 PetscFunctionReturn(PETSC_SUCCESS); 2178 } 2179 2180 static PetscErrorCode MatMult_IS(Mat A, Vec x, Vec y) 2181 { 2182 Mat_IS *is = (Mat_IS *)A->data; 2183 PetscScalar zero = 0.0; 2184 2185 PetscFunctionBegin; 2186 /* scatter the global vector x into the local work vector */ 2187 PetscCall(VecScatterBegin(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD)); 2188 PetscCall(VecScatterEnd(is->cctx, x, is->x, INSERT_VALUES, SCATTER_FORWARD)); 2189 2190 /* multiply the local matrix */ 2191 PetscCall(MatMult(is->A, is->x, is->y)); 2192 2193 /* scatter product back into global memory */ 2194 PetscCall(VecSet(y, zero)); 2195 PetscCall(VecScatterBegin(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE)); 2196 PetscCall(VecScatterEnd(is->rctx, is->y, y, ADD_VALUES, SCATTER_REVERSE)); 2197 PetscFunctionReturn(PETSC_SUCCESS); 2198 } 2199 2200 static PetscErrorCode MatMultAdd_IS(Mat A, Vec v1, Vec v2, Vec v3) 2201 { 2202 Vec temp_vec; 2203 2204 PetscFunctionBegin; /* v3 = v2 + A * v1.*/ 2205 if (v3 != v2) { 2206 PetscCall(MatMult(A, v1, v3)); 2207 PetscCall(VecAXPY(v3, 1.0, v2)); 2208 } else { 2209 PetscCall(VecDuplicate(v2, &temp_vec)); 2210 PetscCall(MatMult(A, v1, temp_vec)); 2211 PetscCall(VecAXPY(temp_vec, 1.0, v2)); 2212 PetscCall(VecCopy(temp_vec, v3)); 2213 PetscCall(VecDestroy(&temp_vec)); 2214 } 2215 PetscFunctionReturn(PETSC_SUCCESS); 2216 } 2217 2218 static PetscErrorCode MatMultTranspose_IS(Mat A, Vec y, Vec x) 2219 { 2220 Mat_IS *is = (Mat_IS *)A->data; 2221 2222 PetscFunctionBegin; 2223 /* scatter the global vector x into the local work vector */ 2224 PetscCall(VecScatterBegin(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD)); 2225 PetscCall(VecScatterEnd(is->rctx, y, is->y, INSERT_VALUES, SCATTER_FORWARD)); 2226 2227 /* multiply the local matrix */ 2228 PetscCall(MatMultTranspose(is->A, is->y, is->x)); 2229 2230 /* scatter product back into global vector */ 2231 PetscCall(VecSet(x, 0)); 2232 PetscCall(VecScatterBegin(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE)); 2233 PetscCall(VecScatterEnd(is->cctx, is->x, x, ADD_VALUES, SCATTER_REVERSE)); 2234 PetscFunctionReturn(PETSC_SUCCESS); 2235 } 2236 2237 static PetscErrorCode MatMultTransposeAdd_IS(Mat A, Vec v1, Vec v2, Vec v3) 2238 { 2239 Vec temp_vec; 2240 2241 PetscFunctionBegin; /* v3 = v2 + A' * v1.*/ 2242 if (v3 != v2) { 2243 PetscCall(MatMultTranspose(A, v1, v3)); 2244 PetscCall(VecAXPY(v3, 1.0, v2)); 2245 } else { 2246 PetscCall(VecDuplicate(v2, &temp_vec)); 2247 PetscCall(MatMultTranspose(A, v1, temp_vec)); 2248 PetscCall(VecAXPY(temp_vec, 1.0, v2)); 2249 PetscCall(VecCopy(temp_vec, v3)); 2250 PetscCall(VecDestroy(&temp_vec)); 2251 } 2252 PetscFunctionReturn(PETSC_SUCCESS); 2253 } 2254 2255 static PetscErrorCode ISLocalToGlobalMappingView_Multi(ISLocalToGlobalMapping mapping, PetscInt lsize, PetscInt gsize, const PetscInt vblocks[], PetscViewer viewer) 2256 { 2257 PetscInt tr[3], n; 2258 const PetscInt *indices; 2259 2260 PetscFunctionBegin; 2261 tr[0] = IS_LTOGM_FILE_CLASSID; 2262 tr[1] = 1; 2263 tr[2] = gsize; 2264 PetscCall(PetscViewerBinaryWrite(viewer, tr, 3, PETSC_INT)); 2265 PetscCall(PetscViewerBinaryWriteAll(viewer, vblocks, lsize, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT)); 2266 PetscCall(ISLocalToGlobalMappingGetSize(mapping, &n)); 2267 PetscCall(ISLocalToGlobalMappingGetIndices(mapping, &indices)); 2268 PetscCall(PetscViewerBinaryWriteAll(viewer, indices, n, PETSC_DETERMINE, PETSC_DETERMINE, PETSC_INT)); 2269 PetscCall(ISLocalToGlobalMappingRestoreIndices(mapping, &indices)); 2270 PetscFunctionReturn(PETSC_SUCCESS); 2271 } 2272 2273 static PetscErrorCode MatView_IS(Mat A, PetscViewer viewer) 2274 { 2275 Mat_IS *a = (Mat_IS *)A->data; 2276 PetscViewer sviewer; 2277 PetscBool isascii, isbinary, viewl2g = PETSC_FALSE, native; 2278 PetscViewerFormat format; 2279 ISLocalToGlobalMapping rmap, cmap; 2280 2281 PetscFunctionBegin; 2282 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 2283 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 2284 PetscCall(PetscViewerGetFormat(viewer, &format)); 2285 native = (PetscBool)(format == PETSC_VIEWER_NATIVE); 2286 if (native) { 2287 rmap = A->rmap->mapping; 2288 cmap = A->cmap->mapping; 2289 } else { 2290 rmap = a->rmapping; 2291 cmap = a->cmapping; 2292 } 2293 if (isascii) { 2294 if (format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS); 2295 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL || format == PETSC_VIEWER_ASCII_MATLAB) viewl2g = PETSC_TRUE; 2296 } else if (isbinary) { 2297 PetscInt tr[6], nr, nc, lsize = 0; 2298 char lmattype[64] = {'\0'}; 2299 PetscMPIInt size; 2300 PetscBool skipHeader, vbs = PETSC_FALSE; 2301 IS is; 2302 const PetscInt *vblocks = NULL; 2303 2304 PetscCall(PetscViewerSetUp(viewer)); 2305 PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)A)->prefix, "-mat_is_view_variableblocksizes", &vbs, NULL)); 2306 if (vbs) { 2307 PetscCall(MatGetVariableBlockSizes(a->A, &lsize, &vblocks)); 2308 PetscCall(PetscMPIIntCast(lsize, &size)); 2309 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &size, 1, MPI_INT, MPI_SUM, PetscObjectComm((PetscObject)viewer))); 2310 } else { 2311 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size)); 2312 } 2313 tr[0] = MAT_FILE_CLASSID; 2314 tr[1] = A->rmap->N; 2315 tr[2] = A->cmap->N; 2316 tr[3] = -size; /* AIJ stores nnz here */ 2317 tr[4] = (PetscInt)(rmap == cmap); 2318 tr[5] = a->allow_repeated; 2319 PetscCall(PetscSNPrintf(lmattype, sizeof(lmattype), "%s", a->lmattype)); 2320 2321 PetscCall(PetscViewerBinaryWrite(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), PETSC_INT)); 2322 PetscCall(PetscViewerBinaryWrite(viewer, lmattype, sizeof(lmattype), PETSC_CHAR)); 2323 2324 /* first dump l2g info (we need the header for proper loading on different number of processes) */ 2325 PetscCall(PetscViewerBinaryGetSkipHeader(viewer, &skipHeader)); 2326 PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_FALSE)); 2327 if (vbs) { 2328 PetscCall(ISLocalToGlobalMappingView_Multi(rmap, lsize, size, vblocks, viewer)); 2329 if (cmap != rmap) PetscCall(ISLocalToGlobalMappingView_Multi(cmap, lsize, size, vblocks, viewer)); 2330 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), lsize, vblocks, PETSC_USE_POINTER, &is)); 2331 PetscCall(ISView(is, viewer)); 2332 PetscCall(ISView(is, viewer)); 2333 PetscCall(ISDestroy(&is)); 2334 } else { 2335 PetscCall(ISLocalToGlobalMappingView(rmap, viewer)); 2336 if (cmap != rmap) PetscCall(ISLocalToGlobalMappingView(cmap, viewer)); 2337 2338 /* then the sizes of the local matrices */ 2339 PetscCall(MatGetSize(a->A, &nr, &nc)); 2340 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nr, PETSC_USE_POINTER, &is)); 2341 PetscCall(ISView(is, viewer)); 2342 PetscCall(ISDestroy(&is)); 2343 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)viewer), 1, &nc, PETSC_USE_POINTER, &is)); 2344 PetscCall(ISView(is, viewer)); 2345 PetscCall(ISDestroy(&is)); 2346 } 2347 PetscCall(PetscViewerBinarySetSkipHeader(viewer, skipHeader)); 2348 } 2349 if (format == PETSC_VIEWER_ASCII_MATLAB) { 2350 char name[64]; 2351 PetscMPIInt size, rank; 2352 2353 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size)); 2354 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 2355 if (size > 1) PetscCall(PetscSNPrintf(name, sizeof(name), "lmat_%d", rank)); 2356 else PetscCall(PetscSNPrintf(name, sizeof(name), "lmat")); 2357 PetscCall(PetscObjectSetName((PetscObject)a->A, name)); 2358 } 2359 2360 /* Dump the local matrices */ 2361 if (isbinary) { /* ViewerGetSubViewer does not work in parallel */ 2362 PetscBool isaij; 2363 PetscInt nr, nc; 2364 Mat lA, B; 2365 Mat_MPIAIJ *b; 2366 2367 /* We create a temporary MPIAIJ matrix that stores the unassembled operator */ 2368 PetscCall(PetscObjectBaseTypeCompare((PetscObject)a->A, MATAIJ, &isaij)); 2369 if (!isaij) PetscCall(MatConvert(a->A, MATSEQAIJ, MAT_INITIAL_MATRIX, &lA)); 2370 else { 2371 PetscCall(PetscObjectReference((PetscObject)a->A)); 2372 lA = a->A; 2373 } 2374 PetscCall(MatCreate(PetscObjectComm((PetscObject)viewer), &B)); 2375 PetscCall(MatSetType(B, MATMPIAIJ)); 2376 PetscCall(MatGetSize(lA, &nr, &nc)); 2377 PetscCall(MatSetSizes(B, nr, nc, PETSC_DECIDE, PETSC_DECIDE)); 2378 PetscCall(MatMPIAIJSetPreallocation(B, 0, NULL, 0, NULL)); 2379 2380 b = (Mat_MPIAIJ *)B->data; 2381 PetscCall(MatDestroy(&b->A)); 2382 b->A = lA; 2383 2384 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 2385 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 2386 PetscCall(MatView(B, viewer)); 2387 PetscCall(MatDestroy(&B)); 2388 } else { 2389 PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 2390 PetscCall(MatView(a->A, sviewer)); 2391 PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 2392 } 2393 2394 /* with ASCII, we dump the l2gmaps at the end */ 2395 if (viewl2g) { 2396 if (format == PETSC_VIEWER_ASCII_MATLAB) { 2397 PetscCall(PetscObjectSetName((PetscObject)rmap, "row")); 2398 PetscCall(ISLocalToGlobalMappingView(rmap, viewer)); 2399 PetscCall(PetscObjectSetName((PetscObject)cmap, "col")); 2400 PetscCall(ISLocalToGlobalMappingView(cmap, viewer)); 2401 } else { 2402 PetscCall(ISLocalToGlobalMappingView(rmap, viewer)); 2403 PetscCall(ISLocalToGlobalMappingView(cmap, viewer)); 2404 } 2405 } 2406 PetscFunctionReturn(PETSC_SUCCESS); 2407 } 2408 2409 static PetscErrorCode ISLocalToGlobalMappingHasRepeatedLocal_Private(ISLocalToGlobalMapping map, PetscBool *has) 2410 { 2411 const PetscInt *idxs; 2412 PetscHSetI ht; 2413 PetscInt n, bs; 2414 2415 PetscFunctionBegin; 2416 PetscCall(ISLocalToGlobalMappingGetSize(map, &n)); 2417 PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs)); 2418 PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs)); 2419 PetscCall(PetscHSetICreate(&ht)); 2420 *has = PETSC_FALSE; 2421 for (PetscInt i = 0; i < n / bs; i++) { 2422 PetscBool missing = PETSC_TRUE; 2423 if (idxs[i] < 0) continue; 2424 PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing)); 2425 if (!missing) { 2426 *has = PETSC_TRUE; 2427 break; 2428 } 2429 } 2430 PetscCall(PetscHSetIDestroy(&ht)); 2431 PetscFunctionReturn(PETSC_SUCCESS); 2432 } 2433 2434 static PetscErrorCode MatLoad_IS(Mat A, PetscViewer viewer) 2435 { 2436 ISLocalToGlobalMapping rmap, cmap; 2437 MPI_Comm comm = PetscObjectComm((PetscObject)A); 2438 PetscBool isbinary, samel, allow, isbaij; 2439 PetscInt tr[6], M, N, nr, nc, Asize, isn; 2440 const PetscInt *idx; 2441 PetscMPIInt size; 2442 char lmattype[64]; 2443 Mat dA, lA; 2444 IS is; 2445 2446 PetscFunctionBegin; 2447 PetscCheckSameComm(A, 1, viewer, 2); 2448 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary)); 2449 PetscCheck(isbinary, PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "Invalid viewer of type %s", ((PetscObject)viewer)->type_name); 2450 2451 PetscCall(PetscViewerBinaryRead(viewer, tr, PETSC_STATIC_ARRAY_LENGTH(tr), NULL, PETSC_INT)); 2452 PetscCheck(tr[0] == MAT_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a matrix next in file"); 2453 PetscCheck(tr[1] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file"); 2454 PetscCheck(tr[2] >= 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file"); 2455 PetscCheck(tr[3] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file"); 2456 PetscCheck(tr[4] == 0 || tr[4] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file"); 2457 PetscCheck(tr[5] == 0 || tr[5] == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Not a IS matrix next in file"); 2458 M = tr[1]; 2459 N = tr[2]; 2460 Asize = -tr[3]; 2461 samel = (PetscBool)tr[4]; 2462 allow = (PetscBool)tr[5]; 2463 PetscCall(PetscViewerBinaryRead(viewer, lmattype, sizeof(lmattype), NULL, PETSC_CHAR)); 2464 2465 /* if we are loading from a larger set of processes, allow repeated entries */ 2466 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)viewer), &size)); 2467 if (Asize > size) allow = PETSC_TRUE; 2468 2469 /* set global sizes if not set already */ 2470 if (A->rmap->N < 0) A->rmap->N = M; 2471 if (A->cmap->N < 0) A->cmap->N = N; 2472 PetscCall(PetscLayoutSetUp(A->rmap)); 2473 PetscCall(PetscLayoutSetUp(A->cmap)); 2474 PetscCheck(M == A->rmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix rows should be %" PetscInt_FMT ", found %" PetscInt_FMT, M, A->rmap->N); 2475 PetscCheck(N == A->cmap->N, comm, PETSC_ERR_ARG_SIZ, "Matrix columns should be %" PetscInt_FMT ", found %" PetscInt_FMT, N, A->cmap->N); 2476 2477 /* load l2g maps */ 2478 PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &rmap)); 2479 PetscCall(ISLocalToGlobalMappingLoad(rmap, viewer)); 2480 if (!samel) { 2481 PetscCall(ISLocalToGlobalMappingCreate(comm, 0, 0, NULL, PETSC_USE_POINTER, &cmap)); 2482 PetscCall(ISLocalToGlobalMappingLoad(cmap, viewer)); 2483 } else { 2484 PetscCall(PetscObjectReference((PetscObject)rmap)); 2485 cmap = rmap; 2486 } 2487 2488 /* load sizes of local matrices */ 2489 PetscCall(ISCreate(comm, &is)); 2490 PetscCall(ISSetType(is, ISGENERAL)); 2491 PetscCall(ISLoad(is, viewer)); 2492 PetscCall(ISGetLocalSize(is, &isn)); 2493 PetscCall(ISGetIndices(is, &idx)); 2494 nr = 0; 2495 for (PetscInt i = 0; i < isn; i++) nr += idx[i]; 2496 PetscCall(ISRestoreIndices(is, &idx)); 2497 PetscCall(ISDestroy(&is)); 2498 PetscCall(ISCreate(comm, &is)); 2499 PetscCall(ISSetType(is, ISGENERAL)); 2500 PetscCall(ISLoad(is, viewer)); 2501 PetscCall(ISGetLocalSize(is, &isn)); 2502 PetscCall(ISGetIndices(is, &idx)); 2503 nc = 0; 2504 for (PetscInt i = 0; i < isn; i++) nc += idx[i]; 2505 PetscCall(ISRestoreIndices(is, &idx)); 2506 PetscCall(ISDestroy(&is)); 2507 2508 /* now load the unassembled operator */ 2509 PetscCall(MatCreate(comm, &dA)); 2510 PetscCall(MatSetType(dA, MATMPIAIJ)); 2511 PetscCall(MatSetSizes(dA, nr, nc, PETSC_DECIDE, PETSC_DECIDE)); 2512 PetscCall(MatLoad(dA, viewer)); 2513 PetscCall(MatMPIAIJGetSeqAIJ(dA, &lA, NULL, NULL)); 2514 PetscCall(PetscObjectReference((PetscObject)lA)); 2515 PetscCall(MatDestroy(&dA)); 2516 2517 /* and convert to the desired format */ 2518 PetscCall(PetscStrcmpAny(lmattype, &isbaij, MATSBAIJ, MATSEQSBAIJ, "")); 2519 if (isbaij) PetscCall(MatSetOption(lA, MAT_SYMMETRIC, PETSC_TRUE)); 2520 PetscCall(MatConvert(lA, lmattype, MAT_INPLACE_MATRIX, &lA)); 2521 2522 /* check if we actually have repeated entries */ 2523 if (allow) { 2524 PetscBool rhas, chas, hasrepeated; 2525 2526 PetscCall(ISLocalToGlobalMappingHasRepeatedLocal_Private(rmap, &rhas)); 2527 if (rmap != cmap) PetscCall(ISLocalToGlobalMappingHasRepeatedLocal_Private(cmap, &chas)); 2528 else chas = rhas; 2529 hasrepeated = (PetscBool)(rhas || chas); 2530 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &hasrepeated, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A))); 2531 if (!hasrepeated) allow = PETSC_FALSE; 2532 } 2533 2534 /* assemble the MATIS object */ 2535 PetscCall(MatISSetAllowRepeated(A, allow)); 2536 PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap)); 2537 PetscCall(MatISSetLocalMat(A, lA)); 2538 PetscCall(MatDestroy(&lA)); 2539 PetscCall(ISLocalToGlobalMappingDestroy(&rmap)); 2540 PetscCall(ISLocalToGlobalMappingDestroy(&cmap)); 2541 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 2542 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 2543 PetscFunctionReturn(PETSC_SUCCESS); 2544 } 2545 2546 static PetscErrorCode MatInvertBlockDiagonal_IS(Mat mat, const PetscScalar **values) 2547 { 2548 Mat_IS *is = (Mat_IS *)mat->data; 2549 MPI_Datatype nodeType; 2550 const PetscScalar *lv; 2551 PetscInt bs; 2552 PetscMPIInt mbs; 2553 2554 PetscFunctionBegin; 2555 PetscCall(MatGetBlockSize(mat, &bs)); 2556 PetscCall(MatSetBlockSize(is->A, bs)); 2557 PetscCall(MatInvertBlockDiagonal(is->A, &lv)); 2558 if (!is->bdiag) PetscCall(PetscMalloc1(bs * mat->rmap->n, &is->bdiag)); 2559 PetscCall(PetscMPIIntCast(bs, &mbs)); 2560 PetscCallMPI(MPI_Type_contiguous(mbs, MPIU_SCALAR, &nodeType)); 2561 PetscCallMPI(MPI_Type_commit(&nodeType)); 2562 PetscCall(PetscSFReduceBegin(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE)); 2563 PetscCall(PetscSFReduceEnd(is->sf, nodeType, lv, is->bdiag, MPI_REPLACE)); 2564 PetscCallMPI(MPI_Type_free(&nodeType)); 2565 if (values) *values = is->bdiag; 2566 PetscFunctionReturn(PETSC_SUCCESS); 2567 } 2568 2569 static PetscErrorCode MatISSetUpScatters_Private(Mat A) 2570 { 2571 Vec cglobal, rglobal; 2572 IS from; 2573 Mat_IS *is = (Mat_IS *)A->data; 2574 PetscScalar sum; 2575 const PetscInt *garray; 2576 PetscInt nr, rbs, nc, cbs; 2577 VecType rtype; 2578 2579 PetscFunctionBegin; 2580 PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr)); 2581 PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs)); 2582 PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc)); 2583 PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs)); 2584 PetscCall(VecDestroy(&is->x)); 2585 PetscCall(VecDestroy(&is->y)); 2586 PetscCall(VecDestroy(&is->counter)); 2587 PetscCall(VecScatterDestroy(&is->rctx)); 2588 PetscCall(VecScatterDestroy(&is->cctx)); 2589 PetscCall(MatCreateVecs(is->A, &is->x, &is->y)); 2590 PetscCall(VecBindToCPU(is->y, PETSC_TRUE)); 2591 PetscCall(VecGetRootType_Private(is->y, &rtype)); 2592 PetscCall(PetscFree(A->defaultvectype)); 2593 PetscCall(PetscStrallocpy(rtype, &A->defaultvectype)); 2594 PetscCall(MatCreateVecs(A, &cglobal, &rglobal)); 2595 PetscCall(VecBindToCPU(rglobal, PETSC_TRUE)); 2596 PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &garray)); 2597 PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), rbs, nr / rbs, garray, PETSC_USE_POINTER, &from)); 2598 PetscCall(VecScatterCreate(rglobal, from, is->y, NULL, &is->rctx)); 2599 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &garray)); 2600 PetscCall(ISDestroy(&from)); 2601 if (is->rmapping != is->cmapping) { 2602 PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &garray)); 2603 PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), cbs, nc / cbs, garray, PETSC_USE_POINTER, &from)); 2604 PetscCall(VecScatterCreate(cglobal, from, is->x, NULL, &is->cctx)); 2605 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &garray)); 2606 PetscCall(ISDestroy(&from)); 2607 } else { 2608 PetscCall(PetscObjectReference((PetscObject)is->rctx)); 2609 is->cctx = is->rctx; 2610 } 2611 PetscCall(VecDestroy(&cglobal)); 2612 2613 /* interface counter vector (local) */ 2614 PetscCall(VecDuplicate(is->y, &is->counter)); 2615 PetscCall(VecBindToCPU(is->counter, PETSC_TRUE)); 2616 PetscCall(VecSet(is->y, 1.)); 2617 PetscCall(VecScatterBegin(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE)); 2618 PetscCall(VecScatterEnd(is->rctx, is->y, rglobal, ADD_VALUES, SCATTER_REVERSE)); 2619 PetscCall(VecScatterBegin(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD)); 2620 PetscCall(VecScatterEnd(is->rctx, rglobal, is->counter, INSERT_VALUES, SCATTER_FORWARD)); 2621 PetscCall(VecBindToCPU(is->y, PETSC_FALSE)); 2622 PetscCall(VecBindToCPU(is->counter, PETSC_FALSE)); 2623 2624 /* special functions for block-diagonal matrices */ 2625 PetscCall(VecSum(rglobal, &sum)); 2626 A->ops->invertblockdiagonal = NULL; 2627 if ((PetscInt)(PetscRealPart(sum)) == A->rmap->N && A->rmap->N == A->cmap->N && is->rmapping == is->cmapping) A->ops->invertblockdiagonal = MatInvertBlockDiagonal_IS; 2628 PetscCall(VecDestroy(&rglobal)); 2629 2630 /* setup SF for general purpose shared indices based communications */ 2631 PetscCall(MatISSetUpSF_IS(A)); 2632 PetscFunctionReturn(PETSC_SUCCESS); 2633 } 2634 2635 static PetscErrorCode MatISFilterL2GMap(Mat A, ISLocalToGlobalMapping map, ISLocalToGlobalMapping *nmap, ISLocalToGlobalMapping *lmap) 2636 { 2637 Mat_IS *matis = (Mat_IS *)A->data; 2638 IS is; 2639 ISLocalToGlobalMappingType l2gtype; 2640 const PetscInt *idxs; 2641 PetscHSetI ht; 2642 PetscInt *nidxs; 2643 PetscInt i, n, bs, c; 2644 PetscBool flg[] = {PETSC_FALSE, PETSC_FALSE}; 2645 2646 PetscFunctionBegin; 2647 PetscCall(ISLocalToGlobalMappingGetSize(map, &n)); 2648 PetscCall(ISLocalToGlobalMappingGetBlockSize(map, &bs)); 2649 PetscCall(ISLocalToGlobalMappingGetBlockIndices(map, &idxs)); 2650 PetscCall(PetscHSetICreate(&ht)); 2651 PetscCall(PetscMalloc1(n / bs, &nidxs)); 2652 for (i = 0, c = 0; i < n / bs; i++) { 2653 PetscBool missing = PETSC_TRUE; 2654 if (idxs[i] < 0) { 2655 flg[0] = PETSC_TRUE; 2656 continue; 2657 } 2658 if (!matis->allow_repeated) PetscCall(PetscHSetIQueryAdd(ht, idxs[i], &missing)); 2659 if (!missing) flg[1] = PETSC_TRUE; 2660 else nidxs[c++] = idxs[i]; 2661 } 2662 PetscCall(PetscHSetIDestroy(&ht)); 2663 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, flg, 2, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A))); 2664 if (!flg[0] && !flg[1]) { /* Entries are all non negative and unique */ 2665 *nmap = NULL; 2666 *lmap = NULL; 2667 PetscCall(PetscFree(nidxs)); 2668 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs)); 2669 PetscFunctionReturn(PETSC_SUCCESS); 2670 } 2671 2672 /* New l2g map without negative indices (and repeated indices if not allowed) */ 2673 PetscCall(ISCreateBlock(PetscObjectComm((PetscObject)A), bs, c, nidxs, PETSC_USE_POINTER, &is)); 2674 PetscCall(ISLocalToGlobalMappingCreateIS(is, nmap)); 2675 PetscCall(ISDestroy(&is)); 2676 PetscCall(ISLocalToGlobalMappingGetType(map, &l2gtype)); 2677 PetscCall(ISLocalToGlobalMappingSetType(*nmap, l2gtype)); 2678 2679 /* New local l2g map for repeated indices if not allowed */ 2680 PetscCall(ISGlobalToLocalMappingApplyBlock(*nmap, IS_GTOLM_MASK, n / bs, idxs, NULL, nidxs)); 2681 PetscCall(ISCreateBlock(PETSC_COMM_SELF, bs, n / bs, nidxs, PETSC_USE_POINTER, &is)); 2682 PetscCall(ISLocalToGlobalMappingCreateIS(is, lmap)); 2683 PetscCall(ISDestroy(&is)); 2684 PetscCall(PetscFree(nidxs)); 2685 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(map, &idxs)); 2686 PetscFunctionReturn(PETSC_SUCCESS); 2687 } 2688 2689 static PetscErrorCode MatSetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping rmapping, ISLocalToGlobalMapping cmapping) 2690 { 2691 Mat_IS *is = (Mat_IS *)A->data; 2692 ISLocalToGlobalMapping localrmapping = NULL, localcmapping = NULL; 2693 PetscInt nr, rbs, nc, cbs; 2694 PetscBool cong, freem[] = {PETSC_FALSE, PETSC_FALSE}; 2695 2696 PetscFunctionBegin; 2697 if (rmapping) PetscCheckSameComm(A, 1, rmapping, 2); 2698 if (cmapping) PetscCheckSameComm(A, 1, cmapping, 3); 2699 2700 PetscCall(ISLocalToGlobalMappingDestroy(&is->rmapping)); 2701 PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping)); 2702 PetscCall(PetscLayoutSetUp(A->rmap)); 2703 PetscCall(PetscLayoutSetUp(A->cmap)); 2704 PetscCall(MatHasCongruentLayouts(A, &cong)); 2705 2706 /* If NULL, local space matches global space */ 2707 if (!rmapping) { 2708 IS is; 2709 2710 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->rmap->N, 0, 1, &is)); 2711 PetscCall(ISLocalToGlobalMappingCreateIS(is, &rmapping)); 2712 PetscCall(ISLocalToGlobalMappingSetBlockSize(rmapping, A->rmap->bs)); 2713 PetscCall(ISDestroy(&is)); 2714 freem[0] = PETSC_TRUE; 2715 if (!cmapping && cong && A->rmap->bs == A->cmap->bs) cmapping = rmapping; 2716 } else if (!is->islocalref) { /* check if the l2g map has negative or repeated entries */ 2717 PetscCall(MatISFilterL2GMap(A, rmapping, &is->rmapping, &localrmapping)); 2718 if (rmapping == cmapping) { 2719 PetscCall(PetscObjectReference((PetscObject)is->rmapping)); 2720 is->cmapping = is->rmapping; 2721 PetscCall(PetscObjectReference((PetscObject)localrmapping)); 2722 localcmapping = localrmapping; 2723 } 2724 } 2725 if (!cmapping) { 2726 IS is; 2727 2728 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)A), A->cmap->N, 0, 1, &is)); 2729 PetscCall(ISLocalToGlobalMappingCreateIS(is, &cmapping)); 2730 PetscCall(ISLocalToGlobalMappingSetBlockSize(cmapping, A->cmap->bs)); 2731 PetscCall(ISDestroy(&is)); 2732 freem[1] = PETSC_TRUE; 2733 } else if (cmapping != rmapping && !is->islocalref) { /* check if the l2g map has negative or repeated entries */ 2734 PetscCall(MatISFilterL2GMap(A, cmapping, &is->cmapping, &localcmapping)); 2735 } 2736 if (!is->rmapping) { 2737 PetscCall(PetscObjectReference((PetscObject)rmapping)); 2738 is->rmapping = rmapping; 2739 } 2740 if (!is->cmapping) { 2741 PetscCall(PetscObjectReference((PetscObject)cmapping)); 2742 is->cmapping = cmapping; 2743 } 2744 2745 /* Clean up */ 2746 is->lnnzstate = 0; 2747 PetscCall(MatDestroy(&is->dA)); 2748 PetscCall(MatDestroy(&is->assembledA)); 2749 PetscCall(MatDestroy(&is->A)); 2750 if (is->csf != is->sf) { 2751 PetscCall(PetscSFDestroy(&is->csf)); 2752 PetscCall(PetscFree2(is->csf_rootdata, is->csf_leafdata)); 2753 } else is->csf = NULL; 2754 PetscCall(PetscSFDestroy(&is->sf)); 2755 PetscCall(PetscFree2(is->sf_rootdata, is->sf_leafdata)); 2756 PetscCall(PetscFree(is->bdiag)); 2757 2758 /* check if the two mappings are actually the same for square matrices since MATIS has some optimization for this case 2759 (DOLFIN passes 2 different objects) */ 2760 PetscCall(ISLocalToGlobalMappingGetSize(is->rmapping, &nr)); 2761 PetscCall(ISLocalToGlobalMappingGetBlockSize(is->rmapping, &rbs)); 2762 PetscCall(ISLocalToGlobalMappingGetSize(is->cmapping, &nc)); 2763 PetscCall(ISLocalToGlobalMappingGetBlockSize(is->cmapping, &cbs)); 2764 if (is->rmapping != is->cmapping && cong) { 2765 PetscBool same = PETSC_FALSE; 2766 if (nr == nc && cbs == rbs) { 2767 const PetscInt *idxs1, *idxs2; 2768 2769 PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->rmapping, &idxs1)); 2770 PetscCall(ISLocalToGlobalMappingGetBlockIndices(is->cmapping, &idxs2)); 2771 PetscCall(PetscArraycmp(idxs1, idxs2, nr / rbs, &same)); 2772 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->rmapping, &idxs1)); 2773 PetscCall(ISLocalToGlobalMappingRestoreBlockIndices(is->cmapping, &idxs2)); 2774 } 2775 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &same, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A))); 2776 if (same) { 2777 PetscCall(ISLocalToGlobalMappingDestroy(&is->cmapping)); 2778 PetscCall(PetscObjectReference((PetscObject)is->rmapping)); 2779 is->cmapping = is->rmapping; 2780 } 2781 } 2782 PetscCall(PetscLayoutSetBlockSize(A->rmap, rbs)); 2783 PetscCall(PetscLayoutSetBlockSize(A->cmap, cbs)); 2784 /* Pass the user defined maps to the layout */ 2785 PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->rmap, rmapping)); 2786 PetscCall(PetscLayoutSetISLocalToGlobalMapping(A->cmap, cmapping)); 2787 if (freem[0]) PetscCall(ISLocalToGlobalMappingDestroy(&rmapping)); 2788 if (freem[1]) PetscCall(ISLocalToGlobalMappingDestroy(&cmapping)); 2789 2790 if (!is->islocalref) { 2791 /* Create the local matrix A */ 2792 PetscCall(MatCreate(PETSC_COMM_SELF, &is->A)); 2793 PetscCall(MatSetType(is->A, is->lmattype)); 2794 PetscCall(MatSetSizes(is->A, nr, nc, nr, nc)); 2795 PetscCall(MatSetBlockSizes(is->A, rbs, cbs)); 2796 PetscCall(MatSetOptionsPrefix(is->A, "is_")); 2797 PetscCall(MatAppendOptionsPrefix(is->A, ((PetscObject)A)->prefix)); 2798 PetscCall(PetscLayoutSetUp(is->A->rmap)); 2799 PetscCall(PetscLayoutSetUp(is->A->cmap)); 2800 PetscCall(MatSetLocalToGlobalMapping(is->A, localrmapping, localcmapping)); 2801 PetscCall(ISLocalToGlobalMappingDestroy(&localrmapping)); 2802 PetscCall(ISLocalToGlobalMappingDestroy(&localcmapping)); 2803 /* setup scatters and local vectors for MatMult */ 2804 PetscCall(MatISSetUpScatters_Private(A)); 2805 } 2806 A->preallocated = PETSC_TRUE; 2807 PetscFunctionReturn(PETSC_SUCCESS); 2808 } 2809 2810 static PetscErrorCode MatSetUp_IS(Mat A) 2811 { 2812 Mat_IS *is = (Mat_IS *)A->data; 2813 ISLocalToGlobalMapping rmap, cmap; 2814 2815 PetscFunctionBegin; 2816 if (!is->sf) { 2817 PetscCall(MatGetLocalToGlobalMapping(A, &rmap, &cmap)); 2818 PetscCall(MatSetLocalToGlobalMapping(A, rmap, cmap)); 2819 } 2820 PetscFunctionReturn(PETSC_SUCCESS); 2821 } 2822 2823 static PetscErrorCode MatSetValues_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) 2824 { 2825 Mat_IS *is = (Mat_IS *)mat->data; 2826 PetscInt buf[2 * MATIS_MAX_ENTRIES_INSERTION], *rows_l = NULL, *cols_l = NULL; 2827 2828 PetscFunctionBegin; 2829 IndexSpaceGet(buf, m, n, rows_l, cols_l); 2830 PetscCall(ISGlobalToLocalMappingApply(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l)); 2831 if (m != n || rows != cols || is->cmapping != is->rmapping) { 2832 PetscCall(ISGlobalToLocalMappingApply(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l)); 2833 PetscCall(MatSetValues(is->A, m, rows_l, n, cols_l, values, addv)); 2834 } else { 2835 PetscCall(MatSetValues(is->A, m, rows_l, m, rows_l, values, addv)); 2836 } 2837 IndexSpaceRestore(buf, m, n, rows_l, cols_l); 2838 PetscFunctionReturn(PETSC_SUCCESS); 2839 } 2840 2841 static PetscErrorCode MatSetValuesBlocked_IS(Mat mat, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) 2842 { 2843 Mat_IS *is = (Mat_IS *)mat->data; 2844 PetscInt buf[2 * MATIS_MAX_ENTRIES_INSERTION], *rows_l = NULL, *cols_l = NULL; 2845 2846 PetscFunctionBegin; 2847 IndexSpaceGet(buf, m, n, rows_l, cols_l); 2848 PetscCall(ISGlobalToLocalMappingApplyBlock(is->rmapping, IS_GTOLM_MASK, m, rows, &m, rows_l)); 2849 if (m != n || rows != cols || is->cmapping != is->rmapping) { 2850 PetscCall(ISGlobalToLocalMappingApplyBlock(is->cmapping, IS_GTOLM_MASK, n, cols, &n, cols_l)); 2851 PetscCall(MatSetValuesBlocked(is->A, m, rows_l, n, cols_l, values, addv)); 2852 } else { 2853 PetscCall(MatSetValuesBlocked(is->A, m, rows_l, m, rows_l, values, addv)); 2854 } 2855 IndexSpaceRestore(buf, m, n, rows_l, cols_l); 2856 PetscFunctionReturn(PETSC_SUCCESS); 2857 } 2858 2859 static PetscErrorCode MatSetValuesLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) 2860 { 2861 Mat_IS *is = (Mat_IS *)A->data; 2862 2863 PetscFunctionBegin; 2864 if (is->A->rmap->mapping || is->A->cmap->mapping) { 2865 PetscCall(MatSetValuesLocal(is->A, m, rows, n, cols, values, addv)); 2866 } else { 2867 PetscCall(MatSetValues(is->A, m, rows, n, cols, values, addv)); 2868 } 2869 PetscFunctionReturn(PETSC_SUCCESS); 2870 } 2871 2872 static PetscErrorCode MatSetValuesBlockedLocal_IS(Mat A, PetscInt m, const PetscInt *rows, PetscInt n, const PetscInt *cols, const PetscScalar *values, InsertMode addv) 2873 { 2874 Mat_IS *is = (Mat_IS *)A->data; 2875 2876 PetscFunctionBegin; 2877 if (is->A->rmap->mapping || is->A->cmap->mapping) { 2878 PetscCall(MatSetValuesBlockedLocal(is->A, m, rows, n, cols, values, addv)); 2879 } else { 2880 PetscCall(MatSetValuesBlocked(is->A, m, rows, n, cols, values, addv)); 2881 } 2882 PetscFunctionReturn(PETSC_SUCCESS); 2883 } 2884 2885 static PetscErrorCode MatISZeroRowsColumnsLocal_Private(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, PetscBool columns) 2886 { 2887 Mat_IS *is = (Mat_IS *)A->data; 2888 2889 PetscFunctionBegin; 2890 if (!n) PetscFunctionReturn(PETSC_SUCCESS); 2891 is->pure_neumann = PETSC_FALSE; 2892 2893 if (columns) { 2894 PetscCall(MatZeroRowsColumns(is->A, n, rows, diag, NULL, NULL)); 2895 } else { 2896 PetscCall(MatZeroRows(is->A, n, rows, diag, NULL, NULL)); 2897 } 2898 if (diag != 0.) { 2899 const PetscScalar *array; 2900 2901 PetscCall(VecGetArrayRead(is->counter, &array)); 2902 for (PetscInt i = 0; i < n; i++) PetscCall(MatSetValue(is->A, rows[i], rows[i], diag / (array[rows[i]]), INSERT_VALUES)); 2903 PetscCall(VecRestoreArrayRead(is->counter, &array)); 2904 PetscCall(MatAssemblyBegin(is->A, MAT_FINAL_ASSEMBLY)); 2905 PetscCall(MatAssemblyEnd(is->A, MAT_FINAL_ASSEMBLY)); 2906 } 2907 PetscFunctionReturn(PETSC_SUCCESS); 2908 } 2909 2910 static PetscErrorCode MatZeroRowsColumns_Private_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b, PetscBool columns) 2911 { 2912 Mat_IS *matis = (Mat_IS *)A->data; 2913 PetscInt nr, nl, len; 2914 PetscInt *lrows = NULL; 2915 2916 PetscFunctionBegin; 2917 if (PetscUnlikelyDebug(columns || diag != 0. || (x && b))) { 2918 PetscBool cong; 2919 2920 PetscCall(PetscLayoutCompare(A->rmap, A->cmap, &cong)); 2921 cong = (PetscBool)(cong && matis->sf == matis->csf); 2922 PetscCheck(cong || !columns, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Columns can be zeroed if and only if A->rmap and A->cmap are congruent and the l2g maps are the same for MATIS"); 2923 PetscCheck(cong || diag == 0., PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "Nonzero diagonal value supported if and only if A->rmap and A->cmap are congruent and the l2g maps are the same for MATIS"); 2924 PetscCheck(cong || !x || !b, PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "A->rmap and A->cmap need to be congruent, and the l2g maps be the same"); 2925 } 2926 PetscCall(MatGetSize(matis->A, &nl, NULL)); 2927 /* get locally owned rows */ 2928 PetscCall(PetscLayoutMapLocal(A->rmap, n, rows, &len, &lrows, NULL)); 2929 /* fix right-hand side if needed */ 2930 if (x && b) { 2931 const PetscScalar *xx; 2932 PetscScalar *bb; 2933 2934 PetscCall(VecGetArrayRead(x, &xx)); 2935 PetscCall(VecGetArray(b, &bb)); 2936 for (PetscInt i = 0; i < len; ++i) bb[lrows[i]] = diag * xx[lrows[i]]; 2937 PetscCall(VecRestoreArrayRead(x, &xx)); 2938 PetscCall(VecRestoreArray(b, &bb)); 2939 } 2940 /* get rows associated to the local matrices */ 2941 PetscCall(PetscArrayzero(matis->sf_leafdata, nl)); 2942 PetscCall(PetscArrayzero(matis->sf_rootdata, A->rmap->n)); 2943 for (PetscInt i = 0; i < len; i++) matis->sf_rootdata[lrows[i]] = 1; 2944 PetscCall(PetscFree(lrows)); 2945 PetscCall(PetscSFBcastBegin(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE)); 2946 PetscCall(PetscSFBcastEnd(matis->sf, MPIU_INT, matis->sf_rootdata, matis->sf_leafdata, MPI_REPLACE)); 2947 PetscCall(PetscMalloc1(nl, &lrows)); 2948 nr = 0; 2949 for (PetscInt i = 0; i < nl; i++) 2950 if (matis->sf_leafdata[i]) lrows[nr++] = i; 2951 PetscCall(MatISZeroRowsColumnsLocal_Private(A, nr, lrows, diag, columns)); 2952 PetscCall(PetscFree(lrows)); 2953 PetscFunctionReturn(PETSC_SUCCESS); 2954 } 2955 2956 static PetscErrorCode MatZeroRows_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 2957 { 2958 PetscFunctionBegin; 2959 PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_FALSE)); 2960 PetscFunctionReturn(PETSC_SUCCESS); 2961 } 2962 2963 static PetscErrorCode MatZeroRowsColumns_IS(Mat A, PetscInt n, const PetscInt rows[], PetscScalar diag, Vec x, Vec b) 2964 { 2965 PetscFunctionBegin; 2966 PetscCall(MatZeroRowsColumns_Private_IS(A, n, rows, diag, x, b, PETSC_TRUE)); 2967 PetscFunctionReturn(PETSC_SUCCESS); 2968 } 2969 2970 static PetscErrorCode MatAssemblyBegin_IS(Mat A, MatAssemblyType type) 2971 { 2972 Mat_IS *is = (Mat_IS *)A->data; 2973 2974 PetscFunctionBegin; 2975 PetscCall(MatAssemblyBegin(is->A, type)); 2976 PetscFunctionReturn(PETSC_SUCCESS); 2977 } 2978 2979 static PetscErrorCode MatAssemblyEnd_IS(Mat A, MatAssemblyType type) 2980 { 2981 Mat_IS *is = (Mat_IS *)A->data; 2982 PetscBool lnnz; 2983 2984 PetscFunctionBegin; 2985 PetscCall(MatAssemblyEnd(is->A, type)); 2986 /* fix for local empty rows/cols */ 2987 if (is->locempty && type == MAT_FINAL_ASSEMBLY) { 2988 Mat newlA; 2989 ISLocalToGlobalMapping rl2g, cl2g; 2990 IS nzr, nzc; 2991 PetscInt nr, nc, nnzr, nnzc; 2992 PetscBool lnewl2g, newl2g; 2993 2994 PetscCall(MatGetSize(is->A, &nr, &nc)); 2995 PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_FALSE, PETSC_SMALL, &nzr)); 2996 if (!nzr) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nr, 0, 1, &nzr)); 2997 PetscCall(MatFindNonzeroRowsOrCols_Basic(is->A, PETSC_TRUE, PETSC_SMALL, &nzc)); 2998 if (!nzc) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)is->A), nc, 0, 1, &nzc)); 2999 PetscCall(ISGetSize(nzr, &nnzr)); 3000 PetscCall(ISGetSize(nzc, &nnzc)); 3001 if (nnzr != nr || nnzc != nc) { /* need new global l2g map */ 3002 lnewl2g = PETSC_TRUE; 3003 PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A))); 3004 3005 /* extract valid submatrix */ 3006 PetscCall(MatCreateSubMatrix(is->A, nzr, nzc, MAT_INITIAL_MATRIX, &newlA)); 3007 } else { /* local matrix fully populated */ 3008 lnewl2g = PETSC_FALSE; 3009 PetscCallMPI(MPIU_Allreduce(&lnewl2g, &newl2g, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)A))); 3010 PetscCall(PetscObjectReference((PetscObject)is->A)); 3011 newlA = is->A; 3012 } 3013 3014 /* attach new global l2g map if needed */ 3015 if (newl2g) { 3016 IS zr, zc; 3017 const PetscInt *ridxs, *cidxs, *zridxs, *zcidxs; 3018 PetscInt *nidxs, i; 3019 3020 PetscCall(ISComplement(nzr, 0, nr, &zr)); 3021 PetscCall(ISComplement(nzc, 0, nc, &zc)); 3022 PetscCall(PetscMalloc1(PetscMax(nr, nc), &nidxs)); 3023 PetscCall(ISLocalToGlobalMappingGetIndices(is->rmapping, &ridxs)); 3024 PetscCall(ISLocalToGlobalMappingGetIndices(is->cmapping, &cidxs)); 3025 PetscCall(ISGetIndices(zr, &zridxs)); 3026 PetscCall(ISGetIndices(zc, &zcidxs)); 3027 PetscCall(ISGetLocalSize(zr, &nnzr)); 3028 PetscCall(ISGetLocalSize(zc, &nnzc)); 3029 3030 PetscCall(PetscArraycpy(nidxs, ridxs, nr)); 3031 for (i = 0; i < nnzr; i++) nidxs[zridxs[i]] = -1; 3032 PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nr, nidxs, PETSC_COPY_VALUES, &rl2g)); 3033 PetscCall(PetscArraycpy(nidxs, cidxs, nc)); 3034 for (i = 0; i < nnzc; i++) nidxs[zcidxs[i]] = -1; 3035 PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)A), 1, nc, nidxs, PETSC_COPY_VALUES, &cl2g)); 3036 3037 PetscCall(ISRestoreIndices(zr, &zridxs)); 3038 PetscCall(ISRestoreIndices(zc, &zcidxs)); 3039 PetscCall(ISLocalToGlobalMappingRestoreIndices(is->rmapping, &ridxs)); 3040 PetscCall(ISLocalToGlobalMappingRestoreIndices(is->cmapping, &cidxs)); 3041 PetscCall(ISDestroy(&nzr)); 3042 PetscCall(ISDestroy(&nzc)); 3043 PetscCall(ISDestroy(&zr)); 3044 PetscCall(ISDestroy(&zc)); 3045 PetscCall(PetscFree(nidxs)); 3046 PetscCall(MatSetLocalToGlobalMapping(A, rl2g, cl2g)); 3047 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 3048 PetscCall(ISLocalToGlobalMappingDestroy(&cl2g)); 3049 } 3050 PetscCall(MatISSetLocalMat(A, newlA)); 3051 PetscCall(MatDestroy(&newlA)); 3052 PetscCall(ISDestroy(&nzr)); 3053 PetscCall(ISDestroy(&nzc)); 3054 is->locempty = PETSC_FALSE; 3055 } 3056 lnnz = (PetscBool)(is->A->nonzerostate == is->lnnzstate); 3057 is->lnnzstate = is->A->nonzerostate; 3058 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &lnnz, 1, MPI_C_BOOL, MPI_LAND, PetscObjectComm((PetscObject)A))); 3059 if (!lnnz) A->nonzerostate++; 3060 PetscFunctionReturn(PETSC_SUCCESS); 3061 } 3062 3063 static PetscErrorCode MatISGetLocalMat_IS(Mat mat, Mat *local) 3064 { 3065 Mat_IS *is = (Mat_IS *)mat->data; 3066 3067 PetscFunctionBegin; 3068 *local = is->A; 3069 PetscFunctionReturn(PETSC_SUCCESS); 3070 } 3071 3072 static PetscErrorCode MatISRestoreLocalMat_IS(Mat mat, Mat *local) 3073 { 3074 PetscFunctionBegin; 3075 *local = NULL; 3076 PetscFunctionReturn(PETSC_SUCCESS); 3077 } 3078 3079 /*@ 3080 MatISGetLocalMat - Gets the local matrix stored inside a `MATIS` matrix. 3081 3082 Not Collective. 3083 3084 Input Parameter: 3085 . mat - the matrix 3086 3087 Output Parameter: 3088 . local - the local matrix 3089 3090 Level: intermediate 3091 3092 Notes: 3093 This can be called if you have precomputed the nonzero structure of the 3094 matrix and want to provide it to the inner matrix object to improve the performance 3095 of the `MatSetValues()` operation. 3096 3097 Call `MatISRestoreLocalMat()` when finished with the local matrix. 3098 3099 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISRestoreLocalMat()` 3100 @*/ 3101 PetscErrorCode MatISGetLocalMat(Mat mat, Mat *local) 3102 { 3103 PetscFunctionBegin; 3104 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3105 PetscAssertPointer(local, 2); 3106 PetscUseMethod(mat, "MatISGetLocalMat_C", (Mat, Mat *), (mat, local)); 3107 PetscFunctionReturn(PETSC_SUCCESS); 3108 } 3109 3110 /*@ 3111 MatISRestoreLocalMat - Restores the local matrix obtained with `MatISGetLocalMat()` 3112 3113 Not Collective. 3114 3115 Input Parameters: 3116 + mat - the matrix 3117 - local - the local matrix 3118 3119 Level: intermediate 3120 3121 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISGetLocalMat()` 3122 @*/ 3123 PetscErrorCode MatISRestoreLocalMat(Mat mat, Mat *local) 3124 { 3125 PetscFunctionBegin; 3126 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3127 PetscAssertPointer(local, 2); 3128 PetscUseMethod(mat, "MatISRestoreLocalMat_C", (Mat, Mat *), (mat, local)); 3129 PetscFunctionReturn(PETSC_SUCCESS); 3130 } 3131 3132 static PetscErrorCode MatISSetLocalMatType_IS(Mat mat, MatType mtype) 3133 { 3134 Mat_IS *is = (Mat_IS *)mat->data; 3135 3136 PetscFunctionBegin; 3137 if (is->A) PetscCall(MatSetType(is->A, mtype)); 3138 PetscCall(PetscFree(is->lmattype)); 3139 PetscCall(PetscStrallocpy(mtype, &is->lmattype)); 3140 PetscFunctionReturn(PETSC_SUCCESS); 3141 } 3142 3143 /*@ 3144 MatISSetLocalMatType - Specifies the type of local matrix inside the `MATIS` 3145 3146 Logically Collective. 3147 3148 Input Parameters: 3149 + mat - the matrix 3150 - mtype - the local matrix type 3151 3152 Level: intermediate 3153 3154 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetType()`, `MatType` 3155 @*/ 3156 PetscErrorCode MatISSetLocalMatType(Mat mat, MatType mtype) 3157 { 3158 PetscFunctionBegin; 3159 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3160 PetscUseMethod(mat, "MatISSetLocalMatType_C", (Mat, MatType), (mat, mtype)); 3161 PetscFunctionReturn(PETSC_SUCCESS); 3162 } 3163 3164 static PetscErrorCode MatISSetLocalMat_IS(Mat mat, Mat local) 3165 { 3166 Mat_IS *is = (Mat_IS *)mat->data; 3167 PetscInt nrows, ncols, orows, ocols; 3168 MatType mtype, otype; 3169 PetscBool sametype = PETSC_TRUE; 3170 3171 PetscFunctionBegin; 3172 if (is->A && !is->islocalref) { 3173 PetscCall(MatGetSize(is->A, &orows, &ocols)); 3174 PetscCall(MatGetSize(local, &nrows, &ncols)); 3175 PetscCheck(orows == nrows && ocols == ncols, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Local MATIS matrix should be of size %" PetscInt_FMT "x%" PetscInt_FMT " (passed a %" PetscInt_FMT "x%" PetscInt_FMT " matrix)", orows, ocols, nrows, ncols); 3176 PetscCall(MatGetType(local, &mtype)); 3177 PetscCall(MatGetType(is->A, &otype)); 3178 PetscCall(PetscStrcmp(mtype, otype, &sametype)); 3179 } 3180 PetscCall(PetscObjectReference((PetscObject)local)); 3181 PetscCall(MatDestroy(&is->A)); 3182 is->A = local; 3183 PetscCall(MatGetType(is->A, &mtype)); 3184 PetscCall(MatISSetLocalMatType(mat, mtype)); 3185 if (!sametype && !is->islocalref) PetscCall(MatISSetUpScatters_Private(mat)); 3186 is->lnnzstate = 0; 3187 PetscFunctionReturn(PETSC_SUCCESS); 3188 } 3189 3190 /*@ 3191 MatISSetLocalMat - Replace the local matrix stored inside a `MATIS` object. 3192 3193 Not Collective 3194 3195 Input Parameters: 3196 + mat - the matrix 3197 - local - the local matrix 3198 3199 Level: intermediate 3200 3201 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatISSetLocalMatType`, `MatISGetLocalMat()` 3202 @*/ 3203 PetscErrorCode MatISSetLocalMat(Mat mat, Mat local) 3204 { 3205 PetscFunctionBegin; 3206 PetscValidHeaderSpecific(mat, MAT_CLASSID, 1); 3207 PetscValidHeaderSpecific(local, MAT_CLASSID, 2); 3208 PetscUseMethod(mat, "MatISSetLocalMat_C", (Mat, Mat), (mat, local)); 3209 PetscFunctionReturn(PETSC_SUCCESS); 3210 } 3211 3212 static PetscErrorCode MatZeroEntries_IS(Mat A) 3213 { 3214 Mat_IS *a = (Mat_IS *)A->data; 3215 3216 PetscFunctionBegin; 3217 PetscCall(MatZeroEntries(a->A)); 3218 PetscFunctionReturn(PETSC_SUCCESS); 3219 } 3220 3221 static PetscErrorCode MatScale_IS(Mat A, PetscScalar a) 3222 { 3223 Mat_IS *is = (Mat_IS *)A->data; 3224 3225 PetscFunctionBegin; 3226 PetscCall(MatScale(is->A, a)); 3227 PetscFunctionReturn(PETSC_SUCCESS); 3228 } 3229 3230 static PetscErrorCode MatGetDiagonal_IS(Mat A, Vec v) 3231 { 3232 Mat_IS *is = (Mat_IS *)A->data; 3233 3234 PetscFunctionBegin; 3235 /* get diagonal of the local matrix */ 3236 PetscCall(MatGetDiagonal(is->A, is->y)); 3237 3238 /* scatter diagonal back into global vector */ 3239 PetscCall(VecSet(v, 0)); 3240 PetscCall(VecScatterBegin(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE)); 3241 PetscCall(VecScatterEnd(is->rctx, is->y, v, ADD_VALUES, SCATTER_REVERSE)); 3242 PetscFunctionReturn(PETSC_SUCCESS); 3243 } 3244 3245 static PetscErrorCode MatSetOption_IS(Mat A, MatOption op, PetscBool flg) 3246 { 3247 Mat_IS *a = (Mat_IS *)A->data; 3248 3249 PetscFunctionBegin; 3250 PetscCall(MatSetOption(a->A, op, flg)); 3251 PetscFunctionReturn(PETSC_SUCCESS); 3252 } 3253 3254 static PetscErrorCode MatAXPY_IS(Mat Y, PetscScalar a, Mat X, MatStructure str) 3255 { 3256 Mat_IS *y = (Mat_IS *)Y->data; 3257 Mat_IS *x; 3258 3259 PetscFunctionBegin; 3260 if (PetscDefined(USE_DEBUG)) { 3261 PetscBool ismatis; 3262 PetscCall(PetscObjectTypeCompare((PetscObject)X, MATIS, &ismatis)); 3263 PetscCheck(ismatis, PetscObjectComm((PetscObject)Y), PETSC_ERR_SUP, "Cannot call MatAXPY(Y,a,X,str) with X not of type MATIS"); 3264 } 3265 x = (Mat_IS *)X->data; 3266 PetscCall(MatAXPY(y->A, a, x->A, str)); 3267 PetscFunctionReturn(PETSC_SUCCESS); 3268 } 3269 3270 static PetscErrorCode MatGetLocalSubMatrix_IS(Mat A, IS row, IS col, Mat *submat) 3271 { 3272 Mat lA; 3273 Mat_IS *matis = (Mat_IS *)A->data; 3274 ISLocalToGlobalMapping rl2g, cl2g; 3275 IS is; 3276 const PetscInt *rg, *rl; 3277 PetscInt nrg, rbs, cbs; 3278 PetscInt N, M, nrl, i, *idxs; 3279 3280 PetscFunctionBegin; 3281 PetscCall(ISGetBlockSize(row, &rbs)); 3282 PetscCall(ISGetBlockSize(col, &cbs)); 3283 PetscCall(ISLocalToGlobalMappingGetIndices(A->rmap->mapping, &rg)); 3284 PetscCall(ISGetLocalSize(row, &nrl)); 3285 PetscCall(ISGetIndices(row, &rl)); 3286 PetscCall(ISLocalToGlobalMappingGetSize(A->rmap->mapping, &nrg)); 3287 if (PetscDefined(USE_DEBUG)) { 3288 for (i = 0; i < nrl; i++) PetscCheck(rl[i] < nrg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Local row index %" PetscInt_FMT " -> %" PetscInt_FMT " greater than maximum possible %" PetscInt_FMT, i, rl[i], nrg); 3289 } 3290 if (nrg % rbs) nrg = rbs * (nrg / rbs + 1); 3291 PetscCall(PetscMalloc1(nrg, &idxs)); 3292 /* map from [0,nrl) to row */ 3293 for (i = 0; i < nrl; i++) idxs[i] = rl[i]; 3294 for (i = nrl; i < nrg; i++) idxs[i] = -1; 3295 PetscCall(ISRestoreIndices(row, &rl)); 3296 PetscCall(ISLocalToGlobalMappingRestoreIndices(A->rmap->mapping, &rg)); 3297 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), nrg, idxs, PETSC_OWN_POINTER, &is)); 3298 PetscCall(ISLocalToGlobalMappingCreateIS(is, &rl2g)); 3299 PetscCall(ISLocalToGlobalMappingSetBlockSize(rl2g, rbs)); 3300 PetscCall(ISDestroy(&is)); 3301 /* compute new l2g map for columns */ 3302 if (col != row || matis->rmapping != matis->cmapping || matis->A->rmap->mapping != matis->A->cmap->mapping) { 3303 const PetscInt *cg, *cl; 3304 PetscInt ncg; 3305 PetscInt ncl; 3306 3307 PetscCall(ISLocalToGlobalMappingGetIndices(A->cmap->mapping, &cg)); 3308 PetscCall(ISGetLocalSize(col, &ncl)); 3309 PetscCall(ISGetIndices(col, &cl)); 3310 PetscCall(ISLocalToGlobalMappingGetSize(A->cmap->mapping, &ncg)); 3311 if (PetscDefined(USE_DEBUG)) { 3312 for (i = 0; i < ncl; i++) PetscCheck(cl[i] < ncg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Local column index %" PetscInt_FMT " -> %" PetscInt_FMT " greater than maximum possible %" PetscInt_FMT, i, cl[i], ncg); 3313 } 3314 if (ncg % cbs) ncg = cbs * (ncg / cbs + 1); 3315 PetscCall(PetscMalloc1(ncg, &idxs)); 3316 /* map from [0,ncl) to col */ 3317 for (i = 0; i < ncl; i++) idxs[i] = cl[i]; 3318 for (i = ncl; i < ncg; i++) idxs[i] = -1; 3319 PetscCall(ISRestoreIndices(col, &cl)); 3320 PetscCall(ISLocalToGlobalMappingRestoreIndices(A->cmap->mapping, &cg)); 3321 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)A), ncg, idxs, PETSC_OWN_POINTER, &is)); 3322 PetscCall(ISLocalToGlobalMappingCreateIS(is, &cl2g)); 3323 PetscCall(ISLocalToGlobalMappingSetBlockSize(cl2g, cbs)); 3324 PetscCall(ISDestroy(&is)); 3325 } else { 3326 PetscCall(PetscObjectReference((PetscObject)rl2g)); 3327 cl2g = rl2g; 3328 } 3329 3330 /* create the MATIS submatrix */ 3331 PetscCall(MatGetSize(A, &M, &N)); 3332 PetscCall(MatCreate(PetscObjectComm((PetscObject)A), submat)); 3333 PetscCall(MatSetSizes(*submat, PETSC_DECIDE, PETSC_DECIDE, M, N)); 3334 PetscCall(MatSetType(*submat, MATIS)); 3335 matis = (Mat_IS *)((*submat)->data); 3336 matis->islocalref = A; 3337 PetscCall(MatSetLocalToGlobalMapping(*submat, rl2g, cl2g)); 3338 PetscCall(MatISGetLocalMat(A, &lA)); 3339 PetscCall(MatISSetLocalMat(*submat, lA)); 3340 PetscCall(ISLocalToGlobalMappingDestroy(&rl2g)); 3341 PetscCall(ISLocalToGlobalMappingDestroy(&cl2g)); 3342 3343 /* remove unsupported ops */ 3344 PetscCall(PetscMemzero((*submat)->ops, sizeof(struct _MatOps))); 3345 (*submat)->ops->destroy = MatDestroy_IS; 3346 (*submat)->ops->setvalueslocal = MatSetValuesLocal_SubMat_IS; 3347 (*submat)->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_SubMat_IS; 3348 (*submat)->ops->zerorowslocal = MatZeroRowsLocal_SubMat_IS; 3349 (*submat)->ops->zerorowscolumnslocal = MatZeroRowsColumnsLocal_SubMat_IS; 3350 (*submat)->ops->getlocalsubmatrix = MatGetLocalSubMatrix_IS; 3351 PetscFunctionReturn(PETSC_SUCCESS); 3352 } 3353 3354 static PetscErrorCode MatSetFromOptions_IS(Mat A, PetscOptionItems PetscOptionsObject) 3355 { 3356 Mat_IS *a = (Mat_IS *)A->data; 3357 char type[256]; 3358 PetscBool flg; 3359 3360 PetscFunctionBegin; 3361 PetscOptionsHeadBegin(PetscOptionsObject, "MATIS options"); 3362 PetscCall(PetscOptionsDeprecated("-matis_keepassembled", "-mat_is_keepassembled", "3.21", NULL)); 3363 PetscCall(PetscOptionsDeprecated("-matis_fixempty", "-mat_is_fixempty", "3.21", NULL)); 3364 PetscCall(PetscOptionsDeprecated("-matis_storel2l", "-mat_is_storel2l", "3.21", NULL)); 3365 PetscCall(PetscOptionsDeprecated("-matis_localmat_type", "-mat_is_localmat_type", "3.21", NULL)); 3366 PetscCall(PetscOptionsBool("-mat_is_keepassembled", "Store an assembled version if needed", NULL, a->keepassembled, &a->keepassembled, NULL)); 3367 PetscCall(PetscOptionsBool("-mat_is_fixempty", "Fix local matrices in case of empty local rows/columns", "MatISFixLocalEmpty", a->locempty, &a->locempty, NULL)); 3368 PetscCall(PetscOptionsBool("-mat_is_storel2l", "Store local-to-local matrices generated from PtAP operations", "MatISStoreL2L", a->storel2l, &a->storel2l, NULL)); 3369 PetscCall(PetscOptionsBool("-mat_is_allow_repeated", "Allow local repeated entries", "MatISSetAllowRepeated", a->allow_repeated, &a->allow_repeated, NULL)); 3370 PetscCall(PetscOptionsFList("-mat_is_localmat_type", "Matrix type", "MatISSetLocalMatType", MatList, a->lmattype, type, 256, &flg)); 3371 if (flg) PetscCall(MatISSetLocalMatType(A, type)); 3372 if (a->A) PetscCall(MatSetFromOptions(a->A)); 3373 PetscOptionsHeadEnd(); 3374 PetscFunctionReturn(PETSC_SUCCESS); 3375 } 3376 3377 /*@ 3378 MatCreateIS - Creates a "process" unassembled matrix. 3379 3380 Collective. 3381 3382 Input Parameters: 3383 + comm - MPI communicator that will share the matrix 3384 . bs - block size of the matrix 3385 . m - local size of left vector used in matrix vector products 3386 . n - local size of right vector used in matrix vector products 3387 . M - global size of left vector used in matrix vector products 3388 . N - global size of right vector used in matrix vector products 3389 . rmap - local to global map for rows 3390 - cmap - local to global map for cols 3391 3392 Output Parameter: 3393 . A - the resulting matrix 3394 3395 Level: intermediate 3396 3397 Notes: 3398 `m` and `n` are NOT related to the size of the map; they represent the size of the local parts of the distributed vectors 3399 used in `MatMult()` operations. The local sizes of `rmap` and `cmap` define the size of the local matrices. 3400 3401 If `rmap` (`cmap`) is `NULL`, then the local row (column) spaces matches the global space. 3402 3403 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()` 3404 @*/ 3405 PetscErrorCode MatCreateIS(MPI_Comm comm, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, ISLocalToGlobalMapping rmap, ISLocalToGlobalMapping cmap, Mat *A) 3406 { 3407 PetscFunctionBegin; 3408 PetscCall(MatCreate(comm, A)); 3409 PetscCall(MatSetSizes(*A, m, n, M, N)); 3410 if (bs > 0) PetscCall(MatSetBlockSize(*A, bs)); 3411 PetscCall(MatSetType(*A, MATIS)); 3412 PetscCall(MatSetLocalToGlobalMapping(*A, rmap, cmap)); 3413 PetscFunctionReturn(PETSC_SUCCESS); 3414 } 3415 3416 static PetscErrorCode MatHasOperation_IS(Mat A, MatOperation op, PetscBool *has) 3417 { 3418 Mat_IS *a = (Mat_IS *)A->data; 3419 MatOperation tobefiltered[] = {MATOP_MULT_ADD, MATOP_MULT_TRANSPOSE_ADD, MATOP_GET_DIAGONAL_BLOCK, MATOP_INCREASE_OVERLAP}; 3420 3421 PetscFunctionBegin; 3422 *has = PETSC_FALSE; 3423 if (!((void **)A->ops)[op] || !a->A) PetscFunctionReturn(PETSC_SUCCESS); 3424 *has = PETSC_TRUE; 3425 for (PetscInt i = 0; i < (PetscInt)PETSC_STATIC_ARRAY_LENGTH(tobefiltered); i++) 3426 if (op == tobefiltered[i]) PetscFunctionReturn(PETSC_SUCCESS); 3427 PetscCall(MatHasOperation(a->A, op, has)); 3428 PetscFunctionReturn(PETSC_SUCCESS); 3429 } 3430 3431 static PetscErrorCode MatSetValuesCOO_IS(Mat A, const PetscScalar v[], InsertMode imode) 3432 { 3433 Mat_IS *a = (Mat_IS *)A->data; 3434 3435 PetscFunctionBegin; 3436 PetscCall(MatSetValuesCOO(a->A, v, imode)); 3437 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 3438 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 3439 PetscFunctionReturn(PETSC_SUCCESS); 3440 } 3441 3442 static PetscErrorCode MatSetPreallocationCOOLocal_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[]) 3443 { 3444 Mat_IS *a = (Mat_IS *)A->data; 3445 3446 PetscFunctionBegin; 3447 PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping"); 3448 if (a->A->rmap->mapping || a->A->cmap->mapping) { 3449 PetscCall(MatSetPreallocationCOOLocal(a->A, ncoo, coo_i, coo_j)); 3450 } else { 3451 PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j)); 3452 } 3453 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS)); 3454 A->preallocated = PETSC_TRUE; 3455 PetscFunctionReturn(PETSC_SUCCESS); 3456 } 3457 3458 static PetscErrorCode MatSetPreallocationCOO_IS(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[]) 3459 { 3460 Mat_IS *a = (Mat_IS *)A->data; 3461 PetscInt ncoo_i; 3462 3463 PetscFunctionBegin; 3464 PetscCheck(a->A, PetscObjectComm((PetscObject)A), PETSC_ERR_ORDER, "Need to provide l2g map first via MatSetLocalToGlobalMapping"); 3465 PetscCall(PetscIntCast(ncoo, &ncoo_i)); 3466 PetscCall(ISGlobalToLocalMappingApply(a->rmapping, IS_GTOLM_MASK, ncoo_i, coo_i, NULL, coo_i)); 3467 PetscCall(ISGlobalToLocalMappingApply(a->cmapping, IS_GTOLM_MASK, ncoo_i, coo_j, NULL, coo_j)); 3468 PetscCall(MatSetPreallocationCOO(a->A, ncoo, coo_i, coo_j)); 3469 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetValuesCOO_C", MatSetValuesCOO_IS)); 3470 A->preallocated = PETSC_TRUE; 3471 PetscFunctionReturn(PETSC_SUCCESS); 3472 } 3473 3474 static PetscErrorCode MatISGetAssembled_Private(Mat A, Mat *tA) 3475 { 3476 Mat_IS *a = (Mat_IS *)A->data; 3477 PetscObjectState Astate, aAstate = PETSC_INT_MIN; 3478 PetscObjectState Annzstate, aAnnzstate = PETSC_INT_MIN; 3479 3480 PetscFunctionBegin; 3481 PetscCall(PetscObjectStateGet((PetscObject)A, &Astate)); 3482 Annzstate = A->nonzerostate; 3483 if (a->assembledA) { 3484 PetscCall(PetscObjectStateGet((PetscObject)a->assembledA, &aAstate)); 3485 aAnnzstate = a->assembledA->nonzerostate; 3486 } 3487 if (aAnnzstate != Annzstate) PetscCall(MatDestroy(&a->assembledA)); 3488 if (Astate != aAstate || !a->assembledA) { 3489 MatType aAtype; 3490 PetscMPIInt size; 3491 PetscInt rbs, cbs, bs; 3492 3493 /* the assembled form is used as temporary storage for parallel operations 3494 like createsubmatrices and the like, do not waste device memory */ 3495 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)A), &size)); 3496 PetscCall(ISLocalToGlobalMappingGetBlockSize(a->cmapping, &cbs)); 3497 PetscCall(ISLocalToGlobalMappingGetBlockSize(a->rmapping, &rbs)); 3498 bs = rbs == cbs ? rbs : 1; 3499 if (a->assembledA) PetscCall(MatGetType(a->assembledA, &aAtype)); 3500 else if (size > 1) aAtype = bs > 1 ? MATMPIBAIJ : MATMPIAIJ; 3501 else aAtype = bs > 1 ? MATSEQBAIJ : MATSEQAIJ; 3502 3503 PetscCall(MatConvert(A, aAtype, a->assembledA ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX, &a->assembledA)); 3504 PetscCall(PetscObjectStateSet((PetscObject)a->assembledA, Astate)); 3505 a->assembledA->nonzerostate = Annzstate; 3506 } 3507 PetscCall(PetscObjectReference((PetscObject)a->assembledA)); 3508 *tA = a->assembledA; 3509 if (!a->keepassembled) PetscCall(MatDestroy(&a->assembledA)); 3510 PetscFunctionReturn(PETSC_SUCCESS); 3511 } 3512 3513 static PetscErrorCode MatISRestoreAssembled_Private(Mat A, Mat *tA) 3514 { 3515 PetscFunctionBegin; 3516 PetscCall(MatDestroy(tA)); 3517 *tA = NULL; 3518 PetscFunctionReturn(PETSC_SUCCESS); 3519 } 3520 3521 static PetscErrorCode MatGetDiagonalBlock_IS(Mat A, Mat *dA) 3522 { 3523 Mat_IS *a = (Mat_IS *)A->data; 3524 PetscObjectState Astate, dAstate = PETSC_INT_MIN; 3525 3526 PetscFunctionBegin; 3527 PetscCall(PetscObjectStateGet((PetscObject)A, &Astate)); 3528 if (a->dA) PetscCall(PetscObjectStateGet((PetscObject)a->dA, &dAstate)); 3529 if (Astate != dAstate) { 3530 Mat tA; 3531 MatType ltype; 3532 3533 PetscCall(MatDestroy(&a->dA)); 3534 PetscCall(MatISGetAssembled_Private(A, &tA)); 3535 PetscCall(MatGetDiagonalBlock(tA, &a->dA)); 3536 PetscCall(MatPropagateSymmetryOptions(tA, a->dA)); 3537 PetscCall(MatGetType(a->A, <ype)); 3538 PetscCall(MatConvert(a->dA, ltype, MAT_INPLACE_MATRIX, &a->dA)); 3539 PetscCall(PetscObjectReference((PetscObject)a->dA)); 3540 PetscCall(MatISRestoreAssembled_Private(A, &tA)); 3541 PetscCall(PetscObjectStateSet((PetscObject)a->dA, Astate)); 3542 } 3543 *dA = a->dA; 3544 PetscFunctionReturn(PETSC_SUCCESS); 3545 } 3546 3547 static PetscErrorCode MatCreateSubMatrices_IS(Mat A, PetscInt n, const IS irow[], const IS icol[], MatReuse reuse, Mat *submat[]) 3548 { 3549 Mat tA; 3550 3551 PetscFunctionBegin; 3552 PetscCall(MatISGetAssembled_Private(A, &tA)); 3553 PetscCall(MatCreateSubMatrices(tA, n, irow, icol, reuse, submat)); 3554 /* MatCreateSubMatrices_MPIAIJ is a mess at the moment */ 3555 #if 0 3556 { 3557 Mat_IS *a = (Mat_IS*)A->data; 3558 MatType ltype; 3559 VecType vtype; 3560 char *flg; 3561 3562 PetscCall(MatGetType(a->A,<ype)); 3563 PetscCall(MatGetVecType(a->A,&vtype)); 3564 PetscCall(PetscStrstr(vtype,"cuda",&flg)); 3565 if (!flg) PetscCall(PetscStrstr(vtype,"hip",&flg)); 3566 if (!flg) PetscCall(PetscStrstr(vtype,"kokkos",&flg)); 3567 if (flg) { 3568 for (PetscInt i = 0; i < n; i++) { 3569 Mat sA = (*submat)[i]; 3570 3571 PetscCall(MatConvert(sA,ltype,MAT_INPLACE_MATRIX,&sA)); 3572 (*submat)[i] = sA; 3573 } 3574 } 3575 } 3576 #endif 3577 PetscCall(MatISRestoreAssembled_Private(A, &tA)); 3578 PetscFunctionReturn(PETSC_SUCCESS); 3579 } 3580 3581 static PetscErrorCode MatIncreaseOverlap_IS(Mat A, PetscInt n, IS is[], PetscInt ov) 3582 { 3583 Mat tA; 3584 3585 PetscFunctionBegin; 3586 PetscCall(MatISGetAssembled_Private(A, &tA)); 3587 PetscCall(MatIncreaseOverlap(tA, n, is, ov)); 3588 PetscCall(MatISRestoreAssembled_Private(A, &tA)); 3589 PetscFunctionReturn(PETSC_SUCCESS); 3590 } 3591 3592 /*@ 3593 MatISGetLocalToGlobalMapping - Gets the local-to-global numbering of the `MATIS` object 3594 3595 Not Collective 3596 3597 Input Parameter: 3598 . A - the matrix 3599 3600 Output Parameters: 3601 + rmapping - row mapping 3602 - cmapping - column mapping 3603 3604 Level: advanced 3605 3606 Note: 3607 The returned map can be different from the one used to construct the `MATIS` object, since it will not contain negative or repeated indices. 3608 3609 .seealso: [](ch_matrices), `Mat`, `MATIS`, `MatSetLocalToGlobalMapping()` 3610 @*/ 3611 PetscErrorCode MatISGetLocalToGlobalMapping(Mat A, ISLocalToGlobalMapping *rmapping, ISLocalToGlobalMapping *cmapping) 3612 { 3613 PetscFunctionBegin; 3614 PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 3615 PetscValidType(A, 1); 3616 if (rmapping) PetscAssertPointer(rmapping, 2); 3617 if (cmapping) PetscAssertPointer(cmapping, 3); 3618 PetscUseMethod(A, "MatISGetLocalToGlobalMapping_C", (Mat, ISLocalToGlobalMapping *, ISLocalToGlobalMapping *), (A, rmapping, cmapping)); 3619 PetscFunctionReturn(PETSC_SUCCESS); 3620 } 3621 3622 static PetscErrorCode MatISGetLocalToGlobalMapping_IS(Mat A, ISLocalToGlobalMapping *r, ISLocalToGlobalMapping *c) 3623 { 3624 Mat_IS *a = (Mat_IS *)A->data; 3625 3626 PetscFunctionBegin; 3627 if (r) *r = a->rmapping; 3628 if (c) *c = a->cmapping; 3629 PetscFunctionReturn(PETSC_SUCCESS); 3630 } 3631 3632 static PetscErrorCode MatSetBlockSizes_IS(Mat A, PetscInt rbs, PetscInt cbs) 3633 { 3634 Mat_IS *a = (Mat_IS *)A->data; 3635 3636 PetscFunctionBegin; 3637 if (a->A) PetscCall(MatSetBlockSizes(a->A, rbs, cbs)); 3638 PetscFunctionReturn(PETSC_SUCCESS); 3639 } 3640 3641 /*MC 3642 MATIS - MATIS = "is" - A matrix type to be used for non-overlapping domain decomposition methods (e.g. `PCBDDC` or `KSPFETIDP`). 3643 This stores the matrices in globally unassembled form and the parallel matrix vector product is handled "implicitly". 3644 3645 Options Database Keys: 3646 + -mat_type is - Set the matrix type to `MATIS`. 3647 . -mat_is_allow_repeated - Allow repeated entries in the local part of the local to global maps. 3648 . -mat_is_fixempty - Fix local matrices in case of empty local rows/columns. 3649 - -mat_is_storel2l - Store the local-to-local operators generated by the Galerkin process of `MatPtAP()`. 3650 3651 Level: intermediate 3652 3653 Notes: 3654 Options prefix for the inner matrix are given by `-is_mat_xxx` 3655 3656 You must call `MatSetLocalToGlobalMapping()` before using this matrix type. 3657 3658 You can do matrix preallocation on the local matrix after you obtain it with 3659 `MatISGetLocalMat()`; otherwise, you could use `MatISSetPreallocation()` or `MatXAIJSetPreallocation()` 3660 3661 .seealso: [](ch_matrices), `Mat`, `MATIS`, `Mat`, `MatISGetLocalMat()`, `MatSetLocalToGlobalMapping()`, `MatISSetPreallocation()`, `MatCreateIS()`, `PCBDDC`, `KSPFETIDP` 3662 M*/ 3663 PETSC_EXTERN PetscErrorCode MatCreate_IS(Mat A) 3664 { 3665 Mat_IS *a; 3666 3667 PetscFunctionBegin; 3668 PetscCall(PetscNew(&a)); 3669 PetscCall(PetscStrallocpy(MATAIJ, &a->lmattype)); 3670 A->data = (void *)a; 3671 3672 /* matrix ops */ 3673 PetscCall(PetscMemzero(A->ops, sizeof(struct _MatOps))); 3674 A->ops->mult = MatMult_IS; 3675 A->ops->multadd = MatMultAdd_IS; 3676 A->ops->multtranspose = MatMultTranspose_IS; 3677 A->ops->multtransposeadd = MatMultTransposeAdd_IS; 3678 A->ops->destroy = MatDestroy_IS; 3679 A->ops->setlocaltoglobalmapping = MatSetLocalToGlobalMapping_IS; 3680 A->ops->setvalues = MatSetValues_IS; 3681 A->ops->setvaluesblocked = MatSetValuesBlocked_IS; 3682 A->ops->setvalueslocal = MatSetValuesLocal_IS; 3683 A->ops->setvaluesblockedlocal = MatSetValuesBlockedLocal_IS; 3684 A->ops->zerorows = MatZeroRows_IS; 3685 A->ops->zerorowscolumns = MatZeroRowsColumns_IS; 3686 A->ops->assemblybegin = MatAssemblyBegin_IS; 3687 A->ops->assemblyend = MatAssemblyEnd_IS; 3688 A->ops->view = MatView_IS; 3689 A->ops->load = MatLoad_IS; 3690 A->ops->zeroentries = MatZeroEntries_IS; 3691 A->ops->scale = MatScale_IS; 3692 A->ops->getdiagonal = MatGetDiagonal_IS; 3693 A->ops->setoption = MatSetOption_IS; 3694 A->ops->ishermitian = MatIsHermitian_IS; 3695 A->ops->issymmetric = MatIsSymmetric_IS; 3696 A->ops->isstructurallysymmetric = MatIsStructurallySymmetric_IS; 3697 A->ops->duplicate = MatDuplicate_IS; 3698 A->ops->missingdiagonal = MatMissingDiagonal_IS; 3699 A->ops->copy = MatCopy_IS; 3700 A->ops->getlocalsubmatrix = MatGetLocalSubMatrix_IS; 3701 A->ops->createsubmatrix = MatCreateSubMatrix_IS; 3702 A->ops->axpy = MatAXPY_IS; 3703 A->ops->diagonalset = MatDiagonalSet_IS; 3704 A->ops->shift = MatShift_IS; 3705 A->ops->transpose = MatTranspose_IS; 3706 A->ops->getinfo = MatGetInfo_IS; 3707 A->ops->diagonalscale = MatDiagonalScale_IS; 3708 A->ops->setfromoptions = MatSetFromOptions_IS; 3709 A->ops->setup = MatSetUp_IS; 3710 A->ops->hasoperation = MatHasOperation_IS; 3711 A->ops->getdiagonalblock = MatGetDiagonalBlock_IS; 3712 A->ops->createsubmatrices = MatCreateSubMatrices_IS; 3713 A->ops->increaseoverlap = MatIncreaseOverlap_IS; 3714 A->ops->setblocksizes = MatSetBlockSizes_IS; 3715 3716 /* special MATIS functions */ 3717 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMatType_C", MatISSetLocalMatType_IS)); 3718 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalMat_C", MatISGetLocalMat_IS)); 3719 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISRestoreLocalMat_C", MatISRestoreLocalMat_IS)); 3720 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetLocalMat_C", MatISSetLocalMat_IS)); 3721 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetPreallocation_C", MatISSetPreallocation_IS)); 3722 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISSetAllowRepeated_C", MatISSetAllowRepeated_IS)); 3723 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISStoreL2L_C", MatISStoreL2L_IS)); 3724 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISFixLocalEmpty_C", MatISFixLocalEmpty_IS)); 3725 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatISGetLocalToGlobalMapping_C", MatISGetLocalToGlobalMapping_IS)); 3726 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpiaij_C", MatConvert_IS_XAIJ)); 3727 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpibaij_C", MatConvert_IS_XAIJ)); 3728 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_mpisbaij_C", MatConvert_IS_XAIJ)); 3729 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqaij_C", MatConvert_IS_XAIJ)); 3730 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqbaij_C", MatConvert_IS_XAIJ)); 3731 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_seqsbaij_C", MatConvert_IS_XAIJ)); 3732 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatConvert_is_aij_C", MatConvert_IS_XAIJ)); 3733 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", MatSetPreallocationCOOLocal_IS)); 3734 PetscCall(PetscObjectComposeFunction((PetscObject)A, "MatSetPreallocationCOO_C", MatSetPreallocationCOO_IS)); 3735 PetscCall(PetscObjectChangeTypeName((PetscObject)A, MATIS)); 3736 PetscFunctionReturn(PETSC_SUCCESS); 3737 } 3738