xref: /petsc/src/ts/utils/dmdats.c (revision 1b37a2a7cc4a4fb30c3e967db1c694c0a1013f51)
1 #include <petscdmda.h> /*I "petscdmda.h" I*/
2 #include <petsc/private/dmimpl.h>
3 #include <petsc/private/tsimpl.h> /*I "petscts.h" I*/
4 #include <petscdraw.h>
5 
6 /* This structure holds the user-provided DMDA callbacks */
7 typedef struct {
8   PetscErrorCode (*ifunctionlocal)(DMDALocalInfo *, PetscReal, void *, void *, void *, void *);
9   PetscErrorCode (*rhsfunctionlocal)(DMDALocalInfo *, PetscReal, void *, void *, void *);
10   PetscErrorCode (*ijacobianlocal)(DMDALocalInfo *, PetscReal, void *, void *, PetscReal, Mat, Mat, void *);
11   PetscErrorCode (*rhsjacobianlocal)(DMDALocalInfo *, PetscReal, void *, Mat, Mat, void *);
12   void      *ifunctionlocalctx;
13   void      *ijacobianlocalctx;
14   void      *rhsfunctionlocalctx;
15   void      *rhsjacobianlocalctx;
16   InsertMode ifunctionlocalimode;
17   InsertMode rhsfunctionlocalimode;
18 } DMTS_DA;
19 
20 static PetscErrorCode DMTSDestroy_DMDA(DMTS sdm)
21 {
22   PetscFunctionBegin;
23   PetscCall(PetscFree(sdm->data));
24   PetscFunctionReturn(PETSC_SUCCESS);
25 }
26 
27 static PetscErrorCode DMTSDuplicate_DMDA(DMTS oldsdm, DMTS sdm)
28 {
29   PetscFunctionBegin;
30   PetscCall(PetscNew((DMTS_DA **)&sdm->data));
31   if (oldsdm->data) PetscCall(PetscMemcpy(sdm->data, oldsdm->data, sizeof(DMTS_DA)));
32   PetscFunctionReturn(PETSC_SUCCESS);
33 }
34 
35 static PetscErrorCode DMDATSGetContext(DM dm, DMTS sdm, DMTS_DA **dmdats)
36 {
37   PetscFunctionBegin;
38   *dmdats = NULL;
39   if (!sdm->data) {
40     PetscCall(PetscNew((DMTS_DA **)&sdm->data));
41     sdm->ops->destroy   = DMTSDestroy_DMDA;
42     sdm->ops->duplicate = DMTSDuplicate_DMDA;
43   }
44   *dmdats = (DMTS_DA *)sdm->data;
45   PetscFunctionReturn(PETSC_SUCCESS);
46 }
47 
48 static PetscErrorCode TSComputeIFunction_DMDA(TS ts, PetscReal ptime, Vec X, Vec Xdot, Vec F, void *ctx)
49 {
50   DM            dm;
51   DMTS_DA      *dmdats = (DMTS_DA *)ctx;
52   DMDALocalInfo info;
53   Vec           Xloc, Xdotloc;
54   void         *x, *f, *xdot;
55 
56   PetscFunctionBegin;
57   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
58   PetscValidHeaderSpecific(X, VEC_CLASSID, 3);
59   PetscValidHeaderSpecific(F, VEC_CLASSID, 5);
60   PetscCheck(dmdats->ifunctionlocal, PetscObjectComm((PetscObject)ts), PETSC_ERR_PLIB, "Corrupt context");
61   PetscCall(TSGetDM(ts, &dm));
62   PetscCall(DMGetLocalVector(dm, &Xdotloc));
63   PetscCall(DMGlobalToLocalBegin(dm, Xdot, INSERT_VALUES, Xdotloc));
64   PetscCall(DMGlobalToLocalEnd(dm, Xdot, INSERT_VALUES, Xdotloc));
65   PetscCall(DMGetLocalVector(dm, &Xloc));
66   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, Xloc));
67   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, Xloc));
68   PetscCall(DMDAGetLocalInfo(dm, &info));
69   PetscCall(DMDAVecGetArray(dm, Xloc, &x));
70   PetscCall(DMDAVecGetArray(dm, Xdotloc, &xdot));
71   switch (dmdats->ifunctionlocalimode) {
72   case INSERT_VALUES: {
73     PetscCall(DMDAVecGetArray(dm, F, &f));
74     CHKMEMQ;
75     PetscCall((*dmdats->ifunctionlocal)(&info, ptime, x, xdot, f, dmdats->ifunctionlocalctx));
76     CHKMEMQ;
77     PetscCall(DMDAVecRestoreArray(dm, F, &f));
78   } break;
79   case ADD_VALUES: {
80     Vec Floc;
81     PetscCall(DMGetLocalVector(dm, &Floc));
82     PetscCall(VecZeroEntries(Floc));
83     PetscCall(DMDAVecGetArray(dm, Floc, &f));
84     CHKMEMQ;
85     PetscCall((*dmdats->ifunctionlocal)(&info, ptime, x, xdot, f, dmdats->ifunctionlocalctx));
86     CHKMEMQ;
87     PetscCall(DMDAVecRestoreArray(dm, Floc, &f));
88     PetscCall(VecZeroEntries(F));
89     PetscCall(DMLocalToGlobalBegin(dm, Floc, ADD_VALUES, F));
90     PetscCall(DMLocalToGlobalEnd(dm, Floc, ADD_VALUES, F));
91     PetscCall(DMRestoreLocalVector(dm, &Floc));
92   } break;
93   default:
94     SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_INCOMP, "Cannot use imode=%d", (int)dmdats->ifunctionlocalimode);
95   }
96   PetscCall(DMDAVecRestoreArray(dm, Xloc, &x));
97   PetscCall(DMRestoreLocalVector(dm, &Xloc));
98   PetscCall(DMDAVecRestoreArray(dm, Xdotloc, &xdot));
99   PetscCall(DMRestoreLocalVector(dm, &Xdotloc));
100   PetscFunctionReturn(PETSC_SUCCESS);
101 }
102 
103 static PetscErrorCode TSComputeIJacobian_DMDA(TS ts, PetscReal ptime, Vec X, Vec Xdot, PetscReal shift, Mat A, Mat B, void *ctx)
104 {
105   DM            dm;
106   DMTS_DA      *dmdats = (DMTS_DA *)ctx;
107   DMDALocalInfo info;
108   Vec           Xloc;
109   void         *x, *xdot;
110 
111   PetscFunctionBegin;
112   PetscCheck(dmdats->ifunctionlocal, PetscObjectComm((PetscObject)ts), PETSC_ERR_PLIB, "Corrupt context");
113   PetscCall(TSGetDM(ts, &dm));
114 
115   if (dmdats->ijacobianlocal) {
116     PetscCall(DMGetLocalVector(dm, &Xloc));
117     PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, Xloc));
118     PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, Xloc));
119     PetscCall(DMDAGetLocalInfo(dm, &info));
120     PetscCall(DMDAVecGetArray(dm, Xloc, &x));
121     PetscCall(DMDAVecGetArray(dm, Xdot, &xdot));
122     CHKMEMQ;
123     PetscCall((*dmdats->ijacobianlocal)(&info, ptime, x, xdot, shift, A, B, dmdats->ijacobianlocalctx));
124     CHKMEMQ;
125     PetscCall(DMDAVecRestoreArray(dm, Xloc, &x));
126     PetscCall(DMDAVecRestoreArray(dm, Xdot, &xdot));
127     PetscCall(DMRestoreLocalVector(dm, &Xloc));
128   } else SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_PLIB, "TSComputeIJacobian_DMDA() called without calling DMDATSSetIJacobian()");
129   /* This will be redundant if the user called both, but it's too common to forget. */
130   if (A != B) {
131     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
132     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
133   }
134   PetscFunctionReturn(PETSC_SUCCESS);
135 }
136 
137 static PetscErrorCode TSComputeRHSFunction_DMDA(TS ts, PetscReal ptime, Vec X, Vec F, void *ctx)
138 {
139   DM            dm;
140   DMTS_DA      *dmdats = (DMTS_DA *)ctx;
141   DMDALocalInfo info;
142   Vec           Xloc;
143   void         *x, *f;
144 
145   PetscFunctionBegin;
146   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
147   PetscValidHeaderSpecific(X, VEC_CLASSID, 3);
148   PetscValidHeaderSpecific(F, VEC_CLASSID, 4);
149   PetscCheck(dmdats->rhsfunctionlocal, PetscObjectComm((PetscObject)ts), PETSC_ERR_PLIB, "Corrupt context");
150   PetscCall(TSGetDM(ts, &dm));
151   PetscCall(DMGetLocalVector(dm, &Xloc));
152   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, Xloc));
153   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, Xloc));
154   PetscCall(DMDAGetLocalInfo(dm, &info));
155   PetscCall(DMDAVecGetArray(dm, Xloc, &x));
156   switch (dmdats->rhsfunctionlocalimode) {
157   case INSERT_VALUES: {
158     PetscCall(DMDAVecGetArray(dm, F, &f));
159     CHKMEMQ;
160     PetscCall((*dmdats->rhsfunctionlocal)(&info, ptime, x, f, dmdats->rhsfunctionlocalctx));
161     CHKMEMQ;
162     PetscCall(DMDAVecRestoreArray(dm, F, &f));
163   } break;
164   case ADD_VALUES: {
165     Vec Floc;
166     PetscCall(DMGetLocalVector(dm, &Floc));
167     PetscCall(VecZeroEntries(Floc));
168     PetscCall(DMDAVecGetArray(dm, Floc, &f));
169     CHKMEMQ;
170     PetscCall((*dmdats->rhsfunctionlocal)(&info, ptime, x, f, dmdats->rhsfunctionlocalctx));
171     CHKMEMQ;
172     PetscCall(DMDAVecRestoreArray(dm, Floc, &f));
173     PetscCall(VecZeroEntries(F));
174     PetscCall(DMLocalToGlobalBegin(dm, Floc, ADD_VALUES, F));
175     PetscCall(DMLocalToGlobalEnd(dm, Floc, ADD_VALUES, F));
176     PetscCall(DMRestoreLocalVector(dm, &Floc));
177   } break;
178   default:
179     SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_INCOMP, "Cannot use imode=%d", (int)dmdats->rhsfunctionlocalimode);
180   }
181   PetscCall(DMDAVecRestoreArray(dm, Xloc, &x));
182   PetscCall(DMRestoreLocalVector(dm, &Xloc));
183   PetscFunctionReturn(PETSC_SUCCESS);
184 }
185 
186 static PetscErrorCode TSComputeRHSJacobian_DMDA(TS ts, PetscReal ptime, Vec X, Mat A, Mat B, void *ctx)
187 {
188   DM            dm;
189   DMTS_DA      *dmdats = (DMTS_DA *)ctx;
190   DMDALocalInfo info;
191   Vec           Xloc;
192   void         *x;
193 
194   PetscFunctionBegin;
195   PetscCheck(dmdats->rhsfunctionlocal, PetscObjectComm((PetscObject)ts), PETSC_ERR_PLIB, "Corrupt context");
196   PetscCall(TSGetDM(ts, &dm));
197 
198   if (dmdats->rhsjacobianlocal) {
199     PetscCall(DMGetLocalVector(dm, &Xloc));
200     PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, Xloc));
201     PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, Xloc));
202     PetscCall(DMDAGetLocalInfo(dm, &info));
203     PetscCall(DMDAVecGetArray(dm, Xloc, &x));
204     CHKMEMQ;
205     PetscCall((*dmdats->rhsjacobianlocal)(&info, ptime, x, A, B, dmdats->rhsjacobianlocalctx));
206     CHKMEMQ;
207     PetscCall(DMDAVecRestoreArray(dm, Xloc, &x));
208     PetscCall(DMRestoreLocalVector(dm, &Xloc));
209   } else SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_PLIB, "TSComputeRHSJacobian_DMDA() called without calling DMDATSSetRHSJacobian()");
210   /* This will be redundant if the user called both, but it's too common to forget. */
211   if (A != B) {
212     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
213     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
214   }
215   PetscFunctionReturn(PETSC_SUCCESS);
216 }
217 
218 /*@C
219   DMDATSSetRHSFunctionLocal - set a local residual evaluation function for use with `DMDA`
220 
221   Logically Collective
222 
223   Input Parameters:
224 + dm    - `DM` to associate callback with
225 . imode - insert mode for the residual
226 . func  - local residual evaluation, see `DMDATSRHSFunctionLocalFn` for the calling sequence
227 - ctx   - optional context for local residual evaluation
228 
229   Level: beginner
230 
231 .seealso: [](ch_ts), `DMDA`, `DMDATSRHSFunctionLocalFn`, `TS`, `TSSetRHSFunction()`, `DMTSSetRHSFunction()`, `DMDATSSetRHSJacobianLocal()`, `DMDASNESSetFunctionLocal()`
232 @*/
233 PetscErrorCode DMDATSSetRHSFunctionLocal(DM dm, InsertMode imode, DMDATSRHSFunctionLocalFn *func, void *ctx)
234 {
235   DMTS     sdm;
236   DMTS_DA *dmdats;
237 
238   PetscFunctionBegin;
239   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
240   PetscCall(DMGetDMTSWrite(dm, &sdm));
241   PetscCall(DMDATSGetContext(dm, sdm, &dmdats));
242   dmdats->rhsfunctionlocalimode = imode;
243   dmdats->rhsfunctionlocal      = func;
244   dmdats->rhsfunctionlocalctx   = ctx;
245   PetscCall(DMTSSetRHSFunction(dm, TSComputeRHSFunction_DMDA, dmdats));
246   PetscFunctionReturn(PETSC_SUCCESS);
247 }
248 
249 /*@C
250   DMDATSSetRHSJacobianLocal - set a local residual evaluation function for use with `DMDA`
251 
252   Logically Collective
253 
254   Input Parameters:
255 + dm   - `DM` to associate callback with
256 . func - local RHS Jacobian evaluation routine, see `DMDATSRHSJacobianLocalFn` for the calling sequence
257 - ctx  - optional context for local jacobian evaluation
258 
259   Level: beginner
260 
261 .seealso: [](ch_ts), `DMDA`, `DMDATSRHSJacobianLocalFn`, `DMTSSetRHSJacobian()`,
262 `DMDATSSetRHSFunctionLocal()`, `DMDASNESSetJacobianLocal()`
263 @*/
264 PetscErrorCode DMDATSSetRHSJacobianLocal(DM dm, DMDATSRHSJacobianLocalFn *func, void *ctx)
265 {
266   DMTS     sdm;
267   DMTS_DA *dmdats;
268 
269   PetscFunctionBegin;
270   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
271   PetscCall(DMGetDMTSWrite(dm, &sdm));
272   PetscCall(DMDATSGetContext(dm, sdm, &dmdats));
273   dmdats->rhsjacobianlocal    = func;
274   dmdats->rhsjacobianlocalctx = ctx;
275   PetscCall(DMTSSetRHSJacobian(dm, TSComputeRHSJacobian_DMDA, dmdats));
276   PetscFunctionReturn(PETSC_SUCCESS);
277 }
278 
279 /*@C
280   DMDATSSetIFunctionLocal - set a local residual evaluation function for use with `DMDA`
281 
282   Logically Collective
283 
284   Input Parameters:
285 + dm    - `DM` to associate callback with
286 . imode - the insert mode of the function
287 . func  - local residual evaluation, see `DMDATSIFunctionLocalFn` for the calling sequence
288 - ctx   - optional context for local residual evaluation
289 
290   Level: beginner
291 
292 .seealso: [](ch_ts), `DMDA`, `DMDATSIFunctionLocalFn`, `DMTSSetIFunction()`,
293 `DMDATSSetIJacobianLocal()`, `DMDASNESSetFunctionLocal()`
294 @*/
295 PetscErrorCode DMDATSSetIFunctionLocal(DM dm, InsertMode imode, DMDATSIFunctionLocalFn *func, void *ctx)
296 {
297   DMTS     sdm;
298   DMTS_DA *dmdats;
299 
300   PetscFunctionBegin;
301   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
302   PetscCall(DMGetDMTSWrite(dm, &sdm));
303   PetscCall(DMDATSGetContext(dm, sdm, &dmdats));
304   dmdats->ifunctionlocalimode = imode;
305   dmdats->ifunctionlocal      = func;
306   dmdats->ifunctionlocalctx   = ctx;
307   PetscCall(DMTSSetIFunction(dm, TSComputeIFunction_DMDA, dmdats));
308   PetscFunctionReturn(PETSC_SUCCESS);
309 }
310 
311 /*@C
312   DMDATSSetIJacobianLocal - set a local residual evaluation function for use with `DMDA`
313 
314   Logically Collective
315 
316   Input Parameters:
317 + dm   - `DM` to associate callback with
318 . func - local residual evaluation, see `DMDATSIJacobianLocalFn` for the calling sequence
319 - ctx  - optional context for local residual evaluation
320 
321   Level: beginner
322 
323 .seealso: [](ch_ts), `DMDA`, `DMDATSIJacobianLocalFn`, `DMTSSetJacobian()`,
324 `DMDATSSetIFunctionLocal()`, `DMDASNESSetJacobianLocal()`
325 @*/
326 PetscErrorCode DMDATSSetIJacobianLocal(DM dm, DMDATSIJacobianLocalFn *func, void *ctx)
327 {
328   DMTS     sdm;
329   DMTS_DA *dmdats;
330 
331   PetscFunctionBegin;
332   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
333   PetscCall(DMGetDMTSWrite(dm, &sdm));
334   PetscCall(DMDATSGetContext(dm, sdm, &dmdats));
335   dmdats->ijacobianlocal    = func;
336   dmdats->ijacobianlocalctx = ctx;
337   PetscCall(DMTSSetIJacobian(dm, TSComputeIJacobian_DMDA, dmdats));
338   PetscFunctionReturn(PETSC_SUCCESS);
339 }
340 
341 PetscErrorCode TSMonitorDMDARayDestroy(void **mctx)
342 {
343   TSMonitorDMDARayCtx *rayctx = (TSMonitorDMDARayCtx *)*mctx;
344 
345   PetscFunctionBegin;
346   if (rayctx->lgctx) PetscCall(TSMonitorLGCtxDestroy(&rayctx->lgctx));
347   PetscCall(VecDestroy(&rayctx->ray));
348   PetscCall(VecScatterDestroy(&rayctx->scatter));
349   PetscCall(PetscViewerDestroy(&rayctx->viewer));
350   PetscCall(PetscFree(rayctx));
351   PetscFunctionReturn(PETSC_SUCCESS);
352 }
353 
354 PetscErrorCode TSMonitorDMDARay(TS ts, PetscInt steps, PetscReal time, Vec u, void *mctx)
355 {
356   TSMonitorDMDARayCtx *rayctx = (TSMonitorDMDARayCtx *)mctx;
357   Vec                  solution;
358 
359   PetscFunctionBegin;
360   PetscCall(TSGetSolution(ts, &solution));
361   PetscCall(VecScatterBegin(rayctx->scatter, solution, rayctx->ray, INSERT_VALUES, SCATTER_FORWARD));
362   PetscCall(VecScatterEnd(rayctx->scatter, solution, rayctx->ray, INSERT_VALUES, SCATTER_FORWARD));
363   if (rayctx->viewer) PetscCall(VecView(rayctx->ray, rayctx->viewer));
364   PetscFunctionReturn(PETSC_SUCCESS);
365 }
366 
367 PetscErrorCode TSMonitorLGDMDARay(TS ts, PetscInt step, PetscReal ptime, Vec u, void *ctx)
368 {
369   TSMonitorDMDARayCtx *rayctx = (TSMonitorDMDARayCtx *)ctx;
370   TSMonitorLGCtx       lgctx  = (TSMonitorLGCtx)rayctx->lgctx;
371   Vec                  v      = rayctx->ray;
372   const PetscScalar   *a;
373   PetscInt             dim;
374 
375   PetscFunctionBegin;
376   PetscCall(VecScatterBegin(rayctx->scatter, u, v, INSERT_VALUES, SCATTER_FORWARD));
377   PetscCall(VecScatterEnd(rayctx->scatter, u, v, INSERT_VALUES, SCATTER_FORWARD));
378   if (!step) {
379     PetscDrawAxis axis;
380 
381     PetscCall(PetscDrawLGGetAxis(lgctx->lg, &axis));
382     PetscCall(PetscDrawAxisSetLabels(axis, "Solution Ray as function of time", "Time", "Solution"));
383     PetscCall(VecGetLocalSize(rayctx->ray, &dim));
384     PetscCall(PetscDrawLGSetDimension(lgctx->lg, dim));
385     PetscCall(PetscDrawLGReset(lgctx->lg));
386   }
387   PetscCall(VecGetArrayRead(v, &a));
388 #if defined(PETSC_USE_COMPLEX)
389   {
390     PetscReal *areal;
391     PetscInt   i, n;
392     PetscCall(VecGetLocalSize(v, &n));
393     PetscCall(PetscMalloc1(n, &areal));
394     for (i = 0; i < n; ++i) areal[i] = PetscRealPart(a[i]);
395     PetscCall(PetscDrawLGAddCommonPoint(lgctx->lg, ptime, areal));
396     PetscCall(PetscFree(areal));
397   }
398 #else
399   PetscCall(PetscDrawLGAddCommonPoint(lgctx->lg, ptime, a));
400 #endif
401   PetscCall(VecRestoreArrayRead(v, &a));
402   if (((lgctx->howoften > 0) && (!(step % lgctx->howoften))) || ((lgctx->howoften == -1) && ts->reason)) {
403     PetscCall(PetscDrawLGDraw(lgctx->lg));
404     PetscCall(PetscDrawLGSave(lgctx->lg));
405   }
406   PetscFunctionReturn(PETSC_SUCCESS);
407 }
408