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