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