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