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