1 /* 2 Defines a SNES that can consist of a collection of SNESes on patches of the domain 3 */ 4 #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/ 5 #include <petsc/private/pcpatchimpl.h> /* We need internal access to PCPatch right now, until that part is moved to Plex */ 6 #include <petscsf.h> 7 #include <petscsection.h> 8 9 typedef struct { 10 PC pc; /* The linear patch preconditioner */ 11 } SNES_Patch; 12 13 static PetscErrorCode SNESPatchComputeResidual_Private(SNES snes, Vec x, Vec F, void *ctx) 14 { 15 PC pc = (PC) ctx; 16 PC_PATCH *pcpatch = (PC_PATCH *) pc->data; 17 PetscInt pt, size, i; 18 const PetscInt *indices; 19 const PetscScalar *X; 20 PetscScalar *XWithAll; 21 PetscErrorCode ierr; 22 23 PetscFunctionBegin; 24 25 /* scatter from x to patch->patchStateWithAll[pt] */ 26 pt = pcpatch->currentPatch; 27 ierr = ISGetSize(pcpatch->dofMappingWithoutToWithAll[pt], &size);CHKERRQ(ierr); 28 29 ierr = ISGetIndices(pcpatch->dofMappingWithoutToWithAll[pt], &indices);CHKERRQ(ierr); 30 ierr = VecGetArrayRead(x, &X);CHKERRQ(ierr); 31 ierr = VecGetArray(pcpatch->patchStateWithAll[pt], &XWithAll);CHKERRQ(ierr); 32 33 for (i = 0; i < size; ++i) { 34 XWithAll[indices[i]] = X[i]; 35 } 36 37 ierr = VecRestoreArray(pcpatch->patchStateWithAll[pt], &XWithAll);CHKERRQ(ierr); 38 ierr = VecRestoreArrayRead(x, &X);CHKERRQ(ierr); 39 ierr = ISRestoreIndices(pcpatch->dofMappingWithoutToWithAll[pt], &indices);CHKERRQ(ierr); 40 41 ierr = PCPatchComputeFunction_Internal(pc, pcpatch->patchStateWithAll[pt], F, pt);CHKERRQ(ierr); 42 PetscFunctionReturn(0); 43 } 44 45 static PetscErrorCode SNESPatchComputeJacobian_Private(SNES snes, Vec x, Mat J, Mat M, void *ctx) 46 { 47 PC pc = (PC) ctx; 48 PC_PATCH *pcpatch = (PC_PATCH *) pc->data; 49 PetscInt pt, size, i; 50 const PetscInt *indices; 51 const PetscScalar *X; 52 PetscScalar *XWithAll; 53 PetscErrorCode ierr; 54 55 PetscFunctionBegin; 56 /* scatter from x to patch->patchStateWithAll[pt] */ 57 pt = pcpatch->currentPatch; 58 ierr = ISGetSize(pcpatch->dofMappingWithoutToWithAll[pt], &size);CHKERRQ(ierr); 59 60 ierr = ISGetIndices(pcpatch->dofMappingWithoutToWithAll[pt], &indices);CHKERRQ(ierr); 61 ierr = VecGetArrayRead(x, &X);CHKERRQ(ierr); 62 ierr = VecGetArray(pcpatch->patchStateWithAll[pt], &XWithAll);CHKERRQ(ierr); 63 64 for (i = 0; i < size; ++i) { 65 XWithAll[indices[i]] = X[i]; 66 } 67 68 ierr = VecRestoreArray(pcpatch->patchStateWithAll[pt], &XWithAll);CHKERRQ(ierr); 69 ierr = VecRestoreArrayRead(x, &X);CHKERRQ(ierr); 70 ierr = ISRestoreIndices(pcpatch->dofMappingWithoutToWithAll[pt], &indices);CHKERRQ(ierr); 71 72 ierr = PCPatchComputeOperator_Internal(pc, pcpatch->patchStateWithAll[pt], M, pcpatch->currentPatch, PETSC_FALSE);CHKERRQ(ierr); 73 PetscFunctionReturn(0); 74 } 75 76 static PetscErrorCode PCSetUp_PATCH_Nonlinear(PC pc) 77 { 78 PC_PATCH *patch = (PC_PATCH *) pc->data; 79 const char *prefix; 80 PetscInt i, pStart, dof; 81 PetscErrorCode ierr; 82 83 PetscFunctionBegin; 84 if (!pc->setupcalled) { 85 ierr = PetscMalloc1(patch->npatch, &patch->solver);CHKERRQ(ierr); 86 ierr = PCGetOptionsPrefix(pc, &prefix);CHKERRQ(ierr); 87 ierr = PetscSectionGetChart(patch->gtolCounts, &pStart, NULL);CHKERRQ(ierr); 88 for (i = 0; i < patch->npatch; ++i) { 89 SNES snes; 90 91 ierr = SNESCreate(PETSC_COMM_SELF, &snes);CHKERRQ(ierr); 92 ierr = SNESSetOptionsPrefix(snes, prefix);CHKERRQ(ierr); 93 ierr = SNESAppendOptionsPrefix(snes, "sub_");CHKERRQ(ierr); 94 ierr = PetscObjectIncrementTabLevel((PetscObject) snes, (PetscObject) pc, 2);CHKERRQ(ierr); 95 ierr = PetscLogObjectParent((PetscObject) pc, (PetscObject) snes);CHKERRQ(ierr); 96 patch->solver[i] = (PetscObject) snes; 97 } 98 99 ierr = PetscMalloc1(patch->npatch, &patch->patchResidual);CHKERRQ(ierr); 100 ierr = PetscMalloc1(patch->npatch, &patch->patchState);CHKERRQ(ierr); 101 ierr = PetscMalloc1(patch->npatch, &patch->patchStateWithAll);CHKERRQ(ierr); 102 for (i = 0; i < patch->npatch; ++i) { 103 ierr = VecDuplicate(patch->patchRHS[i], &patch->patchResidual[i]);CHKERRQ(ierr); 104 ierr = VecDuplicate(patch->patchUpdate[i], &patch->patchState[i]);CHKERRQ(ierr); 105 106 ierr = PetscSectionGetDof(patch->gtolCountsWithAll, i+pStart, &dof);CHKERRQ(ierr); 107 ierr = VecCreateSeq(PETSC_COMM_SELF, dof, &patch->patchStateWithAll[i]);CHKERRQ(ierr); 108 ierr = VecSetUp(patch->patchStateWithAll[i]);CHKERRQ(ierr); 109 } 110 ierr = VecDuplicate(patch->localUpdate, &patch->localState);CHKERRQ(ierr); 111 } 112 for (i = 0; i < patch->npatch; ++i) { 113 SNES snes = (SNES) patch->solver[i]; 114 115 ierr = SNESSetFunction(snes, patch->patchResidual[i], SNESPatchComputeResidual_Private, pc);CHKERRQ(ierr); 116 ierr = SNESSetJacobian(snes, patch->mat[i], patch->mat[i], SNESPatchComputeJacobian_Private, pc);CHKERRQ(ierr); 117 } 118 if (!pc->setupcalled && patch->optionsSet) for (i = 0; i < patch->npatch; ++i) {ierr = SNESSetFromOptions((SNES) patch->solver[i]);CHKERRQ(ierr);} 119 PetscFunctionReturn(0); 120 } 121 122 static PetscErrorCode PCApply_PATCH_Nonlinear(PC pc, PetscInt i, Vec patchRHS, Vec patchUpdate) 123 { 124 PC_PATCH *patch = (PC_PATCH *) pc->data; 125 PetscInt pStart; 126 PetscErrorCode ierr; 127 128 PetscFunctionBegin; 129 patch->currentPatch = i; 130 ierr = PetscLogEventBegin(PC_Patch_Solve, pc, 0, 0, 0);CHKERRQ(ierr); 131 132 /* Scatter the overlapped global state to our patch state vector */ 133 ierr = PetscSectionGetChart(patch->gtolCounts, &pStart, NULL);CHKERRQ(ierr); 134 ierr = PCPatch_ScatterLocal_Private(pc, i+pStart, patch->localState, patch->patchState[i], INSERT_VALUES, SCATTER_FORWARD, SCATTER_INTERIOR);CHKERRQ(ierr); 135 ierr = PCPatch_ScatterLocal_Private(pc, i+pStart, patch->localState, patch->patchStateWithAll[i], INSERT_VALUES, SCATTER_FORWARD, SCATTER_WITHALL);CHKERRQ(ierr); 136 137 /* Set initial guess to be current state*/ 138 ierr = VecCopy(patch->patchState[i], patchUpdate);CHKERRQ(ierr); 139 /* Solve for new state */ 140 ierr = SNESSolve((SNES) patch->solver[i], patchRHS, patchUpdate);CHKERRQ(ierr); 141 /* To compute update, subtract off previous state */ 142 ierr = VecAXPY(patchUpdate, -1.0, patch->patchState[i]);CHKERRQ(ierr); 143 144 ierr = PetscLogEventEnd(PC_Patch_Solve, pc, 0, 0, 0);CHKERRQ(ierr); 145 PetscFunctionReturn(0); 146 } 147 148 static PetscErrorCode PCReset_PATCH_Nonlinear(PC pc) 149 { 150 PC_PATCH *patch = (PC_PATCH *) pc->data; 151 PetscInt i; 152 PetscErrorCode ierr; 153 154 PetscFunctionBegin; 155 if (patch->solver) { 156 for (i = 0; i < patch->npatch; ++i) {ierr = SNESReset((SNES) patch->solver[i]);CHKERRQ(ierr);} 157 } 158 159 if (patch->patchResidual) { 160 for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patchResidual[i]);CHKERRQ(ierr);} 161 ierr = PetscFree(patch->patchResidual);CHKERRQ(ierr); 162 } 163 164 if (patch->patchState) { 165 for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patchState[i]);CHKERRQ(ierr);} 166 ierr = PetscFree(patch->patchState);CHKERRQ(ierr); 167 } 168 169 if (patch->patchStateWithAll) { 170 for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patchStateWithAll[i]);CHKERRQ(ierr);} 171 ierr = PetscFree(patch->patchStateWithAll);CHKERRQ(ierr); 172 } 173 174 ierr = VecDestroy(&patch->localState);CHKERRQ(ierr); 175 PetscFunctionReturn(0); 176 } 177 178 static PetscErrorCode PCDestroy_PATCH_Nonlinear(PC pc) 179 { 180 PC_PATCH *patch = (PC_PATCH *) pc->data; 181 PetscInt i; 182 PetscErrorCode ierr; 183 184 PetscFunctionBegin; 185 if (patch->solver) { 186 for (i = 0; i < patch->npatch; ++i) {ierr = SNESDestroy((SNES *) &patch->solver[i]);CHKERRQ(ierr);} 187 ierr = PetscFree(patch->solver);CHKERRQ(ierr); 188 } 189 PetscFunctionReturn(0); 190 } 191 192 static PetscErrorCode PCUpdateMultiplicative_PATCH_Nonlinear(PC pc, PetscInt i, PetscInt pStart) 193 { 194 PC_PATCH *patch = (PC_PATCH *) pc->data; 195 PetscErrorCode ierr; 196 197 PetscFunctionBegin; 198 ierr = PCPatch_ScatterLocal_Private(pc, i + pStart, patch->patchUpdate[i], patch->localState, ADD_VALUES, SCATTER_REVERSE, SCATTER_INTERIOR);CHKERRQ(ierr); 199 PetscFunctionReturn(0); 200 } 201 202 static PetscErrorCode SNESSetUp_Patch(SNES snes) 203 { 204 SNES_Patch *patch = (SNES_Patch *) snes->data; 205 DM dm; 206 Mat dummy; 207 Vec F; 208 PetscInt n, N; 209 PetscErrorCode ierr; 210 211 PetscFunctionBegin; 212 ierr = SNESGetDM(snes, &dm);CHKERRQ(ierr); 213 ierr = PCSetDM(patch->pc, dm);CHKERRQ(ierr); 214 ierr = SNESGetFunction(snes, &F, NULL, NULL);CHKERRQ(ierr); 215 ierr = VecGetLocalSize(F, &n);CHKERRQ(ierr); 216 ierr = VecGetSize(F, &N);CHKERRQ(ierr); 217 ierr = MatCreateShell(PetscObjectComm((PetscObject) snes), n, n, N, N, (void *) snes, &dummy);CHKERRQ(ierr); 218 ierr = PCSetOperators(patch->pc, dummy, dummy);CHKERRQ(ierr); 219 ierr = MatDestroy(&dummy);CHKERRQ(ierr); 220 ierr = PCSetUp(patch->pc);CHKERRQ(ierr); 221 /* allocate workspace */ 222 PetscFunctionReturn(0); 223 } 224 225 static PetscErrorCode SNESReset_Patch(SNES snes) 226 { 227 SNES_Patch *patch = (SNES_Patch *) snes->data; 228 PetscErrorCode ierr; 229 230 PetscFunctionBegin; 231 ierr = PCReset(patch->pc);CHKERRQ(ierr); 232 PetscFunctionReturn(0); 233 } 234 235 static PetscErrorCode SNESDestroy_Patch(SNES snes) 236 { 237 SNES_Patch *patch = (SNES_Patch *) snes->data; 238 PetscErrorCode ierr; 239 240 PetscFunctionBegin; 241 ierr = SNESReset_Patch(snes);CHKERRQ(ierr); 242 ierr = PCDestroy(&patch->pc);CHKERRQ(ierr); 243 ierr = PetscFree(snes->data);CHKERRQ(ierr); 244 PetscFunctionReturn(0); 245 } 246 247 static PetscErrorCode SNESSetFromOptions_Patch(PetscOptionItems *PetscOptionsObject, SNES snes) 248 { 249 SNES_Patch *patch = (SNES_Patch *) snes->data; 250 const char *prefix; 251 PetscErrorCode ierr; 252 253 PetscFunctionBegin; 254 ierr = PetscObjectGetOptionsPrefix((PetscObject)snes, &prefix);CHKERRQ(ierr); 255 ierr = PetscObjectSetOptionsPrefix((PetscObject)patch->pc, prefix);CHKERRQ(ierr); 256 ierr = PCSetFromOptions(patch->pc);CHKERRQ(ierr); 257 PetscFunctionReturn(0); 258 } 259 260 static PetscErrorCode SNESView_Patch(SNES snes,PetscViewer viewer) 261 { 262 SNES_Patch *patch = (SNES_Patch *) snes->data; 263 PetscBool iascii; 264 PetscErrorCode ierr; 265 266 PetscFunctionBegin; 267 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 268 if (iascii) { 269 ierr = PetscViewerASCIIPrintf(viewer,"SNESPATCH\n");CHKERRQ(ierr); 270 } 271 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 272 ierr = PCView(patch->pc, viewer);CHKERRQ(ierr); 273 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 274 PetscFunctionReturn(0); 275 } 276 277 static PetscErrorCode SNESSolve_Patch(SNES snes) 278 { 279 SNES_Patch *patch = (SNES_Patch *) snes->data; 280 PC_PATCH *pcpatch = (PC_PATCH *) patch->pc->data; 281 SNESLineSearch ls; 282 Vec rhs, update, state, residual; 283 const PetscScalar *globalState = NULL; 284 PetscScalar *localState = NULL; 285 PetscInt its = 0; 286 PetscReal xnorm = 0.0, ynorm = 0.0, fnorm = 0.0; 287 PetscErrorCode ierr; 288 289 PetscFunctionBegin; 290 ierr = SNESGetSolution(snes, &state);CHKERRQ(ierr); 291 ierr = SNESGetSolutionUpdate(snes, &update);CHKERRQ(ierr); 292 ierr = SNESGetRhs(snes, &rhs);CHKERRQ(ierr); 293 294 ierr = SNESGetFunction(snes, &residual, NULL, NULL);CHKERRQ(ierr); 295 ierr = SNESGetLineSearch(snes, &ls);CHKERRQ(ierr); 296 297 ierr = SNESSetConvergedReason(snes, SNES_CONVERGED_ITERATING);CHKERRQ(ierr); 298 ierr = VecSet(update, 0.0);CHKERRQ(ierr); 299 ierr = SNESComputeFunction(snes, state, residual);CHKERRQ(ierr); 300 301 ierr = VecNorm(state, NORM_2, &xnorm);CHKERRQ(ierr); 302 ierr = VecNorm(residual, NORM_2, &fnorm);CHKERRQ(ierr); 303 snes->ttol = fnorm*snes->rtol; 304 305 if (snes->ops->converged) { 306 ierr = (*snes->ops->converged)(snes,its,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 307 } else { 308 ierr = SNESConvergedSkip(snes,its,xnorm,ynorm,fnorm,&snes->reason,0);CHKERRQ(ierr); 309 } 310 ierr = SNESLogConvergenceHistory(snes, fnorm, 0);CHKERRQ(ierr); /* should we count lits from the patches? */ 311 ierr = SNESMonitor(snes, its, fnorm);CHKERRQ(ierr); 312 313 /* The main solver loop */ 314 for (its = 0; its < snes->max_its; its++) { 315 316 ierr = SNESSetIterationNumber(snes, its);CHKERRQ(ierr); 317 318 /* Scatter state vector to overlapped vector on all patches. 319 The vector pcpatch->localState is scattered to each patch 320 in PCApply_PATCH_Nonlinear. */ 321 ierr = VecGetArrayRead(state, &globalState);CHKERRQ(ierr); 322 ierr = VecGetArray(pcpatch->localState, &localState);CHKERRQ(ierr); 323 ierr = PetscSFBcastBegin(pcpatch->sectionSF, MPIU_SCALAR, globalState, localState);CHKERRQ(ierr); 324 ierr = PetscSFBcastEnd(pcpatch->sectionSF, MPIU_SCALAR, globalState, localState);CHKERRQ(ierr); 325 ierr = VecRestoreArray(pcpatch->localState, &localState);CHKERRQ(ierr); 326 ierr = VecRestoreArrayRead(state, &globalState);CHKERRQ(ierr); 327 328 /* The looping over patches happens here */ 329 ierr = PCApply(patch->pc, rhs, update);CHKERRQ(ierr); 330 331 /* Apply a line search. This will often be basic with 332 damping = 1/(max number of patches a dof can be in), 333 but not always */ 334 ierr = VecScale(update, -1.0);CHKERRQ(ierr); 335 ierr = SNESLineSearchApply(ls, state, residual, &fnorm, update);CHKERRQ(ierr); 336 337 ierr = VecNorm(state, NORM_2, &xnorm);CHKERRQ(ierr); 338 ierr = VecNorm(update, NORM_2, &ynorm);CHKERRQ(ierr); 339 340 if (snes->ops->converged) { 341 ierr = (*snes->ops->converged)(snes,its,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 342 } else { 343 ierr = SNESConvergedSkip(snes,its,xnorm,ynorm,fnorm,&snes->reason,0);CHKERRQ(ierr); 344 } 345 ierr = SNESLogConvergenceHistory(snes, fnorm, 0);CHKERRQ(ierr); /* FIXME: should we count lits? */ 346 ierr = SNESMonitor(snes, its, fnorm);CHKERRQ(ierr); 347 } 348 349 if (its == snes->max_its) { ierr = SNESSetConvergedReason(snes, SNES_DIVERGED_MAX_IT);CHKERRQ(ierr); } 350 PetscFunctionReturn(0); 351 } 352 353 /*MC 354 SNESPATCH - Solve a nonlinear problem by composing together many nonlinear solvers on patches 355 356 Level: intermediate 357 358 .seealso: SNESCreate(), SNESSetType(), SNESType (for list of available types), SNES, 359 PCPATCH 360 361 References: 362 . 1. - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers", SIAM Review, 57(4), 2015 363 364 M*/ 365 PETSC_EXTERN PetscErrorCode SNESCreate_Patch(SNES snes) 366 { 367 PetscErrorCode ierr; 368 SNES_Patch *patch; 369 PC_PATCH *patchpc; 370 SNESLineSearch linesearch; 371 372 PetscFunctionBegin; 373 ierr = PetscNewLog(snes, &patch);CHKERRQ(ierr); 374 375 snes->ops->solve = SNESSolve_Patch; 376 snes->ops->setup = SNESSetUp_Patch; 377 snes->ops->reset = SNESReset_Patch; 378 snes->ops->destroy = SNESDestroy_Patch; 379 snes->ops->setfromoptions = SNESSetFromOptions_Patch; 380 snes->ops->view = SNESView_Patch; 381 382 ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr); 383 ierr = SNESLineSearchSetType(linesearch,SNESLINESEARCHBASIC);CHKERRQ(ierr); 384 snes->usesksp = PETSC_FALSE; 385 386 snes->alwayscomputesfinalresidual = PETSC_FALSE; 387 388 snes->data = (void *) patch; 389 ierr = PCCreate(PetscObjectComm((PetscObject) snes), &patch->pc);CHKERRQ(ierr); 390 ierr = PCSetType(patch->pc, PCPATCH);CHKERRQ(ierr); 391 392 patchpc = (PC_PATCH*) patch->pc->data; 393 patchpc->classname = "snes"; 394 patchpc->isNonlinear = PETSC_TRUE; 395 396 patchpc->setupsolver = PCSetUp_PATCH_Nonlinear; 397 patchpc->applysolver = PCApply_PATCH_Nonlinear; 398 patchpc->resetsolver = PCReset_PATCH_Nonlinear; 399 patchpc->destroysolver = PCDestroy_PATCH_Nonlinear; 400 patchpc->updatemultiplicative = PCUpdateMultiplicative_PATCH_Nonlinear; 401 402 PetscFunctionReturn(0); 403 } 404 405 PetscErrorCode SNESPatchSetDiscretisationInfo(SNES snes, PetscInt nsubspaces, DM *dms, PetscInt *bs, PetscInt *nodesPerCell, const PetscInt **cellNodeMap, 406 const PetscInt *subspaceOffsets, PetscInt numGhostBcs, const PetscInt *ghostBcNodes, PetscInt numGlobalBcs, const PetscInt *globalBcNodes) 407 { 408 SNES_Patch *patch = (SNES_Patch *) snes->data; 409 PetscErrorCode ierr; 410 DM dm; 411 412 PetscFunctionBegin; 413 ierr = SNESGetDM(snes, &dm);CHKERRQ(ierr); 414 if (!dm) SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "DM not yet set on patch SNES\n"); 415 ierr = PCSetDM(patch->pc, dm);CHKERRQ(ierr); 416 ierr = PCPatchSetDiscretisationInfo(patch->pc, nsubspaces, dms, bs, nodesPerCell, cellNodeMap, subspaceOffsets, numGhostBcs, ghostBcNodes, numGlobalBcs, globalBcNodes);CHKERRQ(ierr); 417 PetscFunctionReturn(0); 418 } 419 420 PetscErrorCode SNESPatchSetComputeOperator(SNES snes, PetscErrorCode (*func)(PC, PetscInt, Vec, Mat, IS, PetscInt, const PetscInt *, const PetscInt *, void *), void *ctx) 421 { 422 SNES_Patch *patch = (SNES_Patch *) snes->data; 423 PetscErrorCode ierr; 424 425 PetscFunctionBegin; 426 ierr = PCPatchSetComputeOperator(patch->pc, func, ctx);CHKERRQ(ierr); 427 PetscFunctionReturn(0); 428 } 429 430 PetscErrorCode SNESPatchSetComputeFunction(SNES snes, PetscErrorCode (*func)(PC, PetscInt, Vec, Vec, IS, PetscInt, const PetscInt *, const PetscInt *, void *), void *ctx) 431 { 432 SNES_Patch *patch = (SNES_Patch *) snes->data; 433 PetscErrorCode ierr; 434 435 PetscFunctionBegin; 436 ierr = PCPatchSetComputeFunction(patch->pc, func, ctx);CHKERRQ(ierr); 437 PetscFunctionReturn(0); 438 } 439 440 PetscErrorCode SNESPatchSetConstructType(SNES snes, PCPatchConstructType ctype, PetscErrorCode (*func)(PC, PetscInt *, IS **, IS *, void *), void *ctx) 441 { 442 SNES_Patch *patch = (SNES_Patch *) snes->data; 443 PetscErrorCode ierr; 444 445 PetscFunctionBegin; 446 ierr = PCPatchSetConstructType(patch->pc, ctype, func, ctx);CHKERRQ(ierr); 447 PetscFunctionReturn(0); 448 } 449 450 PetscErrorCode SNESPatchSetCellNumbering(SNES snes, PetscSection cellNumbering) 451 { 452 SNES_Patch *patch = (SNES_Patch *) snes->data; 453 PetscErrorCode ierr; 454 455 PetscFunctionBegin; 456 ierr = PCPatchSetCellNumbering(patch->pc, cellNumbering);CHKERRQ(ierr); 457 PetscFunctionReturn(0); 458 } 459