xref: /petsc/src/snes/impls/patch/snespatch.c (revision af0b0351f1892647cb818b9a35bc14f2bdaa64c8)
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 SNESSetUp_Patch(SNES snes)
144 {
145   SNES_Patch    *patch = (SNES_Patch *) snes->data;
146   DM             dm;
147   Mat            dummy;
148   Vec            F;
149   PetscInt       n, N;
150   PetscErrorCode ierr;
151 
152   PetscFunctionBegin;
153   ierr = SNESGetDM(snes, &dm);CHKERRQ(ierr);
154   ierr = PCSetDM(patch->pc, dm);CHKERRQ(ierr);
155   ierr = SNESGetFunction(snes, &F, NULL, NULL);CHKERRQ(ierr);
156   ierr = VecGetLocalSize(F, &n);CHKERRQ(ierr);
157   ierr = VecGetSize(F, &N);CHKERRQ(ierr);
158   ierr = MatCreateShell(PetscObjectComm((PetscObject) snes), n, n, N, N, (void *) snes, &dummy);CHKERRQ(ierr);
159   ierr = PCSetOperators(patch->pc, dummy, dummy);CHKERRQ(ierr);
160   ierr = MatDestroy(&dummy);CHKERRQ(ierr);
161   ierr = PCSetUp(patch->pc);CHKERRQ(ierr);
162   /* allocate workspace */
163   PetscFunctionReturn(0);
164 }
165 
166 static PetscErrorCode SNESReset_Patch(SNES snes)
167 {
168   SNES_Patch    *patch = (SNES_Patch *) snes->data;
169   PetscErrorCode ierr;
170 
171   PetscFunctionBegin;
172   ierr = PCReset(patch->pc);CHKERRQ(ierr);
173   PetscFunctionReturn(0);
174 }
175 
176 static PetscErrorCode SNESDestroy_Patch(SNES snes)
177 {
178   SNES_Patch    *patch = (SNES_Patch *) snes->data;
179   PetscErrorCode ierr;
180 
181   PetscFunctionBegin;
182   ierr = SNESReset_Patch(snes);CHKERRQ(ierr);
183   ierr = PCDestroy(&patch->pc);CHKERRQ(ierr);
184   ierr = PetscFree(snes->data);CHKERRQ(ierr);
185   PetscFunctionReturn(0);
186 }
187 
188 static PetscErrorCode SNESSetFromOptions_Patch(PetscOptionItems *PetscOptionsObject, SNES snes)
189 {
190   SNES_Patch    *patch = (SNES_Patch *) snes->data;
191   PetscBool      flg;
192   const char    *prefix;
193   PetscErrorCode ierr;
194 
195   PetscFunctionBegin;
196   ierr = PetscObjectGetOptionsPrefix((PetscObject)snes, &prefix);CHKERRQ(ierr);
197   ierr = PetscObjectSetOptionsPrefix((PetscObject)patch->pc, prefix);CHKERRQ(ierr);
198   ierr = PCSetFromOptions(patch->pc);CHKERRQ(ierr);
199   PetscFunctionReturn(0);
200 }
201 
202 static PetscErrorCode SNESView_Patch(SNES snes,PetscViewer viewer)
203 {
204   SNES_Patch    *patch = (SNES_Patch *) snes->data;
205   PetscBool      iascii;
206   PetscErrorCode ierr;
207 
208   PetscFunctionBegin;
209   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
210   if (iascii) {
211     ierr = PetscViewerASCIIPrintf(viewer,"SNESPATCH\n");CHKERRQ(ierr);
212   }
213   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
214   ierr = PCView(patch->pc, viewer);CHKERRQ(ierr);
215   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
216   PetscFunctionReturn(0);
217 }
218 
219 static PetscErrorCode SNESSolve_Patch(SNES snes)
220 {
221   SNES_Patch *patch = (SNES_Patch *) snes->data;
222   PC_PATCH   *pcpatch = (PC_PATCH *) patch->pc->data;
223   Vec rhs, update, state;
224   const PetscScalar *globalState  = NULL;
225   PetscScalar       *localState   = NULL;
226 
227   PetscErrorCode ierr;
228 
229   PetscFunctionBegin;
230 
231   ierr = SNESGetSolution(snes, &state);CHKERRQ(ierr);
232   ierr = SNESGetSolutionUpdate(snes, &update);CHKERRQ(ierr);
233   ierr = SNESGetRhs(snes, &rhs);CHKERRQ(ierr);
234 
235   /* These happen in a loop */
236   {
237   /* Scatter state vector to overlapped vector on all patches.
238      The vector pcpatch->localState is scattered to each patch
239      in PCApply_PATCH_Nonlinear. */
240   ierr = VecGetArrayRead(state, &globalState);CHKERRQ(ierr);
241   ierr = VecGetArray(pcpatch->localState, &localState);CHKERRQ(ierr);
242   ierr = PetscSFBcastBegin(pcpatch->defaultSF, MPIU_SCALAR, globalState, localState);CHKERRQ(ierr);
243   ierr = PetscSFBcastEnd(pcpatch->defaultSF, MPIU_SCALAR, globalState, localState);CHKERRQ(ierr);
244   ierr = VecRestoreArray(pcpatch->localState, &localState);CHKERRQ(ierr);
245   ierr = VecRestoreArrayRead(state, &globalState);CHKERRQ(ierr);
246 
247   ierr = PCApply(patch->pc, rhs, update);
248   ierr = VecAXPY(state, 1.0, update);CHKERRQ(ierr); /* FIXME: replace with line search */
249   }
250 
251   ierr = SNESSetConvergedReason(snes, SNES_CONVERGED_ITS);CHKERRQ(ierr);
252   PetscFunctionReturn(0);
253 }
254 
255 /*MC
256   SNESPATCH - Solve a nonlinear problem by composing together many nonlinear solvers on patches
257 
258   Level: intermediate
259 
260   Concepts: composing solvers
261 
262 .seealso:  SNESCreate(), SNESSetType(), SNESType (for list of available types), SNES,
263            PCPATCH
264 
265    References:
266 .  1. - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers", SIAM Review, 57(4), 2015
267 
268 M*/
269 PETSC_EXTERN PetscErrorCode SNESCreate_Patch(SNES snes)
270 {
271   PetscErrorCode ierr;
272   SNES_Patch    *patch;
273   PC_PATCH      *patchpc;
274 
275   PetscFunctionBegin;
276   ierr = PetscNewLog(snes, &patch);CHKERRQ(ierr);
277 
278   snes->ops->solve          = SNESSolve_Patch;
279   snes->ops->setup          = SNESSetUp_Patch;
280   snes->ops->reset          = SNESReset_Patch;
281   snes->ops->destroy        = SNESDestroy_Patch;
282   snes->ops->setfromoptions = SNESSetFromOptions_Patch;
283   snes->ops->view           = SNESView_Patch;
284 
285   snes->alwayscomputesfinalresidual = PETSC_FALSE;
286 
287   snes->data = (void *) patch;
288   ierr = PCCreate(PetscObjectComm((PetscObject) snes), &patch->pc);CHKERRQ(ierr);
289   ierr = PCSetType(patch->pc, PCPATCH);CHKERRQ(ierr);
290 
291   patchpc = (PC_PATCH*) patch->pc->data;
292   patchpc->classname = "snes";
293 
294   patchpc->setupsolver   = PCSetUp_PATCH_Nonlinear;
295   patchpc->applysolver   = PCApply_PATCH_Nonlinear;
296   patchpc->resetsolver   = PCReset_PATCH_Nonlinear;
297   patchpc->destroysolver = PCDestroy_PATCH_Nonlinear;
298 
299   PetscFunctionReturn(0);
300 }
301 
302 PetscErrorCode SNESPatchSetDiscretisationInfo(SNES snes, PetscInt nsubspaces, DM *dms, PetscInt *bs, PetscInt *nodesPerCell, const PetscInt **cellNodeMap,
303                                             const PetscInt *subspaceOffsets, PetscInt numGhostBcs, const PetscInt *ghostBcNodes, PetscInt numGlobalBcs, const PetscInt *globalBcNodes)
304 {
305   SNES_Patch    *patch = (SNES_Patch *) snes->data;
306   PetscErrorCode ierr;
307   DM dm;
308 
309   PetscFunctionBegin;
310   ierr = SNESGetDM(snes, &dm);CHKERRQ(ierr);
311   if (!dm) SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "DM not yet set on patch SNES\n");
312   ierr = PCSetDM(patch->pc, dm);CHKERRQ(ierr);
313   ierr = PCPatchSetDiscretisationInfo(patch->pc, nsubspaces, dms, bs, nodesPerCell, cellNodeMap, subspaceOffsets, numGhostBcs, ghostBcNodes, numGlobalBcs, globalBcNodes);CHKERRQ(ierr);
314   PetscFunctionReturn(0);
315 }
316 
317 PetscErrorCode SNESPatchSetComputeOperator(SNES snes, PetscErrorCode (*func)(PC, PetscInt, Vec, Mat, IS, PetscInt, const PetscInt *, void *), void *ctx)
318 {
319   SNES_Patch    *patch = (SNES_Patch *) snes->data;
320   PetscErrorCode ierr;
321 
322   PetscFunctionBegin;
323   ierr = PCPatchSetComputeOperator(patch->pc, func, ctx);CHKERRQ(ierr);
324   PetscFunctionReturn(0);
325 }
326 
327 PetscErrorCode SNESPatchSetComputeFunction(SNES snes, PetscErrorCode (*func)(PC, PetscInt, Vec, Vec, IS, PetscInt, const PetscInt *, void *), void *ctx)
328 {
329   SNES_Patch    *patch = (SNES_Patch *) snes->data;
330   PetscErrorCode ierr;
331 
332   PetscFunctionBegin;
333   ierr = PCPatchSetComputeFunction(patch->pc, func, ctx);CHKERRQ(ierr);
334   PetscFunctionReturn(0);
335 }
336 
337 PetscErrorCode SNESPatchSetConstructType(SNES snes, PCPatchConstructType ctype, PetscErrorCode (*func)(PC, PetscInt *, IS **, IS *, void *), void *ctx)
338 {
339   SNES_Patch    *patch = (SNES_Patch *) snes->data;
340   PetscErrorCode ierr;
341 
342   PetscFunctionBegin;
343   ierr = PCPatchSetConstructType(patch->pc, ctype, func, ctx);CHKERRQ(ierr);
344   PetscFunctionReturn(0);
345 }
346 
347 PetscErrorCode SNESPatchSetCellNumbering(SNES snes, PetscSection cellNumbering)
348 {
349   SNES_Patch    *patch = (SNES_Patch *) snes->data;
350   PetscErrorCode ierr;
351 
352   PetscFunctionBegin;
353   ierr = PCPatchSetCellNumbering(patch->pc, cellNumbering);CHKERRQ(ierr);
354   PetscFunctionReturn(0);
355 }
356