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