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