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 8 typedef struct { 9 PC pc; /* The linear patch preconditioner */ 10 SNESCompositeType type; 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 PetscErrorCode ierr; 18 19 PetscFunctionBegin; 20 ierr = PCPatchComputeFunction_Internal(pc, x, F, pcpatch->currentPatch);CHKERRQ(ierr); 21 PetscFunctionReturn(0); 22 } 23 24 static PetscErrorCode SNESPatchComputeJacobian_Private(SNES snes, Vec x, Mat J, Mat M, void *ctx) 25 { 26 PC pc = (PC) ctx; 27 PC_PATCH *pcpatch = (PC_PATCH *) pc->data; 28 PetscErrorCode ierr; 29 30 PetscFunctionBegin; 31 ierr = PCPatchComputeOperator_Internal(pc, x, M, pcpatch->currentPatch, PETSC_FALSE);CHKERRQ(ierr); 32 PetscFunctionReturn(0); 33 } 34 35 static PetscErrorCode PCSetUp_PATCH_Nonlinear(PC pc) 36 { 37 PC_PATCH *patch = (PC_PATCH *) pc->data; 38 const char *prefix; 39 PetscInt i; 40 PetscErrorCode ierr; 41 42 PetscFunctionBegin; 43 if (!pc->setupcalled) { 44 ierr = PetscMalloc1(patch->npatch, &patch->solver);CHKERRQ(ierr); 45 ierr = PCGetOptionsPrefix(pc, &prefix);CHKERRQ(ierr); 46 for (i = 0; i < patch->npatch; ++i) { 47 SNES snes; 48 KSP subksp; 49 50 ierr = SNESCreate(PETSC_COMM_SELF, &snes);CHKERRQ(ierr); 51 ierr = SNESSetOptionsPrefix(snes, prefix);CHKERRQ(ierr); 52 ierr = SNESAppendOptionsPrefix(snes, "sub_");CHKERRQ(ierr); 53 ierr = PetscObjectIncrementTabLevel((PetscObject) snes, (PetscObject) pc, 2);CHKERRQ(ierr); 54 ierr = SNESGetKSP(snes, &subksp);CHKERRQ(ierr); 55 ierr = PetscObjectIncrementTabLevel((PetscObject) subksp, (PetscObject) pc, 2);CHKERRQ(ierr); 56 ierr = PetscLogObjectParent((PetscObject) pc, (PetscObject) snes);CHKERRQ(ierr); 57 patch->solver[i] = (PetscObject) snes; 58 } 59 60 ierr = PetscMalloc1(patch->npatch, &patch->patchResidual);CHKERRQ(ierr); 61 ierr = PetscMalloc1(patch->npatch, &patch->patchState);CHKERRQ(ierr); 62 for (i = 0; i < patch->npatch; ++i) { 63 ierr = VecDuplicate(patch->patchRHS[i], &patch->patchResidual[i]);CHKERRQ(ierr); 64 ierr = VecDuplicate(patch->patchUpdate[i], &patch->patchState[i]);CHKERRQ(ierr); 65 } 66 ierr = VecDuplicate(patch->localUpdate, &patch->localState);CHKERRQ(ierr); 67 } 68 for (i = 0; i < patch->npatch; ++i) { 69 SNES snes = (SNES) patch->solver[i]; 70 71 ierr = SNESSetFunction(snes, patch->patchResidual[i], SNESPatchComputeResidual_Private, pc);CHKERRQ(ierr); 72 ierr = SNESSetJacobian(snes, patch->mat[i], patch->mat[i], SNESPatchComputeJacobian_Private, pc);CHKERRQ(ierr); 73 } 74 if (!pc->setupcalled && patch->optionsSet) for (i = 0; i < patch->npatch; ++i) {ierr = SNESSetFromOptions((SNES) patch->solver[i]);CHKERRQ(ierr);} 75 PetscFunctionReturn(0); 76 } 77 78 static PetscErrorCode PCApply_PATCH_Nonlinear(PC pc, PetscInt i, Vec patchRHS, Vec patchUpdate) 79 { 80 PC_PATCH *patch = (PC_PATCH *) pc->data; 81 PetscInt pStart; 82 PetscErrorCode ierr; 83 84 PetscFunctionBegin; 85 patch->currentPatch = i; 86 ierr = PetscLogEventBegin(PC_Patch_Solve, pc, 0, 0, 0);CHKERRQ(ierr); 87 88 /* Scatter the overlapped global state to our patch state vector */ 89 ierr = PetscSectionGetChart(patch->gtolCounts, &pStart, NULL);CHKERRQ(ierr); 90 ierr = PCPatch_ScatterLocal_Private(pc, i+pStart, patch->localState, patch->patchState[i], INSERT_VALUES, SCATTER_FORWARD, PETSC_FALSE);CHKERRQ(ierr); 91 92 /* Set initial guess to be current state*/ 93 ierr = VecCopy(patch->patchState[i], patchUpdate);CHKERRQ(ierr); 94 /* Solve for new state */ 95 ierr = SNESSolve((SNES) patch->solver[i], patchRHS, patchUpdate);CHKERRQ(ierr); 96 /* To compute update, subtract off previous state */ 97 ierr = VecAXPY(patchUpdate, -1.0, patch->patchState[i]);CHKERRQ(ierr); 98 99 ierr = PetscLogEventEnd(PC_Patch_Solve, pc, 0, 0, 0);CHKERRQ(ierr); 100 PetscFunctionReturn(0); 101 } 102 103 static PetscErrorCode PCReset_PATCH_Nonlinear(PC pc) 104 { 105 PC_PATCH *patch = (PC_PATCH *) pc->data; 106 PetscInt i; 107 PetscErrorCode ierr; 108 109 PetscFunctionBegin; 110 111 if (patch->solver) { 112 for (i = 0; i < patch->npatch; ++i) {ierr = SNESReset((SNES) patch->solver[i]);CHKERRQ(ierr);} 113 } 114 115 if (patch->patchResidual) { 116 for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patchResidual[i]);CHKERRQ(ierr);} 117 ierr = PetscFree(patch->patchResidual);CHKERRQ(ierr); 118 } 119 120 if (patch->patchState) { 121 for (i = 0; i < patch->npatch; ++i) {ierr = VecDestroy(&patch->patchState[i]);CHKERRQ(ierr);} 122 ierr = PetscFree(patch->patchState);CHKERRQ(ierr); 123 } 124 125 ierr = VecDestroy(&patch->localState);CHKERRQ(ierr); 126 127 PetscFunctionReturn(0); 128 } 129 130 static PetscErrorCode PCDestroy_PATCH_Nonlinear(PC pc) 131 { 132 PC_PATCH *patch = (PC_PATCH *) pc->data; 133 PetscInt i; 134 PetscErrorCode ierr; 135 136 PetscFunctionBegin; 137 if (patch->solver) { 138 for (i = 0; i < patch->npatch; ++i) {ierr = SNESDestroy((SNES *) &patch->solver[i]);CHKERRQ(ierr);} 139 ierr = PetscFree(patch->solver);CHKERRQ(ierr); 140 } 141 PetscFunctionReturn(0); 142 } 143 144 static PetscErrorCode SNESSetUp_Patch(SNES snes) 145 { 146 SNES_Patch *patch = (SNES_Patch *) snes->data; 147 DM dm; 148 Mat dummy; 149 Vec F; 150 PetscInt n, N; 151 PetscErrorCode ierr; 152 153 PetscFunctionBegin; 154 ierr = SNESGetDM(snes, &dm);CHKERRQ(ierr); 155 ierr = PCSetDM(patch->pc, dm);CHKERRQ(ierr); 156 ierr = SNESGetFunction(snes, &F, NULL, NULL);CHKERRQ(ierr); 157 ierr = VecGetLocalSize(F, &n);CHKERRQ(ierr); 158 ierr = VecGetSize(F, &N);CHKERRQ(ierr); 159 ierr = MatCreateShell(PetscObjectComm((PetscObject) snes), n, n, N, N, (void *) snes, &dummy);CHKERRQ(ierr); 160 ierr = PCSetOperators(patch->pc, dummy, dummy);CHKERRQ(ierr); 161 ierr = MatDestroy(&dummy);CHKERRQ(ierr); 162 ierr = PCSetUp(patch->pc);CHKERRQ(ierr); 163 /* allocate workspace */ 164 PetscFunctionReturn(0); 165 } 166 167 static PetscErrorCode SNESReset_Patch(SNES snes) 168 { 169 SNES_Patch *patch = (SNES_Patch *) snes->data; 170 PetscErrorCode ierr; 171 172 PetscFunctionBegin; 173 ierr = PCReset(patch->pc);CHKERRQ(ierr); 174 PetscFunctionReturn(0); 175 } 176 177 static PetscErrorCode SNESDestroy_Patch(SNES snes) 178 { 179 SNES_Patch *patch = (SNES_Patch *) snes->data; 180 PetscErrorCode ierr; 181 182 PetscFunctionBegin; 183 ierr = SNESReset_Patch(snes);CHKERRQ(ierr); 184 ierr = PCDestroy(&patch->pc);CHKERRQ(ierr); 185 ierr = PetscFree(snes->data);CHKERRQ(ierr); 186 PetscFunctionReturn(0); 187 } 188 189 static PetscErrorCode SNESSetFromOptions_Patch(PetscOptionItems *PetscOptionsObject, SNES snes) 190 { 191 SNES_Patch *patch = (SNES_Patch *) snes->data; 192 PetscBool flg; 193 const char *prefix; 194 PetscErrorCode ierr; 195 196 PetscFunctionBegin; 197 ierr = PetscOptionsHead(PetscOptionsObject, "Patch nonlinear preconditioner options");CHKERRQ(ierr); 198 ierr = PetscOptionsEnum("-snes_patch_type", "Type of composition", "SNESPatchSetType", SNESCompositeTypes, (PetscEnum) patch->type, (PetscEnum *) &patch->type, &flg);CHKERRQ(ierr); 199 if (flg) {ierr = SNESPatchSetType(snes, patch->type);CHKERRQ(ierr);} 200 ierr = PetscOptionsTail();CHKERRQ(ierr); 201 202 ierr = PetscObjectGetOptionsPrefix((PetscObject)snes, &prefix);CHKERRQ(ierr); 203 ierr = PetscObjectSetOptionsPrefix((PetscObject)patch->pc, prefix);CHKERRQ(ierr); 204 ierr = PCSetFromOptions(patch->pc);CHKERRQ(ierr); 205 PetscFunctionReturn(0); 206 } 207 208 static PetscErrorCode SNESView_Patch(SNES snes,PetscViewer viewer) 209 { 210 SNES_Patch *patch = (SNES_Patch *) snes->data; 211 PetscBool iascii; 212 PetscErrorCode ierr; 213 214 PetscFunctionBegin; 215 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 216 if (iascii) { 217 ierr = PetscViewerASCIIPrintf(viewer," type - %s\n",SNESCompositeTypes[patch->type]);CHKERRQ(ierr); 218 } 219 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 220 ierr = PCView(patch->pc, viewer);CHKERRQ(ierr); 221 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 222 PetscFunctionReturn(0); 223 } 224 225 static PetscErrorCode SNESSolve_Patch(SNES snes) 226 { 227 SNES_Patch *patch = (SNES_Patch *) snes->data; 228 PC_PATCH *pcpatch = (PC_PATCH *) patch->pc->data; 229 Vec rhs, update, state; 230 const PetscScalar *globalState = NULL; 231 PetscScalar *localState = NULL; 232 233 PetscErrorCode ierr; 234 235 PetscFunctionBegin; 236 237 ierr = SNESGetSolution(snes, &state);CHKERRQ(ierr); 238 ierr = SNESGetSolutionUpdate(snes, &update);CHKERRQ(ierr); 239 ierr = SNESGetRhs(snes, &rhs);CHKERRQ(ierr); 240 241 /* These happen in a loop */ 242 { 243 /* Scatter state vector to overlapped vector on all patches. 244 The vector pcpatch->localState is scattered to each patch 245 in PCApply_PATCH_Nonlinear. */ 246 ierr = VecGetArrayRead(state, &globalState);CHKERRQ(ierr); 247 ierr = VecGetArray(pcpatch->localState, &localState);CHKERRQ(ierr); 248 ierr = PetscSFBcastBegin(pcpatch->defaultSF, MPIU_SCALAR, globalState, localState);CHKERRQ(ierr); 249 ierr = PetscSFBcastEnd(pcpatch->defaultSF, MPIU_SCALAR, globalState, localState);CHKERRQ(ierr); 250 ierr = VecRestoreArray(pcpatch->localState, &localState);CHKERRQ(ierr); 251 ierr = VecRestoreArrayRead(state, &globalState);CHKERRQ(ierr); 252 253 ierr = PCApply(patch->pc, rhs, update); 254 ierr = VecAXPY(state, 1.0, update);CHKERRQ(ierr); /* FIXME: replace with line search */ 255 } 256 257 ierr = SNESSetConvergedReason(snes, SNES_CONVERGED_ITS);CHKERRQ(ierr); 258 PetscFunctionReturn(0); 259 } 260 261 static PetscErrorCode SNESPatchSetType_Patch(SNES snes, SNESCompositeType type) 262 { 263 SNES_Patch *patch = (SNES_Patch *) snes->data; 264 265 PetscFunctionBegin; 266 patch->type = type; 267 PetscFunctionReturn(0); 268 } 269 270 /*MC 271 SNESPATCH - Solve a nonlinear problem by composing together many nonlinear solvers on patches 272 273 Options Database Keys: 274 . -snes_patch_type <type: one of additive, multiplicative, symmetric_multiplicative> - Sets composition type 275 276 Level: intermediate 277 278 Concepts: composing solvers 279 280 .seealso: SNESCreate(), SNESSetType(), SNESType (for list of available types), SNES, 281 PCPATCH 282 283 References: 284 . 1. - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers", SIAM Review, 57(4), 2015 285 286 M*/ 287 PETSC_EXTERN PetscErrorCode SNESCreate_Patch(SNES snes) 288 { 289 PetscErrorCode ierr; 290 SNES_Patch *patch; 291 292 PetscFunctionBegin; 293 ierr = PetscNewLog(snes, &patch);CHKERRQ(ierr); 294 295 snes->ops->solve = SNESSolve_Patch; 296 snes->ops->setup = SNESSetUp_Patch; 297 snes->ops->reset = SNESReset_Patch; 298 snes->ops->destroy = SNESDestroy_Patch; 299 snes->ops->setfromoptions = SNESSetFromOptions_Patch; 300 snes->ops->view = SNESView_Patch; 301 302 snes->alwayscomputesfinalresidual = PETSC_FALSE; 303 304 snes->data = (void *) patch; 305 patch->type = SNES_COMPOSITE_ADDITIVE; 306 ierr = PCCreate(PetscObjectComm((PetscObject) snes), &patch->pc);CHKERRQ(ierr); 307 ierr = PCSetType(patch->pc, PCPATCH);CHKERRQ(ierr); 308 309 ((PC_PATCH *) patch->pc->data)->setupsolver = PCSetUp_PATCH_Nonlinear; 310 ((PC_PATCH *) patch->pc->data)->applysolver = PCApply_PATCH_Nonlinear; 311 ((PC_PATCH *) patch->pc->data)->resetsolver = PCReset_PATCH_Nonlinear; 312 ((PC_PATCH *) patch->pc->data)->destroysolver = PCDestroy_PATCH_Nonlinear; 313 314 ierr = PetscObjectComposeFunction((PetscObject) snes, "SNESPatchSetType_C", SNESPatchSetType_Patch);CHKERRQ(ierr); 315 PetscFunctionReturn(0); 316 } 317 318 /*@ 319 SNESPatchSetType - Sets the type of composition. 320 321 Logically Collective on SNES 322 323 Input Parameter: 324 + snes - the preconditioner context 325 - type - SNES_COMPOSITE_ADDITIVE (default), SNES_COMPOSITE_MULTIPLICATIVE, etc. 326 327 Options Database Key: 328 . -snes_composite_type <type: one of additive, multiplicative, etc> - Sets composite preconditioner type 329 330 Level: Developer 331 332 .keywords: SNES, set, type, composite preconditioner, additive, multiplicative 333 @*/ 334 PetscErrorCode SNESPatchSetType(SNES snes, SNESCompositeType type) 335 { 336 PetscErrorCode ierr; 337 338 PetscFunctionBegin; 339 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 340 PetscValidLogicalCollectiveEnum(snes,type, 2); 341 ierr = PetscTryMethod(snes, "SNESPatchSetType_C", (SNES,SNESCompositeType), (snes,type));CHKERRQ(ierr); 342 PetscFunctionReturn(0); 343 } 344 345 PetscErrorCode SNESPatchSetDiscretisationInfo(SNES snes, PetscInt nsubspaces, DM *dms, PetscInt *bs, PetscInt *nodesPerCell, const PetscInt **cellNodeMap, 346 const PetscInt *subspaceOffsets, PetscInt numGhostBcs, const PetscInt *ghostBcNodes, PetscInt numGlobalBcs, const PetscInt *globalBcNodes) 347 { 348 SNES_Patch *patch = (SNES_Patch *) snes->data; 349 PetscErrorCode ierr; 350 DM dm; 351 352 PetscFunctionBegin; 353 ierr = SNESGetDM(snes, &dm);CHKERRQ(ierr); 354 if (!dm) SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "DM not yet set on patch SNES\n"); 355 ierr = PCSetDM(patch->pc, dm);CHKERRQ(ierr); 356 ierr = PCPatchSetDiscretisationInfo(patch->pc, nsubspaces, dms, bs, nodesPerCell, cellNodeMap, subspaceOffsets, numGhostBcs, ghostBcNodes, numGlobalBcs, globalBcNodes);CHKERRQ(ierr); 357 PetscFunctionReturn(0); 358 } 359 360 PetscErrorCode SNESPatchSetComputeOperator(SNES snes, PetscErrorCode (*func)(PC, PetscInt, Vec, Mat, IS, PetscInt, const PetscInt *, void *), void *ctx) 361 { 362 SNES_Patch *patch = (SNES_Patch *) snes->data; 363 PetscErrorCode ierr; 364 365 PetscFunctionBegin; 366 ierr = PCPatchSetComputeOperator(patch->pc, func, ctx);CHKERRQ(ierr); 367 PetscFunctionReturn(0); 368 } 369 370 PetscErrorCode SNESPatchSetComputeFunction(SNES snes, PetscErrorCode (*func)(PC, PetscInt, Vec, Vec, IS, PetscInt, const PetscInt *, void *), void *ctx) 371 { 372 SNES_Patch *patch = (SNES_Patch *) snes->data; 373 PetscErrorCode ierr; 374 375 PetscFunctionBegin; 376 ierr = PCPatchSetComputeFunction(patch->pc, func, ctx);CHKERRQ(ierr); 377 PetscFunctionReturn(0); 378 } 379 380 PetscErrorCode SNESPatchSetConstructType(SNES snes, PCPatchConstructType ctype, PetscErrorCode (*func)(PC, PetscInt *, IS **, IS *, void *), void *ctx) 381 { 382 SNES_Patch *patch = (SNES_Patch *) snes->data; 383 PetscErrorCode ierr; 384 385 PetscFunctionBegin; 386 ierr = PCPatchSetConstructType(patch->pc, ctype, func, ctx);CHKERRQ(ierr); 387 PetscFunctionReturn(0); 388 } 389 390 PetscErrorCode SNESPatchSetCellNumbering(SNES snes, PetscSection cellNumbering) 391 { 392 SNES_Patch *patch = (SNES_Patch *) snes->data; 393 PetscErrorCode ierr; 394 395 PetscFunctionBegin; 396 ierr = PCPatchSetCellNumbering(patch->pc, cellNumbering);CHKERRQ(ierr); 397 PetscFunctionReturn(0); 398 } 399