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