1 #include <petsc/private/pcpatchimpl.h> /*I "petscpc.h" I*/ 2 #include <petsc/private/kspimpl.h> /* For ksp->setfromoptionscalled */ 3 #include <petsc/private/vecimpl.h> /* For vec->map */ 4 #include <petsc/private/dmpleximpl.h> /* For DMPlexComputeJacobian_Patch_Internal() */ 5 #include <petscsf.h> 6 #include <petscbt.h> 7 #include <petscds.h> 8 #include <../src/mat/impls/dense/seq/dense.h> /*I "petscmat.h" I*/ 9 10 PetscBool PCPatchcite = PETSC_FALSE; 11 const char PCPatchCitation[] = "@article{FarrellKnepleyWechsungMitchell2020,\n" 12 "title = {{PCPATCH}: software for the topological construction of multigrid relaxation methods},\n" 13 "author = {Patrick E Farrell and Matthew G Knepley and Lawrence Mitchell and Florian Wechsung},\n" 14 "journal = {ACM Transaction on Mathematical Software},\n" 15 "eprint = {http://arxiv.org/abs/1912.08516},\n" 16 "volume = {47},\n" 17 "number = {3},\n" 18 "pages = {1--22},\n" 19 "year = {2021},\n" 20 "petsc_uses={KSP,DMPlex}\n}\n"; 21 22 PetscLogEvent PC_Patch_CreatePatches, PC_Patch_ComputeOp, PC_Patch_Solve, PC_Patch_Apply, PC_Patch_Prealloc; 23 24 static inline PetscErrorCode ObjectView(PetscObject obj, PetscViewer viewer, PetscViewerFormat format) 25 { 26 PetscCall(PetscViewerPushFormat(viewer, format)); 27 PetscCall(PetscObjectView(obj, viewer)); 28 PetscCall(PetscViewerPopFormat(viewer)); 29 return PETSC_SUCCESS; 30 } 31 32 static PetscErrorCode PCPatchConstruct_Star(void *vpatch, DM dm, PetscInt point, PetscHSetI ht) 33 { 34 PetscInt starSize; 35 PetscInt *star = NULL, si; 36 37 PetscFunctionBegin; 38 PetscCall(PetscHSetIClear(ht)); 39 /* To start with, add the point we care about */ 40 PetscCall(PetscHSetIAdd(ht, point)); 41 /* Loop over all the points that this point connects to */ 42 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star)); 43 for (si = 0; si < starSize * 2; si += 2) PetscCall(PetscHSetIAdd(ht, star[si])); 44 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star)); 45 PetscFunctionReturn(PETSC_SUCCESS); 46 } 47 48 static PetscErrorCode PCPatchConstruct_Vanka(void *vpatch, DM dm, PetscInt point, PetscHSetI ht) 49 { 50 PC_PATCH *patch = (PC_PATCH *)vpatch; 51 PetscInt starSize; 52 PetscInt *star = NULL; 53 PetscBool shouldIgnore = PETSC_FALSE; 54 PetscInt cStart, cEnd, iStart, iEnd, si; 55 56 PetscFunctionBegin; 57 PetscCall(PetscHSetIClear(ht)); 58 /* To start with, add the point we care about */ 59 PetscCall(PetscHSetIAdd(ht, point)); 60 /* Should we ignore any points of a certain dimension? */ 61 if (patch->vankadim >= 0) { 62 shouldIgnore = PETSC_TRUE; 63 PetscCall(DMPlexGetDepthStratum(dm, patch->vankadim, &iStart, &iEnd)); 64 } 65 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 66 /* Loop over all the cells that this point connects to */ 67 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star)); 68 for (si = 0; si < starSize * 2; si += 2) { 69 const PetscInt cell = star[si]; 70 PetscInt closureSize; 71 PetscInt *closure = NULL, ci; 72 73 if (cell < cStart || cell >= cEnd) continue; 74 /* now loop over all entities in the closure of that cell */ 75 PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 76 for (ci = 0; ci < closureSize * 2; ci += 2) { 77 const PetscInt newpoint = closure[ci]; 78 79 /* We've been told to ignore entities of this type.*/ 80 if (shouldIgnore && newpoint >= iStart && newpoint < iEnd) continue; 81 PetscCall(PetscHSetIAdd(ht, newpoint)); 82 } 83 PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 84 } 85 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star)); 86 PetscFunctionReturn(PETSC_SUCCESS); 87 } 88 89 static PetscErrorCode PCPatchConstruct_Pardecomp(void *vpatch, DM dm, PetscInt point, PetscHSetI ht) 90 { 91 PC_PATCH *patch = (PC_PATCH *)vpatch; 92 DMLabel ghost = NULL; 93 const PetscInt *leaves = NULL; 94 PetscInt nleaves = 0, pStart, pEnd, loc; 95 PetscBool isFiredrake; 96 PetscBool flg; 97 PetscInt starSize; 98 PetscInt *star = NULL; 99 PetscInt opoint, overlapi; 100 101 PetscFunctionBegin; 102 PetscCall(PetscHSetIClear(ht)); 103 104 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 105 106 PetscCall(DMHasLabel(dm, "pyop2_ghost", &isFiredrake)); 107 if (isFiredrake) { 108 PetscCall(DMGetLabel(dm, "pyop2_ghost", &ghost)); 109 PetscCall(DMLabelCreateIndex(ghost, pStart, pEnd)); 110 } else { 111 PetscSF sf; 112 PetscCall(DMGetPointSF(dm, &sf)); 113 PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL)); 114 nleaves = PetscMax(nleaves, 0); 115 } 116 117 for (opoint = pStart; opoint < pEnd; ++opoint) { 118 if (ghost) PetscCall(DMLabelHasPoint(ghost, opoint, &flg)); 119 else { 120 PetscCall(PetscFindInt(opoint, nleaves, leaves, &loc)); 121 flg = loc >= 0 ? PETSC_TRUE : PETSC_FALSE; 122 } 123 /* Not an owned entity, don't make a cell patch. */ 124 if (flg) continue; 125 PetscCall(PetscHSetIAdd(ht, opoint)); 126 } 127 128 /* Now build the overlap for the patch */ 129 for (overlapi = 0; overlapi < patch->pardecomp_overlap; ++overlapi) { 130 PetscInt index = 0; 131 PetscInt *htpoints = NULL; 132 PetscInt htsize; 133 PetscInt i; 134 135 PetscCall(PetscHSetIGetSize(ht, &htsize)); 136 PetscCall(PetscMalloc1(htsize, &htpoints)); 137 PetscCall(PetscHSetIGetElems(ht, &index, htpoints)); 138 139 for (i = 0; i < htsize; ++i) { 140 PetscInt hpoint = htpoints[i]; 141 PetscInt si; 142 143 PetscCall(DMPlexGetTransitiveClosure(dm, hpoint, PETSC_FALSE, &starSize, &star)); 144 for (si = 0; si < starSize * 2; si += 2) { 145 const PetscInt starp = star[si]; 146 PetscInt closureSize; 147 PetscInt *closure = NULL, ci; 148 149 /* now loop over all entities in the closure of starp */ 150 PetscCall(DMPlexGetTransitiveClosure(dm, starp, PETSC_TRUE, &closureSize, &closure)); 151 for (ci = 0; ci < closureSize * 2; ci += 2) { 152 const PetscInt closstarp = closure[ci]; 153 PetscCall(PetscHSetIAdd(ht, closstarp)); 154 } 155 PetscCall(DMPlexRestoreTransitiveClosure(dm, starp, PETSC_TRUE, &closureSize, &closure)); 156 } 157 PetscCall(DMPlexRestoreTransitiveClosure(dm, hpoint, PETSC_FALSE, &starSize, &star)); 158 } 159 PetscCall(PetscFree(htpoints)); 160 } 161 PetscFunctionReturn(PETSC_SUCCESS); 162 } 163 164 /* The user's already set the patches in patch->userIS. Build the hash tables */ 165 static PetscErrorCode PCPatchConstruct_User(void *vpatch, DM dm, PetscInt point, PetscHSetI ht) 166 { 167 PC_PATCH *patch = (PC_PATCH *)vpatch; 168 IS patchis = patch->userIS[point]; 169 PetscInt n; 170 const PetscInt *patchdata; 171 PetscInt pStart, pEnd, i; 172 173 PetscFunctionBegin; 174 PetscCall(PetscHSetIClear(ht)); 175 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 176 PetscCall(ISGetLocalSize(patchis, &n)); 177 PetscCall(ISGetIndices(patchis, &patchdata)); 178 for (i = 0; i < n; ++i) { 179 const PetscInt ownedpoint = patchdata[i]; 180 181 PetscCheck(ownedpoint >= pStart && ownedpoint < pEnd, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %" PetscInt_FMT " was not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", ownedpoint, pStart, pEnd); 182 PetscCall(PetscHSetIAdd(ht, ownedpoint)); 183 } 184 PetscCall(ISRestoreIndices(patchis, &patchdata)); 185 PetscFunctionReturn(PETSC_SUCCESS); 186 } 187 188 static PetscErrorCode PCPatchCreateDefaultSF_Private(PC pc, PetscInt n, const PetscSF *sf, const PetscInt *bs) 189 { 190 PC_PATCH *patch = (PC_PATCH *)pc->data; 191 PetscInt i; 192 193 PetscFunctionBegin; 194 if (n == 1 && bs[0] == 1) { 195 patch->sectionSF = sf[0]; 196 PetscCall(PetscObjectReference((PetscObject)patch->sectionSF)); 197 } else { 198 PetscInt allRoots = 0, allLeaves = 0; 199 PetscInt leafOffset = 0; 200 PetscInt *ilocal = NULL; 201 PetscSFNode *iremote = NULL; 202 PetscInt *remoteOffsets = NULL; 203 PetscInt index = 0; 204 PetscHMapI rankToIndex; 205 PetscInt numRanks = 0; 206 PetscSFNode *remote = NULL; 207 PetscSF rankSF; 208 PetscInt *ranks = NULL; 209 PetscInt *offsets = NULL; 210 MPI_Datatype contig; 211 PetscHSetI ranksUniq; 212 PetscMPIInt in; 213 214 /* First figure out how many dofs there are in the concatenated numbering. 215 allRoots: number of owned global dofs; 216 allLeaves: number of visible dofs (global + ghosted). 217 */ 218 for (i = 0; i < n; ++i) { 219 PetscInt nroots, nleaves; 220 221 PetscCall(PetscSFGetGraph(sf[i], &nroots, &nleaves, NULL, NULL)); 222 allRoots += nroots * bs[i]; 223 allLeaves += nleaves * bs[i]; 224 } 225 PetscCall(PetscMalloc1(allLeaves, &ilocal)); 226 PetscCall(PetscMalloc1(allLeaves, &iremote)); 227 /* Now build an SF that just contains process connectivity. */ 228 PetscCall(PetscHSetICreate(&ranksUniq)); 229 for (i = 0; i < n; ++i) { 230 const PetscMPIInt *ranks = NULL; 231 PetscMPIInt nranks; 232 233 PetscCall(PetscSFSetUp(sf[i])); 234 PetscCall(PetscSFGetRootRanks(sf[i], &nranks, &ranks, NULL, NULL, NULL)); 235 /* These are all the ranks who communicate with me. */ 236 for (PetscMPIInt j = 0; j < nranks; ++j) PetscCall(PetscHSetIAdd(ranksUniq, (PetscInt)ranks[j])); 237 } 238 PetscCall(PetscHSetIGetSize(ranksUniq, &numRanks)); 239 PetscCall(PetscMalloc1(numRanks, &remote)); 240 PetscCall(PetscMalloc1(numRanks, &ranks)); 241 PetscCall(PetscHSetIGetElems(ranksUniq, &index, ranks)); 242 243 PetscCall(PetscHMapICreate(&rankToIndex)); 244 for (PetscInt i = 0; i < numRanks; ++i) { 245 remote[i].rank = (PetscMPIInt)ranks[i]; 246 remote[i].index = 0; 247 PetscCall(PetscHMapISet(rankToIndex, ranks[i], i)); 248 } 249 PetscCall(PetscFree(ranks)); 250 PetscCall(PetscHSetIDestroy(&ranksUniq)); 251 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)pc), &rankSF)); 252 PetscCall(PetscSFSetGraph(rankSF, 1, numRanks, NULL, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER)); 253 PetscCall(PetscSFSetUp(rankSF)); 254 /* OK, use it to communicate the root offset on the remote processes for each subspace. */ 255 PetscCall(PetscMalloc1(n, &offsets)); 256 PetscCall(PetscMalloc1(n * numRanks, &remoteOffsets)); 257 258 offsets[0] = 0; 259 for (i = 1; i < n; ++i) { 260 PetscInt nroots; 261 262 PetscCall(PetscSFGetGraph(sf[i - 1], &nroots, NULL, NULL, NULL)); 263 offsets[i] = offsets[i - 1] + nroots * bs[i - 1]; 264 } 265 /* Offsets are the offsets on the current process of the global dof numbering for the subspaces. */ 266 PetscCall(PetscMPIIntCast(n, &in)); 267 PetscCallMPI(MPI_Type_contiguous(in, MPIU_INT, &contig)); 268 PetscCallMPI(MPI_Type_commit(&contig)); 269 270 PetscCall(PetscSFBcastBegin(rankSF, contig, offsets, remoteOffsets, MPI_REPLACE)); 271 PetscCall(PetscSFBcastEnd(rankSF, contig, offsets, remoteOffsets, MPI_REPLACE)); 272 PetscCallMPI(MPI_Type_free(&contig)); 273 PetscCall(PetscFree(offsets)); 274 PetscCall(PetscSFDestroy(&rankSF)); 275 /* Now remoteOffsets contains the offsets on the remote 276 processes who communicate with me. So now we can 277 concatenate the list of SFs into a single one. */ 278 index = 0; 279 for (i = 0; i < n; ++i) { 280 const PetscSFNode *remote = NULL; 281 const PetscInt *local = NULL; 282 PetscInt nroots, nleaves, j; 283 284 PetscCall(PetscSFGetGraph(sf[i], &nroots, &nleaves, &local, &remote)); 285 for (j = 0; j < nleaves; ++j) { 286 PetscInt rank = remote[j].rank; 287 PetscInt idx, rootOffset, k; 288 289 PetscCall(PetscHMapIGet(rankToIndex, rank, &idx)); 290 PetscCheck(idx != -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Didn't find rank, huh?"); 291 /* Offset on given rank for ith subspace */ 292 rootOffset = remoteOffsets[n * idx + i]; 293 for (k = 0; k < bs[i]; ++k) { 294 ilocal[index] = (local ? local[j] : j) * bs[i] + k + leafOffset; 295 iremote[index].rank = remote[j].rank; 296 iremote[index].index = remote[j].index * bs[i] + k + rootOffset; 297 ++index; 298 } 299 } 300 leafOffset += nleaves * bs[i]; 301 } 302 PetscCall(PetscHMapIDestroy(&rankToIndex)); 303 PetscCall(PetscFree(remoteOffsets)); 304 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)pc), &patch->sectionSF)); 305 PetscCall(PetscSFSetGraph(patch->sectionSF, allRoots, allLeaves, ilocal, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER)); 306 } 307 PetscFunctionReturn(PETSC_SUCCESS); 308 } 309 310 /* TODO: Docs */ 311 static PetscErrorCode PCPatchGetIgnoreDim(PC pc, PetscInt *dim) 312 { 313 PC_PATCH *patch = (PC_PATCH *)pc->data; 314 315 PetscFunctionBegin; 316 *dim = patch->ignoredim; 317 PetscFunctionReturn(PETSC_SUCCESS); 318 } 319 320 /* TODO: Docs */ 321 PetscErrorCode PCPatchSetSaveOperators(PC pc, PetscBool flg) 322 { 323 PC_PATCH *patch = (PC_PATCH *)pc->data; 324 325 PetscFunctionBegin; 326 patch->save_operators = flg; 327 PetscFunctionReturn(PETSC_SUCCESS); 328 } 329 330 /* TODO: Docs */ 331 PetscErrorCode PCPatchGetSaveOperators(PC pc, PetscBool *flg) 332 { 333 PC_PATCH *patch = (PC_PATCH *)pc->data; 334 335 PetscFunctionBegin; 336 *flg = patch->save_operators; 337 PetscFunctionReturn(PETSC_SUCCESS); 338 } 339 340 /* TODO: Docs */ 341 PetscErrorCode PCPatchSetPrecomputeElementTensors(PC pc, PetscBool flg) 342 { 343 PC_PATCH *patch = (PC_PATCH *)pc->data; 344 345 PetscFunctionBegin; 346 patch->precomputeElementTensors = flg; 347 PetscFunctionReturn(PETSC_SUCCESS); 348 } 349 350 /* TODO: Docs */ 351 PetscErrorCode PCPatchGetPrecomputeElementTensors(PC pc, PetscBool *flg) 352 { 353 PC_PATCH *patch = (PC_PATCH *)pc->data; 354 355 PetscFunctionBegin; 356 *flg = patch->precomputeElementTensors; 357 PetscFunctionReturn(PETSC_SUCCESS); 358 } 359 360 /* TODO: Docs */ 361 PetscErrorCode PCPatchSetPartitionOfUnity(PC pc, PetscBool flg) 362 { 363 PC_PATCH *patch = (PC_PATCH *)pc->data; 364 365 PetscFunctionBegin; 366 patch->partition_of_unity = flg; 367 PetscFunctionReturn(PETSC_SUCCESS); 368 } 369 370 /* TODO: Docs */ 371 PetscErrorCode PCPatchGetPartitionOfUnity(PC pc, PetscBool *flg) 372 { 373 PC_PATCH *patch = (PC_PATCH *)pc->data; 374 375 PetscFunctionBegin; 376 *flg = patch->partition_of_unity; 377 PetscFunctionReturn(PETSC_SUCCESS); 378 } 379 380 /* TODO: Docs */ 381 static PetscErrorCode PCPatchSetLocalComposition(PC pc, PCCompositeType type) 382 { 383 PC_PATCH *patch = (PC_PATCH *)pc->data; 384 385 PetscFunctionBegin; 386 PetscCheck(type == PC_COMPOSITE_ADDITIVE || type == PC_COMPOSITE_MULTIPLICATIVE, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Only supports additive or multiplicative as the local type"); 387 patch->local_composition_type = type; 388 PetscFunctionReturn(PETSC_SUCCESS); 389 } 390 391 /* TODO: Docs */ 392 PetscErrorCode PCPatchGetSubKSP(PC pc, PetscInt *npatch, KSP **ksp) 393 { 394 PC_PATCH *patch = (PC_PATCH *)pc->data; 395 PetscInt i; 396 397 PetscFunctionBegin; 398 PetscCheck(pc->setupcalled, PetscObjectComm((PetscObject)pc), PETSC_ERR_ORDER, "Need to call PCSetUp() on PC (or KSPSetUp() on the outer KSP object) before calling here"); 399 400 PetscCall(PetscMalloc1(patch->npatch, ksp)); 401 for (i = 0; i < patch->npatch; ++i) (*ksp)[i] = (KSP)patch->solver[i]; 402 if (npatch) *npatch = patch->npatch; 403 PetscFunctionReturn(PETSC_SUCCESS); 404 } 405 406 /* TODO: Docs */ 407 PetscErrorCode PCPatchSetSubMatType(PC pc, MatType sub_mat_type) 408 { 409 PC_PATCH *patch = (PC_PATCH *)pc->data; 410 411 PetscFunctionBegin; 412 if (patch->sub_mat_type) PetscCall(PetscFree(patch->sub_mat_type)); 413 PetscCall(PetscStrallocpy(sub_mat_type, (char **)&patch->sub_mat_type)); 414 PetscFunctionReturn(PETSC_SUCCESS); 415 } 416 417 /* TODO: Docs */ 418 PetscErrorCode PCPatchGetSubMatType(PC pc, MatType *sub_mat_type) 419 { 420 PC_PATCH *patch = (PC_PATCH *)pc->data; 421 422 PetscFunctionBegin; 423 *sub_mat_type = patch->sub_mat_type; 424 PetscFunctionReturn(PETSC_SUCCESS); 425 } 426 427 /* TODO: Docs */ 428 PetscErrorCode PCPatchSetCellNumbering(PC pc, PetscSection cellNumbering) 429 { 430 PC_PATCH *patch = (PC_PATCH *)pc->data; 431 432 PetscFunctionBegin; 433 patch->cellNumbering = cellNumbering; 434 PetscCall(PetscObjectReference((PetscObject)cellNumbering)); 435 PetscFunctionReturn(PETSC_SUCCESS); 436 } 437 438 /* TODO: Docs */ 439 PetscErrorCode PCPatchGetCellNumbering(PC pc, PetscSection *cellNumbering) 440 { 441 PC_PATCH *patch = (PC_PATCH *)pc->data; 442 443 PetscFunctionBegin; 444 *cellNumbering = patch->cellNumbering; 445 PetscFunctionReturn(PETSC_SUCCESS); 446 } 447 448 /* TODO: Docs */ 449 PetscErrorCode PCPatchSetConstructType(PC pc, PCPatchConstructType ctype, PetscErrorCode (*func)(PC, PetscInt *, IS **, IS *, void *), void *ctx) 450 { 451 PC_PATCH *patch = (PC_PATCH *)pc->data; 452 453 PetscFunctionBegin; 454 patch->ctype = ctype; 455 switch (ctype) { 456 case PC_PATCH_STAR: 457 patch->user_patches = PETSC_FALSE; 458 patch->patchconstructop = PCPatchConstruct_Star; 459 break; 460 case PC_PATCH_VANKA: 461 patch->user_patches = PETSC_FALSE; 462 patch->patchconstructop = PCPatchConstruct_Vanka; 463 break; 464 case PC_PATCH_PARDECOMP: 465 patch->user_patches = PETSC_FALSE; 466 patch->patchconstructop = PCPatchConstruct_Pardecomp; 467 break; 468 case PC_PATCH_USER: 469 case PC_PATCH_PYTHON: 470 patch->user_patches = PETSC_TRUE; 471 patch->patchconstructop = PCPatchConstruct_User; 472 if (func) { 473 patch->userpatchconstructionop = func; 474 patch->userpatchconstructctx = ctx; 475 } 476 break; 477 default: 478 SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Unknown patch construction type %" PetscInt_FMT, (PetscInt)patch->ctype); 479 } 480 PetscFunctionReturn(PETSC_SUCCESS); 481 } 482 483 /* TODO: Docs */ 484 PetscErrorCode PCPatchGetConstructType(PC pc, PCPatchConstructType *ctype, PetscErrorCode (**func)(PC, PetscInt *, IS **, IS *, void *), void **ctx) 485 { 486 PC_PATCH *patch = (PC_PATCH *)pc->data; 487 488 PetscFunctionBegin; 489 *ctype = patch->ctype; 490 switch (patch->ctype) { 491 case PC_PATCH_STAR: 492 case PC_PATCH_VANKA: 493 case PC_PATCH_PARDECOMP: 494 break; 495 case PC_PATCH_USER: 496 case PC_PATCH_PYTHON: 497 *func = patch->userpatchconstructionop; 498 *ctx = patch->userpatchconstructctx; 499 break; 500 default: 501 SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_USER, "Unknown patch construction type %" PetscInt_FMT, (PetscInt)patch->ctype); 502 } 503 PetscFunctionReturn(PETSC_SUCCESS); 504 } 505 506 /* TODO: Docs */ 507 PetscErrorCode PCPatchSetDiscretisationInfo(PC pc, PetscInt nsubspaces, DM *dms, PetscInt *bs, PetscInt *nodesPerCell, const PetscInt **cellNodeMap, const PetscInt *subspaceOffsets, PetscInt numGhostBcs, const PetscInt *ghostBcNodes, PetscInt numGlobalBcs, const PetscInt *globalBcNodes) 508 { 509 PC_PATCH *patch = (PC_PATCH *)pc->data; 510 DM dm, plex; 511 PetscSF *sfs; 512 PetscInt cStart, cEnd, i, j; 513 514 PetscFunctionBegin; 515 PetscCall(PCGetDM(pc, &dm)); 516 PetscCall(DMConvert(dm, DMPLEX, &plex)); 517 dm = plex; 518 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 519 PetscCall(PetscMalloc1(nsubspaces, &sfs)); 520 PetscCall(PetscMalloc1(nsubspaces, &patch->dofSection)); 521 PetscCall(PetscMalloc1(nsubspaces, &patch->bs)); 522 PetscCall(PetscMalloc1(nsubspaces, &patch->nodesPerCell)); 523 PetscCall(PetscMalloc1(nsubspaces, &patch->cellNodeMap)); 524 PetscCall(PetscMalloc1(nsubspaces + 1, &patch->subspaceOffsets)); 525 526 patch->nsubspaces = nsubspaces; 527 patch->totalDofsPerCell = 0; 528 for (i = 0; i < nsubspaces; ++i) { 529 PetscCall(DMGetLocalSection(dms[i], &patch->dofSection[i])); 530 PetscCall(PetscObjectReference((PetscObject)patch->dofSection[i])); 531 PetscCall(DMGetSectionSF(dms[i], &sfs[i])); 532 patch->bs[i] = bs[i]; 533 patch->nodesPerCell[i] = nodesPerCell[i]; 534 patch->totalDofsPerCell += nodesPerCell[i] * bs[i]; 535 PetscCall(PetscMalloc1((cEnd - cStart) * nodesPerCell[i], &patch->cellNodeMap[i])); 536 for (j = 0; j < (cEnd - cStart) * nodesPerCell[i]; ++j) patch->cellNodeMap[i][j] = cellNodeMap[i][j]; 537 patch->subspaceOffsets[i] = subspaceOffsets[i]; 538 } 539 PetscCall(PCPatchCreateDefaultSF_Private(pc, nsubspaces, sfs, patch->bs)); 540 PetscCall(PetscFree(sfs)); 541 542 patch->subspaceOffsets[nsubspaces] = subspaceOffsets[nsubspaces]; 543 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGhostBcs, ghostBcNodes, PETSC_COPY_VALUES, &patch->ghostBcNodes)); 544 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGlobalBcs, globalBcNodes, PETSC_COPY_VALUES, &patch->globalBcNodes)); 545 PetscCall(DMDestroy(&dm)); 546 PetscFunctionReturn(PETSC_SUCCESS); 547 } 548 549 /* TODO: Docs */ 550 static PetscErrorCode PCPatchSetDiscretisationInfoCombined(PC pc, DM dm, PetscInt *nodesPerCell, const PetscInt **cellNodeMap, PetscInt numGhostBcs, const PetscInt *ghostBcNodes, PetscInt numGlobalBcs, const PetscInt *globalBcNodes) 551 { 552 PC_PATCH *patch = (PC_PATCH *)pc->data; 553 PetscInt cStart, cEnd, i, j; 554 555 PetscFunctionBegin; 556 patch->combined = PETSC_TRUE; 557 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 558 PetscCall(DMGetNumFields(dm, &patch->nsubspaces)); 559 PetscCall(PetscCalloc1(patch->nsubspaces, &patch->dofSection)); 560 PetscCall(PetscMalloc1(patch->nsubspaces, &patch->bs)); 561 PetscCall(PetscMalloc1(patch->nsubspaces, &patch->nodesPerCell)); 562 PetscCall(PetscMalloc1(patch->nsubspaces, &patch->cellNodeMap)); 563 PetscCall(PetscCalloc1(patch->nsubspaces + 1, &patch->subspaceOffsets)); 564 PetscCall(DMGetLocalSection(dm, &patch->dofSection[0])); 565 PetscCall(PetscObjectReference((PetscObject)patch->dofSection[0])); 566 PetscCall(PetscSectionGetStorageSize(patch->dofSection[0], &patch->subspaceOffsets[patch->nsubspaces])); 567 patch->totalDofsPerCell = 0; 568 for (i = 0; i < patch->nsubspaces; ++i) { 569 patch->bs[i] = 1; 570 patch->nodesPerCell[i] = nodesPerCell[i]; 571 patch->totalDofsPerCell += nodesPerCell[i]; 572 PetscCall(PetscMalloc1((cEnd - cStart) * nodesPerCell[i], &patch->cellNodeMap[i])); 573 for (j = 0; j < (cEnd - cStart) * nodesPerCell[i]; ++j) patch->cellNodeMap[i][j] = cellNodeMap[i][j]; 574 } 575 PetscCall(DMGetSectionSF(dm, &patch->sectionSF)); 576 PetscCall(PetscObjectReference((PetscObject)patch->sectionSF)); 577 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGhostBcs, ghostBcNodes, PETSC_COPY_VALUES, &patch->ghostBcNodes)); 578 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGlobalBcs, globalBcNodes, PETSC_COPY_VALUES, &patch->globalBcNodes)); 579 PetscFunctionReturn(PETSC_SUCCESS); 580 } 581 582 /*@C 583 PCPatchSetComputeFunction - Set the callback function used to compute patch residuals 584 585 Logically Collective 586 587 Input Parameters: 588 + pc - The `PC` 589 . func - The callback function 590 - ctx - The user context 591 592 Calling sequence of `func`: 593 + pc - The `PC` 594 . point - The point 595 . x - The input solution (not used in linear problems) 596 . f - The patch residual vector 597 . cellIS - An array of the cell numbers 598 . n - The size of `dofsArray` 599 . dofsArray - The dofmap for the dofs to be solved for 600 . dofsArrayWithAll - The dofmap for all dofs on the patch 601 - ctx - The user context 602 603 Level: advanced 604 605 Note: 606 The entries of `f` (the output residual vector) have been set to zero before the call. 607 608 .seealso: [](ch_ksp), `PCPatchSetComputeOperator()`, `PCPatchGetComputeOperator()`, `PCPatchSetDiscretisationInfo()`, `PCPatchSetComputeFunctionInteriorFacets()` 609 @*/ 610 PetscErrorCode PCPatchSetComputeFunction(PC pc, PetscErrorCode (*func)(PC pc, PetscInt point, Vec x, Vec f, IS cellIS, PetscInt n, const PetscInt *dofsArray, const PetscInt *dofsArrayWithAll, void *ctx), void *ctx) 611 { 612 PC_PATCH *patch = (PC_PATCH *)pc->data; 613 614 PetscFunctionBegin; 615 patch->usercomputef = func; 616 patch->usercomputefctx = ctx; 617 PetscFunctionReturn(PETSC_SUCCESS); 618 } 619 620 /*@C 621 PCPatchSetComputeFunctionInteriorFacets - Set the callback function used to compute facet integrals for patch residuals 622 623 Logically Collective 624 625 Input Parameters: 626 + pc - The `PC` 627 . func - The callback function 628 - ctx - The user context 629 630 Calling sequence of `func`: 631 + pc - The `PC` 632 . point - The point 633 . x - The input solution (not used in linear problems) 634 . f - The patch residual vector 635 . facetIS - An array of the facet numbers 636 . n - The size of `dofsArray` 637 . dofsArray - The dofmap for the dofs to be solved for 638 . dofsArrayWithAll - The dofmap for all dofs on the patch 639 - ctx - The user context 640 641 Level: advanced 642 643 Note: 644 The entries of `f` (the output residual vector) have been set to zero before the call. 645 646 .seealso: [](ch_ksp), `PCPatchSetComputeOperator()`, `PCPatchGetComputeOperator()`, `PCPatchSetDiscretisationInfo()`, `PCPatchSetComputeFunction()` 647 @*/ 648 PetscErrorCode PCPatchSetComputeFunctionInteriorFacets(PC pc, PetscErrorCode (*func)(PC pc, PetscInt point, Vec x, Vec f, IS facetIS, PetscInt n, const PetscInt *dofsArray, const PetscInt *dofsArrayWithAll, void *ctx), void *ctx) 649 { 650 PC_PATCH *patch = (PC_PATCH *)pc->data; 651 652 PetscFunctionBegin; 653 patch->usercomputefintfacet = func; 654 patch->usercomputefintfacetctx = ctx; 655 PetscFunctionReturn(PETSC_SUCCESS); 656 } 657 658 /*@C 659 PCPatchSetComputeOperator - Set the callback function used to compute patch matrices 660 661 Logically Collective 662 663 Input Parameters: 664 + pc - The `PC` 665 . func - The callback function 666 - ctx - The user context 667 668 Calling sequence of `func`: 669 + pc - The `PC` 670 . point - The point 671 . x - The input solution (not used in linear problems) 672 . mat - The patch matrix 673 . facetIS - An array of the cell numbers 674 . n - The size of `dofsArray` 675 . dofsArray - The dofmap for the dofs to be solved for 676 . dofsArrayWithAll - The dofmap for all dofs on the patch 677 - ctx - The user context 678 679 Level: advanced 680 681 Note: 682 The matrix entries have been set to zero before the call. 683 684 .seealso: [](ch_ksp), `PCPatchGetComputeOperator()`, `PCPatchSetComputeFunction()`, `PCPatchSetDiscretisationInfo()` 685 @*/ 686 PetscErrorCode PCPatchSetComputeOperator(PC pc, PetscErrorCode (*func)(PC pc, PetscInt point, Vec x, Mat mat, IS facetIS, PetscInt n, const PetscInt *dofsArray, const PetscInt *dofsArrayWithAll, void *ctx), void *ctx) 687 { 688 PC_PATCH *patch = (PC_PATCH *)pc->data; 689 690 PetscFunctionBegin; 691 patch->usercomputeop = func; 692 patch->usercomputeopctx = ctx; 693 PetscFunctionReturn(PETSC_SUCCESS); 694 } 695 696 /*@C 697 PCPatchSetComputeOperatorInteriorFacets - Set the callback function used to compute facet integrals for patch matrices 698 699 Logically Collective 700 701 Input Parameters: 702 + pc - The `PC` 703 . func - The callback function 704 - ctx - The user context 705 706 Calling sequence of `func`: 707 + pc - The `PC` 708 . point - The point 709 . x - The input solution (not used in linear problems) 710 . mat - The patch matrix 711 . facetIS - An array of the facet numbers 712 . n - The size of `dofsArray` 713 . dofsArray - The dofmap for the dofs to be solved for 714 . dofsArrayWithAll - The dofmap for all dofs on the patch 715 - ctx - The user context 716 717 Level: advanced 718 719 Note: 720 The matrix entries have been set to zero before the call. 721 722 .seealso: [](ch_ksp), `PCPatchGetComputeOperator()`, `PCPatchSetComputeFunction()`, `PCPatchSetDiscretisationInfo()` 723 @*/ 724 PetscErrorCode PCPatchSetComputeOperatorInteriorFacets(PC pc, PetscErrorCode (*func)(PC pc, PetscInt point, Vec x, Mat mat, IS facetIS, PetscInt n, const PetscInt *dofsArray, const PetscInt *dofsArrayWithAll, void *ctx), void *ctx) 725 { 726 PC_PATCH *patch = (PC_PATCH *)pc->data; 727 728 PetscFunctionBegin; 729 patch->usercomputeopintfacet = func; 730 patch->usercomputeopintfacetctx = ctx; 731 PetscFunctionReturn(PETSC_SUCCESS); 732 } 733 734 /* On entry, ht contains the topological entities whose dofs we are responsible for solving for; 735 on exit, cht contains all the topological entities we need to compute their residuals. 736 In full generality this should incorporate knowledge of the sparsity pattern of the matrix; 737 here we assume a standard FE sparsity pattern.*/ 738 /* TODO: Use DMPlexGetAdjacency() */ 739 static PetscErrorCode PCPatchCompleteCellPatch(PC pc, PetscHSetI ht, PetscHSetI cht) 740 { 741 DM dm, plex; 742 PC_PATCH *patch = (PC_PATCH *)pc->data; 743 PetscHashIter hi; 744 PetscInt point; 745 PetscInt *star = NULL, *closure = NULL; 746 PetscInt ignoredim, iStart = 0, iEnd = -1, starSize, closureSize, si, ci; 747 PetscInt *fStar = NULL, *fClosure = NULL; 748 PetscInt fBegin, fEnd, fsi, fci, fStarSize, fClosureSize; 749 750 PetscFunctionBegin; 751 PetscCall(PCGetDM(pc, &dm)); 752 PetscCall(DMConvert(dm, DMPLEX, &plex)); 753 dm = plex; 754 PetscCall(DMPlexGetHeightStratum(dm, 1, &fBegin, &fEnd)); 755 PetscCall(PCPatchGetIgnoreDim(pc, &ignoredim)); 756 if (ignoredim >= 0) PetscCall(DMPlexGetDepthStratum(dm, ignoredim, &iStart, &iEnd)); 757 PetscCall(PetscHSetIClear(cht)); 758 PetscHashIterBegin(ht, hi); 759 while (!PetscHashIterAtEnd(ht, hi)) { 760 PetscHashIterGetKey(ht, hi, point); 761 PetscHashIterNext(ht, hi); 762 763 /* Loop over all the cells that this point connects to */ 764 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &starSize, &star)); 765 for (si = 0; si < starSize * 2; si += 2) { 766 const PetscInt ownedpoint = star[si]; 767 /* TODO Check for point in cht before running through closure again */ 768 /* now loop over all entities in the closure of that cell */ 769 PetscCall(DMPlexGetTransitiveClosure(dm, ownedpoint, PETSC_TRUE, &closureSize, &closure)); 770 for (ci = 0; ci < closureSize * 2; ci += 2) { 771 const PetscInt seenpoint = closure[ci]; 772 if (ignoredim >= 0 && seenpoint >= iStart && seenpoint < iEnd) continue; 773 PetscCall(PetscHSetIAdd(cht, seenpoint)); 774 /* Facet integrals couple dofs across facets, so in that case for each of 775 the facets we need to add all dofs on the other side of the facet to 776 the seen dofs. */ 777 if (patch->usercomputeopintfacet) { 778 if (fBegin <= seenpoint && seenpoint < fEnd) { 779 PetscCall(DMPlexGetTransitiveClosure(dm, seenpoint, PETSC_FALSE, &fStarSize, &fStar)); 780 for (fsi = 0; fsi < fStarSize * 2; fsi += 2) { 781 PetscCall(DMPlexGetTransitiveClosure(dm, fStar[fsi], PETSC_TRUE, &fClosureSize, &fClosure)); 782 for (fci = 0; fci < fClosureSize * 2; fci += 2) PetscCall(PetscHSetIAdd(cht, fClosure[fci])); 783 PetscCall(DMPlexRestoreTransitiveClosure(dm, fStar[fsi], PETSC_TRUE, NULL, &fClosure)); 784 } 785 PetscCall(DMPlexRestoreTransitiveClosure(dm, seenpoint, PETSC_FALSE, NULL, &fStar)); 786 } 787 } 788 } 789 PetscCall(DMPlexRestoreTransitiveClosure(dm, ownedpoint, PETSC_TRUE, NULL, &closure)); 790 } 791 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, NULL, &star)); 792 } 793 PetscCall(DMDestroy(&dm)); 794 PetscFunctionReturn(PETSC_SUCCESS); 795 } 796 797 static PetscErrorCode PCPatchGetGlobalDofs(PC pc, PetscSection dofSection[], PetscInt f, PetscBool combined, PetscInt p, PetscInt *dof, PetscInt *off) 798 { 799 PetscFunctionBegin; 800 if (combined) { 801 if (f < 0) { 802 if (dof) PetscCall(PetscSectionGetDof(dofSection[0], p, dof)); 803 if (off) PetscCall(PetscSectionGetOffset(dofSection[0], p, off)); 804 } else { 805 if (dof) PetscCall(PetscSectionGetFieldDof(dofSection[0], p, f, dof)); 806 if (off) PetscCall(PetscSectionGetFieldOffset(dofSection[0], p, f, off)); 807 } 808 } else { 809 if (f < 0) { 810 PC_PATCH *patch = (PC_PATCH *)pc->data; 811 PetscInt fdof, g; 812 813 if (dof) { 814 *dof = 0; 815 for (g = 0; g < patch->nsubspaces; ++g) { 816 PetscCall(PetscSectionGetDof(dofSection[g], p, &fdof)); 817 *dof += fdof; 818 } 819 } 820 if (off) { 821 *off = 0; 822 for (g = 0; g < patch->nsubspaces; ++g) { 823 PetscCall(PetscSectionGetOffset(dofSection[g], p, &fdof)); 824 *off += fdof; 825 } 826 } 827 } else { 828 if (dof) PetscCall(PetscSectionGetDof(dofSection[f], p, dof)); 829 if (off) PetscCall(PetscSectionGetOffset(dofSection[f], p, off)); 830 } 831 } 832 PetscFunctionReturn(PETSC_SUCCESS); 833 } 834 835 /* Given a hash table with a set of topological entities (pts), compute the degrees of 836 freedom in global concatenated numbering on those entities. 837 For Vanka smoothing, this needs to do something special: ignore dofs of the 838 constraint subspace on entities that aren't the base entity we're building the patch 839 around. */ 840 static PetscErrorCode PCPatchGetPointDofs(PC pc, PetscHSetI pts, PetscHSetI dofs, PetscInt base, PetscHSetI *subspaces_to_exclude) 841 { 842 PC_PATCH *patch = (PC_PATCH *)pc->data; 843 PetscHashIter hi; 844 PetscInt ldof, loff; 845 PetscInt k, p; 846 847 PetscFunctionBegin; 848 PetscCall(PetscHSetIClear(dofs)); 849 for (k = 0; k < patch->nsubspaces; ++k) { 850 PetscInt subspaceOffset = patch->subspaceOffsets[k]; 851 PetscInt bs = patch->bs[k]; 852 PetscInt j, l; 853 854 if (subspaces_to_exclude != NULL) { 855 PetscBool should_exclude_k = PETSC_FALSE; 856 PetscCall(PetscHSetIHas(*subspaces_to_exclude, k, &should_exclude_k)); 857 if (should_exclude_k) { 858 /* only get this subspace dofs at the base entity, not any others */ 859 PetscCall(PCPatchGetGlobalDofs(pc, patch->dofSection, k, patch->combined, base, &ldof, &loff)); 860 if (0 == ldof) continue; 861 for (j = loff; j < ldof + loff; ++j) { 862 for (l = 0; l < bs; ++l) { 863 PetscInt dof = bs * j + l + subspaceOffset; 864 PetscCall(PetscHSetIAdd(dofs, dof)); 865 } 866 } 867 continue; /* skip the other dofs of this subspace */ 868 } 869 } 870 871 PetscHashIterBegin(pts, hi); 872 while (!PetscHashIterAtEnd(pts, hi)) { 873 PetscHashIterGetKey(pts, hi, p); 874 PetscHashIterNext(pts, hi); 875 PetscCall(PCPatchGetGlobalDofs(pc, patch->dofSection, k, patch->combined, p, &ldof, &loff)); 876 if (0 == ldof) continue; 877 for (j = loff; j < ldof + loff; ++j) { 878 for (l = 0; l < bs; ++l) { 879 PetscInt dof = bs * j + l + subspaceOffset; 880 PetscCall(PetscHSetIAdd(dofs, dof)); 881 } 882 } 883 } 884 } 885 PetscFunctionReturn(PETSC_SUCCESS); 886 } 887 888 /* Given two hash tables A and B, compute the keys in B that are not in A, and put them in C */ 889 static PetscErrorCode PCPatchComputeSetDifference_Private(PetscHSetI A, PetscHSetI B, PetscHSetI C) 890 { 891 PetscHashIter hi; 892 PetscInt key; 893 PetscBool flg; 894 895 PetscFunctionBegin; 896 PetscCall(PetscHSetIClear(C)); 897 PetscHashIterBegin(B, hi); 898 while (!PetscHashIterAtEnd(B, hi)) { 899 PetscHashIterGetKey(B, hi, key); 900 PetscHashIterNext(B, hi); 901 PetscCall(PetscHSetIHas(A, key, &flg)); 902 if (!flg) PetscCall(PetscHSetIAdd(C, key)); 903 } 904 PetscFunctionReturn(PETSC_SUCCESS); 905 } 906 907 // PetscClangLinter pragma disable: -fdoc-sowing-chars 908 /* 909 PCPatchCreateCellPatches - create patches. 910 911 Input Parameter: 912 . dm - The DMPlex object defining the mesh 913 914 Output Parameters: 915 + cellCounts - Section with counts of cells around each vertex 916 . cells - IS of the cell point indices of cells in each patch 917 . pointCounts - Section with counts of cells around each vertex 918 - point - IS of the cell point indices of cells in each patch 919 */ 920 static PetscErrorCode PCPatchCreateCellPatches(PC pc) 921 { 922 PC_PATCH *patch = (PC_PATCH *)pc->data; 923 DMLabel ghost = NULL; 924 DM dm, plex; 925 PetscHSetI ht = NULL, cht = NULL; 926 PetscSection cellCounts, pointCounts, intFacetCounts, extFacetCounts; 927 PetscInt *cellsArray, *pointsArray, *intFacetsArray, *extFacetsArray, *intFacetsToPatchCell; 928 PetscInt numCells, numPoints, numIntFacets, numExtFacets; 929 const PetscInt *leaves; 930 PetscInt nleaves, pStart, pEnd, cStart, cEnd, vStart, vEnd, fStart, fEnd, v; 931 PetscBool isFiredrake; 932 933 PetscFunctionBegin; 934 /* Used to keep track of the cells in the patch. */ 935 PetscCall(PetscHSetICreate(&ht)); 936 PetscCall(PetscHSetICreate(&cht)); 937 938 PetscCall(PCGetDM(pc, &dm)); 939 PetscCheck(dm, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "DM not yet set on patch PC"); 940 PetscCall(DMConvert(dm, DMPLEX, &plex)); 941 dm = plex; 942 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 943 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 944 945 if (patch->user_patches) { 946 PetscCall(patch->userpatchconstructionop(pc, &patch->npatch, &patch->userIS, &patch->iterationSet, patch->userpatchconstructctx)); 947 vStart = 0; 948 vEnd = patch->npatch; 949 } else if (patch->ctype == PC_PATCH_PARDECOMP) { 950 vStart = 0; 951 vEnd = 1; 952 } else if (patch->codim < 0) { 953 if (patch->dim < 0) PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 954 else PetscCall(DMPlexGetDepthStratum(dm, patch->dim, &vStart, &vEnd)); 955 } else PetscCall(DMPlexGetHeightStratum(dm, patch->codim, &vStart, &vEnd)); 956 patch->npatch = vEnd - vStart; 957 958 /* These labels mark the owned points. We only create patches around points that this process owns. */ 959 PetscCall(DMHasLabel(dm, "pyop2_ghost", &isFiredrake)); 960 if (isFiredrake) { 961 PetscCall(DMGetLabel(dm, "pyop2_ghost", &ghost)); 962 PetscCall(DMLabelCreateIndex(ghost, pStart, pEnd)); 963 } else { 964 PetscSF sf; 965 966 PetscCall(DMGetPointSF(dm, &sf)); 967 PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL)); 968 nleaves = PetscMax(nleaves, 0); 969 } 970 971 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->cellCounts)); 972 PetscCall(PetscObjectSetName((PetscObject)patch->cellCounts, "Patch Cell Layout")); 973 cellCounts = patch->cellCounts; 974 PetscCall(PetscSectionSetChart(cellCounts, vStart, vEnd)); 975 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->pointCounts)); 976 PetscCall(PetscObjectSetName((PetscObject)patch->pointCounts, "Patch Point Layout")); 977 pointCounts = patch->pointCounts; 978 PetscCall(PetscSectionSetChart(pointCounts, vStart, vEnd)); 979 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->extFacetCounts)); 980 PetscCall(PetscObjectSetName((PetscObject)patch->extFacetCounts, "Patch Exterior Facet Layout")); 981 extFacetCounts = patch->extFacetCounts; 982 PetscCall(PetscSectionSetChart(extFacetCounts, vStart, vEnd)); 983 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->intFacetCounts)); 984 PetscCall(PetscObjectSetName((PetscObject)patch->intFacetCounts, "Patch Interior Facet Layout")); 985 intFacetCounts = patch->intFacetCounts; 986 PetscCall(PetscSectionSetChart(intFacetCounts, vStart, vEnd)); 987 /* Count cells and points in the patch surrounding each entity */ 988 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 989 for (v = vStart; v < vEnd; ++v) { 990 PetscHashIter hi; 991 PetscInt chtSize, loc = -1; 992 PetscBool flg; 993 994 if (!patch->user_patches && patch->ctype != PC_PATCH_PARDECOMP) { 995 if (ghost) PetscCall(DMLabelHasPoint(ghost, v, &flg)); 996 else { 997 PetscCall(PetscFindInt(v, nleaves, leaves, &loc)); 998 flg = loc >= 0 ? PETSC_TRUE : PETSC_FALSE; 999 } 1000 /* Not an owned entity, don't make a cell patch. */ 1001 if (flg) continue; 1002 } 1003 1004 PetscCall(patch->patchconstructop((void *)patch, dm, v, ht)); 1005 PetscCall(PCPatchCompleteCellPatch(pc, ht, cht)); 1006 PetscCall(PetscHSetIGetSize(cht, &chtSize)); 1007 /* empty patch, continue */ 1008 if (chtSize == 0) continue; 1009 1010 /* safe because size(cht) > 0 from above */ 1011 PetscHashIterBegin(cht, hi); 1012 while (!PetscHashIterAtEnd(cht, hi)) { 1013 PetscInt point, pdof; 1014 1015 PetscHashIterGetKey(cht, hi, point); 1016 if (fStart <= point && point < fEnd) { 1017 const PetscInt *support; 1018 PetscInt supportSize, p; 1019 PetscBool interior = PETSC_TRUE; 1020 PetscCall(DMPlexGetSupport(dm, point, &support)); 1021 PetscCall(DMPlexGetSupportSize(dm, point, &supportSize)); 1022 if (supportSize == 1) { 1023 interior = PETSC_FALSE; 1024 } else { 1025 for (p = 0; p < supportSize; p++) { 1026 PetscBool found; 1027 /* FIXME: can I do this while iterating over cht? */ 1028 PetscCall(PetscHSetIHas(cht, support[p], &found)); 1029 if (!found) { 1030 interior = PETSC_FALSE; 1031 break; 1032 } 1033 } 1034 } 1035 if (interior) { 1036 PetscCall(PetscSectionAddDof(intFacetCounts, v, 1)); 1037 } else { 1038 PetscCall(PetscSectionAddDof(extFacetCounts, v, 1)); 1039 } 1040 } 1041 PetscCall(PCPatchGetGlobalDofs(pc, patch->dofSection, -1, patch->combined, point, &pdof, NULL)); 1042 if (pdof) PetscCall(PetscSectionAddDof(pointCounts, v, 1)); 1043 if (point >= cStart && point < cEnd) PetscCall(PetscSectionAddDof(cellCounts, v, 1)); 1044 PetscHashIterNext(cht, hi); 1045 } 1046 } 1047 if (isFiredrake) PetscCall(DMLabelDestroyIndex(ghost)); 1048 1049 PetscCall(PetscSectionSetUp(cellCounts)); 1050 PetscCall(PetscSectionGetStorageSize(cellCounts, &numCells)); 1051 PetscCall(PetscMalloc1(numCells, &cellsArray)); 1052 PetscCall(PetscSectionSetUp(pointCounts)); 1053 PetscCall(PetscSectionGetStorageSize(pointCounts, &numPoints)); 1054 PetscCall(PetscMalloc1(numPoints, &pointsArray)); 1055 1056 PetscCall(PetscSectionSetUp(intFacetCounts)); 1057 PetscCall(PetscSectionSetUp(extFacetCounts)); 1058 PetscCall(PetscSectionGetStorageSize(intFacetCounts, &numIntFacets)); 1059 PetscCall(PetscSectionGetStorageSize(extFacetCounts, &numExtFacets)); 1060 PetscCall(PetscMalloc1(numIntFacets, &intFacetsArray)); 1061 PetscCall(PetscMalloc1(numIntFacets * 2, &intFacetsToPatchCell)); 1062 PetscCall(PetscMalloc1(numExtFacets, &extFacetsArray)); 1063 1064 /* Now that we know how much space we need, run through again and actually remember the cells. */ 1065 for (v = vStart; v < vEnd; v++) { 1066 PetscHashIter hi; 1067 PetscInt dof, off, cdof, coff, efdof, efoff, ifdof, ifoff, pdof, n = 0, cn = 0, ifn = 0, efn = 0; 1068 1069 PetscCall(PetscSectionGetDof(pointCounts, v, &dof)); 1070 PetscCall(PetscSectionGetOffset(pointCounts, v, &off)); 1071 PetscCall(PetscSectionGetDof(cellCounts, v, &cdof)); 1072 PetscCall(PetscSectionGetOffset(cellCounts, v, &coff)); 1073 PetscCall(PetscSectionGetDof(intFacetCounts, v, &ifdof)); 1074 PetscCall(PetscSectionGetOffset(intFacetCounts, v, &ifoff)); 1075 PetscCall(PetscSectionGetDof(extFacetCounts, v, &efdof)); 1076 PetscCall(PetscSectionGetOffset(extFacetCounts, v, &efoff)); 1077 if (dof <= 0) continue; 1078 PetscCall(patch->patchconstructop((void *)patch, dm, v, ht)); 1079 PetscCall(PCPatchCompleteCellPatch(pc, ht, cht)); 1080 PetscHashIterBegin(cht, hi); 1081 while (!PetscHashIterAtEnd(cht, hi)) { 1082 PetscInt point; 1083 1084 PetscHashIterGetKey(cht, hi, point); 1085 if (fStart <= point && point < fEnd) { 1086 const PetscInt *support; 1087 PetscInt supportSize, p; 1088 PetscBool interior = PETSC_TRUE; 1089 PetscCall(DMPlexGetSupport(dm, point, &support)); 1090 PetscCall(DMPlexGetSupportSize(dm, point, &supportSize)); 1091 if (supportSize == 1) { 1092 interior = PETSC_FALSE; 1093 } else { 1094 for (p = 0; p < supportSize; p++) { 1095 PetscBool found; 1096 /* FIXME: can I do this while iterating over cht? */ 1097 PetscCall(PetscHSetIHas(cht, support[p], &found)); 1098 if (!found) { 1099 interior = PETSC_FALSE; 1100 break; 1101 } 1102 } 1103 } 1104 if (interior) { 1105 intFacetsToPatchCell[2 * (ifoff + ifn)] = support[0]; 1106 intFacetsToPatchCell[2 * (ifoff + ifn) + 1] = support[1]; 1107 intFacetsArray[ifoff + ifn++] = point; 1108 } else { 1109 extFacetsArray[efoff + efn++] = point; 1110 } 1111 } 1112 PetscCall(PCPatchGetGlobalDofs(pc, patch->dofSection, -1, patch->combined, point, &pdof, NULL)); 1113 if (pdof) pointsArray[off + n++] = point; 1114 if (point >= cStart && point < cEnd) cellsArray[coff + cn++] = point; 1115 PetscHashIterNext(cht, hi); 1116 } 1117 PetscCheck(ifn == ifdof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of interior facets in patch %" PetscInt_FMT " is %" PetscInt_FMT ", but should be %" PetscInt_FMT, v, ifn, ifdof); 1118 PetscCheck(efn == efdof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of exterior facets in patch %" PetscInt_FMT " is %" PetscInt_FMT ", but should be %" PetscInt_FMT, v, efn, efdof); 1119 PetscCheck(cn == cdof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of cells in patch %" PetscInt_FMT " is %" PetscInt_FMT ", but should be %" PetscInt_FMT, v, cn, cdof); 1120 PetscCheck(n == dof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of points in patch %" PetscInt_FMT " is %" PetscInt_FMT ", but should be %" PetscInt_FMT, v, n, dof); 1121 1122 for (ifn = 0; ifn < ifdof; ifn++) { 1123 PetscInt cell0 = intFacetsToPatchCell[2 * (ifoff + ifn)]; 1124 PetscInt cell1 = intFacetsToPatchCell[2 * (ifoff + ifn) + 1]; 1125 PetscBool found0 = PETSC_FALSE, found1 = PETSC_FALSE; 1126 for (n = 0; n < cdof; n++) { 1127 if (!found0 && cell0 == cellsArray[coff + n]) { 1128 intFacetsToPatchCell[2 * (ifoff + ifn)] = n; 1129 found0 = PETSC_TRUE; 1130 } 1131 if (!found1 && cell1 == cellsArray[coff + n]) { 1132 intFacetsToPatchCell[2 * (ifoff + ifn) + 1] = n; 1133 found1 = PETSC_TRUE; 1134 } 1135 if (found0 && found1) break; 1136 } 1137 PetscCheck(found0 && found1, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Didn't manage to find local point numbers for facet support"); 1138 } 1139 } 1140 PetscCall(PetscHSetIDestroy(&ht)); 1141 PetscCall(PetscHSetIDestroy(&cht)); 1142 1143 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numCells, cellsArray, PETSC_OWN_POINTER, &patch->cells)); 1144 PetscCall(PetscObjectSetName((PetscObject)patch->cells, "Patch Cells")); 1145 if (patch->viewCells) { 1146 PetscCall(ObjectView((PetscObject)patch->cellCounts, patch->viewerCells, patch->formatCells)); 1147 PetscCall(ObjectView((PetscObject)patch->cells, patch->viewerCells, patch->formatCells)); 1148 } 1149 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numIntFacets, intFacetsArray, PETSC_OWN_POINTER, &patch->intFacets)); 1150 PetscCall(PetscObjectSetName((PetscObject)patch->intFacets, "Patch Interior Facets")); 1151 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 2 * numIntFacets, intFacetsToPatchCell, PETSC_OWN_POINTER, &patch->intFacetsToPatchCell)); 1152 PetscCall(PetscObjectSetName((PetscObject)patch->intFacetsToPatchCell, "Patch Interior Facets local support")); 1153 if (patch->viewIntFacets) { 1154 PetscCall(ObjectView((PetscObject)patch->intFacetCounts, patch->viewerIntFacets, patch->formatIntFacets)); 1155 PetscCall(ObjectView((PetscObject)patch->intFacets, patch->viewerIntFacets, patch->formatIntFacets)); 1156 PetscCall(ObjectView((PetscObject)patch->intFacetsToPatchCell, patch->viewerIntFacets, patch->formatIntFacets)); 1157 } 1158 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numExtFacets, extFacetsArray, PETSC_OWN_POINTER, &patch->extFacets)); 1159 PetscCall(PetscObjectSetName((PetscObject)patch->extFacets, "Patch Exterior Facets")); 1160 if (patch->viewExtFacets) { 1161 PetscCall(ObjectView((PetscObject)patch->extFacetCounts, patch->viewerExtFacets, patch->formatExtFacets)); 1162 PetscCall(ObjectView((PetscObject)patch->extFacets, patch->viewerExtFacets, patch->formatExtFacets)); 1163 } 1164 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numPoints, pointsArray, PETSC_OWN_POINTER, &patch->points)); 1165 PetscCall(PetscObjectSetName((PetscObject)patch->points, "Patch Points")); 1166 if (patch->viewPoints) { 1167 PetscCall(ObjectView((PetscObject)patch->pointCounts, patch->viewerPoints, patch->formatPoints)); 1168 PetscCall(ObjectView((PetscObject)patch->points, patch->viewerPoints, patch->formatPoints)); 1169 } 1170 PetscCall(DMDestroy(&dm)); 1171 PetscFunctionReturn(PETSC_SUCCESS); 1172 } 1173 1174 /* 1175 PCPatchCreateCellPatchDiscretisationInfo - Build the dof maps for cell patches 1176 1177 Input Parameters: 1178 + dm - The DMPlex object defining the mesh 1179 . cellCounts - Section with counts of cells around each vertex 1180 . cells - IS of the cell point indices of cells in each patch 1181 . cellNumbering - Section mapping plex cell points to Firedrake cell indices. 1182 . nodesPerCell - number of nodes per cell. 1183 - cellNodeMap - map from cells to node indices (nodesPerCell * numCells) 1184 1185 Output Parameters: 1186 + dofs - IS of local dof numbers of each cell in the patch, where local is a patch local numbering 1187 . gtolCounts - Section with counts of dofs per cell patch 1188 - gtol - IS mapping from global dofs to local dofs for each patch. 1189 */ 1190 static PetscErrorCode PCPatchCreateCellPatchDiscretisationInfo(PC pc) 1191 { 1192 PC_PATCH *patch = (PC_PATCH *)pc->data; 1193 PetscSection cellCounts = patch->cellCounts; 1194 PetscSection pointCounts = patch->pointCounts; 1195 PetscSection gtolCounts, gtolCountsWithArtificial = NULL, gtolCountsWithAll = NULL; 1196 IS cells = patch->cells; 1197 IS points = patch->points; 1198 PetscSection cellNumbering = patch->cellNumbering; 1199 PetscInt Nf = patch->nsubspaces; 1200 PetscInt numCells, numPoints; 1201 PetscInt numDofs; 1202 PetscInt numGlobalDofs, numGlobalDofsWithArtificial, numGlobalDofsWithAll; 1203 PetscInt totalDofsPerCell = patch->totalDofsPerCell; 1204 PetscInt vStart, vEnd, v; 1205 const PetscInt *cellsArray, *pointsArray; 1206 PetscInt *newCellsArray = NULL; 1207 PetscInt *dofsArray = NULL; 1208 PetscInt *dofsArrayWithArtificial = NULL; 1209 PetscInt *dofsArrayWithAll = NULL; 1210 PetscInt *offsArray = NULL; 1211 PetscInt *offsArrayWithArtificial = NULL; 1212 PetscInt *offsArrayWithAll = NULL; 1213 PetscInt *asmArray = NULL; 1214 PetscInt *asmArrayWithArtificial = NULL; 1215 PetscInt *asmArrayWithAll = NULL; 1216 PetscInt *globalDofsArray = NULL; 1217 PetscInt *globalDofsArrayWithArtificial = NULL; 1218 PetscInt *globalDofsArrayWithAll = NULL; 1219 PetscInt globalIndex = 0; 1220 PetscInt key = 0; 1221 PetscInt asmKey = 0; 1222 DM dm = NULL, plex; 1223 const PetscInt *bcNodes = NULL; 1224 PetscHMapI ht; 1225 PetscHMapI htWithArtificial; 1226 PetscHMapI htWithAll; 1227 PetscHSetI globalBcs; 1228 PetscInt numBcs; 1229 PetscHSetI ownedpts, seenpts, owneddofs, seendofs, artificialbcs; 1230 PetscInt pStart, pEnd, p, i; 1231 char option[PETSC_MAX_PATH_LEN]; 1232 PetscBool isNonlinear; 1233 1234 PetscFunctionBegin; 1235 PetscCall(PCGetDM(pc, &dm)); 1236 PetscCall(DMConvert(dm, DMPLEX, &plex)); 1237 dm = plex; 1238 /* dofcounts section is cellcounts section * dofPerCell */ 1239 PetscCall(PetscSectionGetStorageSize(cellCounts, &numCells)); 1240 PetscCall(PetscSectionGetStorageSize(patch->pointCounts, &numPoints)); 1241 numDofs = numCells * totalDofsPerCell; 1242 PetscCall(PetscMalloc1(numDofs, &dofsArray)); 1243 PetscCall(PetscMalloc1(numPoints * Nf, &offsArray)); 1244 PetscCall(PetscMalloc1(numDofs, &asmArray)); 1245 PetscCall(PetscMalloc1(numCells, &newCellsArray)); 1246 PetscCall(PetscSectionGetChart(cellCounts, &vStart, &vEnd)); 1247 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->gtolCounts)); 1248 gtolCounts = patch->gtolCounts; 1249 PetscCall(PetscSectionSetChart(gtolCounts, vStart, vEnd)); 1250 PetscCall(PetscObjectSetName((PetscObject)patch->gtolCounts, "Patch Global Index Section")); 1251 1252 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 1253 PetscCall(PetscMalloc1(numPoints * Nf, &offsArrayWithArtificial)); 1254 PetscCall(PetscMalloc1(numDofs, &asmArrayWithArtificial)); 1255 PetscCall(PetscMalloc1(numDofs, &dofsArrayWithArtificial)); 1256 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->gtolCountsWithArtificial)); 1257 gtolCountsWithArtificial = patch->gtolCountsWithArtificial; 1258 PetscCall(PetscSectionSetChart(gtolCountsWithArtificial, vStart, vEnd)); 1259 PetscCall(PetscObjectSetName((PetscObject)patch->gtolCountsWithArtificial, "Patch Global Index Section Including Artificial BCs")); 1260 } 1261 1262 isNonlinear = patch->isNonlinear; 1263 if (isNonlinear) { 1264 PetscCall(PetscMalloc1(numPoints * Nf, &offsArrayWithAll)); 1265 PetscCall(PetscMalloc1(numDofs, &asmArrayWithAll)); 1266 PetscCall(PetscMalloc1(numDofs, &dofsArrayWithAll)); 1267 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->gtolCountsWithAll)); 1268 gtolCountsWithAll = patch->gtolCountsWithAll; 1269 PetscCall(PetscSectionSetChart(gtolCountsWithAll, vStart, vEnd)); 1270 PetscCall(PetscObjectSetName((PetscObject)patch->gtolCountsWithAll, "Patch Global Index Section Including All BCs")); 1271 } 1272 1273 /* Outside the patch loop, get the dofs that are globally-enforced Dirichlet 1274 conditions */ 1275 PetscCall(PetscHSetICreate(&globalBcs)); 1276 PetscCall(ISGetIndices(patch->ghostBcNodes, &bcNodes)); 1277 PetscCall(ISGetSize(patch->ghostBcNodes, &numBcs)); 1278 for (i = 0; i < numBcs; ++i) { PetscCall(PetscHSetIAdd(globalBcs, bcNodes[i])); /* these are already in concatenated numbering */ } 1279 PetscCall(ISRestoreIndices(patch->ghostBcNodes, &bcNodes)); 1280 PetscCall(ISDestroy(&patch->ghostBcNodes)); /* memory optimisation */ 1281 1282 /* Hash tables for artificial BC construction */ 1283 PetscCall(PetscHSetICreate(&ownedpts)); 1284 PetscCall(PetscHSetICreate(&seenpts)); 1285 PetscCall(PetscHSetICreate(&owneddofs)); 1286 PetscCall(PetscHSetICreate(&seendofs)); 1287 PetscCall(PetscHSetICreate(&artificialbcs)); 1288 1289 PetscCall(ISGetIndices(cells, &cellsArray)); 1290 PetscCall(ISGetIndices(points, &pointsArray)); 1291 PetscCall(PetscHMapICreate(&ht)); 1292 PetscCall(PetscHMapICreate(&htWithArtificial)); 1293 PetscCall(PetscHMapICreate(&htWithAll)); 1294 for (v = vStart; v < vEnd; ++v) { 1295 PetscInt localIndex = 0; 1296 PetscInt localIndexWithArtificial = 0; 1297 PetscInt localIndexWithAll = 0; 1298 PetscInt dof, off, i, j, k, l; 1299 1300 PetscCall(PetscHMapIClear(ht)); 1301 PetscCall(PetscHMapIClear(htWithArtificial)); 1302 PetscCall(PetscHMapIClear(htWithAll)); 1303 PetscCall(PetscSectionGetDof(cellCounts, v, &dof)); 1304 PetscCall(PetscSectionGetOffset(cellCounts, v, &off)); 1305 if (dof <= 0) continue; 1306 1307 /* Calculate the global numbers of the artificial BC dofs here first */ 1308 PetscCall(patch->patchconstructop((void *)patch, dm, v, ownedpts)); 1309 PetscCall(PCPatchCompleteCellPatch(pc, ownedpts, seenpts)); 1310 PetscCall(PCPatchGetPointDofs(pc, ownedpts, owneddofs, v, &patch->subspaces_to_exclude)); 1311 PetscCall(PCPatchGetPointDofs(pc, seenpts, seendofs, v, NULL)); 1312 PetscCall(PCPatchComputeSetDifference_Private(owneddofs, seendofs, artificialbcs)); 1313 if (patch->viewPatches) { 1314 PetscHSetI globalbcdofs; 1315 PetscHashIter hi; 1316 MPI_Comm comm = PetscObjectComm((PetscObject)pc); 1317 1318 PetscCall(PetscHSetICreate(&globalbcdofs)); 1319 PetscCall(PetscSynchronizedPrintf(comm, "Patch %" PetscInt_FMT ": owned dofs:\n", v)); 1320 PetscHashIterBegin(owneddofs, hi); 1321 while (!PetscHashIterAtEnd(owneddofs, hi)) { 1322 PetscInt globalDof; 1323 1324 PetscHashIterGetKey(owneddofs, hi, globalDof); 1325 PetscHashIterNext(owneddofs, hi); 1326 PetscCall(PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", globalDof)); 1327 } 1328 PetscCall(PetscSynchronizedPrintf(comm, "\n")); 1329 PetscCall(PetscSynchronizedPrintf(comm, "Patch %" PetscInt_FMT ": seen dofs:\n", v)); 1330 PetscHashIterBegin(seendofs, hi); 1331 while (!PetscHashIterAtEnd(seendofs, hi)) { 1332 PetscInt globalDof; 1333 PetscBool flg; 1334 1335 PetscHashIterGetKey(seendofs, hi, globalDof); 1336 PetscHashIterNext(seendofs, hi); 1337 PetscCall(PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", globalDof)); 1338 1339 PetscCall(PetscHSetIHas(globalBcs, globalDof, &flg)); 1340 if (flg) PetscCall(PetscHSetIAdd(globalbcdofs, globalDof)); 1341 } 1342 PetscCall(PetscSynchronizedPrintf(comm, "\n")); 1343 PetscCall(PetscSynchronizedPrintf(comm, "Patch %" PetscInt_FMT ": global BCs:\n", v)); 1344 PetscCall(PetscHSetIGetSize(globalbcdofs, &numBcs)); 1345 if (numBcs > 0) { 1346 PetscHashIterBegin(globalbcdofs, hi); 1347 while (!PetscHashIterAtEnd(globalbcdofs, hi)) { 1348 PetscInt globalDof; 1349 PetscHashIterGetKey(globalbcdofs, hi, globalDof); 1350 PetscHashIterNext(globalbcdofs, hi); 1351 PetscCall(PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", globalDof)); 1352 } 1353 } 1354 PetscCall(PetscSynchronizedPrintf(comm, "\n")); 1355 PetscCall(PetscSynchronizedPrintf(comm, "Patch %" PetscInt_FMT ": artificial BCs:\n", v)); 1356 PetscCall(PetscHSetIGetSize(artificialbcs, &numBcs)); 1357 if (numBcs > 0) { 1358 PetscHashIterBegin(artificialbcs, hi); 1359 while (!PetscHashIterAtEnd(artificialbcs, hi)) { 1360 PetscInt globalDof; 1361 PetscHashIterGetKey(artificialbcs, hi, globalDof); 1362 PetscHashIterNext(artificialbcs, hi); 1363 PetscCall(PetscSynchronizedPrintf(comm, "%" PetscInt_FMT " ", globalDof)); 1364 } 1365 } 1366 PetscCall(PetscSynchronizedPrintf(comm, "\n\n")); 1367 PetscCall(PetscHSetIDestroy(&globalbcdofs)); 1368 } 1369 for (k = 0; k < patch->nsubspaces; ++k) { 1370 const PetscInt *cellNodeMap = patch->cellNodeMap[k]; 1371 PetscInt nodesPerCell = patch->nodesPerCell[k]; 1372 PetscInt subspaceOffset = patch->subspaceOffsets[k]; 1373 PetscInt bs = patch->bs[k]; 1374 1375 for (i = off; i < off + dof; ++i) { 1376 /* Walk over the cells in this patch. */ 1377 const PetscInt c = cellsArray[i]; 1378 PetscInt cell = c; 1379 1380 /* TODO Change this to an IS */ 1381 if (cellNumbering) { 1382 PetscCall(PetscSectionGetDof(cellNumbering, c, &cell)); 1383 PetscCheck(cell > 0, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " doesn't appear in cell numbering map", c); 1384 PetscCall(PetscSectionGetOffset(cellNumbering, c, &cell)); 1385 } 1386 newCellsArray[i] = cell; 1387 for (j = 0; j < nodesPerCell; ++j) { 1388 /* For each global dof, map it into contiguous local storage. */ 1389 const PetscInt globalDof = cellNodeMap[cell * nodesPerCell + j] * bs + subspaceOffset; 1390 /* finally, loop over block size */ 1391 for (l = 0; l < bs; ++l) { 1392 PetscInt localDof; 1393 PetscBool isGlobalBcDof, isArtificialBcDof; 1394 1395 /* first, check if this is either a globally enforced or locally enforced BC dof */ 1396 PetscCall(PetscHSetIHas(globalBcs, globalDof + l, &isGlobalBcDof)); 1397 PetscCall(PetscHSetIHas(artificialbcs, globalDof + l, &isArtificialBcDof)); 1398 1399 /* if it's either, don't ever give it a local dof number */ 1400 if (isGlobalBcDof || isArtificialBcDof) { 1401 dofsArray[globalIndex] = -1; /* don't use this in assembly in this patch */ 1402 } else { 1403 PetscCall(PetscHMapIGet(ht, globalDof + l, &localDof)); 1404 if (localDof == -1) { 1405 localDof = localIndex++; 1406 PetscCall(PetscHMapISet(ht, globalDof + l, localDof)); 1407 } 1408 PetscCheck(globalIndex < numDofs, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Found more dofs %" PetscInt_FMT " than expected %" PetscInt_FMT, globalIndex + 1, numDofs); 1409 /* And store. */ 1410 dofsArray[globalIndex] = localDof; 1411 } 1412 1413 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 1414 if (isGlobalBcDof) { 1415 dofsArrayWithArtificial[globalIndex] = -1; /* don't use this in assembly in this patch */ 1416 } else { 1417 PetscCall(PetscHMapIGet(htWithArtificial, globalDof + l, &localDof)); 1418 if (localDof == -1) { 1419 localDof = localIndexWithArtificial++; 1420 PetscCall(PetscHMapISet(htWithArtificial, globalDof + l, localDof)); 1421 } 1422 PetscCheck(globalIndex < numDofs, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Found more dofs %" PetscInt_FMT " than expected %" PetscInt_FMT, globalIndex + 1, numDofs); 1423 /* And store.*/ 1424 dofsArrayWithArtificial[globalIndex] = localDof; 1425 } 1426 } 1427 1428 if (isNonlinear) { 1429 /* Build the dofmap for the function space with _all_ dofs, 1430 including those in any kind of boundary condition */ 1431 PetscCall(PetscHMapIGet(htWithAll, globalDof + l, &localDof)); 1432 if (localDof == -1) { 1433 localDof = localIndexWithAll++; 1434 PetscCall(PetscHMapISet(htWithAll, globalDof + l, localDof)); 1435 } 1436 PetscCheck(globalIndex < numDofs, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Found more dofs %" PetscInt_FMT " than expected %" PetscInt_FMT, globalIndex + 1, numDofs); 1437 /* And store.*/ 1438 dofsArrayWithAll[globalIndex] = localDof; 1439 } 1440 globalIndex++; 1441 } 1442 } 1443 } 1444 } 1445 /* How many local dofs in this patch? */ 1446 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 1447 PetscCall(PetscHMapIGetSize(htWithArtificial, &dof)); 1448 PetscCall(PetscSectionSetDof(gtolCountsWithArtificial, v, dof)); 1449 } 1450 if (isNonlinear) { 1451 PetscCall(PetscHMapIGetSize(htWithAll, &dof)); 1452 PetscCall(PetscSectionSetDof(gtolCountsWithAll, v, dof)); 1453 } 1454 PetscCall(PetscHMapIGetSize(ht, &dof)); 1455 PetscCall(PetscSectionSetDof(gtolCounts, v, dof)); 1456 } 1457 1458 PetscCall(DMDestroy(&dm)); 1459 PetscCheck(globalIndex == numDofs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Expected number of dofs (%" PetscInt_FMT ") doesn't match found number (%" PetscInt_FMT ")", numDofs, globalIndex); 1460 PetscCall(PetscSectionSetUp(gtolCounts)); 1461 PetscCall(PetscSectionGetStorageSize(gtolCounts, &numGlobalDofs)); 1462 PetscCall(PetscMalloc1(numGlobalDofs, &globalDofsArray)); 1463 1464 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 1465 PetscCall(PetscSectionSetUp(gtolCountsWithArtificial)); 1466 PetscCall(PetscSectionGetStorageSize(gtolCountsWithArtificial, &numGlobalDofsWithArtificial)); 1467 PetscCall(PetscMalloc1(numGlobalDofsWithArtificial, &globalDofsArrayWithArtificial)); 1468 } 1469 if (isNonlinear) { 1470 PetscCall(PetscSectionSetUp(gtolCountsWithAll)); 1471 PetscCall(PetscSectionGetStorageSize(gtolCountsWithAll, &numGlobalDofsWithAll)); 1472 PetscCall(PetscMalloc1(numGlobalDofsWithAll, &globalDofsArrayWithAll)); 1473 } 1474 /* Now populate the global to local map. This could be merged into the above loop if we were willing to deal with reallocs. */ 1475 for (v = vStart; v < vEnd; ++v) { 1476 PetscHashIter hi; 1477 PetscInt dof, off, Np, ooff, i, j, k, l; 1478 1479 PetscCall(PetscHMapIClear(ht)); 1480 PetscCall(PetscHMapIClear(htWithArtificial)); 1481 PetscCall(PetscHMapIClear(htWithAll)); 1482 PetscCall(PetscSectionGetDof(cellCounts, v, &dof)); 1483 PetscCall(PetscSectionGetOffset(cellCounts, v, &off)); 1484 PetscCall(PetscSectionGetDof(pointCounts, v, &Np)); 1485 PetscCall(PetscSectionGetOffset(pointCounts, v, &ooff)); 1486 if (dof <= 0) continue; 1487 1488 for (k = 0; k < patch->nsubspaces; ++k) { 1489 const PetscInt *cellNodeMap = patch->cellNodeMap[k]; 1490 PetscInt nodesPerCell = patch->nodesPerCell[k]; 1491 PetscInt subspaceOffset = patch->subspaceOffsets[k]; 1492 PetscInt bs = patch->bs[k]; 1493 PetscInt goff; 1494 1495 for (i = off; i < off + dof; ++i) { 1496 /* Reconstruct mapping of global-to-local on this patch. */ 1497 const PetscInt c = cellsArray[i]; 1498 PetscInt cell = c; 1499 1500 if (cellNumbering) PetscCall(PetscSectionGetOffset(cellNumbering, c, &cell)); 1501 for (j = 0; j < nodesPerCell; ++j) { 1502 for (l = 0; l < bs; ++l) { 1503 const PetscInt globalDof = cellNodeMap[cell * nodesPerCell + j] * bs + l + subspaceOffset; 1504 const PetscInt localDof = dofsArray[key]; 1505 if (localDof >= 0) PetscCall(PetscHMapISet(ht, globalDof, localDof)); 1506 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 1507 const PetscInt localDofWithArtificial = dofsArrayWithArtificial[key]; 1508 if (localDofWithArtificial >= 0) PetscCall(PetscHMapISet(htWithArtificial, globalDof, localDofWithArtificial)); 1509 } 1510 if (isNonlinear) { 1511 const PetscInt localDofWithAll = dofsArrayWithAll[key]; 1512 if (localDofWithAll >= 0) PetscCall(PetscHMapISet(htWithAll, globalDof, localDofWithAll)); 1513 } 1514 key++; 1515 } 1516 } 1517 } 1518 1519 /* Shove it in the output data structure. */ 1520 PetscCall(PetscSectionGetOffset(gtolCounts, v, &goff)); 1521 PetscHashIterBegin(ht, hi); 1522 while (!PetscHashIterAtEnd(ht, hi)) { 1523 PetscInt globalDof, localDof; 1524 1525 PetscHashIterGetKey(ht, hi, globalDof); 1526 PetscHashIterGetVal(ht, hi, localDof); 1527 if (globalDof >= 0) globalDofsArray[goff + localDof] = globalDof; 1528 PetscHashIterNext(ht, hi); 1529 } 1530 1531 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 1532 PetscCall(PetscSectionGetOffset(gtolCountsWithArtificial, v, &goff)); 1533 PetscHashIterBegin(htWithArtificial, hi); 1534 while (!PetscHashIterAtEnd(htWithArtificial, hi)) { 1535 PetscInt globalDof, localDof; 1536 PetscHashIterGetKey(htWithArtificial, hi, globalDof); 1537 PetscHashIterGetVal(htWithArtificial, hi, localDof); 1538 if (globalDof >= 0) globalDofsArrayWithArtificial[goff + localDof] = globalDof; 1539 PetscHashIterNext(htWithArtificial, hi); 1540 } 1541 } 1542 if (isNonlinear) { 1543 PetscCall(PetscSectionGetOffset(gtolCountsWithAll, v, &goff)); 1544 PetscHashIterBegin(htWithAll, hi); 1545 while (!PetscHashIterAtEnd(htWithAll, hi)) { 1546 PetscInt globalDof, localDof; 1547 PetscHashIterGetKey(htWithAll, hi, globalDof); 1548 PetscHashIterGetVal(htWithAll, hi, localDof); 1549 if (globalDof >= 0) globalDofsArrayWithAll[goff + localDof] = globalDof; 1550 PetscHashIterNext(htWithAll, hi); 1551 } 1552 } 1553 1554 for (p = 0; p < Np; ++p) { 1555 const PetscInt point = pointsArray[ooff + p]; 1556 PetscInt globalDof, localDof; 1557 1558 PetscCall(PCPatchGetGlobalDofs(pc, patch->dofSection, k, patch->combined, point, NULL, &globalDof)); 1559 PetscCall(PetscHMapIGet(ht, globalDof, &localDof)); 1560 offsArray[(ooff + p) * Nf + k] = localDof; 1561 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 1562 PetscCall(PetscHMapIGet(htWithArtificial, globalDof, &localDof)); 1563 offsArrayWithArtificial[(ooff + p) * Nf + k] = localDof; 1564 } 1565 if (isNonlinear) { 1566 PetscCall(PetscHMapIGet(htWithAll, globalDof, &localDof)); 1567 offsArrayWithAll[(ooff + p) * Nf + k] = localDof; 1568 } 1569 } 1570 } 1571 1572 PetscCall(PetscHSetIDestroy(&globalBcs)); 1573 PetscCall(PetscHSetIDestroy(&ownedpts)); 1574 PetscCall(PetscHSetIDestroy(&seenpts)); 1575 PetscCall(PetscHSetIDestroy(&owneddofs)); 1576 PetscCall(PetscHSetIDestroy(&seendofs)); 1577 PetscCall(PetscHSetIDestroy(&artificialbcs)); 1578 1579 /* At this point, we have a hash table ht built that maps globalDof -> localDof. 1580 We need to create the dof table laid out cellwise first, then by subspace, 1581 as the assembler assembles cell-wise and we need to stuff the different 1582 contributions of the different function spaces to the right places. So we loop 1583 over cells, then over subspaces. */ 1584 if (patch->nsubspaces > 1) { /* for nsubspaces = 1, data we need is already in dofsArray */ 1585 for (i = off; i < off + dof; ++i) { 1586 const PetscInt c = cellsArray[i]; 1587 PetscInt cell = c; 1588 1589 if (cellNumbering) PetscCall(PetscSectionGetOffset(cellNumbering, c, &cell)); 1590 for (k = 0; k < patch->nsubspaces; ++k) { 1591 const PetscInt *cellNodeMap = patch->cellNodeMap[k]; 1592 PetscInt nodesPerCell = patch->nodesPerCell[k]; 1593 PetscInt subspaceOffset = patch->subspaceOffsets[k]; 1594 PetscInt bs = patch->bs[k]; 1595 1596 for (j = 0; j < nodesPerCell; ++j) { 1597 for (l = 0; l < bs; ++l) { 1598 const PetscInt globalDof = cellNodeMap[cell * nodesPerCell + j] * bs + l + subspaceOffset; 1599 PetscInt localDof; 1600 1601 PetscCall(PetscHMapIGet(ht, globalDof, &localDof)); 1602 /* If it's not in the hash table, i.e. is a BC dof, 1603 then the PetscHSetIMap above gives -1, which matches 1604 exactly the convention for PETSc's matrix assembly to 1605 ignore the dof. So we don't need to do anything here */ 1606 asmArray[asmKey] = localDof; 1607 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 1608 PetscCall(PetscHMapIGet(htWithArtificial, globalDof, &localDof)); 1609 asmArrayWithArtificial[asmKey] = localDof; 1610 } 1611 if (isNonlinear) { 1612 PetscCall(PetscHMapIGet(htWithAll, globalDof, &localDof)); 1613 asmArrayWithAll[asmKey] = localDof; 1614 } 1615 asmKey++; 1616 } 1617 } 1618 } 1619 } 1620 } 1621 } 1622 if (1 == patch->nsubspaces) { 1623 PetscCall(PetscArraycpy(asmArray, dofsArray, numDofs)); 1624 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) PetscCall(PetscArraycpy(asmArrayWithArtificial, dofsArrayWithArtificial, numDofs)); 1625 if (isNonlinear) PetscCall(PetscArraycpy(asmArrayWithAll, dofsArrayWithAll, numDofs)); 1626 } 1627 1628 PetscCall(PetscHMapIDestroy(&ht)); 1629 PetscCall(PetscHMapIDestroy(&htWithArtificial)); 1630 PetscCall(PetscHMapIDestroy(&htWithAll)); 1631 PetscCall(ISRestoreIndices(cells, &cellsArray)); 1632 PetscCall(ISRestoreIndices(points, &pointsArray)); 1633 PetscCall(PetscFree(dofsArray)); 1634 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) PetscCall(PetscFree(dofsArrayWithArtificial)); 1635 if (isNonlinear) PetscCall(PetscFree(dofsArrayWithAll)); 1636 /* Create placeholder section for map from points to patch dofs */ 1637 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &patch->patchSection)); 1638 PetscCall(PetscSectionSetNumFields(patch->patchSection, patch->nsubspaces)); 1639 if (patch->combined) { 1640 PetscInt numFields; 1641 PetscCall(PetscSectionGetNumFields(patch->dofSection[0], &numFields)); 1642 PetscCheck(numFields == patch->nsubspaces, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Mismatch between number of section fields %" PetscInt_FMT " and number of subspaces %" PetscInt_FMT, numFields, patch->nsubspaces); 1643 PetscCall(PetscSectionGetChart(patch->dofSection[0], &pStart, &pEnd)); 1644 PetscCall(PetscSectionSetChart(patch->patchSection, pStart, pEnd)); 1645 for (p = pStart; p < pEnd; ++p) { 1646 PetscInt dof, fdof, f; 1647 1648 PetscCall(PetscSectionGetDof(patch->dofSection[0], p, &dof)); 1649 PetscCall(PetscSectionSetDof(patch->patchSection, p, dof)); 1650 for (f = 0; f < patch->nsubspaces; ++f) { 1651 PetscCall(PetscSectionGetFieldDof(patch->dofSection[0], p, f, &fdof)); 1652 PetscCall(PetscSectionSetFieldDof(patch->patchSection, p, f, fdof)); 1653 } 1654 } 1655 } else { 1656 PetscInt pStartf, pEndf, f; 1657 pStart = PETSC_INT_MAX; 1658 pEnd = PETSC_INT_MIN; 1659 for (f = 0; f < patch->nsubspaces; ++f) { 1660 PetscCall(PetscSectionGetChart(patch->dofSection[f], &pStartf, &pEndf)); 1661 pStart = PetscMin(pStart, pStartf); 1662 pEnd = PetscMax(pEnd, pEndf); 1663 } 1664 PetscCall(PetscSectionSetChart(patch->patchSection, pStart, pEnd)); 1665 for (f = 0; f < patch->nsubspaces; ++f) { 1666 PetscCall(PetscSectionGetChart(patch->dofSection[f], &pStartf, &pEndf)); 1667 for (p = pStartf; p < pEndf; ++p) { 1668 PetscInt fdof; 1669 PetscCall(PetscSectionGetDof(patch->dofSection[f], p, &fdof)); 1670 PetscCall(PetscSectionAddDof(patch->patchSection, p, fdof)); 1671 PetscCall(PetscSectionSetFieldDof(patch->patchSection, p, f, fdof)); 1672 } 1673 } 1674 } 1675 PetscCall(PetscSectionSetUp(patch->patchSection)); 1676 PetscCall(PetscSectionSetUseFieldOffsets(patch->patchSection, PETSC_TRUE)); 1677 /* Replace cell indices with firedrake-numbered ones. */ 1678 PetscCall(ISGeneralSetIndices(cells, numCells, (const PetscInt *)newCellsArray, PETSC_OWN_POINTER)); 1679 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGlobalDofs, globalDofsArray, PETSC_OWN_POINTER, &patch->gtol)); 1680 PetscCall(PetscObjectSetName((PetscObject)patch->gtol, "Global Indices")); 1681 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_g2l_view", patch->classname)); 1682 PetscCall(PetscSectionViewFromOptions(patch->gtolCounts, (PetscObject)pc, option)); 1683 PetscCall(ISViewFromOptions(patch->gtol, (PetscObject)pc, option)); 1684 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numDofs, asmArray, PETSC_OWN_POINTER, &patch->dofs)); 1685 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numPoints * Nf, offsArray, PETSC_OWN_POINTER, &patch->offs)); 1686 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 1687 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGlobalDofsWithArtificial, globalDofsArrayWithArtificial, PETSC_OWN_POINTER, &patch->gtolWithArtificial)); 1688 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numDofs, asmArrayWithArtificial, PETSC_OWN_POINTER, &patch->dofsWithArtificial)); 1689 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numPoints * Nf, offsArrayWithArtificial, PETSC_OWN_POINTER, &patch->offsWithArtificial)); 1690 } 1691 if (isNonlinear) { 1692 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numGlobalDofsWithAll, globalDofsArrayWithAll, PETSC_OWN_POINTER, &patch->gtolWithAll)); 1693 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numDofs, asmArrayWithAll, PETSC_OWN_POINTER, &patch->dofsWithAll)); 1694 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numPoints * Nf, offsArrayWithAll, PETSC_OWN_POINTER, &patch->offsWithAll)); 1695 } 1696 PetscFunctionReturn(PETSC_SUCCESS); 1697 } 1698 1699 static PetscErrorCode PCPatchCreateMatrix_Private(PC pc, PetscInt point, Mat *mat, PetscBool withArtificial) 1700 { 1701 PC_PATCH *patch = (PC_PATCH *)pc->data; 1702 PetscBool flg; 1703 PetscInt csize, rsize; 1704 const char *prefix = NULL; 1705 1706 PetscFunctionBegin; 1707 if (withArtificial) { 1708 /* would be nice if we could create a rectangular matrix of size numDofsWithArtificial x numDofs here */ 1709 PetscInt pStart; 1710 PetscCall(PetscSectionGetChart(patch->gtolCountsWithArtificial, &pStart, NULL)); 1711 PetscCall(PetscSectionGetDof(patch->gtolCountsWithArtificial, point + pStart, &rsize)); 1712 csize = rsize; 1713 } else { 1714 PetscInt pStart; 1715 PetscCall(PetscSectionGetChart(patch->gtolCounts, &pStart, NULL)); 1716 PetscCall(PetscSectionGetDof(patch->gtolCounts, point + pStart, &rsize)); 1717 csize = rsize; 1718 } 1719 1720 PetscCall(MatCreate(PETSC_COMM_SELF, mat)); 1721 PetscCall(PCGetOptionsPrefix(pc, &prefix)); 1722 PetscCall(MatSetOptionsPrefix(*mat, prefix)); 1723 PetscCall(MatAppendOptionsPrefix(*mat, "pc_patch_sub_")); 1724 if (patch->sub_mat_type) PetscCall(MatSetType(*mat, patch->sub_mat_type)); 1725 else if (!patch->sub_mat_type) PetscCall(MatSetType(*mat, MATDENSE)); 1726 PetscCall(MatSetSizes(*mat, rsize, csize, rsize, csize)); 1727 PetscCall(PetscObjectTypeCompare((PetscObject)*mat, MATDENSE, &flg)); 1728 if (!flg) PetscCall(PetscObjectTypeCompare((PetscObject)*mat, MATSEQDENSE, &flg)); 1729 /* Sparse patch matrices */ 1730 if (!flg) { 1731 PetscBT bt; 1732 PetscInt *dnnz = NULL; 1733 const PetscInt *dofsArray = NULL; 1734 PetscInt pStart, pEnd, ncell, offset, c, i, j; 1735 1736 if (withArtificial) { 1737 PetscCall(ISGetIndices(patch->dofsWithArtificial, &dofsArray)); 1738 } else { 1739 PetscCall(ISGetIndices(patch->dofs, &dofsArray)); 1740 } 1741 PetscCall(PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd)); 1742 point += pStart; 1743 PetscCheck(point < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Operator point %" PetscInt_FMT " not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, pStart, pEnd); 1744 PetscCall(PetscSectionGetDof(patch->cellCounts, point, &ncell)); 1745 PetscCall(PetscSectionGetOffset(patch->cellCounts, point, &offset)); 1746 PetscCall(PetscLogEventBegin(PC_Patch_Prealloc, pc, 0, 0, 0)); 1747 /* A PetscBT uses N^2 bits to store the sparsity pattern on a 1748 * patch. This is probably OK if the patches are not too big, 1749 * but uses too much memory. We therefore switch based on rsize. */ 1750 if (rsize < 3000) { /* FIXME: I picked this switch value out of my hat */ 1751 PetscScalar *zeroes; 1752 PetscInt rows; 1753 1754 PetscCall(PetscCalloc1(rsize, &dnnz)); 1755 PetscCall(PetscBTCreate(rsize * rsize, &bt)); 1756 for (c = 0; c < ncell; ++c) { 1757 const PetscInt *idx = dofsArray + (offset + c) * patch->totalDofsPerCell; 1758 for (i = 0; i < patch->totalDofsPerCell; ++i) { 1759 const PetscInt row = idx[i]; 1760 if (row < 0) continue; 1761 for (j = 0; j < patch->totalDofsPerCell; ++j) { 1762 const PetscInt col = idx[j]; 1763 const PetscInt key = row * rsize + col; 1764 if (col < 0) continue; 1765 if (!PetscBTLookupSet(bt, key)) ++dnnz[row]; 1766 } 1767 } 1768 } 1769 1770 if (patch->usercomputeopintfacet) { 1771 const PetscInt *intFacetsArray = NULL; 1772 PetscInt i, numIntFacets, intFacetOffset; 1773 const PetscInt *facetCells = NULL; 1774 1775 PetscCall(PetscSectionGetDof(patch->intFacetCounts, point, &numIntFacets)); 1776 PetscCall(PetscSectionGetOffset(patch->intFacetCounts, point, &intFacetOffset)); 1777 PetscCall(ISGetIndices(patch->intFacetsToPatchCell, &facetCells)); 1778 PetscCall(ISGetIndices(patch->intFacets, &intFacetsArray)); 1779 for (i = 0; i < numIntFacets; i++) { 1780 const PetscInt cell0 = facetCells[2 * (intFacetOffset + i) + 0]; 1781 const PetscInt cell1 = facetCells[2 * (intFacetOffset + i) + 1]; 1782 PetscInt celli, cellj; 1783 1784 for (celli = 0; celli < patch->totalDofsPerCell; celli++) { 1785 const PetscInt row = dofsArray[(offset + cell0) * patch->totalDofsPerCell + celli]; 1786 if (row < 0) continue; 1787 for (cellj = 0; cellj < patch->totalDofsPerCell; cellj++) { 1788 const PetscInt col = dofsArray[(offset + cell1) * patch->totalDofsPerCell + cellj]; 1789 const PetscInt key = row * rsize + col; 1790 if (col < 0) continue; 1791 if (!PetscBTLookupSet(bt, key)) ++dnnz[row]; 1792 } 1793 } 1794 1795 for (celli = 0; celli < patch->totalDofsPerCell; celli++) { 1796 const PetscInt row = dofsArray[(offset + cell1) * patch->totalDofsPerCell + celli]; 1797 if (row < 0) continue; 1798 for (cellj = 0; cellj < patch->totalDofsPerCell; cellj++) { 1799 const PetscInt col = dofsArray[(offset + cell0) * patch->totalDofsPerCell + cellj]; 1800 const PetscInt key = row * rsize + col; 1801 if (col < 0) continue; 1802 if (!PetscBTLookupSet(bt, key)) ++dnnz[row]; 1803 } 1804 } 1805 } 1806 } 1807 PetscCall(PetscBTDestroy(&bt)); 1808 PetscCall(MatXAIJSetPreallocation(*mat, 1, dnnz, NULL, NULL, NULL)); 1809 PetscCall(PetscFree(dnnz)); 1810 1811 PetscCall(PetscCalloc1(patch->totalDofsPerCell * patch->totalDofsPerCell, &zeroes)); 1812 for (c = 0; c < ncell; ++c) { 1813 const PetscInt *idx = &dofsArray[(offset + c) * patch->totalDofsPerCell]; 1814 PetscCall(MatSetValues(*mat, patch->totalDofsPerCell, idx, patch->totalDofsPerCell, idx, zeroes, INSERT_VALUES)); 1815 } 1816 PetscCall(MatGetLocalSize(*mat, &rows, NULL)); 1817 for (i = 0; i < rows; ++i) PetscCall(MatSetValues(*mat, 1, &i, 1, &i, zeroes, INSERT_VALUES)); 1818 1819 if (patch->usercomputeopintfacet) { 1820 const PetscInt *intFacetsArray = NULL; 1821 PetscInt i, numIntFacets, intFacetOffset; 1822 const PetscInt *facetCells = NULL; 1823 1824 PetscCall(PetscSectionGetDof(patch->intFacetCounts, point, &numIntFacets)); 1825 PetscCall(PetscSectionGetOffset(patch->intFacetCounts, point, &intFacetOffset)); 1826 PetscCall(ISGetIndices(patch->intFacetsToPatchCell, &facetCells)); 1827 PetscCall(ISGetIndices(patch->intFacets, &intFacetsArray)); 1828 for (i = 0; i < numIntFacets; i++) { 1829 const PetscInt cell0 = facetCells[2 * (intFacetOffset + i) + 0]; 1830 const PetscInt cell1 = facetCells[2 * (intFacetOffset + i) + 1]; 1831 const PetscInt *cell0idx = &dofsArray[(offset + cell0) * patch->totalDofsPerCell]; 1832 const PetscInt *cell1idx = &dofsArray[(offset + cell1) * patch->totalDofsPerCell]; 1833 PetscCall(MatSetValues(*mat, patch->totalDofsPerCell, cell0idx, patch->totalDofsPerCell, cell1idx, zeroes, INSERT_VALUES)); 1834 PetscCall(MatSetValues(*mat, patch->totalDofsPerCell, cell1idx, patch->totalDofsPerCell, cell0idx, zeroes, INSERT_VALUES)); 1835 } 1836 } 1837 1838 PetscCall(MatAssemblyBegin(*mat, MAT_FINAL_ASSEMBLY)); 1839 PetscCall(MatAssemblyEnd(*mat, MAT_FINAL_ASSEMBLY)); 1840 1841 PetscCall(PetscFree(zeroes)); 1842 1843 } else { /* rsize too big, use MATPREALLOCATOR */ 1844 Mat preallocator; 1845 PetscScalar *vals; 1846 1847 PetscCall(PetscCalloc1(patch->totalDofsPerCell * patch->totalDofsPerCell, &vals)); 1848 PetscCall(MatCreate(PETSC_COMM_SELF, &preallocator)); 1849 PetscCall(MatSetType(preallocator, MATPREALLOCATOR)); 1850 PetscCall(MatSetSizes(preallocator, rsize, rsize, rsize, rsize)); 1851 PetscCall(MatSetUp(preallocator)); 1852 1853 for (c = 0; c < ncell; ++c) { 1854 const PetscInt *idx = dofsArray + (offset + c) * patch->totalDofsPerCell; 1855 PetscCall(MatSetValues(preallocator, patch->totalDofsPerCell, idx, patch->totalDofsPerCell, idx, vals, INSERT_VALUES)); 1856 } 1857 1858 if (patch->usercomputeopintfacet) { 1859 const PetscInt *intFacetsArray = NULL; 1860 PetscInt i, numIntFacets, intFacetOffset; 1861 const PetscInt *facetCells = NULL; 1862 1863 PetscCall(PetscSectionGetDof(patch->intFacetCounts, point, &numIntFacets)); 1864 PetscCall(PetscSectionGetOffset(patch->intFacetCounts, point, &intFacetOffset)); 1865 PetscCall(ISGetIndices(patch->intFacetsToPatchCell, &facetCells)); 1866 PetscCall(ISGetIndices(patch->intFacets, &intFacetsArray)); 1867 for (i = 0; i < numIntFacets; i++) { 1868 const PetscInt cell0 = facetCells[2 * (intFacetOffset + i) + 0]; 1869 const PetscInt cell1 = facetCells[2 * (intFacetOffset + i) + 1]; 1870 const PetscInt *cell0idx = &dofsArray[(offset + cell0) * patch->totalDofsPerCell]; 1871 const PetscInt *cell1idx = &dofsArray[(offset + cell1) * patch->totalDofsPerCell]; 1872 PetscCall(MatSetValues(preallocator, patch->totalDofsPerCell, cell0idx, patch->totalDofsPerCell, cell1idx, vals, INSERT_VALUES)); 1873 PetscCall(MatSetValues(preallocator, patch->totalDofsPerCell, cell1idx, patch->totalDofsPerCell, cell0idx, vals, INSERT_VALUES)); 1874 } 1875 } 1876 1877 PetscCall(PetscFree(vals)); 1878 PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY)); 1879 PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY)); 1880 PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, *mat)); 1881 PetscCall(MatDestroy(&preallocator)); 1882 } 1883 PetscCall(PetscLogEventEnd(PC_Patch_Prealloc, pc, 0, 0, 0)); 1884 if (withArtificial) { 1885 PetscCall(ISRestoreIndices(patch->dofsWithArtificial, &dofsArray)); 1886 } else { 1887 PetscCall(ISRestoreIndices(patch->dofs, &dofsArray)); 1888 } 1889 } 1890 PetscCall(MatSetUp(*mat)); 1891 PetscFunctionReturn(PETSC_SUCCESS); 1892 } 1893 1894 static PetscErrorCode PCPatchComputeFunction_DMPlex_Private(PC pc, PetscInt patchNum, Vec x, Vec F, IS cellIS, PetscInt n, const PetscInt *l2p, const PetscInt *l2pWithAll, void *ctx) 1895 { 1896 PC_PATCH *patch = (PC_PATCH *)pc->data; 1897 DM dm, plex; 1898 PetscSection s; 1899 const PetscInt *parray, *oarray; 1900 PetscInt Nf = patch->nsubspaces, Np, poff, p, f; 1901 1902 PetscFunctionBegin; 1903 PetscCheck(!patch->precomputeElementTensors, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Precomputing element tensors not implemented with DMPlex compute operator"); 1904 PetscCall(PCGetDM(pc, &dm)); 1905 PetscCall(DMConvert(dm, DMPLEX, &plex)); 1906 dm = plex; 1907 PetscCall(DMGetLocalSection(dm, &s)); 1908 /* Set offset into patch */ 1909 PetscCall(PetscSectionGetDof(patch->pointCounts, patchNum, &Np)); 1910 PetscCall(PetscSectionGetOffset(patch->pointCounts, patchNum, &poff)); 1911 PetscCall(ISGetIndices(patch->points, &parray)); 1912 PetscCall(ISGetIndices(patch->offs, &oarray)); 1913 for (f = 0; f < Nf; ++f) { 1914 for (p = 0; p < Np; ++p) { 1915 const PetscInt point = parray[poff + p]; 1916 PetscInt dof; 1917 1918 PetscCall(PetscSectionGetFieldDof(patch->patchSection, point, f, &dof)); 1919 PetscCall(PetscSectionSetFieldOffset(patch->patchSection, point, f, oarray[(poff + p) * Nf + f])); 1920 if (patch->nsubspaces == 1) PetscCall(PetscSectionSetOffset(patch->patchSection, point, oarray[(poff + p) * Nf + f])); 1921 else PetscCall(PetscSectionSetOffset(patch->patchSection, point, -1)); 1922 } 1923 } 1924 PetscCall(ISRestoreIndices(patch->points, &parray)); 1925 PetscCall(ISRestoreIndices(patch->offs, &oarray)); 1926 if (patch->viewSection) PetscCall(ObjectView((PetscObject)patch->patchSection, patch->viewerSection, patch->formatSection)); 1927 PetscCall(DMPlexComputeResidual_Patch_Internal(dm, patch->patchSection, cellIS, 0.0, x, NULL, F, ctx)); 1928 PetscCall(DMDestroy(&dm)); 1929 PetscFunctionReturn(PETSC_SUCCESS); 1930 } 1931 1932 PetscErrorCode PCPatchComputeFunction_Internal(PC pc, Vec x, Vec F, PetscInt point) 1933 { 1934 PC_PATCH *patch = (PC_PATCH *)pc->data; 1935 const PetscInt *dofsArray; 1936 const PetscInt *dofsArrayWithAll; 1937 const PetscInt *cellsArray; 1938 PetscInt ncell, offset, pStart, pEnd; 1939 1940 PetscFunctionBegin; 1941 PetscCall(PetscLogEventBegin(PC_Patch_ComputeOp, pc, 0, 0, 0)); 1942 PetscCheck(patch->usercomputeop, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PCPatchSetComputeOperator() to set callback"); 1943 PetscCall(ISGetIndices(patch->dofs, &dofsArray)); 1944 PetscCall(ISGetIndices(patch->dofsWithAll, &dofsArrayWithAll)); 1945 PetscCall(ISGetIndices(patch->cells, &cellsArray)); 1946 PetscCall(PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd)); 1947 1948 point += pStart; 1949 PetscCheck(point < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Operator point %" PetscInt_FMT " not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, pStart, pEnd); 1950 1951 PetscCall(PetscSectionGetDof(patch->cellCounts, point, &ncell)); 1952 PetscCall(PetscSectionGetOffset(patch->cellCounts, point, &offset)); 1953 if (ncell <= 0) { 1954 PetscCall(PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0)); 1955 PetscFunctionReturn(PETSC_SUCCESS); 1956 } 1957 PetscCall(VecSet(F, 0.0)); 1958 /* Cannot reuse the same IS because the geometry info is being cached in it */ 1959 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncell, cellsArray + offset, PETSC_USE_POINTER, &patch->cellIS)); 1960 PetscCallBack("PCPatch callback", patch->usercomputef(pc, point, x, F, patch->cellIS, ncell * patch->totalDofsPerCell, dofsArray + offset * patch->totalDofsPerCell, dofsArrayWithAll + offset * patch->totalDofsPerCell, patch->usercomputefctx)); 1961 PetscCall(ISDestroy(&patch->cellIS)); 1962 PetscCall(ISRestoreIndices(patch->dofs, &dofsArray)); 1963 PetscCall(ISRestoreIndices(patch->dofsWithAll, &dofsArrayWithAll)); 1964 PetscCall(ISRestoreIndices(patch->cells, &cellsArray)); 1965 if (patch->viewMatrix) { 1966 char name[PETSC_MAX_PATH_LEN]; 1967 1968 PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "Patch vector for Point %" PetscInt_FMT, point)); 1969 PetscCall(PetscObjectSetName((PetscObject)F, name)); 1970 PetscCall(ObjectView((PetscObject)F, patch->viewerMatrix, patch->formatMatrix)); 1971 } 1972 PetscCall(PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0)); 1973 PetscFunctionReturn(PETSC_SUCCESS); 1974 } 1975 1976 static PetscErrorCode PCPatchComputeOperator_DMPlex_Private(PC pc, PetscInt patchNum, Vec x, Mat J, IS cellIS, PetscInt n, const PetscInt *l2p, const PetscInt *l2pWithAll, void *ctx) 1977 { 1978 PC_PATCH *patch = (PC_PATCH *)pc->data; 1979 DM dm, plex; 1980 PetscSection s; 1981 const PetscInt *parray, *oarray; 1982 PetscInt Nf = patch->nsubspaces, Np, poff, p, f; 1983 1984 PetscFunctionBegin; 1985 PetscCall(PCGetDM(pc, &dm)); 1986 PetscCall(DMConvert(dm, DMPLEX, &plex)); 1987 dm = plex; 1988 PetscCall(DMGetLocalSection(dm, &s)); 1989 /* Set offset into patch */ 1990 PetscCall(PetscSectionGetDof(patch->pointCounts, patchNum, &Np)); 1991 PetscCall(PetscSectionGetOffset(patch->pointCounts, patchNum, &poff)); 1992 PetscCall(ISGetIndices(patch->points, &parray)); 1993 PetscCall(ISGetIndices(patch->offs, &oarray)); 1994 for (f = 0; f < Nf; ++f) { 1995 for (p = 0; p < Np; ++p) { 1996 const PetscInt point = parray[poff + p]; 1997 PetscInt dof; 1998 1999 PetscCall(PetscSectionGetFieldDof(patch->patchSection, point, f, &dof)); 2000 PetscCall(PetscSectionSetFieldOffset(patch->patchSection, point, f, oarray[(poff + p) * Nf + f])); 2001 if (patch->nsubspaces == 1) PetscCall(PetscSectionSetOffset(patch->patchSection, point, oarray[(poff + p) * Nf + f])); 2002 else PetscCall(PetscSectionSetOffset(patch->patchSection, point, -1)); 2003 } 2004 } 2005 PetscCall(ISRestoreIndices(patch->points, &parray)); 2006 PetscCall(ISRestoreIndices(patch->offs, &oarray)); 2007 if (patch->viewSection) PetscCall(ObjectView((PetscObject)patch->patchSection, patch->viewerSection, patch->formatSection)); 2008 /* TODO Shut off MatViewFromOptions() in MatAssemblyEnd() here */ 2009 PetscCall(DMPlexComputeJacobian_Patch_Internal(dm, patch->patchSection, patch->patchSection, cellIS, 0.0, 0.0, x, NULL, J, J, ctx)); 2010 PetscCall(DMDestroy(&dm)); 2011 PetscFunctionReturn(PETSC_SUCCESS); 2012 } 2013 2014 /* This function zeros mat on entry */ 2015 PetscErrorCode PCPatchComputeOperator_Internal(PC pc, Vec x, Mat mat, PetscInt point, PetscBool withArtificial) 2016 { 2017 PC_PATCH *patch = (PC_PATCH *)pc->data; 2018 const PetscInt *dofsArray; 2019 const PetscInt *dofsArrayWithAll = NULL; 2020 const PetscInt *cellsArray; 2021 PetscInt ncell, offset, pStart, pEnd, numIntFacets, intFacetOffset; 2022 PetscBool isNonlinear; 2023 2024 PetscFunctionBegin; 2025 PetscCall(PetscLogEventBegin(PC_Patch_ComputeOp, pc, 0, 0, 0)); 2026 isNonlinear = patch->isNonlinear; 2027 PetscCheck(patch->usercomputeop, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must call PCPatchSetComputeOperator() to set callback"); 2028 if (withArtificial) { 2029 PetscCall(ISGetIndices(patch->dofsWithArtificial, &dofsArray)); 2030 } else { 2031 PetscCall(ISGetIndices(patch->dofs, &dofsArray)); 2032 } 2033 if (isNonlinear) PetscCall(ISGetIndices(patch->dofsWithAll, &dofsArrayWithAll)); 2034 PetscCall(ISGetIndices(patch->cells, &cellsArray)); 2035 PetscCall(PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd)); 2036 2037 point += pStart; 2038 PetscCheck(point < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Operator point %" PetscInt_FMT " not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, pStart, pEnd); 2039 2040 PetscCall(PetscSectionGetDof(patch->cellCounts, point, &ncell)); 2041 PetscCall(PetscSectionGetOffset(patch->cellCounts, point, &offset)); 2042 if (ncell <= 0) { 2043 PetscCall(PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0)); 2044 PetscFunctionReturn(PETSC_SUCCESS); 2045 } 2046 PetscCall(MatZeroEntries(mat)); 2047 if (patch->precomputeElementTensors) { 2048 PetscInt i; 2049 PetscInt ndof = patch->totalDofsPerCell; 2050 const PetscScalar *elementTensors; 2051 2052 PetscCall(VecGetArrayRead(patch->cellMats, &elementTensors)); 2053 for (i = 0; i < ncell; i++) { 2054 const PetscInt cell = cellsArray[i + offset]; 2055 const PetscInt *idx = dofsArray + (offset + i) * ndof; 2056 const PetscScalar *v = elementTensors + patch->precomputedTensorLocations[cell] * ndof * ndof; 2057 PetscCall(MatSetValues(mat, ndof, idx, ndof, idx, v, ADD_VALUES)); 2058 } 2059 PetscCall(VecRestoreArrayRead(patch->cellMats, &elementTensors)); 2060 PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 2061 PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 2062 } else { 2063 /* Cannot reuse the same IS because the geometry info is being cached in it */ 2064 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncell, cellsArray + offset, PETSC_USE_POINTER, &patch->cellIS)); 2065 PetscCallBack("PCPatch callback", 2066 patch->usercomputeop(pc, point, x, mat, patch->cellIS, ncell * patch->totalDofsPerCell, dofsArray + offset * patch->totalDofsPerCell, PetscSafePointerPlusOffset(dofsArrayWithAll, offset * patch->totalDofsPerCell), patch->usercomputeopctx)); 2067 } 2068 if (patch->usercomputeopintfacet) { 2069 PetscCall(PetscSectionGetDof(patch->intFacetCounts, point, &numIntFacets)); 2070 PetscCall(PetscSectionGetOffset(patch->intFacetCounts, point, &intFacetOffset)); 2071 if (numIntFacets > 0) { 2072 /* For each interior facet, grab the two cells (in local numbering, and concatenate dof numberings for those cells) */ 2073 PetscInt *facetDofs = NULL, *facetDofsWithAll = NULL; 2074 const PetscInt *intFacetsArray = NULL; 2075 PetscInt idx = 0; 2076 PetscInt i, c, d; 2077 PetscInt fStart; 2078 DM dm, plex; 2079 IS facetIS = NULL; 2080 const PetscInt *facetCells = NULL; 2081 2082 PetscCall(ISGetIndices(patch->intFacetsToPatchCell, &facetCells)); 2083 PetscCall(ISGetIndices(patch->intFacets, &intFacetsArray)); 2084 PetscCall(PCGetDM(pc, &dm)); 2085 PetscCall(DMConvert(dm, DMPLEX, &plex)); 2086 dm = plex; 2087 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, NULL)); 2088 /* FIXME: Pull this malloc out. */ 2089 PetscCall(PetscMalloc1(2 * patch->totalDofsPerCell * numIntFacets, &facetDofs)); 2090 if (dofsArrayWithAll) PetscCall(PetscMalloc1(2 * patch->totalDofsPerCell * numIntFacets, &facetDofsWithAll)); 2091 if (patch->precomputeElementTensors) { 2092 PetscInt nFacetDof = 2 * patch->totalDofsPerCell; 2093 const PetscScalar *elementTensors; 2094 2095 PetscCall(VecGetArrayRead(patch->intFacetMats, &elementTensors)); 2096 2097 for (i = 0; i < numIntFacets; i++) { 2098 const PetscInt facet = intFacetsArray[i + intFacetOffset]; 2099 const PetscScalar *v = elementTensors + patch->precomputedIntFacetTensorLocations[facet - fStart] * nFacetDof * nFacetDof; 2100 idx = 0; 2101 /* 2102 0--1 2103 |\-| 2104 |+\| 2105 2--3 2106 [0, 2, 3, 0, 1, 3] 2107 */ 2108 for (c = 0; c < 2; c++) { 2109 const PetscInt cell = facetCells[2 * (intFacetOffset + i) + c]; 2110 for (d = 0; d < patch->totalDofsPerCell; d++) { 2111 facetDofs[idx] = dofsArray[(offset + cell) * patch->totalDofsPerCell + d]; 2112 idx++; 2113 } 2114 } 2115 PetscCall(MatSetValues(mat, nFacetDof, facetDofs, nFacetDof, facetDofs, v, ADD_VALUES)); 2116 } 2117 PetscCall(VecRestoreArrayRead(patch->intFacetMats, &elementTensors)); 2118 } else { 2119 /* 2120 0--1 2121 |\-| 2122 |+\| 2123 2--3 2124 [0, 2, 3, 0, 1, 3] 2125 */ 2126 for (i = 0; i < numIntFacets; i++) { 2127 for (c = 0; c < 2; c++) { 2128 const PetscInt cell = facetCells[2 * (intFacetOffset + i) + c]; 2129 for (d = 0; d < patch->totalDofsPerCell; d++) { 2130 facetDofs[idx] = dofsArray[(offset + cell) * patch->totalDofsPerCell + d]; 2131 if (dofsArrayWithAll) facetDofsWithAll[idx] = dofsArrayWithAll[(offset + cell) * patch->totalDofsPerCell + d]; 2132 idx++; 2133 } 2134 } 2135 } 2136 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numIntFacets, intFacetsArray + intFacetOffset, PETSC_USE_POINTER, &facetIS)); 2137 PetscCall(patch->usercomputeopintfacet(pc, point, x, mat, facetIS, 2 * numIntFacets * patch->totalDofsPerCell, facetDofs, facetDofsWithAll, patch->usercomputeopintfacetctx)); 2138 PetscCall(ISDestroy(&facetIS)); 2139 } 2140 PetscCall(ISRestoreIndices(patch->intFacetsToPatchCell, &facetCells)); 2141 PetscCall(ISRestoreIndices(patch->intFacets, &intFacetsArray)); 2142 PetscCall(PetscFree(facetDofs)); 2143 PetscCall(PetscFree(facetDofsWithAll)); 2144 PetscCall(DMDestroy(&dm)); 2145 } 2146 } 2147 2148 PetscCall(MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY)); 2149 PetscCall(MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY)); 2150 2151 if (!(withArtificial || isNonlinear) && patch->denseinverse) { 2152 MatFactorInfo info; 2153 PetscBool flg; 2154 PetscCall(PetscObjectTypeCompare((PetscObject)mat, MATSEQDENSE, &flg)); 2155 PetscCheck(flg, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Invalid Mat type for dense inverse"); 2156 PetscCall(MatFactorInfoInitialize(&info)); 2157 PetscCall(MatLUFactor(mat, NULL, NULL, &info)); 2158 PetscCall(MatSeqDenseInvertFactors_Private(mat)); 2159 } 2160 PetscCall(ISDestroy(&patch->cellIS)); 2161 if (withArtificial) { 2162 PetscCall(ISRestoreIndices(patch->dofsWithArtificial, &dofsArray)); 2163 } else { 2164 PetscCall(ISRestoreIndices(patch->dofs, &dofsArray)); 2165 } 2166 if (isNonlinear) PetscCall(ISRestoreIndices(patch->dofsWithAll, &dofsArrayWithAll)); 2167 PetscCall(ISRestoreIndices(patch->cells, &cellsArray)); 2168 if (patch->viewMatrix) { 2169 char name[PETSC_MAX_PATH_LEN]; 2170 2171 PetscCall(PetscSNPrintf(name, PETSC_MAX_PATH_LEN - 1, "Patch matrix for Point %" PetscInt_FMT, point)); 2172 PetscCall(PetscObjectSetName((PetscObject)mat, name)); 2173 PetscCall(ObjectView((PetscObject)mat, patch->viewerMatrix, patch->formatMatrix)); 2174 } 2175 PetscCall(PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0)); 2176 PetscFunctionReturn(PETSC_SUCCESS); 2177 } 2178 2179 static PetscErrorCode MatSetValues_PCPatch_Private(Mat mat, PetscInt m, const PetscInt idxm[], PetscInt n, const PetscInt idxn[], const PetscScalar *v, InsertMode addv) 2180 { 2181 Vec data; 2182 PetscScalar *array; 2183 PetscInt bs, nz, i, j, cell; 2184 2185 PetscCall(MatShellGetContext(mat, &data)); 2186 PetscCall(VecGetBlockSize(data, &bs)); 2187 PetscCall(VecGetSize(data, &nz)); 2188 PetscCall(VecGetArray(data, &array)); 2189 PetscCheck(m == n, PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Only for square insertion"); 2190 cell = (PetscInt)(idxm[0] / bs); /* use the fact that this is called once per cell */ 2191 for (i = 0; i < m; i++) { 2192 PetscCheck(idxm[i] == idxn[i], PetscObjectComm((PetscObject)mat), PETSC_ERR_ARG_WRONG, "Row and column indices must match!"); 2193 for (j = 0; j < n; j++) { 2194 const PetscScalar v_ = v[i * bs + j]; 2195 /* Indexing is special to the data structure we have! */ 2196 if (addv == INSERT_VALUES) { 2197 array[cell * bs * bs + i * bs + j] = v_; 2198 } else { 2199 array[cell * bs * bs + i * bs + j] += v_; 2200 } 2201 } 2202 } 2203 PetscCall(VecRestoreArray(data, &array)); 2204 PetscFunctionReturn(PETSC_SUCCESS); 2205 } 2206 2207 static PetscErrorCode PCPatchPrecomputePatchTensors_Private(PC pc) 2208 { 2209 PC_PATCH *patch = (PC_PATCH *)pc->data; 2210 const PetscInt *cellsArray; 2211 PetscInt ncell, offset; 2212 const PetscInt *dofMapArray; 2213 PetscInt i, j; 2214 IS dofMap; 2215 IS cellIS; 2216 const PetscInt ndof = patch->totalDofsPerCell; 2217 Mat vecMat; 2218 PetscInt cStart, cEnd; 2219 DM dm, plex; 2220 2221 PetscCall(ISGetSize(patch->cells, &ncell)); 2222 if (!ncell) { /* No cells to assemble over -> skip */ 2223 PetscFunctionReturn(PETSC_SUCCESS); 2224 } 2225 2226 PetscCall(PetscLogEventBegin(PC_Patch_ComputeOp, pc, 0, 0, 0)); 2227 2228 PetscCall(PCGetDM(pc, &dm)); 2229 PetscCall(DMConvert(dm, DMPLEX, &plex)); 2230 dm = plex; 2231 if (!patch->allCells) { 2232 PetscHSetI cells; 2233 PetscHashIter hi; 2234 PetscInt pStart, pEnd; 2235 PetscInt *allCells = NULL; 2236 PetscCall(PetscHSetICreate(&cells)); 2237 PetscCall(ISGetIndices(patch->cells, &cellsArray)); 2238 PetscCall(PetscSectionGetChart(patch->cellCounts, &pStart, &pEnd)); 2239 for (i = pStart; i < pEnd; i++) { 2240 PetscCall(PetscSectionGetDof(patch->cellCounts, i, &ncell)); 2241 PetscCall(PetscSectionGetOffset(patch->cellCounts, i, &offset)); 2242 if (ncell <= 0) continue; 2243 for (j = 0; j < ncell; j++) PetscCall(PetscHSetIAdd(cells, cellsArray[offset + j])); 2244 } 2245 PetscCall(ISRestoreIndices(patch->cells, &cellsArray)); 2246 PetscCall(PetscHSetIGetSize(cells, &ncell)); 2247 PetscCall(PetscMalloc1(ncell, &allCells)); 2248 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2249 PetscCall(PetscMalloc1(cEnd - cStart, &patch->precomputedTensorLocations)); 2250 i = 0; 2251 PetscHashIterBegin(cells, hi); 2252 while (!PetscHashIterAtEnd(cells, hi)) { 2253 PetscHashIterGetKey(cells, hi, allCells[i]); 2254 patch->precomputedTensorLocations[allCells[i]] = i; 2255 PetscHashIterNext(cells, hi); 2256 i++; 2257 } 2258 PetscCall(PetscHSetIDestroy(&cells)); 2259 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncell, allCells, PETSC_OWN_POINTER, &patch->allCells)); 2260 } 2261 PetscCall(ISGetSize(patch->allCells, &ncell)); 2262 if (!patch->cellMats) { 2263 PetscCall(VecCreateSeq(PETSC_COMM_SELF, ncell * ndof * ndof, &patch->cellMats)); 2264 PetscCall(VecSetBlockSize(patch->cellMats, ndof)); 2265 } 2266 PetscCall(VecSet(patch->cellMats, 0)); 2267 2268 PetscCall(MatCreateShell(PETSC_COMM_SELF, ncell * ndof, ncell * ndof, ncell * ndof, ncell * ndof, (void *)patch->cellMats, &vecMat)); 2269 PetscCall(MatShellSetOperation(vecMat, MATOP_SET_VALUES, (void (*)(void)) & MatSetValues_PCPatch_Private)); 2270 PetscCall(ISGetSize(patch->allCells, &ncell)); 2271 PetscCall(ISCreateStride(PETSC_COMM_SELF, ndof * ncell, 0, 1, &dofMap)); 2272 PetscCall(ISGetIndices(dofMap, &dofMapArray)); 2273 PetscCall(ISGetIndices(patch->allCells, &cellsArray)); 2274 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncell, cellsArray, PETSC_USE_POINTER, &cellIS)); 2275 /* TODO: Fix for DMPlex compute op, this bypasses a lot of the machinery and just assembles every element tensor. */ 2276 PetscCallBack("PCPatch callback", patch->usercomputeop(pc, -1, NULL, vecMat, cellIS, ndof * ncell, dofMapArray, NULL, patch->usercomputeopctx)); 2277 PetscCall(ISDestroy(&cellIS)); 2278 PetscCall(MatDestroy(&vecMat)); 2279 PetscCall(ISRestoreIndices(patch->allCells, &cellsArray)); 2280 PetscCall(ISRestoreIndices(dofMap, &dofMapArray)); 2281 PetscCall(ISDestroy(&dofMap)); 2282 2283 if (patch->usercomputeopintfacet) { 2284 PetscInt nIntFacets; 2285 IS intFacetsIS; 2286 const PetscInt *intFacetsArray = NULL; 2287 if (!patch->allIntFacets) { 2288 PetscHSetI facets; 2289 PetscHashIter hi; 2290 PetscInt pStart, pEnd, fStart, fEnd; 2291 PetscInt *allIntFacets = NULL; 2292 PetscCall(PetscHSetICreate(&facets)); 2293 PetscCall(ISGetIndices(patch->intFacets, &intFacetsArray)); 2294 PetscCall(PetscSectionGetChart(patch->intFacetCounts, &pStart, &pEnd)); 2295 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 2296 for (i = pStart; i < pEnd; i++) { 2297 PetscCall(PetscSectionGetDof(patch->intFacetCounts, i, &nIntFacets)); 2298 PetscCall(PetscSectionGetOffset(patch->intFacetCounts, i, &offset)); 2299 if (nIntFacets <= 0) continue; 2300 for (j = 0; j < nIntFacets; j++) PetscCall(PetscHSetIAdd(facets, intFacetsArray[offset + j])); 2301 } 2302 PetscCall(ISRestoreIndices(patch->intFacets, &intFacetsArray)); 2303 PetscCall(PetscHSetIGetSize(facets, &nIntFacets)); 2304 PetscCall(PetscMalloc1(nIntFacets, &allIntFacets)); 2305 PetscCall(PetscMalloc1(fEnd - fStart, &patch->precomputedIntFacetTensorLocations)); 2306 i = 0; 2307 PetscHashIterBegin(facets, hi); 2308 while (!PetscHashIterAtEnd(facets, hi)) { 2309 PetscHashIterGetKey(facets, hi, allIntFacets[i]); 2310 patch->precomputedIntFacetTensorLocations[allIntFacets[i] - fStart] = i; 2311 PetscHashIterNext(facets, hi); 2312 i++; 2313 } 2314 PetscCall(PetscHSetIDestroy(&facets)); 2315 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nIntFacets, allIntFacets, PETSC_OWN_POINTER, &patch->allIntFacets)); 2316 } 2317 PetscCall(ISGetSize(patch->allIntFacets, &nIntFacets)); 2318 if (!patch->intFacetMats) { 2319 PetscCall(VecCreateSeq(PETSC_COMM_SELF, nIntFacets * ndof * ndof * 4, &patch->intFacetMats)); 2320 PetscCall(VecSetBlockSize(patch->intFacetMats, ndof * 2)); 2321 } 2322 PetscCall(VecSet(patch->intFacetMats, 0)); 2323 2324 PetscCall(MatCreateShell(PETSC_COMM_SELF, nIntFacets * ndof * 2, nIntFacets * ndof * 2, nIntFacets * ndof * 2, nIntFacets * ndof * 2, (void *)patch->intFacetMats, &vecMat)); 2325 PetscCall(MatShellSetOperation(vecMat, MATOP_SET_VALUES, (void (*)(void)) & MatSetValues_PCPatch_Private)); 2326 PetscCall(ISCreateStride(PETSC_COMM_SELF, 2 * ndof * nIntFacets, 0, 1, &dofMap)); 2327 PetscCall(ISGetIndices(dofMap, &dofMapArray)); 2328 PetscCall(ISGetIndices(patch->allIntFacets, &intFacetsArray)); 2329 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nIntFacets, intFacetsArray, PETSC_USE_POINTER, &intFacetsIS)); 2330 /* TODO: Fix for DMPlex compute op, this bypasses a lot of the machinery and just assembles every element tensor. */ 2331 PetscCallBack("PCPatch callback (interior facets)", patch->usercomputeopintfacet(pc, -1, NULL, vecMat, intFacetsIS, 2 * ndof * nIntFacets, dofMapArray, NULL, patch->usercomputeopintfacetctx)); 2332 PetscCall(ISDestroy(&intFacetsIS)); 2333 PetscCall(MatDestroy(&vecMat)); 2334 PetscCall(ISRestoreIndices(patch->allIntFacets, &intFacetsArray)); 2335 PetscCall(ISRestoreIndices(dofMap, &dofMapArray)); 2336 PetscCall(ISDestroy(&dofMap)); 2337 } 2338 PetscCall(DMDestroy(&dm)); 2339 PetscCall(PetscLogEventEnd(PC_Patch_ComputeOp, pc, 0, 0, 0)); 2340 PetscFunctionReturn(PETSC_SUCCESS); 2341 } 2342 2343 PetscErrorCode PCPatch_ScatterLocal_Private(PC pc, PetscInt p, Vec x, Vec y, InsertMode mode, ScatterMode scat, PatchScatterType scattertype) 2344 { 2345 PC_PATCH *patch = (PC_PATCH *)pc->data; 2346 const PetscScalar *xArray = NULL; 2347 PetscScalar *yArray = NULL; 2348 const PetscInt *gtolArray = NULL; 2349 PetscInt dof, offset, lidx; 2350 2351 PetscFunctionBeginHot; 2352 PetscCall(VecGetArrayRead(x, &xArray)); 2353 PetscCall(VecGetArray(y, &yArray)); 2354 if (scattertype == SCATTER_WITHARTIFICIAL) { 2355 PetscCall(PetscSectionGetDof(patch->gtolCountsWithArtificial, p, &dof)); 2356 PetscCall(PetscSectionGetOffset(patch->gtolCountsWithArtificial, p, &offset)); 2357 PetscCall(ISGetIndices(patch->gtolWithArtificial, >olArray)); 2358 } else if (scattertype == SCATTER_WITHALL) { 2359 PetscCall(PetscSectionGetDof(patch->gtolCountsWithAll, p, &dof)); 2360 PetscCall(PetscSectionGetOffset(patch->gtolCountsWithAll, p, &offset)); 2361 PetscCall(ISGetIndices(patch->gtolWithAll, >olArray)); 2362 } else { 2363 PetscCall(PetscSectionGetDof(patch->gtolCounts, p, &dof)); 2364 PetscCall(PetscSectionGetOffset(patch->gtolCounts, p, &offset)); 2365 PetscCall(ISGetIndices(patch->gtol, >olArray)); 2366 } 2367 PetscCheck(mode != INSERT_VALUES || scat == SCATTER_FORWARD, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Can't insert if not scattering forward"); 2368 PetscCheck(mode != ADD_VALUES || scat == SCATTER_REVERSE, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Can't add if not scattering reverse"); 2369 for (lidx = 0; lidx < dof; ++lidx) { 2370 const PetscInt gidx = gtolArray[offset + lidx]; 2371 2372 if (mode == INSERT_VALUES) yArray[lidx] = xArray[gidx]; /* Forward */ 2373 else yArray[gidx] += xArray[lidx]; /* Reverse */ 2374 } 2375 if (scattertype == SCATTER_WITHARTIFICIAL) { 2376 PetscCall(ISRestoreIndices(patch->gtolWithArtificial, >olArray)); 2377 } else if (scattertype == SCATTER_WITHALL) { 2378 PetscCall(ISRestoreIndices(patch->gtolWithAll, >olArray)); 2379 } else { 2380 PetscCall(ISRestoreIndices(patch->gtol, >olArray)); 2381 } 2382 PetscCall(VecRestoreArrayRead(x, &xArray)); 2383 PetscCall(VecRestoreArray(y, &yArray)); 2384 PetscFunctionReturn(PETSC_SUCCESS); 2385 } 2386 2387 static PetscErrorCode PCSetUp_PATCH_Linear(PC pc) 2388 { 2389 PC_PATCH *patch = (PC_PATCH *)pc->data; 2390 const char *prefix; 2391 PetscInt i; 2392 2393 PetscFunctionBegin; 2394 if (!pc->setupcalled) { 2395 PetscCheck(patch->save_operators || !patch->denseinverse, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Can't have dense inverse without save operators"); 2396 if (!patch->denseinverse) { 2397 PetscCall(PetscMalloc1(patch->npatch, &patch->solver)); 2398 PetscCall(PCGetOptionsPrefix(pc, &prefix)); 2399 for (i = 0; i < patch->npatch; ++i) { 2400 KSP ksp; 2401 PC subpc; 2402 2403 PetscCall(KSPCreate(PETSC_COMM_SELF, &ksp)); 2404 PetscCall(KSPSetNestLevel(ksp, pc->kspnestlevel)); 2405 PetscCall(KSPSetErrorIfNotConverged(ksp, pc->erroriffailure)); 2406 PetscCall(KSPSetOptionsPrefix(ksp, prefix)); 2407 PetscCall(KSPAppendOptionsPrefix(ksp, "sub_")); 2408 PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp, (PetscObject)pc, 1)); 2409 PetscCall(KSPGetPC(ksp, &subpc)); 2410 PetscCall(PetscObjectIncrementTabLevel((PetscObject)subpc, (PetscObject)pc, 1)); 2411 patch->solver[i] = (PetscObject)ksp; 2412 } 2413 } 2414 } 2415 if (patch->save_operators) { 2416 if (patch->precomputeElementTensors) PetscCall(PCPatchPrecomputePatchTensors_Private(pc)); 2417 for (i = 0; i < patch->npatch; ++i) { 2418 PetscCall(PCPatchComputeOperator_Internal(pc, NULL, patch->mat[i], i, PETSC_FALSE)); 2419 if (!patch->denseinverse) { 2420 PetscCall(KSPSetOperators((KSP)patch->solver[i], patch->mat[i], patch->mat[i])); 2421 } else if (patch->mat[i] && !patch->densesolve) { 2422 /* Setup matmult callback */ 2423 PetscCall(MatGetOperation(patch->mat[i], MATOP_MULT, (void (**)(void)) & patch->densesolve)); 2424 } 2425 } 2426 } 2427 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 2428 for (i = 0; i < patch->npatch; ++i) { 2429 /* Instead of padding patch->patchUpdate with zeros to get */ 2430 /* patch->patchUpdateWithArtificial and then multiplying with the matrix, */ 2431 /* just get rid of the columns that correspond to the dofs with */ 2432 /* artificial bcs. That's of course fairly inefficient, hopefully we */ 2433 /* can just assemble the rectangular matrix in the first place. */ 2434 Mat matSquare; 2435 IS rowis; 2436 PetscInt dof; 2437 2438 PetscCall(MatGetSize(patch->mat[i], &dof, NULL)); 2439 if (dof == 0) { 2440 patch->matWithArtificial[i] = NULL; 2441 continue; 2442 } 2443 2444 PetscCall(PCPatchCreateMatrix_Private(pc, i, &matSquare, PETSC_TRUE)); 2445 PetscCall(PCPatchComputeOperator_Internal(pc, NULL, matSquare, i, PETSC_TRUE)); 2446 2447 PetscCall(MatGetSize(matSquare, &dof, NULL)); 2448 PetscCall(ISCreateStride(PETSC_COMM_SELF, dof, 0, 1, &rowis)); 2449 if (pc->setupcalled) { 2450 PetscCall(MatCreateSubMatrix(matSquare, rowis, patch->dofMappingWithoutToWithArtificial[i], MAT_REUSE_MATRIX, &patch->matWithArtificial[i])); 2451 } else { 2452 PetscCall(MatCreateSubMatrix(matSquare, rowis, patch->dofMappingWithoutToWithArtificial[i], MAT_INITIAL_MATRIX, &patch->matWithArtificial[i])); 2453 } 2454 PetscCall(ISDestroy(&rowis)); 2455 PetscCall(MatDestroy(&matSquare)); 2456 } 2457 } 2458 PetscFunctionReturn(PETSC_SUCCESS); 2459 } 2460 2461 static PetscErrorCode PCSetUp_PATCH(PC pc) 2462 { 2463 PC_PATCH *patch = (PC_PATCH *)pc->data; 2464 PetscInt i; 2465 PetscBool isNonlinear; 2466 PetscInt maxDof = -1, maxDofWithArtificial = -1; 2467 2468 PetscFunctionBegin; 2469 if (!pc->setupcalled) { 2470 PetscInt pStart, pEnd, p; 2471 PetscInt localSize; 2472 2473 PetscCall(PetscLogEventBegin(PC_Patch_CreatePatches, pc, 0, 0, 0)); 2474 2475 isNonlinear = patch->isNonlinear; 2476 if (!patch->nsubspaces) { 2477 DM dm, plex; 2478 PetscSection s; 2479 PetscInt cStart, cEnd, c, Nf, f, numGlobalBcs = 0, *globalBcs, *Nb, **cellDofs; 2480 2481 PetscCall(PCGetDM(pc, &dm)); 2482 PetscCheck(dm, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Must set DM for PCPATCH or call PCPatchSetDiscretisationInfo()"); 2483 PetscCall(DMConvert(dm, DMPLEX, &plex)); 2484 dm = plex; 2485 PetscCall(DMGetLocalSection(dm, &s)); 2486 PetscCall(PetscSectionGetNumFields(s, &Nf)); 2487 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2488 for (p = pStart; p < pEnd; ++p) { 2489 PetscInt cdof; 2490 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2491 numGlobalBcs += cdof; 2492 } 2493 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2494 PetscCall(PetscMalloc3(Nf, &Nb, Nf, &cellDofs, numGlobalBcs, &globalBcs)); 2495 for (f = 0; f < Nf; ++f) { 2496 PetscFE fe; 2497 PetscDualSpace sp; 2498 PetscInt cdoff = 0; 2499 2500 PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe)); 2501 /* PetscCall(PetscFEGetNumComponents(fe, &Nc[f])); */ 2502 PetscCall(PetscFEGetDualSpace(fe, &sp)); 2503 PetscCall(PetscDualSpaceGetDimension(sp, &Nb[f])); 2504 2505 PetscCall(PetscMalloc1((cEnd - cStart) * Nb[f], &cellDofs[f])); 2506 for (c = cStart; c < cEnd; ++c) { 2507 PetscInt *closure = NULL; 2508 PetscInt clSize = 0, cl; 2509 2510 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 2511 for (cl = 0; cl < clSize * 2; cl += 2) { 2512 const PetscInt p = closure[cl]; 2513 PetscInt fdof, d, foff; 2514 2515 PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof)); 2516 PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff)); 2517 for (d = 0; d < fdof; ++d, ++cdoff) cellDofs[f][cdoff] = foff + d; 2518 } 2519 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 2520 } 2521 PetscCheck(cdoff == (cEnd - cStart) * Nb[f], PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_SIZ, "Total number of cellDofs %" PetscInt_FMT " for field %" PetscInt_FMT " should be Nc (%" PetscInt_FMT ") * cellDof (%" PetscInt_FMT ")", cdoff, f, cEnd - cStart, Nb[f]); 2522 } 2523 numGlobalBcs = 0; 2524 for (p = pStart; p < pEnd; ++p) { 2525 const PetscInt *ind; 2526 PetscInt off, cdof, d; 2527 2528 PetscCall(PetscSectionGetOffset(s, p, &off)); 2529 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2530 PetscCall(PetscSectionGetConstraintIndices(s, p, &ind)); 2531 for (d = 0; d < cdof; ++d) globalBcs[numGlobalBcs++] = off + ind[d]; 2532 } 2533 2534 PetscCall(PCPatchSetDiscretisationInfoCombined(pc, dm, Nb, (const PetscInt **)cellDofs, numGlobalBcs, globalBcs, numGlobalBcs, globalBcs)); 2535 for (f = 0; f < Nf; ++f) PetscCall(PetscFree(cellDofs[f])); 2536 PetscCall(PetscFree3(Nb, cellDofs, globalBcs)); 2537 PetscCall(PCPatchSetComputeFunction(pc, PCPatchComputeFunction_DMPlex_Private, NULL)); 2538 PetscCall(PCPatchSetComputeOperator(pc, PCPatchComputeOperator_DMPlex_Private, NULL)); 2539 PetscCall(DMDestroy(&dm)); 2540 } 2541 2542 localSize = patch->subspaceOffsets[patch->nsubspaces]; 2543 PetscCall(VecCreateSeq(PETSC_COMM_SELF, localSize, &patch->localRHS)); 2544 PetscCall(VecSetUp(patch->localRHS)); 2545 PetscCall(VecDuplicate(patch->localRHS, &patch->localUpdate)); 2546 PetscCall(PCPatchCreateCellPatches(pc)); 2547 PetscCall(PCPatchCreateCellPatchDiscretisationInfo(pc)); 2548 2549 /* OK, now build the work vectors */ 2550 PetscCall(PetscSectionGetChart(patch->gtolCounts, &pStart, &pEnd)); 2551 2552 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) PetscCall(PetscMalloc1(patch->npatch, &patch->dofMappingWithoutToWithArtificial)); 2553 if (isNonlinear) PetscCall(PetscMalloc1(patch->npatch, &patch->dofMappingWithoutToWithAll)); 2554 for (p = pStart; p < pEnd; ++p) { 2555 PetscInt dof; 2556 2557 PetscCall(PetscSectionGetDof(patch->gtolCounts, p, &dof)); 2558 maxDof = PetscMax(maxDof, dof); 2559 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 2560 const PetscInt *gtolArray, *gtolArrayWithArtificial = NULL; 2561 PetscInt numPatchDofs, offset; 2562 PetscInt numPatchDofsWithArtificial, offsetWithArtificial; 2563 PetscInt dofWithoutArtificialCounter = 0; 2564 PetscInt *patchWithoutArtificialToWithArtificialArray; 2565 2566 PetscCall(PetscSectionGetDof(patch->gtolCountsWithArtificial, p, &dof)); 2567 maxDofWithArtificial = PetscMax(maxDofWithArtificial, dof); 2568 2569 /* Now build the mapping that for a dof in a patch WITHOUT dofs that have artificial bcs gives the */ 2570 /* the index in the patch with all dofs */ 2571 PetscCall(ISGetIndices(patch->gtol, >olArray)); 2572 2573 PetscCall(PetscSectionGetDof(patch->gtolCounts, p, &numPatchDofs)); 2574 if (numPatchDofs == 0) { 2575 patch->dofMappingWithoutToWithArtificial[p - pStart] = NULL; 2576 continue; 2577 } 2578 2579 PetscCall(PetscSectionGetOffset(patch->gtolCounts, p, &offset)); 2580 PetscCall(ISGetIndices(patch->gtolWithArtificial, >olArrayWithArtificial)); 2581 PetscCall(PetscSectionGetDof(patch->gtolCountsWithArtificial, p, &numPatchDofsWithArtificial)); 2582 PetscCall(PetscSectionGetOffset(patch->gtolCountsWithArtificial, p, &offsetWithArtificial)); 2583 2584 PetscCall(PetscMalloc1(numPatchDofs, &patchWithoutArtificialToWithArtificialArray)); 2585 for (i = 0; i < numPatchDofsWithArtificial; i++) { 2586 if (gtolArrayWithArtificial[i + offsetWithArtificial] == gtolArray[offset + dofWithoutArtificialCounter]) { 2587 patchWithoutArtificialToWithArtificialArray[dofWithoutArtificialCounter] = i; 2588 dofWithoutArtificialCounter++; 2589 if (dofWithoutArtificialCounter == numPatchDofs) break; 2590 } 2591 } 2592 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numPatchDofs, patchWithoutArtificialToWithArtificialArray, PETSC_OWN_POINTER, &patch->dofMappingWithoutToWithArtificial[p - pStart])); 2593 PetscCall(ISRestoreIndices(patch->gtol, >olArray)); 2594 PetscCall(ISRestoreIndices(patch->gtolWithArtificial, >olArrayWithArtificial)); 2595 } 2596 } 2597 for (p = pStart; p < pEnd; ++p) { 2598 if (isNonlinear) { 2599 const PetscInt *gtolArray, *gtolArrayWithAll = NULL; 2600 PetscInt numPatchDofs, offset; 2601 PetscInt numPatchDofsWithAll, offsetWithAll; 2602 PetscInt dofWithoutAllCounter = 0; 2603 PetscInt *patchWithoutAllToWithAllArray; 2604 2605 /* Now build the mapping that for a dof in a patch WITHOUT dofs that have artificial bcs gives the */ 2606 /* the index in the patch with all dofs */ 2607 PetscCall(ISGetIndices(patch->gtol, >olArray)); 2608 2609 PetscCall(PetscSectionGetDof(patch->gtolCounts, p, &numPatchDofs)); 2610 if (numPatchDofs == 0) { 2611 patch->dofMappingWithoutToWithAll[p - pStart] = NULL; 2612 continue; 2613 } 2614 2615 PetscCall(PetscSectionGetOffset(patch->gtolCounts, p, &offset)); 2616 PetscCall(ISGetIndices(patch->gtolWithAll, >olArrayWithAll)); 2617 PetscCall(PetscSectionGetDof(patch->gtolCountsWithAll, p, &numPatchDofsWithAll)); 2618 PetscCall(PetscSectionGetOffset(patch->gtolCountsWithAll, p, &offsetWithAll)); 2619 2620 PetscCall(PetscMalloc1(numPatchDofs, &patchWithoutAllToWithAllArray)); 2621 2622 for (i = 0; i < numPatchDofsWithAll; i++) { 2623 if (gtolArrayWithAll[i + offsetWithAll] == gtolArray[offset + dofWithoutAllCounter]) { 2624 patchWithoutAllToWithAllArray[dofWithoutAllCounter] = i; 2625 dofWithoutAllCounter++; 2626 if (dofWithoutAllCounter == numPatchDofs) break; 2627 } 2628 } 2629 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, numPatchDofs, patchWithoutAllToWithAllArray, PETSC_OWN_POINTER, &patch->dofMappingWithoutToWithAll[p - pStart])); 2630 PetscCall(ISRestoreIndices(patch->gtol, >olArray)); 2631 PetscCall(ISRestoreIndices(patch->gtolWithAll, >olArrayWithAll)); 2632 } 2633 } 2634 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 2635 PetscCall(VecCreateSeq(PETSC_COMM_SELF, maxDofWithArtificial, &patch->patchRHSWithArtificial)); 2636 PetscCall(VecSetUp(patch->patchRHSWithArtificial)); 2637 } 2638 PetscCall(VecCreateSeq(PETSC_COMM_SELF, maxDof, &patch->patchRHS)); 2639 PetscCall(VecSetUp(patch->patchRHS)); 2640 PetscCall(VecCreateSeq(PETSC_COMM_SELF, maxDof, &patch->patchUpdate)); 2641 PetscCall(VecSetUp(patch->patchUpdate)); 2642 if (patch->save_operators) { 2643 PetscCall(PetscMalloc1(patch->npatch, &patch->mat)); 2644 for (i = 0; i < patch->npatch; ++i) PetscCall(PCPatchCreateMatrix_Private(pc, i, &patch->mat[i], PETSC_FALSE)); 2645 } 2646 PetscCall(PetscLogEventEnd(PC_Patch_CreatePatches, pc, 0, 0, 0)); 2647 2648 /* If desired, calculate weights for dof multiplicity */ 2649 if (patch->partition_of_unity) { 2650 PetscScalar *input = NULL; 2651 PetscScalar *output = NULL; 2652 Vec global; 2653 2654 PetscCall(VecDuplicate(patch->localRHS, &patch->dof_weights)); 2655 if (patch->local_composition_type == PC_COMPOSITE_ADDITIVE) { 2656 for (i = 0; i < patch->npatch; ++i) { 2657 PetscInt dof; 2658 2659 PetscCall(PetscSectionGetDof(patch->gtolCounts, i + pStart, &dof)); 2660 if (dof <= 0) continue; 2661 PetscCall(VecSet(patch->patchRHS, 1.0)); 2662 PetscCall(PCPatch_ScatterLocal_Private(pc, i + pStart, patch->patchRHS, patch->dof_weights, ADD_VALUES, SCATTER_REVERSE, SCATTER_INTERIOR)); 2663 } 2664 } else { 2665 /* multiplicative is actually only locally multiplicative and globally additive. need the pou where the mesh decomposition overlaps */ 2666 PetscCall(VecSet(patch->dof_weights, 1.0)); 2667 } 2668 2669 PetscCall(VecDuplicate(patch->dof_weights, &global)); 2670 PetscCall(VecSet(global, 0.)); 2671 2672 PetscCall(VecGetArray(patch->dof_weights, &input)); 2673 PetscCall(VecGetArray(global, &output)); 2674 PetscCall(PetscSFReduceBegin(patch->sectionSF, MPIU_SCALAR, input, output, MPI_SUM)); 2675 PetscCall(PetscSFReduceEnd(patch->sectionSF, MPIU_SCALAR, input, output, MPI_SUM)); 2676 PetscCall(VecRestoreArray(patch->dof_weights, &input)); 2677 PetscCall(VecRestoreArray(global, &output)); 2678 2679 PetscCall(VecReciprocal(global)); 2680 2681 PetscCall(VecGetArray(patch->dof_weights, &output)); 2682 PetscCall(VecGetArray(global, &input)); 2683 PetscCall(PetscSFBcastBegin(patch->sectionSF, MPIU_SCALAR, input, output, MPI_REPLACE)); 2684 PetscCall(PetscSFBcastEnd(patch->sectionSF, MPIU_SCALAR, input, output, MPI_REPLACE)); 2685 PetscCall(VecRestoreArray(patch->dof_weights, &output)); 2686 PetscCall(VecRestoreArray(global, &input)); 2687 PetscCall(VecDestroy(&global)); 2688 } 2689 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE && patch->save_operators && !patch->isNonlinear) PetscCall(PetscMalloc1(patch->npatch, &patch->matWithArtificial)); 2690 } 2691 PetscCall((*patch->setupsolver)(pc)); 2692 PetscFunctionReturn(PETSC_SUCCESS); 2693 } 2694 2695 static PetscErrorCode PCApply_PATCH_Linear(PC pc, PetscInt i, Vec x, Vec y) 2696 { 2697 PC_PATCH *patch = (PC_PATCH *)pc->data; 2698 KSP ksp; 2699 Mat op; 2700 PetscInt m, n; 2701 2702 PetscFunctionBegin; 2703 if (patch->denseinverse) { 2704 PetscCall((*patch->densesolve)(patch->mat[i], x, y)); 2705 PetscFunctionReturn(PETSC_SUCCESS); 2706 } 2707 ksp = (KSP)patch->solver[i]; 2708 if (!patch->save_operators) { 2709 Mat mat; 2710 2711 PetscCall(PCPatchCreateMatrix_Private(pc, i, &mat, PETSC_FALSE)); 2712 /* Populate operator here. */ 2713 PetscCall(PCPatchComputeOperator_Internal(pc, NULL, mat, i, PETSC_FALSE)); 2714 PetscCall(KSPSetOperators(ksp, mat, mat)); 2715 /* Drop reference so the KSPSetOperators below will blow it away. */ 2716 PetscCall(MatDestroy(&mat)); 2717 } 2718 PetscCall(PetscLogEventBegin(PC_Patch_Solve, pc, 0, 0, 0)); 2719 if (!ksp->setfromoptionscalled) PetscCall(KSPSetFromOptions(ksp)); 2720 /* Disgusting trick to reuse work vectors */ 2721 PetscCall(KSPGetOperators(ksp, &op, NULL)); 2722 PetscCall(MatGetLocalSize(op, &m, &n)); 2723 x->map->n = m; 2724 y->map->n = n; 2725 x->map->N = m; 2726 y->map->N = n; 2727 PetscCall(KSPSolve(ksp, x, y)); 2728 PetscCall(KSPCheckSolve(ksp, pc, y)); 2729 PetscCall(PetscLogEventEnd(PC_Patch_Solve, pc, 0, 0, 0)); 2730 if (!patch->save_operators) { 2731 PC pc; 2732 PetscCall(KSPSetOperators(ksp, NULL, NULL)); 2733 PetscCall(KSPGetPC(ksp, &pc)); 2734 /* Destroy PC context too, otherwise the factored matrix hangs around. */ 2735 PetscCall(PCReset(pc)); 2736 } 2737 PetscFunctionReturn(PETSC_SUCCESS); 2738 } 2739 2740 static PetscErrorCode PCUpdateMultiplicative_PATCH_Linear(PC pc, PetscInt i, PetscInt pStart) 2741 { 2742 PC_PATCH *patch = (PC_PATCH *)pc->data; 2743 Mat multMat; 2744 PetscInt n, m; 2745 2746 PetscFunctionBegin; 2747 if (patch->save_operators) { 2748 multMat = patch->matWithArtificial[i]; 2749 } else { 2750 /*Very inefficient, hopefully we can just assemble the rectangular matrix in the first place.*/ 2751 Mat matSquare; 2752 PetscInt dof; 2753 IS rowis; 2754 PetscCall(PCPatchCreateMatrix_Private(pc, i, &matSquare, PETSC_TRUE)); 2755 PetscCall(PCPatchComputeOperator_Internal(pc, NULL, matSquare, i, PETSC_TRUE)); 2756 PetscCall(MatGetSize(matSquare, &dof, NULL)); 2757 PetscCall(ISCreateStride(PETSC_COMM_SELF, dof, 0, 1, &rowis)); 2758 PetscCall(MatCreateSubMatrix(matSquare, rowis, patch->dofMappingWithoutToWithArtificial[i], MAT_INITIAL_MATRIX, &multMat)); 2759 PetscCall(MatDestroy(&matSquare)); 2760 PetscCall(ISDestroy(&rowis)); 2761 } 2762 /* Disgusting trick to reuse work vectors */ 2763 PetscCall(MatGetLocalSize(multMat, &m, &n)); 2764 patch->patchUpdate->map->n = n; 2765 patch->patchRHSWithArtificial->map->n = m; 2766 patch->patchUpdate->map->N = n; 2767 patch->patchRHSWithArtificial->map->N = m; 2768 PetscCall(MatMult(multMat, patch->patchUpdate, patch->patchRHSWithArtificial)); 2769 PetscCall(VecScale(patch->patchRHSWithArtificial, -1.0)); 2770 PetscCall(PCPatch_ScatterLocal_Private(pc, i + pStart, patch->patchRHSWithArtificial, patch->localRHS, ADD_VALUES, SCATTER_REVERSE, SCATTER_WITHARTIFICIAL)); 2771 if (!patch->save_operators) PetscCall(MatDestroy(&multMat)); 2772 PetscFunctionReturn(PETSC_SUCCESS); 2773 } 2774 2775 static PetscErrorCode PCApply_PATCH(PC pc, Vec x, Vec y) 2776 { 2777 PC_PATCH *patch = (PC_PATCH *)pc->data; 2778 const PetscScalar *globalRHS = NULL; 2779 PetscScalar *localRHS = NULL; 2780 PetscScalar *globalUpdate = NULL; 2781 const PetscInt *bcNodes = NULL; 2782 PetscInt nsweep = patch->symmetrise_sweep ? 2 : 1; 2783 PetscInt start[2] = {0, 0}; 2784 PetscInt end[2] = {-1, -1}; 2785 const PetscInt inc[2] = {1, -1}; 2786 const PetscScalar *localUpdate; 2787 const PetscInt *iterationSet; 2788 PetscInt pStart, numBcs, n, sweep, bc, j; 2789 2790 PetscFunctionBegin; 2791 PetscCall(PetscLogEventBegin(PC_Patch_Apply, pc, 0, 0, 0)); 2792 PetscCall(PetscOptionsPushCreateViewerOff(PETSC_TRUE)); 2793 /* start, end, inc have 2 entries to manage a second backward sweep if we symmetrize */ 2794 end[0] = patch->npatch; 2795 start[1] = patch->npatch - 1; 2796 if (patch->user_patches) { 2797 PetscCall(ISGetLocalSize(patch->iterationSet, &end[0])); 2798 start[1] = end[0] - 1; 2799 PetscCall(ISGetIndices(patch->iterationSet, &iterationSet)); 2800 } 2801 /* Scatter from global space into overlapped local spaces */ 2802 PetscCall(VecGetArrayRead(x, &globalRHS)); 2803 PetscCall(VecGetArray(patch->localRHS, &localRHS)); 2804 PetscCall(PetscSFBcastBegin(patch->sectionSF, MPIU_SCALAR, globalRHS, localRHS, MPI_REPLACE)); 2805 PetscCall(PetscSFBcastEnd(patch->sectionSF, MPIU_SCALAR, globalRHS, localRHS, MPI_REPLACE)); 2806 PetscCall(VecRestoreArrayRead(x, &globalRHS)); 2807 PetscCall(VecRestoreArray(patch->localRHS, &localRHS)); 2808 2809 PetscCall(VecSet(patch->localUpdate, 0.0)); 2810 PetscCall(PetscSectionGetChart(patch->gtolCounts, &pStart, NULL)); 2811 PetscCall(PetscLogEventBegin(PC_Patch_Solve, pc, 0, 0, 0)); 2812 for (sweep = 0; sweep < nsweep; sweep++) { 2813 for (j = start[sweep]; j * inc[sweep] < end[sweep] * inc[sweep]; j += inc[sweep]) { 2814 PetscInt i = patch->user_patches ? iterationSet[j] : j; 2815 PetscInt start, len; 2816 2817 PetscCall(PetscSectionGetDof(patch->gtolCounts, i + pStart, &len)); 2818 PetscCall(PetscSectionGetOffset(patch->gtolCounts, i + pStart, &start)); 2819 /* TODO: Squash out these guys in the setup as well. */ 2820 if (len <= 0) continue; 2821 /* TODO: Do we need different scatters for X and Y? */ 2822 PetscCall(PCPatch_ScatterLocal_Private(pc, i + pStart, patch->localRHS, patch->patchRHS, INSERT_VALUES, SCATTER_FORWARD, SCATTER_INTERIOR)); 2823 PetscCall((*patch->applysolver)(pc, i, patch->patchRHS, patch->patchUpdate)); 2824 PetscCall(PCPatch_ScatterLocal_Private(pc, i + pStart, patch->patchUpdate, patch->localUpdate, ADD_VALUES, SCATTER_REVERSE, SCATTER_INTERIOR)); 2825 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) PetscCall((*patch->updatemultiplicative)(pc, i, pStart)); 2826 } 2827 } 2828 PetscCall(PetscLogEventEnd(PC_Patch_Solve, pc, 0, 0, 0)); 2829 if (patch->user_patches) PetscCall(ISRestoreIndices(patch->iterationSet, &iterationSet)); 2830 /* XXX: should we do this on the global vector? */ 2831 if (patch->partition_of_unity) PetscCall(VecPointwiseMult(patch->localUpdate, patch->localUpdate, patch->dof_weights)); 2832 /* Now patch->localUpdate contains the solution of the patch solves, so we need to combine them all. */ 2833 PetscCall(VecSet(y, 0.0)); 2834 PetscCall(VecGetArray(y, &globalUpdate)); 2835 PetscCall(VecGetArrayRead(patch->localUpdate, &localUpdate)); 2836 PetscCall(PetscSFReduceBegin(patch->sectionSF, MPIU_SCALAR, localUpdate, globalUpdate, MPI_SUM)); 2837 PetscCall(PetscSFReduceEnd(patch->sectionSF, MPIU_SCALAR, localUpdate, globalUpdate, MPI_SUM)); 2838 PetscCall(VecRestoreArrayRead(patch->localUpdate, &localUpdate)); 2839 2840 /* Now we need to send the global BC values through */ 2841 PetscCall(VecGetArrayRead(x, &globalRHS)); 2842 PetscCall(ISGetSize(patch->globalBcNodes, &numBcs)); 2843 PetscCall(ISGetIndices(patch->globalBcNodes, &bcNodes)); 2844 PetscCall(VecGetLocalSize(x, &n)); 2845 for (bc = 0; bc < numBcs; ++bc) { 2846 const PetscInt idx = bcNodes[bc]; 2847 if (idx < n) globalUpdate[idx] = globalRHS[idx]; 2848 } 2849 2850 PetscCall(ISRestoreIndices(patch->globalBcNodes, &bcNodes)); 2851 PetscCall(VecRestoreArrayRead(x, &globalRHS)); 2852 PetscCall(VecRestoreArray(y, &globalUpdate)); 2853 2854 PetscCall(PetscOptionsPopCreateViewerOff()); 2855 PetscCall(PetscLogEventEnd(PC_Patch_Apply, pc, 0, 0, 0)); 2856 PetscFunctionReturn(PETSC_SUCCESS); 2857 } 2858 2859 static PetscErrorCode PCReset_PATCH_Linear(PC pc) 2860 { 2861 PC_PATCH *patch = (PC_PATCH *)pc->data; 2862 PetscInt i; 2863 2864 PetscFunctionBegin; 2865 if (patch->solver) { 2866 for (i = 0; i < patch->npatch; ++i) PetscCall(KSPReset((KSP)patch->solver[i])); 2867 } 2868 PetscFunctionReturn(PETSC_SUCCESS); 2869 } 2870 2871 static PetscErrorCode PCReset_PATCH(PC pc) 2872 { 2873 PC_PATCH *patch = (PC_PATCH *)pc->data; 2874 PetscInt i; 2875 2876 PetscFunctionBegin; 2877 PetscCall(PetscSFDestroy(&patch->sectionSF)); 2878 PetscCall(PetscSectionDestroy(&patch->cellCounts)); 2879 PetscCall(PetscSectionDestroy(&patch->pointCounts)); 2880 PetscCall(PetscSectionDestroy(&patch->cellNumbering)); 2881 PetscCall(PetscSectionDestroy(&patch->gtolCounts)); 2882 PetscCall(ISDestroy(&patch->gtol)); 2883 PetscCall(ISDestroy(&patch->cells)); 2884 PetscCall(ISDestroy(&patch->points)); 2885 PetscCall(ISDestroy(&patch->dofs)); 2886 PetscCall(ISDestroy(&patch->offs)); 2887 PetscCall(PetscSectionDestroy(&patch->patchSection)); 2888 PetscCall(ISDestroy(&patch->ghostBcNodes)); 2889 PetscCall(ISDestroy(&patch->globalBcNodes)); 2890 PetscCall(PetscSectionDestroy(&patch->gtolCountsWithArtificial)); 2891 PetscCall(ISDestroy(&patch->gtolWithArtificial)); 2892 PetscCall(ISDestroy(&patch->dofsWithArtificial)); 2893 PetscCall(ISDestroy(&patch->offsWithArtificial)); 2894 PetscCall(PetscSectionDestroy(&patch->gtolCountsWithAll)); 2895 PetscCall(ISDestroy(&patch->gtolWithAll)); 2896 PetscCall(ISDestroy(&patch->dofsWithAll)); 2897 PetscCall(ISDestroy(&patch->offsWithAll)); 2898 PetscCall(VecDestroy(&patch->cellMats)); 2899 PetscCall(VecDestroy(&patch->intFacetMats)); 2900 PetscCall(ISDestroy(&patch->allCells)); 2901 PetscCall(ISDestroy(&patch->intFacets)); 2902 PetscCall(ISDestroy(&patch->extFacets)); 2903 PetscCall(ISDestroy(&patch->intFacetsToPatchCell)); 2904 PetscCall(PetscSectionDestroy(&patch->intFacetCounts)); 2905 PetscCall(PetscSectionDestroy(&patch->extFacetCounts)); 2906 2907 if (patch->dofSection) 2908 for (i = 0; i < patch->nsubspaces; i++) PetscCall(PetscSectionDestroy(&patch->dofSection[i])); 2909 PetscCall(PetscFree(patch->dofSection)); 2910 PetscCall(PetscFree(patch->bs)); 2911 PetscCall(PetscFree(patch->nodesPerCell)); 2912 if (patch->cellNodeMap) 2913 for (i = 0; i < patch->nsubspaces; i++) PetscCall(PetscFree(patch->cellNodeMap[i])); 2914 PetscCall(PetscFree(patch->cellNodeMap)); 2915 PetscCall(PetscFree(patch->subspaceOffsets)); 2916 2917 PetscCall((*patch->resetsolver)(pc)); 2918 2919 if (patch->subspaces_to_exclude) PetscCall(PetscHSetIDestroy(&patch->subspaces_to_exclude)); 2920 2921 PetscCall(VecDestroy(&patch->localRHS)); 2922 PetscCall(VecDestroy(&patch->localUpdate)); 2923 PetscCall(VecDestroy(&patch->patchRHS)); 2924 PetscCall(VecDestroy(&patch->patchUpdate)); 2925 PetscCall(VecDestroy(&patch->dof_weights)); 2926 if (patch->patch_dof_weights) { 2927 for (i = 0; i < patch->npatch; ++i) PetscCall(VecDestroy(&patch->patch_dof_weights[i])); 2928 PetscCall(PetscFree(patch->patch_dof_weights)); 2929 } 2930 if (patch->mat) { 2931 for (i = 0; i < patch->npatch; ++i) PetscCall(MatDestroy(&patch->mat[i])); 2932 PetscCall(PetscFree(patch->mat)); 2933 } 2934 if (patch->matWithArtificial && !patch->isNonlinear) { 2935 for (i = 0; i < patch->npatch; ++i) PetscCall(MatDestroy(&patch->matWithArtificial[i])); 2936 PetscCall(PetscFree(patch->matWithArtificial)); 2937 } 2938 PetscCall(VecDestroy(&patch->patchRHSWithArtificial)); 2939 if (patch->dofMappingWithoutToWithArtificial) { 2940 for (i = 0; i < patch->npatch; ++i) PetscCall(ISDestroy(&patch->dofMappingWithoutToWithArtificial[i])); 2941 PetscCall(PetscFree(patch->dofMappingWithoutToWithArtificial)); 2942 } 2943 if (patch->dofMappingWithoutToWithAll) { 2944 for (i = 0; i < patch->npatch; ++i) PetscCall(ISDestroy(&patch->dofMappingWithoutToWithAll[i])); 2945 PetscCall(PetscFree(patch->dofMappingWithoutToWithAll)); 2946 } 2947 PetscCall(PetscFree(patch->sub_mat_type)); 2948 if (patch->userIS) { 2949 for (i = 0; i < patch->npatch; ++i) PetscCall(ISDestroy(&patch->userIS[i])); 2950 PetscCall(PetscFree(patch->userIS)); 2951 } 2952 PetscCall(PetscFree(patch->precomputedTensorLocations)); 2953 PetscCall(PetscFree(patch->precomputedIntFacetTensorLocations)); 2954 2955 patch->bs = NULL; 2956 patch->cellNodeMap = NULL; 2957 patch->nsubspaces = 0; 2958 PetscCall(ISDestroy(&patch->iterationSet)); 2959 2960 PetscCall(PetscViewerDestroy(&patch->viewerCells)); 2961 PetscCall(PetscViewerDestroy(&patch->viewerIntFacets)); 2962 PetscCall(PetscViewerDestroy(&patch->viewerPoints)); 2963 PetscCall(PetscViewerDestroy(&patch->viewerSection)); 2964 PetscCall(PetscViewerDestroy(&patch->viewerMatrix)); 2965 PetscFunctionReturn(PETSC_SUCCESS); 2966 } 2967 2968 static PetscErrorCode PCDestroy_PATCH_Linear(PC pc) 2969 { 2970 PC_PATCH *patch = (PC_PATCH *)pc->data; 2971 PetscInt i; 2972 2973 PetscFunctionBegin; 2974 if (patch->solver) { 2975 for (i = 0; i < patch->npatch; ++i) PetscCall(KSPDestroy((KSP *)&patch->solver[i])); 2976 PetscCall(PetscFree(patch->solver)); 2977 } 2978 PetscFunctionReturn(PETSC_SUCCESS); 2979 } 2980 2981 static PetscErrorCode PCDestroy_PATCH(PC pc) 2982 { 2983 PC_PATCH *patch = (PC_PATCH *)pc->data; 2984 2985 PetscFunctionBegin; 2986 PetscCall(PCReset_PATCH(pc)); 2987 PetscCall((*patch->destroysolver)(pc)); 2988 PetscCall(PetscFree(pc->data)); 2989 PetscFunctionReturn(PETSC_SUCCESS); 2990 } 2991 2992 static PetscErrorCode PCSetFromOptions_PATCH(PC pc, PetscOptionItems *PetscOptionsObject) 2993 { 2994 PC_PATCH *patch = (PC_PATCH *)pc->data; 2995 PCPatchConstructType patchConstructionType = PC_PATCH_STAR; 2996 char sub_mat_type[PETSC_MAX_PATH_LEN]; 2997 char option[PETSC_MAX_PATH_LEN]; 2998 const char *prefix; 2999 PetscBool flg, dimflg, codimflg; 3000 MPI_Comm comm; 3001 PetscInt *ifields, nfields, k; 3002 PCCompositeType loctype = PC_COMPOSITE_ADDITIVE; 3003 3004 PetscFunctionBegin; 3005 PetscCall(PetscObjectGetComm((PetscObject)pc, &comm)); 3006 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)pc, &prefix)); 3007 PetscOptionsHeadBegin(PetscOptionsObject, "Patch solver options"); 3008 3009 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_save_operators", patch->classname)); 3010 PetscCall(PetscOptionsBool(option, "Store all patch operators for lifetime of object?", "PCPatchSetSaveOperators", patch->save_operators, &patch->save_operators, &flg)); 3011 3012 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_precompute_element_tensors", patch->classname)); 3013 PetscCall(PetscOptionsBool(option, "Compute each element tensor only once?", "PCPatchSetPrecomputeElementTensors", patch->precomputeElementTensors, &patch->precomputeElementTensors, &flg)); 3014 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_partition_of_unity", patch->classname)); 3015 PetscCall(PetscOptionsBool(option, "Weight contributions by dof multiplicity?", "PCPatchSetPartitionOfUnity", patch->partition_of_unity, &patch->partition_of_unity, &flg)); 3016 3017 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_local_type", patch->classname)); 3018 PetscCall(PetscOptionsEnum(option, "Type of local solver composition (additive or multiplicative)", "PCPatchSetLocalComposition", PCCompositeTypes, (PetscEnum)loctype, (PetscEnum *)&loctype, &flg)); 3019 if (flg) PetscCall(PCPatchSetLocalComposition(pc, loctype)); 3020 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_dense_inverse", patch->classname)); 3021 PetscCall(PetscOptionsBool(option, "Compute inverses of patch matrices and apply directly? Ignores KSP/PC settings on patch.", "PCPatchSetDenseInverse", patch->denseinverse, &patch->denseinverse, &flg)); 3022 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_construct_dim", patch->classname)); 3023 PetscCall(PetscOptionsInt(option, "What dimension of mesh point to construct patches by? (0 = vertices)", "PCPATCH", patch->dim, &patch->dim, &dimflg)); 3024 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_construct_codim", patch->classname)); 3025 PetscCall(PetscOptionsInt(option, "What co-dimension of mesh point to construct patches by? (0 = cells)", "PCPATCH", patch->codim, &patch->codim, &codimflg)); 3026 PetscCheck(!dimflg || !codimflg, comm, PETSC_ERR_ARG_WRONG, "Can only set one of dimension or co-dimension"); 3027 3028 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_construct_type", patch->classname)); 3029 PetscCall(PetscOptionsEnum(option, "How should the patches be constructed?", "PCPatchSetConstructType", PCPatchConstructTypes, (PetscEnum)patchConstructionType, (PetscEnum *)&patchConstructionType, &flg)); 3030 if (flg) PetscCall(PCPatchSetConstructType(pc, patchConstructionType, NULL, NULL)); 3031 3032 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_vanka_dim", patch->classname)); 3033 PetscCall(PetscOptionsInt(option, "Topological dimension of entities for Vanka to ignore", "PCPATCH", patch->vankadim, &patch->vankadim, &flg)); 3034 3035 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_ignore_dim", patch->classname)); 3036 PetscCall(PetscOptionsInt(option, "Topological dimension of entities for completion to ignore", "PCPATCH", patch->ignoredim, &patch->ignoredim, &flg)); 3037 3038 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_pardecomp_overlap", patch->classname)); 3039 PetscCall(PetscOptionsInt(option, "What overlap should we use in construct type pardecomp?", "PCPATCH", patch->pardecomp_overlap, &patch->pardecomp_overlap, &flg)); 3040 3041 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_sub_mat_type", patch->classname)); 3042 PetscCall(PetscOptionsFList(option, "Matrix type for patch solves", "PCPatchSetSubMatType", MatList, NULL, sub_mat_type, PETSC_MAX_PATH_LEN, &flg)); 3043 if (flg) PetscCall(PCPatchSetSubMatType(pc, sub_mat_type)); 3044 3045 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_symmetrise_sweep", patch->classname)); 3046 PetscCall(PetscOptionsBool(option, "Go start->end, end->start?", "PCPATCH", patch->symmetrise_sweep, &patch->symmetrise_sweep, &flg)); 3047 3048 /* If the user has set the number of subspaces, use that for the buffer size, 3049 otherwise use a large number */ 3050 if (patch->nsubspaces <= 0) { 3051 nfields = 128; 3052 } else { 3053 nfields = patch->nsubspaces; 3054 } 3055 PetscCall(PetscMalloc1(nfields, &ifields)); 3056 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_exclude_subspaces", patch->classname)); 3057 PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, option, ifields, &nfields, &flg)); 3058 PetscCheck(!flg || !(patchConstructionType == PC_PATCH_USER), comm, PETSC_ERR_ARG_INCOMP, "We cannot support excluding a subspace with user patches because we do not index patches with a mesh point"); 3059 if (flg) { 3060 PetscCall(PetscHSetIClear(patch->subspaces_to_exclude)); 3061 for (k = 0; k < nfields; k++) PetscCall(PetscHSetIAdd(patch->subspaces_to_exclude, ifields[k])); 3062 } 3063 PetscCall(PetscFree(ifields)); 3064 3065 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_patches_view", patch->classname)); 3066 PetscCall(PetscOptionsBool(option, "Print out information during patch construction", "PCPATCH", patch->viewPatches, &patch->viewPatches, &flg)); 3067 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_cells_view", patch->classname)); 3068 PetscCall(PetscOptionsCreateViewer(comm, ((PetscObject)pc)->options, prefix, option, &patch->viewerCells, &patch->formatCells, &patch->viewCells)); 3069 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_interior_facets_view", patch->classname)); 3070 PetscCall(PetscOptionsCreateViewer(comm, ((PetscObject)pc)->options, prefix, option, &patch->viewerIntFacets, &patch->formatIntFacets, &patch->viewIntFacets)); 3071 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_exterior_facets_view", patch->classname)); 3072 PetscCall(PetscOptionsCreateViewer(comm, ((PetscObject)pc)->options, prefix, option, &patch->viewerExtFacets, &patch->formatExtFacets, &patch->viewExtFacets)); 3073 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_points_view", patch->classname)); 3074 PetscCall(PetscOptionsCreateViewer(comm, ((PetscObject)pc)->options, prefix, option, &patch->viewerPoints, &patch->formatPoints, &patch->viewPoints)); 3075 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_section_view", patch->classname)); 3076 PetscCall(PetscOptionsCreateViewer(comm, ((PetscObject)pc)->options, prefix, option, &patch->viewerSection, &patch->formatSection, &patch->viewSection)); 3077 PetscCall(PetscSNPrintf(option, PETSC_MAX_PATH_LEN, "-%s_patch_mat_view", patch->classname)); 3078 PetscCall(PetscOptionsCreateViewer(comm, ((PetscObject)pc)->options, prefix, option, &patch->viewerMatrix, &patch->formatMatrix, &patch->viewMatrix)); 3079 PetscOptionsHeadEnd(); 3080 patch->optionsSet = PETSC_TRUE; 3081 PetscFunctionReturn(PETSC_SUCCESS); 3082 } 3083 3084 static PetscErrorCode PCSetUpOnBlocks_PATCH(PC pc) 3085 { 3086 PC_PATCH *patch = (PC_PATCH *)pc->data; 3087 KSPConvergedReason reason; 3088 PetscInt i; 3089 3090 PetscFunctionBegin; 3091 if (!patch->save_operators) { 3092 /* Can't do this here because the sub KSPs don't have an operator attached yet. */ 3093 PetscFunctionReturn(PETSC_SUCCESS); 3094 } 3095 if (patch->denseinverse) { 3096 /* No solvers */ 3097 PetscFunctionReturn(PETSC_SUCCESS); 3098 } 3099 for (i = 0; i < patch->npatch; ++i) { 3100 if (!((KSP)patch->solver[i])->setfromoptionscalled) PetscCall(KSPSetFromOptions((KSP)patch->solver[i])); 3101 PetscCall(KSPSetUp((KSP)patch->solver[i])); 3102 PetscCall(KSPGetConvergedReason((KSP)patch->solver[i], &reason)); 3103 if (reason == KSP_DIVERGED_PC_FAILED) pc->failedreason = PC_SUBPC_ERROR; 3104 } 3105 PetscFunctionReturn(PETSC_SUCCESS); 3106 } 3107 3108 static PetscErrorCode PCView_PATCH(PC pc, PetscViewer viewer) 3109 { 3110 PC_PATCH *patch = (PC_PATCH *)pc->data; 3111 PetscViewer sviewer; 3112 PetscBool isascii; 3113 PetscMPIInt rank; 3114 3115 PetscFunctionBegin; 3116 /* TODO Redo tabbing with set tbas in new style */ 3117 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 3118 if (!isascii) PetscFunctionReturn(PETSC_SUCCESS); 3119 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc), &rank)); 3120 PetscCall(PetscViewerASCIIPushTab(viewer)); 3121 PetscCall(PetscViewerASCIIPrintf(viewer, "Subspace Correction preconditioner with %" PetscInt_FMT " patches\n", patch->npatch)); 3122 if (patch->local_composition_type == PC_COMPOSITE_MULTIPLICATIVE) { 3123 PetscCall(PetscViewerASCIIPrintf(viewer, "Schwarz type: multiplicative\n")); 3124 } else { 3125 PetscCall(PetscViewerASCIIPrintf(viewer, "Schwarz type: additive\n")); 3126 } 3127 if (patch->partition_of_unity) PetscCall(PetscViewerASCIIPrintf(viewer, "Weighting by partition of unity\n")); 3128 else PetscCall(PetscViewerASCIIPrintf(viewer, "Not weighting by partition of unity\n")); 3129 if (patch->symmetrise_sweep) PetscCall(PetscViewerASCIIPrintf(viewer, "Symmetrising sweep (start->end, then end->start)\n")); 3130 else PetscCall(PetscViewerASCIIPrintf(viewer, "Not symmetrising sweep\n")); 3131 if (!patch->precomputeElementTensors) PetscCall(PetscViewerASCIIPrintf(viewer, "Not precomputing element tensors (overlapping cells rebuilt in every patch assembly)\n")); 3132 else PetscCall(PetscViewerASCIIPrintf(viewer, "Precomputing element tensors (each cell assembled only once)\n")); 3133 if (!patch->save_operators) PetscCall(PetscViewerASCIIPrintf(viewer, "Not saving patch operators (rebuilt every PCApply)\n")); 3134 else PetscCall(PetscViewerASCIIPrintf(viewer, "Saving patch operators (rebuilt every PCSetUp)\n")); 3135 if (patch->patchconstructop == PCPatchConstruct_Star) PetscCall(PetscViewerASCIIPrintf(viewer, "Patch construction operator: star\n")); 3136 else if (patch->patchconstructop == PCPatchConstruct_Vanka) PetscCall(PetscViewerASCIIPrintf(viewer, "Patch construction operator: Vanka\n")); 3137 else if (patch->patchconstructop == PCPatchConstruct_User) PetscCall(PetscViewerASCIIPrintf(viewer, "Patch construction operator: user-specified\n")); 3138 else PetscCall(PetscViewerASCIIPrintf(viewer, "Patch construction operator: unknown\n")); 3139 3140 if (patch->denseinverse) { 3141 PetscCall(PetscViewerASCIIPrintf(viewer, "Explicitly forming dense inverse and applying patch solver via MatMult.\n")); 3142 } else { 3143 if (patch->isNonlinear) { 3144 PetscCall(PetscViewerASCIIPrintf(viewer, "SNES on patches (all same):\n")); 3145 } else { 3146 PetscCall(PetscViewerASCIIPrintf(viewer, "KSP on patches (all same):\n")); 3147 } 3148 if (patch->solver) { 3149 PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 3150 if (rank == 0) { 3151 PetscCall(PetscViewerASCIIPushTab(sviewer)); 3152 PetscCall(PetscObjectView(patch->solver[0], sviewer)); 3153 PetscCall(PetscViewerASCIIPopTab(sviewer)); 3154 } 3155 PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 3156 } else { 3157 PetscCall(PetscViewerASCIIPushTab(viewer)); 3158 PetscCall(PetscViewerASCIIPrintf(viewer, "Solver not yet set.\n")); 3159 PetscCall(PetscViewerASCIIPopTab(viewer)); 3160 } 3161 } 3162 PetscCall(PetscViewerASCIIPopTab(viewer)); 3163 PetscFunctionReturn(PETSC_SUCCESS); 3164 } 3165 3166 /*MC 3167 PCPATCH - A `PC` object that encapsulates flexible definition of blocks for overlapping and non-overlapping 3168 small block additive preconditioners. Block definition is based on topology from 3169 a `DM` and equation numbering from a `PetscSection`. 3170 3171 Options Database Keys: 3172 + -pc_patch_cells_view - Views the process local cell numbers for each patch 3173 . -pc_patch_points_view - Views the process local mesh point numbers for each patch 3174 . -pc_patch_g2l_view - Views the map between global dofs and patch local dofs for each patch 3175 . -pc_patch_patches_view - Views the global dofs associated with each patch and its boundary 3176 - -pc_patch_sub_mat_view - Views the matrix associated with each patch 3177 3178 Level: intermediate 3179 3180 .seealso: [](ch_ksp), `PCType`, `PCCreate()`, `PCSetType()`, `PCASM`, `PCJACOBI`, `PCPBJACOBI`, `PCVPBJACOBI`, `SNESPATCH` 3181 M*/ 3182 PETSC_EXTERN PetscErrorCode PCCreate_Patch(PC pc) 3183 { 3184 PC_PATCH *patch; 3185 3186 PetscFunctionBegin; 3187 PetscCall(PetscCitationsRegister(PCPatchCitation, &PCPatchcite)); 3188 PetscCall(PetscNew(&patch)); 3189 3190 if (patch->subspaces_to_exclude) PetscCall(PetscHSetIDestroy(&patch->subspaces_to_exclude)); 3191 PetscCall(PetscHSetICreate(&patch->subspaces_to_exclude)); 3192 3193 patch->classname = "pc"; 3194 patch->isNonlinear = PETSC_FALSE; 3195 3196 /* Set some defaults */ 3197 patch->combined = PETSC_FALSE; 3198 patch->save_operators = PETSC_TRUE; 3199 patch->local_composition_type = PC_COMPOSITE_ADDITIVE; 3200 patch->precomputeElementTensors = PETSC_FALSE; 3201 patch->partition_of_unity = PETSC_FALSE; 3202 patch->codim = -1; 3203 patch->dim = -1; 3204 patch->vankadim = -1; 3205 patch->ignoredim = -1; 3206 patch->pardecomp_overlap = 0; 3207 patch->patchconstructop = PCPatchConstruct_Star; 3208 patch->symmetrise_sweep = PETSC_FALSE; 3209 patch->npatch = 0; 3210 patch->userIS = NULL; 3211 patch->optionsSet = PETSC_FALSE; 3212 patch->iterationSet = NULL; 3213 patch->user_patches = PETSC_FALSE; 3214 PetscCall(PetscStrallocpy(MATDENSE, (char **)&patch->sub_mat_type)); 3215 patch->viewPatches = PETSC_FALSE; 3216 patch->viewCells = PETSC_FALSE; 3217 patch->viewPoints = PETSC_FALSE; 3218 patch->viewSection = PETSC_FALSE; 3219 patch->viewMatrix = PETSC_FALSE; 3220 patch->densesolve = NULL; 3221 patch->setupsolver = PCSetUp_PATCH_Linear; 3222 patch->applysolver = PCApply_PATCH_Linear; 3223 patch->resetsolver = PCReset_PATCH_Linear; 3224 patch->destroysolver = PCDestroy_PATCH_Linear; 3225 patch->updatemultiplicative = PCUpdateMultiplicative_PATCH_Linear; 3226 patch->dofMappingWithoutToWithArtificial = NULL; 3227 patch->dofMappingWithoutToWithAll = NULL; 3228 3229 pc->data = (void *)patch; 3230 pc->ops->apply = PCApply_PATCH; 3231 pc->ops->applytranspose = NULL; /* PCApplyTranspose_PATCH; */ 3232 pc->ops->setup = PCSetUp_PATCH; 3233 pc->ops->reset = PCReset_PATCH; 3234 pc->ops->destroy = PCDestroy_PATCH; 3235 pc->ops->setfromoptions = PCSetFromOptions_PATCH; 3236 pc->ops->setuponblocks = PCSetUpOnBlocks_PATCH; 3237 pc->ops->view = PCView_PATCH; 3238 pc->ops->applyrichardson = NULL; 3239 PetscFunctionReturn(PETSC_SUCCESS); 3240 } 3241