xref: /petsc/src/ts/impls/symplectic/basicsymplectic/basicsymplectic.c (revision f023dd217de76aac760b27f3417a565a5758a616)
1e49d4f37SHong Zhang /*
2e49d4f37SHong Zhang   Code for Timestepping with basic symplectic integrators for separable Hamiltonian systems
3e49d4f37SHong Zhang */
4e49d4f37SHong Zhang #include <petsc/private/tsimpl.h> /*I   "petscts.h"   I*/
5e49d4f37SHong Zhang #include <petscdm.h>
6e49d4f37SHong Zhang 
7e49d4f37SHong Zhang static TSBasicSymplecticType TSBasicSymplecticDefault = TSBASICSYMPLECTICSIEULER;
8e49d4f37SHong Zhang static PetscBool             TSBasicSymplecticRegisterAllCalled;
9e49d4f37SHong Zhang static PetscBool             TSBasicSymplecticPackageInitialized;
10e49d4f37SHong Zhang 
11e49d4f37SHong Zhang typedef struct _BasicSymplecticScheme     *BasicSymplecticScheme;
12e49d4f37SHong Zhang typedef struct _BasicSymplecticSchemeLink *BasicSymplecticSchemeLink;
13e49d4f37SHong Zhang 
14e49d4f37SHong Zhang struct _BasicSymplecticScheme {
15e49d4f37SHong Zhang   char      *name;
16e49d4f37SHong Zhang   PetscInt   order;
17e49d4f37SHong Zhang   PetscInt   s; /* number of stages */
18e49d4f37SHong Zhang   PetscReal *c, *d;
19e49d4f37SHong Zhang };
20e49d4f37SHong Zhang struct _BasicSymplecticSchemeLink {
21e49d4f37SHong Zhang   struct _BasicSymplecticScheme sch;
22e49d4f37SHong Zhang   BasicSymplecticSchemeLink     next;
23e49d4f37SHong Zhang };
24e49d4f37SHong Zhang static BasicSymplecticSchemeLink BasicSymplecticSchemeList;
25e49d4f37SHong Zhang typedef struct {
26e49d4f37SHong Zhang   TS                    subts_p, subts_q; /* sub TS contexts that holds the RHSFunction pointers */
27e49d4f37SHong Zhang   IS                    is_p, is_q;       /* IS sets for position and momentum respectively */
28e49d4f37SHong Zhang   Vec                   update;           /* a nest work vector for generalized coordinates */
29e49d4f37SHong Zhang   BasicSymplecticScheme scheme;
30e49d4f37SHong Zhang } TS_BasicSymplectic;
31e49d4f37SHong Zhang 
32e49d4f37SHong Zhang /*MC
33e49d4f37SHong Zhang   TSBASICSYMPLECTICSIEULER - first order semi-implicit Euler method
34bcf0153eSBarry Smith 
35e49d4f37SHong Zhang   Level: intermediate
36bcf0153eSBarry Smith 
371cc06b55SBarry Smith .seealso: [](ch_ts), `TSBASICSYMPLECTIC`
38e49d4f37SHong Zhang M*/
39e49d4f37SHong Zhang 
40e49d4f37SHong Zhang /*MC
41aaa8cc7dSPierre Jolivet   TSBASICSYMPLECTICVELVERLET - second order Velocity Verlet method (leapfrog method with starting process and determining velocity and position at the same time)
42bcf0153eSBarry Smith 
43e49d4f37SHong Zhang Level: intermediate
44bcf0153eSBarry Smith 
451cc06b55SBarry Smith .seealso: [](ch_ts), `TSBASICSYMPLECTIC`
46e49d4f37SHong Zhang M*/
47e49d4f37SHong Zhang 
48e49d4f37SHong Zhang /*@C
49bcf0153eSBarry Smith   TSBasicSymplecticRegisterAll - Registers all of the basic symplectic integration methods in `TSBASICSYMPLECTIC`
50e49d4f37SHong Zhang 
51e49d4f37SHong Zhang   Not Collective, but should be called by all processes which will need the schemes to be registered
52e49d4f37SHong Zhang 
53e49d4f37SHong Zhang   Level: advanced
54e49d4f37SHong Zhang 
551cc06b55SBarry Smith .seealso: [](ch_ts), `TSBASICSYMPLECTIC`, `TSBasicSymplecticRegisterDestroy()`
56e49d4f37SHong Zhang @*/
57d71ae5a4SJacob Faibussowitsch PetscErrorCode TSBasicSymplecticRegisterAll(void)
58d71ae5a4SJacob Faibussowitsch {
59e49d4f37SHong Zhang   PetscFunctionBegin;
603ba16761SJacob Faibussowitsch   if (TSBasicSymplecticRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS);
61e49d4f37SHong Zhang   TSBasicSymplecticRegisterAllCalled = PETSC_TRUE;
62e49d4f37SHong Zhang   {
63e49d4f37SHong Zhang     PetscReal c[1] = {1.0}, d[1] = {1.0};
649566063dSJacob Faibussowitsch     PetscCall(TSBasicSymplecticRegister(TSBASICSYMPLECTICSIEULER, 1, 1, c, d));
65e49d4f37SHong Zhang   }
66e49d4f37SHong Zhang   {
67e49d4f37SHong Zhang     PetscReal c[2] = {0, 1.0}, d[2] = {0.5, 0.5};
689566063dSJacob Faibussowitsch     PetscCall(TSBasicSymplecticRegister(TSBASICSYMPLECTICVELVERLET, 2, 2, c, d));
69e49d4f37SHong Zhang   }
70e49d4f37SHong Zhang   {
71e49d4f37SHong Zhang     PetscReal c[3] = {1, -2.0 / 3.0, 2.0 / 3.0}, d[3] = {-1.0 / 24.0, 3.0 / 4.0, 7.0 / 24.0};
729566063dSJacob Faibussowitsch     PetscCall(TSBasicSymplecticRegister(TSBASICSYMPLECTIC3, 3, 3, c, d));
73e49d4f37SHong Zhang   }
74e49d4f37SHong Zhang   {
75e49d4f37SHong Zhang #define CUBEROOTOFTWO 1.2599210498948731647672106
76e49d4f37SHong Zhang     PetscReal c[4] = {1.0 / 2.0 / (2.0 - CUBEROOTOFTWO), (1.0 - CUBEROOTOFTWO) / 2.0 / (2.0 - CUBEROOTOFTWO), (1.0 - CUBEROOTOFTWO) / 2.0 / (2.0 - CUBEROOTOFTWO), 1.0 / 2.0 / (2.0 - CUBEROOTOFTWO)}, d[4] = {1.0 / (2.0 - CUBEROOTOFTWO), -CUBEROOTOFTWO / (2.0 - CUBEROOTOFTWO), 1.0 / (2.0 - CUBEROOTOFTWO), 0};
779566063dSJacob Faibussowitsch     PetscCall(TSBasicSymplecticRegister(TSBASICSYMPLECTIC4, 4, 4, c, d));
78e49d4f37SHong Zhang   }
793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
80e49d4f37SHong Zhang }
81e49d4f37SHong Zhang 
82e49d4f37SHong Zhang /*@C
83bcf0153eSBarry Smith   TSBasicSymplecticRegisterDestroy - Frees the list of schemes that were registered by `TSBasicSymplecticRegister()`.
84e49d4f37SHong Zhang 
85e49d4f37SHong Zhang   Not Collective
86e49d4f37SHong Zhang 
87e49d4f37SHong Zhang   Level: advanced
88e49d4f37SHong Zhang 
891cc06b55SBarry Smith .seealso: [](ch_ts), `TSBasicSymplecticRegister()`, `TSBasicSymplecticRegisterAll()`, `TSBASICSYMPLECTIC`
90e49d4f37SHong Zhang @*/
91d71ae5a4SJacob Faibussowitsch PetscErrorCode TSBasicSymplecticRegisterDestroy(void)
92d71ae5a4SJacob Faibussowitsch {
93e49d4f37SHong Zhang   BasicSymplecticSchemeLink link;
94e49d4f37SHong Zhang 
95e49d4f37SHong Zhang   PetscFunctionBegin;
96e49d4f37SHong Zhang   while ((link = BasicSymplecticSchemeList)) {
97e49d4f37SHong Zhang     BasicSymplecticScheme scheme = &link->sch;
98e49d4f37SHong Zhang     BasicSymplecticSchemeList    = link->next;
999566063dSJacob Faibussowitsch     PetscCall(PetscFree2(scheme->c, scheme->d));
1009566063dSJacob Faibussowitsch     PetscCall(PetscFree(scheme->name));
1019566063dSJacob Faibussowitsch     PetscCall(PetscFree(link));
102e49d4f37SHong Zhang   }
103e49d4f37SHong Zhang   TSBasicSymplecticRegisterAllCalled = PETSC_FALSE;
1043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
105e49d4f37SHong Zhang }
106e49d4f37SHong Zhang 
107e49d4f37SHong Zhang /*@C
108bcf0153eSBarry Smith   TSBasicSymplecticInitializePackage - This function initializes everything in the `TSBASICSYMPLECTIC` package. It is called
109bcf0153eSBarry Smith   from `TSInitializePackage()`.
110e49d4f37SHong Zhang 
111e49d4f37SHong Zhang   Level: developer
112e49d4f37SHong Zhang 
1131cc06b55SBarry Smith .seealso: [](ch_ts), `PetscInitialize()`, `TSBASICSYMPLECTIC`
114e49d4f37SHong Zhang @*/
115d71ae5a4SJacob Faibussowitsch PetscErrorCode TSBasicSymplecticInitializePackage(void)
116d71ae5a4SJacob Faibussowitsch {
117e49d4f37SHong Zhang   PetscFunctionBegin;
1183ba16761SJacob Faibussowitsch   if (TSBasicSymplecticPackageInitialized) PetscFunctionReturn(PETSC_SUCCESS);
119e49d4f37SHong Zhang   TSBasicSymplecticPackageInitialized = PETSC_TRUE;
1209566063dSJacob Faibussowitsch   PetscCall(TSBasicSymplecticRegisterAll());
1219566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(TSBasicSymplecticFinalizePackage));
1223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
123e49d4f37SHong Zhang }
124e49d4f37SHong Zhang 
125e49d4f37SHong Zhang /*@C
126bcf0153eSBarry Smith   TSBasicSymplecticFinalizePackage - This function destroys everything in the `TSBASICSYMPLECTIC` package. It is
127bcf0153eSBarry Smith   called from `PetscFinalize()`.
128e49d4f37SHong Zhang 
129e49d4f37SHong Zhang   Level: developer
130e49d4f37SHong Zhang 
1311cc06b55SBarry Smith .seealso: [](ch_ts), `PetscFinalize()`, `TSBASICSYMPLECTIC`
132e49d4f37SHong Zhang @*/
133d71ae5a4SJacob Faibussowitsch PetscErrorCode TSBasicSymplecticFinalizePackage(void)
134d71ae5a4SJacob Faibussowitsch {
135e49d4f37SHong Zhang   PetscFunctionBegin;
136e49d4f37SHong Zhang   TSBasicSymplecticPackageInitialized = PETSC_FALSE;
1379566063dSJacob Faibussowitsch   PetscCall(TSBasicSymplecticRegisterDestroy());
1383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
139e49d4f37SHong Zhang }
140e49d4f37SHong Zhang 
141e49d4f37SHong Zhang /*@C
142e49d4f37SHong Zhang   TSBasicSymplecticRegister - register a basic symplectic integration scheme by providing the coefficients.
143e49d4f37SHong Zhang 
144e49d4f37SHong Zhang   Not Collective, but the same schemes should be registered on all processes on which they will be used
145e49d4f37SHong Zhang 
146e49d4f37SHong Zhang   Input Parameters:
147e49d4f37SHong Zhang + name  - identifier for method
148e49d4f37SHong Zhang . order - approximation order of method
149e49d4f37SHong Zhang . s     - number of stages, this is the dimension of the matrices below
150e49d4f37SHong Zhang . c     - coefficients for updating generalized position (dimension s)
151e49d4f37SHong Zhang - d     - coefficients for updating generalized momentum (dimension s)
152e49d4f37SHong Zhang 
153bcf0153eSBarry Smith   Level: advanced
154bcf0153eSBarry Smith 
1551d27aa22SBarry Smith   Note:
156e49d4f37SHong Zhang   Several symplectic methods are provided, this function is only needed to create new methods.
157e49d4f37SHong Zhang 
1581cc06b55SBarry Smith .seealso: [](ch_ts), `TSBASICSYMPLECTIC`
159e49d4f37SHong Zhang @*/
160d71ae5a4SJacob Faibussowitsch PetscErrorCode TSBasicSymplecticRegister(TSRosWType name, PetscInt order, PetscInt s, PetscReal c[], PetscReal d[])
161d71ae5a4SJacob Faibussowitsch {
162e49d4f37SHong Zhang   BasicSymplecticSchemeLink link;
163e49d4f37SHong Zhang   BasicSymplecticScheme     scheme;
164e49d4f37SHong Zhang 
165e49d4f37SHong Zhang   PetscFunctionBegin;
1664f572ea9SToby Isaac   PetscAssertPointer(name, 1);
1674f572ea9SToby Isaac   PetscAssertPointer(c, 4);
1684f572ea9SToby Isaac   PetscAssertPointer(d, 5);
169e49d4f37SHong Zhang 
1709566063dSJacob Faibussowitsch   PetscCall(TSBasicSymplecticInitializePackage());
1719566063dSJacob Faibussowitsch   PetscCall(PetscNew(&link));
172e49d4f37SHong Zhang   scheme = &link->sch;
1739566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(name, &scheme->name));
174e49d4f37SHong Zhang   scheme->order = order;
175e49d4f37SHong Zhang   scheme->s     = s;
1769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(s, &scheme->c, s, &scheme->d));
1779566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(scheme->c, c, s));
1789566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(scheme->d, d, s));
179e49d4f37SHong Zhang   link->next                = BasicSymplecticSchemeList;
180e49d4f37SHong Zhang   BasicSymplecticSchemeList = link;
1813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
182e49d4f37SHong Zhang }
183e49d4f37SHong Zhang 
184e49d4f37SHong Zhang /*
185e49d4f37SHong Zhang The simplified form of the equations are:
186e49d4f37SHong Zhang 
18737fdd005SBarry Smith .vb
18825de42d4SHong Zhang  q_{i+1} = q_i + c_i*g(p_i)*h
18925de42d4SHong Zhang  p_{i+1} = p_i + d_i*f(q_{i+1})*h
19037fdd005SBarry Smith .ve
191e49d4f37SHong Zhang 
192e49d4f37SHong Zhang Several symplectic integrators are given below. An illustrative way to use them is to consider a particle with position q and velocity p.
193e49d4f37SHong Zhang 
194e49d4f37SHong Zhang To apply a timestep with values c_{1,2},d_{1,2} to the particle, carry out the following steps:
19537fdd005SBarry Smith .vb
19625de42d4SHong Zhang - Update the position of the particle by adding to it its velocity multiplied by c_1
19725de42d4SHong Zhang - Update the velocity of the particle by adding to it its acceleration (at the updated position) multiplied by d_1
19825de42d4SHong Zhang - Update the position of the particle by adding to it its (updated) velocity multiplied by c_2
19925de42d4SHong Zhang - Update the velocity of the particle by adding to it its acceleration (at the updated position) multiplied by d_2
20037fdd005SBarry Smith .ve
201e49d4f37SHong Zhang 
202e49d4f37SHong Zhang */
203d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSStep_BasicSymplectic(TS ts)
204d71ae5a4SJacob Faibussowitsch {
205e49d4f37SHong Zhang   TS_BasicSymplectic   *bsymp    = (TS_BasicSymplectic *)ts->data;
206e49d4f37SHong Zhang   BasicSymplecticScheme scheme   = bsymp->scheme;
207e49d4f37SHong Zhang   Vec                   solution = ts->vec_sol, update = bsymp->update, q, p, q_update, p_update;
208e49d4f37SHong Zhang   IS                    is_q = bsymp->is_q, is_p = bsymp->is_p;
209e49d4f37SHong Zhang   TS                    subts_q = bsymp->subts_q, subts_p = bsymp->subts_p;
210f9813ea2SStefano Zampini   PetscBool             stageok = PETSC_TRUE;
211*f023dd21SMatthew G. Knepley   PetscReal             ptime, next_time_step = ts->time_step;
212*f023dd21SMatthew G. Knepley   PetscInt              n;
213e49d4f37SHong Zhang 
214e49d4f37SHong Zhang   PetscFunctionBegin;
215*f023dd21SMatthew G. Knepley   PetscCall(TSGetStepNumber(ts, &n));
216*f023dd21SMatthew G. Knepley   PetscCall(TSSetStepNumber(subts_p, n));
217*f023dd21SMatthew G. Knepley   PetscCall(TSSetStepNumber(subts_q, n));
218*f023dd21SMatthew G. Knepley   PetscCall(TSGetTime(ts, &ptime));
219*f023dd21SMatthew G. Knepley   PetscCall(TSSetTime(subts_p, ptime));
220*f023dd21SMatthew G. Knepley   PetscCall(TSSetTime(subts_q, ptime));
2219566063dSJacob Faibussowitsch   PetscCall(VecGetSubVector(update, is_q, &q_update));
2229566063dSJacob Faibussowitsch   PetscCall(VecGetSubVector(update, is_p, &p_update));
223*f023dd21SMatthew G. Knepley   for (PetscInt iter = 0; iter < scheme->s; iter++) {
224f9813ea2SStefano Zampini     PetscCall(TSPreStage(ts, ptime));
225f9813ea2SStefano Zampini     PetscCall(VecGetSubVector(solution, is_q, &q));
226f9813ea2SStefano Zampini     PetscCall(VecGetSubVector(solution, is_p, &p));
227e49d4f37SHong Zhang     /* update position q */
22825de42d4SHong Zhang     if (scheme->c[iter]) {
229f9813ea2SStefano Zampini       PetscCall(TSComputeRHSFunction(subts_q, ptime, p, q_update));
23025de42d4SHong Zhang       PetscCall(VecAXPY(q, scheme->c[iter] * ts->time_step, q_update));
23125de42d4SHong Zhang     }
23225de42d4SHong Zhang     /* update velocity p */
23325de42d4SHong Zhang     if (scheme->d[iter]) {
234f9813ea2SStefano Zampini       ptime = ptime + scheme->d[iter] * ts->time_step;
23525de42d4SHong Zhang       PetscCall(TSComputeRHSFunction(subts_p, ptime, q, p_update));
23625de42d4SHong Zhang       PetscCall(VecAXPY(p, scheme->d[iter] * ts->time_step, p_update));
237e49d4f37SHong Zhang     }
2389566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(solution, is_q, &q));
2399566063dSJacob Faibussowitsch     PetscCall(VecRestoreSubVector(solution, is_p, &p));
240f9813ea2SStefano Zampini     PetscCall(TSPostStage(ts, ptime, 0, &solution));
241f9813ea2SStefano Zampini     PetscCall(TSAdaptCheckStage(ts->adapt, ts, ptime, solution, &stageok));
242f9813ea2SStefano Zampini     if (!stageok) goto finally;
243f9813ea2SStefano Zampini     PetscCall(TSFunctionDomainError(ts, ptime, solution, &stageok));
244f9813ea2SStefano Zampini     if (!stageok) goto finally;
245f9813ea2SStefano Zampini   }
246f9813ea2SStefano Zampini 
247f9813ea2SStefano Zampini finally:
248f9813ea2SStefano Zampini   if (!stageok) ts->reason = TS_DIVERGED_STEP_REJECTED;
249f9813ea2SStefano Zampini   else ts->ptime += next_time_step;
2509566063dSJacob Faibussowitsch   PetscCall(VecRestoreSubVector(update, is_q, &q_update));
2519566063dSJacob Faibussowitsch   PetscCall(VecRestoreSubVector(update, is_p, &p_update));
2523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
253e49d4f37SHong Zhang }
254e49d4f37SHong Zhang 
255d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCoarsenHook_BasicSymplectic(DM fine, DM coarse, void *ctx)
256d71ae5a4SJacob Faibussowitsch {
257e49d4f37SHong Zhang   PetscFunctionBegin;
2583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
259e49d4f37SHong Zhang }
260e49d4f37SHong Zhang 
261d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMRestrictHook_BasicSymplectic(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse, void *ctx)
262d71ae5a4SJacob Faibussowitsch {
263e49d4f37SHong Zhang   PetscFunctionBegin;
2643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
265e49d4f37SHong Zhang }
266e49d4f37SHong Zhang 
267d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainHook_BasicSymplectic(DM dm, DM subdm, void *ctx)
268d71ae5a4SJacob Faibussowitsch {
269e49d4f37SHong Zhang   PetscFunctionBegin;
2703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
271e49d4f37SHong Zhang }
272e49d4f37SHong Zhang 
273d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSubDomainRestrictHook_BasicSymplectic(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx)
274d71ae5a4SJacob Faibussowitsch {
275e49d4f37SHong Zhang   PetscFunctionBegin;
2763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
277e49d4f37SHong Zhang }
278e49d4f37SHong Zhang 
279d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_BasicSymplectic(TS ts)
280d71ae5a4SJacob Faibussowitsch {
281e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic *)ts->data;
282e49d4f37SHong Zhang   DM                  dm;
283e49d4f37SHong Zhang 
284e49d4f37SHong Zhang   PetscFunctionBegin;
2859566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitGetIS(ts, "position", &bsymp->is_q));
2869566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitGetIS(ts, "momentum", &bsymp->is_p));
287aaa8cc7dSPierre Jolivet   PetscCheck(bsymp->is_q && bsymp->is_p, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must set up RHSSplits with TSRHSSplitSetIS() using split names position and momentum respectively in order to use -ts_type basicsymplectic");
2889566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitGetSubTS(ts, "position", &bsymp->subts_q));
2899566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitGetSubTS(ts, "momentum", &bsymp->subts_p));
2903c633725SBarry Smith   PetscCheck(bsymp->subts_q && bsymp->subts_p, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must set up the RHSFunctions for position and momentum using TSRHSSplitSetRHSFunction() or calling TSSetRHSFunction() for each sub-TS");
291e49d4f37SHong Zhang 
2929566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &bsymp->update));
293e49d4f37SHong Zhang 
2949566063dSJacob Faibussowitsch   PetscCall(TSGetAdapt(ts, &ts->adapt));
2959566063dSJacob Faibussowitsch   PetscCall(TSAdaptCandidatesClear(ts->adapt)); /* make sure to use fixed time stepping */
2969566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts, &dm));
297e49d4f37SHong Zhang   if (dm) {
2989566063dSJacob Faibussowitsch     PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_BasicSymplectic, DMRestrictHook_BasicSymplectic, ts));
2999566063dSJacob Faibussowitsch     PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_BasicSymplectic, DMSubDomainRestrictHook_BasicSymplectic, ts));
300e49d4f37SHong Zhang   }
3013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
302e49d4f37SHong Zhang }
303e49d4f37SHong Zhang 
304d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSReset_BasicSymplectic(TS ts)
305d71ae5a4SJacob Faibussowitsch {
306e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic *)ts->data;
307e49d4f37SHong Zhang 
308e49d4f37SHong Zhang   PetscFunctionBegin;
3099566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bsymp->update));
3103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
311e49d4f37SHong Zhang }
312e49d4f37SHong Zhang 
313d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDestroy_BasicSymplectic(TS ts)
314d71ae5a4SJacob Faibussowitsch {
315e49d4f37SHong Zhang   PetscFunctionBegin;
3169566063dSJacob Faibussowitsch   PetscCall(TSReset_BasicSymplectic(ts));
3172e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSBasicSymplecticSetType_C", NULL));
3182e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSBasicSymplecticGetType_C", NULL));
3199566063dSJacob Faibussowitsch   PetscCall(PetscFree(ts->data));
3203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
321e49d4f37SHong Zhang }
322e49d4f37SHong Zhang 
323d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetFromOptions_BasicSymplectic(TS ts, PetscOptionItems *PetscOptionsObject)
324d71ae5a4SJacob Faibussowitsch {
325e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic *)ts->data;
326e49d4f37SHong Zhang 
327e49d4f37SHong Zhang   PetscFunctionBegin;
328d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Basic symplectic integrator options");
329e49d4f37SHong Zhang   {
330e49d4f37SHong Zhang     BasicSymplecticSchemeLink link;
331e49d4f37SHong Zhang     PetscInt                  count, choice;
332e49d4f37SHong Zhang     PetscBool                 flg;
333e49d4f37SHong Zhang     const char              **namelist;
334e49d4f37SHong Zhang 
335fbccb6d4SPierre Jolivet     for (link = BasicSymplecticSchemeList, count = 0; link; link = link->next, count++);
3369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(count, (char ***)&namelist));
337e49d4f37SHong Zhang     for (link = BasicSymplecticSchemeList, count = 0; link; link = link->next, count++) namelist[count] = link->sch.name;
3389566063dSJacob Faibussowitsch     PetscCall(PetscOptionsEList("-ts_basicsymplectic_type", "Family of basic symplectic integration method", "TSBasicSymplecticSetType", (const char *const *)namelist, count, bsymp->scheme->name, &choice, &flg));
3399566063dSJacob Faibussowitsch     if (flg) PetscCall(TSBasicSymplecticSetType(ts, namelist[choice]));
3409566063dSJacob Faibussowitsch     PetscCall(PetscFree(namelist));
341e49d4f37SHong Zhang   }
342d0609cedSBarry Smith   PetscOptionsHeadEnd();
3433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
344e49d4f37SHong Zhang }
345e49d4f37SHong Zhang 
346d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_BasicSymplectic(TS ts, PetscViewer viewer)
347d71ae5a4SJacob Faibussowitsch {
348e49d4f37SHong Zhang   PetscFunctionBegin;
3493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
350e49d4f37SHong Zhang }
351e49d4f37SHong Zhang 
352d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSInterpolate_BasicSymplectic(TS ts, PetscReal t, Vec X)
353d71ae5a4SJacob Faibussowitsch {
354e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp  = (TS_BasicSymplectic *)ts->data;
355e49d4f37SHong Zhang   Vec                 update = bsymp->update;
356e49d4f37SHong Zhang   PetscReal           alpha  = (ts->ptime - t) / ts->time_step;
357e49d4f37SHong Zhang 
358e49d4f37SHong Zhang   PetscFunctionBegin;
3599566063dSJacob Faibussowitsch   PetscCall(VecWAXPY(X, -ts->time_step, update, ts->vec_sol));
3609566063dSJacob Faibussowitsch   PetscCall(VecAXPBY(X, 1.0 - alpha, alpha, ts->vec_sol));
3613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
362e49d4f37SHong Zhang }
363e49d4f37SHong Zhang 
364d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSComputeLinearStability_BasicSymplectic(TS ts, PetscReal xr, PetscReal xi, PetscReal *yr, PetscReal *yi)
365d71ae5a4SJacob Faibussowitsch {
366e49d4f37SHong Zhang   PetscFunctionBegin;
367e49d4f37SHong Zhang   *yr = 1.0 + xr;
368e49d4f37SHong Zhang   *yi = xi;
3693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
370e49d4f37SHong Zhang }
371e49d4f37SHong Zhang 
372cc4c1da9SBarry Smith /*@
373e49d4f37SHong Zhang   TSBasicSymplecticSetType - Set the type of the basic symplectic method
374e49d4f37SHong Zhang 
375c3339decSBarry Smith   Logically Collective
376e49d4f37SHong Zhang 
377d8d19677SJose E. Roman   Input Parameters:
378e49d4f37SHong Zhang + ts        - timestepping context
379e49d4f37SHong Zhang - bsymptype - type of the symplectic scheme
380e49d4f37SHong Zhang 
381bcf0153eSBarry Smith   Options Database Key:
382147403d9SBarry Smith . -ts_basicsymplectic_type <scheme> - select the scheme
383e49d4f37SHong Zhang 
384bcf0153eSBarry Smith   Level: intermediate
385bcf0153eSBarry Smith 
386bcf0153eSBarry Smith   Note:
3871d27aa22SBarry Smith   The symplectic solver always expects a two-way splitting with the split names being "position" and "momentum".
3881d27aa22SBarry Smith   Each split is associated with an `IS` object and a sub-`TS`
389147403d9SBarry Smith   that is intended to store the user-provided RHS function.
390e49d4f37SHong Zhang 
39142747ad1SJacob Faibussowitsch .seealso: [](ch_ts), `TSBASICSYMPLECTIC`, `TSBasicSymplecticType`
392e49d4f37SHong Zhang @*/
393d71ae5a4SJacob Faibussowitsch PetscErrorCode TSBasicSymplecticSetType(TS ts, TSBasicSymplecticType bsymptype)
394d71ae5a4SJacob Faibussowitsch {
395e49d4f37SHong Zhang   PetscFunctionBegin;
396e49d4f37SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
397cac4c232SBarry Smith   PetscTryMethod(ts, "TSBasicSymplecticSetType_C", (TS, TSBasicSymplecticType), (ts, bsymptype));
3983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
399e49d4f37SHong Zhang }
400e49d4f37SHong Zhang 
401cc4c1da9SBarry Smith /*@
402e49d4f37SHong Zhang   TSBasicSymplecticGetType - Get the type of the basic symplectic method
403e49d4f37SHong Zhang 
404c3339decSBarry Smith   Logically Collective
405e49d4f37SHong Zhang 
406d8d19677SJose E. Roman   Input Parameters:
407e49d4f37SHong Zhang + ts        - timestepping context
408e49d4f37SHong Zhang - bsymptype - type of the basic symplectic scheme
409e49d4f37SHong Zhang 
410e49d4f37SHong Zhang   Level: intermediate
411bcf0153eSBarry Smith 
4121cc06b55SBarry Smith .seealso: [](ch_ts), `TSBASICSYMPLECTIC`, `TSBasicSymplecticType`, `TSBasicSymplecticSetType()`
413e49d4f37SHong Zhang @*/
414d71ae5a4SJacob Faibussowitsch PetscErrorCode TSBasicSymplecticGetType(TS ts, TSBasicSymplecticType *bsymptype)
415d71ae5a4SJacob Faibussowitsch {
416e49d4f37SHong Zhang   PetscFunctionBegin;
417e49d4f37SHong Zhang   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
418cac4c232SBarry Smith   PetscUseMethod(ts, "TSBasicSymplecticGetType_C", (TS, TSBasicSymplecticType *), (ts, bsymptype));
4193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
420e49d4f37SHong Zhang }
421e49d4f37SHong Zhang 
422d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSBasicSymplecticSetType_BasicSymplectic(TS ts, TSBasicSymplecticType bsymptype)
423d71ae5a4SJacob Faibussowitsch {
424e49d4f37SHong Zhang   TS_BasicSymplectic       *bsymp = (TS_BasicSymplectic *)ts->data;
425e49d4f37SHong Zhang   BasicSymplecticSchemeLink link;
426e49d4f37SHong Zhang   PetscBool                 match;
427e49d4f37SHong Zhang 
428e49d4f37SHong Zhang   PetscFunctionBegin;
429e49d4f37SHong Zhang   if (bsymp->scheme) {
4309566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(bsymp->scheme->name, bsymptype, &match));
4313ba16761SJacob Faibussowitsch     if (match) PetscFunctionReturn(PETSC_SUCCESS);
432e49d4f37SHong Zhang   }
433e49d4f37SHong Zhang   for (link = BasicSymplecticSchemeList; link; link = link->next) {
4349566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(link->sch.name, bsymptype, &match));
435e49d4f37SHong Zhang     if (match) {
436e49d4f37SHong Zhang       bsymp->scheme = &link->sch;
4373ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
438e49d4f37SHong Zhang     }
439e49d4f37SHong Zhang   }
44098921bdaSJacob Faibussowitsch   SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_UNKNOWN_TYPE, "Could not find '%s'", bsymptype);
441e49d4f37SHong Zhang }
442e49d4f37SHong Zhang 
443d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSBasicSymplecticGetType_BasicSymplectic(TS ts, TSBasicSymplecticType *bsymptype)
444d71ae5a4SJacob Faibussowitsch {
445e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic *)ts->data;
446e49d4f37SHong Zhang 
447e49d4f37SHong Zhang   PetscFunctionBegin;
448e49d4f37SHong Zhang   *bsymptype = bsymp->scheme->name;
4493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
450e49d4f37SHong Zhang }
451e49d4f37SHong Zhang 
452e49d4f37SHong Zhang /*MC
4531d27aa22SBarry Smith   TSBASICSYMPLECTIC - ODE solver using basic symplectic integration schemes <https://en.wikipedia.org/wiki/Symplectic_integrator>
454e49d4f37SHong Zhang 
455bcf0153eSBarry Smith   These methods are intended for separable Hamiltonian systems
4561d27aa22SBarry Smith 
4571d27aa22SBarry Smith   $$
4581d27aa22SBarry Smith   \begin{align*}
4591d27aa22SBarry Smith   qdot = dH(q,p,t)/dp   \\
460bcf0153eSBarry Smith   pdot = -dH(q,p,t)/dq
4611d27aa22SBarry Smith   \end{align*}
4621d27aa22SBarry Smith   $$
463e49d4f37SHong Zhang 
464e49d4f37SHong Zhang   where the Hamiltonian can be split into the sum of kinetic energy and potential energy
4651d27aa22SBarry Smith 
4661d27aa22SBarry Smith   $$
467bcf0153eSBarry Smith   H(q,p,t) = T(p,t) + V(q,t).
4681d27aa22SBarry Smith   $$
469e49d4f37SHong Zhang 
470145b44c9SPierre Jolivet   As a result, the system can be generally represented by
4711d27aa22SBarry Smith 
4721d27aa22SBarry Smith   $$
4731d27aa22SBarry Smith   \begin{align*}
4741d27aa22SBarry Smith   qdot = f(p,t) = dT(p,t)/dp \\
475bcf0153eSBarry Smith   pdot = g(q,t) = -dV(q,t)/dq
4761d27aa22SBarry Smith   \end{align*}
4771d27aa22SBarry Smith   $$
478e49d4f37SHong Zhang 
479e49d4f37SHong Zhang   and solved iteratively with
4801d27aa22SBarry Smith 
4811d27aa22SBarry Smith   $$
4821d27aa22SBarry Smith   \begin{align*}
4831d27aa22SBarry Smith   q_new = q_old + d_i*h*f(p_old,t_old) \\
4841d27aa22SBarry Smith   t_new = t_old + d_i*h \\
4851d27aa22SBarry Smith   p_new = p_old + c_i*h*g(p_new,t_new) \\
486bcf0153eSBarry Smith   i     = 0,1,...,n.
4871d27aa22SBarry Smith   \end{align*}
4881d27aa22SBarry Smith   $$
489e49d4f37SHong Zhang 
490bcf0153eSBarry Smith   The solution vector should contain both q and p, which correspond to (generalized) position and momentum respectively. Note that the momentum component
491bcf0153eSBarry Smith   could simply be velocity in some representations. The symplectic solver always expects a two-way splitting with the split names being "position" and "momentum".
492bcf0153eSBarry Smith   Each split is associated with an `IS` object and a sub-`TS` that is intended to store the user-provided RHS function.
493e49d4f37SHong Zhang 
494e49d4f37SHong Zhang   Level: beginner
495e49d4f37SHong Zhang 
4961cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TSSetType()`, `TSRHSSplitSetIS()`, `TSRHSSplitSetRHSFunction()`, `TSType`
497e49d4f37SHong Zhang M*/
498d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_BasicSymplectic(TS ts)
499d71ae5a4SJacob Faibussowitsch {
500e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp;
501e49d4f37SHong Zhang 
502e49d4f37SHong Zhang   PetscFunctionBegin;
5039566063dSJacob Faibussowitsch   PetscCall(TSBasicSymplecticInitializePackage());
5044dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&bsymp));
505e49d4f37SHong Zhang   ts->data = (void *)bsymp;
506e49d4f37SHong Zhang 
507e49d4f37SHong Zhang   ts->ops->setup           = TSSetUp_BasicSymplectic;
508e49d4f37SHong Zhang   ts->ops->step            = TSStep_BasicSymplectic;
509e49d4f37SHong Zhang   ts->ops->reset           = TSReset_BasicSymplectic;
510e49d4f37SHong Zhang   ts->ops->destroy         = TSDestroy_BasicSymplectic;
511e49d4f37SHong Zhang   ts->ops->setfromoptions  = TSSetFromOptions_BasicSymplectic;
512e49d4f37SHong Zhang   ts->ops->view            = TSView_BasicSymplectic;
513e49d4f37SHong Zhang   ts->ops->interpolate     = TSInterpolate_BasicSymplectic;
514e49d4f37SHong Zhang   ts->ops->linearstability = TSComputeLinearStability_BasicSymplectic;
515e49d4f37SHong Zhang 
5169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSBasicSymplecticSetType_C", TSBasicSymplecticSetType_BasicSymplectic));
5179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSBasicSymplecticGetType_C", TSBasicSymplecticGetType_BasicSymplectic));
518e49d4f37SHong Zhang 
5199566063dSJacob Faibussowitsch   PetscCall(TSBasicSymplecticSetType(ts, TSBasicSymplecticDefault));
5203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
521e49d4f37SHong Zhang }
522