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