xref: /petsc/src/ts/impls/symplectic/basicsymplectic/basicsymplectic.c (revision cac4c232dc4f93991e342196e27ef7b0655dac7b)
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
34e49d4f37SHong Zhang   Level: intermediate
35e49d4f37SHong Zhang .seealso: TSBASICSYMPLECTIC
36e49d4f37SHong Zhang M*/
37e49d4f37SHong Zhang 
38e49d4f37SHong Zhang /*MC
39e49d4f37SHong Zhang   TSBASICSYMPLECTICVELVERLET - second order Velocity Verlet method (leapfrog method with starting process and determing velocity and position at the same time)
40e49d4f37SHong Zhang Level: intermediate
41e49d4f37SHong Zhang .seealso: TSBASICSYMPLECTIC
42e49d4f37SHong Zhang M*/
43e49d4f37SHong Zhang 
44e49d4f37SHong Zhang /*@C
45e49d4f37SHong Zhang   TSBasicSymplecticRegisterAll - Registers all of the basic symplectic integration methods in TSBasicSymplectic
46e49d4f37SHong Zhang 
47e49d4f37SHong Zhang   Not Collective, but should be called by all processes which will need the schemes to be registered
48e49d4f37SHong Zhang 
49e49d4f37SHong Zhang   Level: advanced
50e49d4f37SHong Zhang 
51e49d4f37SHong Zhang .seealso:  TSBasicSymplecticRegisterDestroy()
52e49d4f37SHong Zhang @*/
53e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticRegisterAll(void)
54e49d4f37SHong Zhang {
55e49d4f37SHong Zhang   PetscFunctionBegin;
56e49d4f37SHong Zhang   if (TSBasicSymplecticRegisterAllCalled) PetscFunctionReturn(0);
57e49d4f37SHong Zhang   TSBasicSymplecticRegisterAllCalled = PETSC_TRUE;
58e49d4f37SHong Zhang   {
59e49d4f37SHong Zhang     PetscReal c[1] = {1.0},d[1] = {1.0};
609566063dSJacob Faibussowitsch     PetscCall(TSBasicSymplecticRegister(TSBASICSYMPLECTICSIEULER,1,1,c,d));
61e49d4f37SHong Zhang   }
62e49d4f37SHong Zhang   {
63e49d4f37SHong Zhang     PetscReal c[2] = {0,1.0},d[2] = {0.5,0.5};
649566063dSJacob Faibussowitsch     PetscCall(TSBasicSymplecticRegister(TSBASICSYMPLECTICVELVERLET,2,2,c,d));
65e49d4f37SHong Zhang   }
66e49d4f37SHong Zhang   {
67e49d4f37SHong 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};
689566063dSJacob Faibussowitsch     PetscCall(TSBasicSymplecticRegister(TSBASICSYMPLECTIC3,3,3,c,d));
69e49d4f37SHong Zhang   }
70e49d4f37SHong Zhang   {
71e49d4f37SHong Zhang #define CUBEROOTOFTWO 1.2599210498948731647672106
72e49d4f37SHong 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};
739566063dSJacob Faibussowitsch     PetscCall(TSBasicSymplecticRegister(TSBASICSYMPLECTIC4,4,4,c,d));
74e49d4f37SHong Zhang   }
75e49d4f37SHong Zhang   PetscFunctionReturn(0);
76e49d4f37SHong Zhang }
77e49d4f37SHong Zhang 
78e49d4f37SHong Zhang /*@C
79e49d4f37SHong Zhang    TSBasicSymplecticRegisterDestroy - Frees the list of schemes that were registered by TSBasicSymplecticRegister().
80e49d4f37SHong Zhang 
81e49d4f37SHong Zhang    Not Collective
82e49d4f37SHong Zhang 
83e49d4f37SHong Zhang    Level: advanced
84e49d4f37SHong Zhang 
85e49d4f37SHong Zhang .seealso: TSBasicSymplecticRegister(), TSBasicSymplecticRegisterAll()
86e49d4f37SHong Zhang @*/
87e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticRegisterDestroy(void)
88e49d4f37SHong Zhang {
89e49d4f37SHong Zhang   BasicSymplecticSchemeLink link;
90e49d4f37SHong Zhang 
91e49d4f37SHong Zhang   PetscFunctionBegin;
92e49d4f37SHong Zhang   while ((link = BasicSymplecticSchemeList)) {
93e49d4f37SHong Zhang     BasicSymplecticScheme scheme = &link->sch;
94e49d4f37SHong Zhang     BasicSymplecticSchemeList = link->next;
959566063dSJacob Faibussowitsch     PetscCall(PetscFree2(scheme->c,scheme->d));
969566063dSJacob Faibussowitsch     PetscCall(PetscFree(scheme->name));
979566063dSJacob Faibussowitsch     PetscCall(PetscFree(link));
98e49d4f37SHong Zhang   }
99e49d4f37SHong Zhang   TSBasicSymplecticRegisterAllCalled = PETSC_FALSE;
100e49d4f37SHong Zhang   PetscFunctionReturn(0);
101e49d4f37SHong Zhang }
102e49d4f37SHong Zhang 
103e49d4f37SHong Zhang /*@C
104e49d4f37SHong Zhang   TSBasicSymplecticInitializePackage - This function initializes everything in the TSBasicSymplectic package. It is called
1058a690491SBarry Smith   from TSInitializePackage().
106e49d4f37SHong Zhang 
107e49d4f37SHong Zhang   Level: developer
108e49d4f37SHong Zhang 
109e49d4f37SHong Zhang .seealso: PetscInitialize()
110e49d4f37SHong Zhang @*/
111e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticInitializePackage(void)
112e49d4f37SHong Zhang {
113e49d4f37SHong Zhang   PetscFunctionBegin;
114e49d4f37SHong Zhang   if (TSBasicSymplecticPackageInitialized) PetscFunctionReturn(0);
115e49d4f37SHong Zhang   TSBasicSymplecticPackageInitialized = PETSC_TRUE;
1169566063dSJacob Faibussowitsch   PetscCall(TSBasicSymplecticRegisterAll());
1179566063dSJacob Faibussowitsch   PetscCall(PetscRegisterFinalize(TSBasicSymplecticFinalizePackage));
118e49d4f37SHong Zhang   PetscFunctionReturn(0);
119e49d4f37SHong Zhang }
120e49d4f37SHong Zhang 
121e49d4f37SHong Zhang /*@C
122e49d4f37SHong Zhang   TSBasicSymplecticFinalizePackage - This function destroys everything in the TSBasicSymplectic package. It is
123e49d4f37SHong Zhang   called from PetscFinalize().
124e49d4f37SHong Zhang 
125e49d4f37SHong Zhang   Level: developer
126e49d4f37SHong Zhang 
127e49d4f37SHong Zhang .seealso: PetscFinalize()
128e49d4f37SHong Zhang @*/
129e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticFinalizePackage(void)
130e49d4f37SHong Zhang {
131e49d4f37SHong Zhang   PetscFunctionBegin;
132e49d4f37SHong Zhang   TSBasicSymplecticPackageInitialized = PETSC_FALSE;
1339566063dSJacob Faibussowitsch   PetscCall(TSBasicSymplecticRegisterDestroy());
134e49d4f37SHong Zhang   PetscFunctionReturn(0);
135e49d4f37SHong Zhang }
136e49d4f37SHong Zhang 
137e49d4f37SHong Zhang /*@C
138e49d4f37SHong Zhang    TSBasicSymplecticRegister - register a basic symplectic integration scheme by providing the coefficients.
139e49d4f37SHong Zhang 
140e49d4f37SHong Zhang    Not Collective, but the same schemes should be registered on all processes on which they will be used
141e49d4f37SHong Zhang 
142e49d4f37SHong Zhang    Input Parameters:
143e49d4f37SHong Zhang +  name - identifier for method
144e49d4f37SHong Zhang .  order - approximation order of method
145e49d4f37SHong Zhang .  s - number of stages, this is the dimension of the matrices below
146e49d4f37SHong Zhang .  c - coefficients for updating generalized position (dimension s)
147e49d4f37SHong Zhang -  d - coefficients for updating generalized momentum (dimension s)
148e49d4f37SHong Zhang 
149e49d4f37SHong Zhang    Notes:
150e49d4f37SHong Zhang    Several symplectic methods are provided, this function is only needed to create new methods.
151e49d4f37SHong Zhang 
152e49d4f37SHong Zhang    Level: advanced
153e49d4f37SHong Zhang 
154e49d4f37SHong Zhang .seealso: TSBasicSymplectic
155e49d4f37SHong Zhang @*/
156e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticRegister(TSRosWType name,PetscInt order,PetscInt s,PetscReal c[],PetscReal d[])
157e49d4f37SHong Zhang {
158e49d4f37SHong Zhang   BasicSymplecticSchemeLink link;
159e49d4f37SHong Zhang   BasicSymplecticScheme     scheme;
160e49d4f37SHong Zhang 
161e49d4f37SHong Zhang   PetscFunctionBegin;
162e49d4f37SHong Zhang   PetscValidCharPointer(name,1);
163dadcf809SJacob Faibussowitsch   PetscValidRealPointer(c,4);
164dadcf809SJacob Faibussowitsch   PetscValidRealPointer(d,5);
165e49d4f37SHong Zhang 
1669566063dSJacob Faibussowitsch   PetscCall(TSBasicSymplecticInitializePackage());
1679566063dSJacob Faibussowitsch   PetscCall(PetscNew(&link));
168e49d4f37SHong Zhang   scheme = &link->sch;
1699566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(name,&scheme->name));
170e49d4f37SHong Zhang   scheme->order = order;
171e49d4f37SHong Zhang   scheme->s = s;
1729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(s,&scheme->c,s,&scheme->d));
1739566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(scheme->c,c,s));
1749566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(scheme->d,d,s));
175e49d4f37SHong Zhang   link->next = BasicSymplecticSchemeList;
176e49d4f37SHong Zhang   BasicSymplecticSchemeList = link;
177e49d4f37SHong Zhang   PetscFunctionReturn(0);
178e49d4f37SHong Zhang }
179e49d4f37SHong Zhang 
180e49d4f37SHong Zhang /*
181e49d4f37SHong Zhang The simplified form of the equations are:
182e49d4f37SHong Zhang 
183e49d4f37SHong Zhang $ p_{i+1} = p_i + c_i*g(q_i)*h
184e49d4f37SHong Zhang $ q_{i+1} = q_i + d_i*f(p_{i+1},t_{i+1})*h
185e49d4f37SHong Zhang 
186e49d4f37SHong Zhang Several symplectic integrators are given below. An illustrative way to use them is to consider a particle with position q and velocity p.
187e49d4f37SHong Zhang 
188e49d4f37SHong Zhang To apply a timestep with values c_{1,2},d_{1,2} to the particle, carry out the following steps:
189e49d4f37SHong Zhang 
190e49d4f37SHong Zhang - Update the velocity of the particle by adding to it its acceleration multiplied by c_1
191e49d4f37SHong Zhang - Update the position of the particle by adding to it its (updated) velocity multiplied by d_1
192e49d4f37SHong Zhang - Update the velocity of the particle by adding to it its acceleration (at the updated position) multiplied by c_2
193e49d4f37SHong Zhang - Update the position of the particle by adding to it its (double-updated) velocity multiplied by d_2
194e49d4f37SHong Zhang 
195e49d4f37SHong Zhang */
196e49d4f37SHong Zhang static PetscErrorCode TSStep_BasicSymplectic(TS ts)
197e49d4f37SHong Zhang {
198e49d4f37SHong Zhang   TS_BasicSymplectic    *bsymp = (TS_BasicSymplectic*)ts->data;
199e49d4f37SHong Zhang   BasicSymplecticScheme scheme = bsymp->scheme;
200e49d4f37SHong Zhang   Vec                   solution = ts->vec_sol,update = bsymp->update,q,p,q_update,p_update;
201e49d4f37SHong Zhang   IS                    is_q = bsymp->is_q,is_p = bsymp->is_p;
202e49d4f37SHong Zhang   TS                    subts_q = bsymp->subts_q,subts_p = bsymp->subts_p;
203e49d4f37SHong Zhang   PetscBool             stageok;
204e49d4f37SHong Zhang   PetscReal             next_time_step = ts->time_step;
205e49d4f37SHong Zhang   PetscInt              iter;
206e49d4f37SHong Zhang 
207e49d4f37SHong Zhang   PetscFunctionBegin;
2089566063dSJacob Faibussowitsch   PetscCall(VecGetSubVector(solution,is_q,&q));
2099566063dSJacob Faibussowitsch   PetscCall(VecGetSubVector(solution,is_p,&p));
2109566063dSJacob Faibussowitsch   PetscCall(VecGetSubVector(update,is_q,&q_update));
2119566063dSJacob Faibussowitsch   PetscCall(VecGetSubVector(update,is_p,&p_update));
212e49d4f37SHong Zhang 
213e49d4f37SHong Zhang   for (iter = 0;iter<scheme->s;iter++) {
2149566063dSJacob Faibussowitsch     PetscCall(TSPreStage(ts,ts->ptime));
215e49d4f37SHong Zhang     /* update velocity p */
216e49d4f37SHong Zhang     if (scheme->c[iter]) {
2179566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSFunction(subts_p,ts->ptime,q,p_update));
2189566063dSJacob Faibussowitsch       PetscCall(VecAXPY(p,scheme->c[iter]*ts->time_step,p_update));
219e49d4f37SHong Zhang     }
220e49d4f37SHong Zhang     /* update position q */
221e49d4f37SHong Zhang     if (scheme->d[iter]) {
2229566063dSJacob Faibussowitsch       PetscCall(TSComputeRHSFunction(subts_q,ts->ptime,p,q_update));
2239566063dSJacob Faibussowitsch       PetscCall(VecAXPY(q,scheme->d[iter]*ts->time_step,q_update));
224e49d4f37SHong Zhang       ts->ptime = ts->ptime+scheme->d[iter]*ts->time_step;
225e49d4f37SHong Zhang     }
2269566063dSJacob Faibussowitsch     PetscCall(TSPostStage(ts,ts->ptime,0,&solution));
2279566063dSJacob Faibussowitsch     PetscCall(TSAdaptCheckStage(ts->adapt,ts,ts->ptime,solution,&stageok));
228e49d4f37SHong Zhang     if (!stageok) {ts->reason = TS_DIVERGED_STEP_REJECTED; PetscFunctionReturn(0);}
2299566063dSJacob Faibussowitsch     PetscCall(TSFunctionDomainError(ts,ts->ptime+ts->time_step,update,&stageok));
230e49d4f37SHong Zhang     if (!stageok) {ts->reason = TS_DIVERGED_STEP_REJECTED; PetscFunctionReturn(0);}
231e49d4f37SHong Zhang   }
232e49d4f37SHong Zhang 
233e49d4f37SHong Zhang   ts->time_step = next_time_step;
2349566063dSJacob Faibussowitsch   PetscCall(VecRestoreSubVector(solution,is_q,&q));
2359566063dSJacob Faibussowitsch   PetscCall(VecRestoreSubVector(solution,is_p,&p));
2369566063dSJacob Faibussowitsch   PetscCall(VecRestoreSubVector(update,is_q,&q_update));
2379566063dSJacob Faibussowitsch   PetscCall(VecRestoreSubVector(update,is_p,&p_update));
238e49d4f37SHong Zhang   PetscFunctionReturn(0);
239e49d4f37SHong Zhang }
240e49d4f37SHong Zhang 
241e49d4f37SHong Zhang static PetscErrorCode DMCoarsenHook_BasicSymplectic(DM fine,DM coarse,void *ctx)
242e49d4f37SHong Zhang {
243e49d4f37SHong Zhang   PetscFunctionBegin;
244e49d4f37SHong Zhang   PetscFunctionReturn(0);
245e49d4f37SHong Zhang }
246e49d4f37SHong Zhang 
247e49d4f37SHong Zhang static PetscErrorCode DMRestrictHook_BasicSymplectic(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse,void *ctx)
248e49d4f37SHong Zhang {
249e49d4f37SHong Zhang   PetscFunctionBegin;
250e49d4f37SHong Zhang   PetscFunctionReturn(0);
251e49d4f37SHong Zhang }
252e49d4f37SHong Zhang 
253e49d4f37SHong Zhang static PetscErrorCode DMSubDomainHook_BasicSymplectic(DM dm,DM subdm,void *ctx)
254e49d4f37SHong Zhang {
255e49d4f37SHong Zhang   PetscFunctionBegin;
256e49d4f37SHong Zhang   PetscFunctionReturn(0);
257e49d4f37SHong Zhang }
258e49d4f37SHong Zhang 
259e49d4f37SHong Zhang static PetscErrorCode DMSubDomainRestrictHook_BasicSymplectic(DM dm,VecScatter gscat,VecScatter lscat,DM subdm,void *ctx)
260e49d4f37SHong Zhang {
261e49d4f37SHong Zhang   PetscFunctionBegin;
262e49d4f37SHong Zhang   PetscFunctionReturn(0);
263e49d4f37SHong Zhang }
264e49d4f37SHong Zhang 
265e49d4f37SHong Zhang static PetscErrorCode TSSetUp_BasicSymplectic(TS ts)
266e49d4f37SHong Zhang {
267e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic*)ts->data;
268e49d4f37SHong Zhang   DM                 dm;
269e49d4f37SHong Zhang 
270e49d4f37SHong Zhang   PetscFunctionBegin;
2719566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitGetIS(ts,"position",&bsymp->is_q));
2729566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitGetIS(ts,"momentum",&bsymp->is_p));
2733c633725SBarry Smith   PetscCheck(bsymp->is_q && bsymp->is_p,PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"Must set up RHSSplits with TSRHSSplitSetIS() using split names positon and momentum respectively in order to use -ts_type basicsymplectic");
2749566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitGetSubTS(ts,"position",&bsymp->subts_q));
2759566063dSJacob Faibussowitsch   PetscCall(TSRHSSplitGetSubTS(ts,"momentum",&bsymp->subts_p));
2763c633725SBarry 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");
277e49d4f37SHong Zhang 
2789566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol,&bsymp->update));
279e49d4f37SHong Zhang 
2809566063dSJacob Faibussowitsch   PetscCall(TSGetAdapt(ts,&ts->adapt));
2819566063dSJacob Faibussowitsch   PetscCall(TSAdaptCandidatesClear(ts->adapt)); /* make sure to use fixed time stepping */
2829566063dSJacob Faibussowitsch   PetscCall(TSGetDM(ts,&dm));
283e49d4f37SHong Zhang   if (dm) {
2849566063dSJacob Faibussowitsch     PetscCall(DMCoarsenHookAdd(dm,DMCoarsenHook_BasicSymplectic,DMRestrictHook_BasicSymplectic,ts));
2859566063dSJacob Faibussowitsch     PetscCall(DMSubDomainHookAdd(dm,DMSubDomainHook_BasicSymplectic,DMSubDomainRestrictHook_BasicSymplectic,ts));
286e49d4f37SHong Zhang   }
287e49d4f37SHong Zhang   PetscFunctionReturn(0);
288e49d4f37SHong Zhang }
289e49d4f37SHong Zhang 
290e49d4f37SHong Zhang static PetscErrorCode TSReset_BasicSymplectic(TS ts)
291e49d4f37SHong Zhang {
292e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic*)ts->data;
293e49d4f37SHong Zhang 
294e49d4f37SHong Zhang   PetscFunctionBegin;
2959566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bsymp->update));
296e49d4f37SHong Zhang   PetscFunctionReturn(0);
297e49d4f37SHong Zhang }
298e49d4f37SHong Zhang 
299e49d4f37SHong Zhang static PetscErrorCode TSDestroy_BasicSymplectic(TS ts)
300e49d4f37SHong Zhang {
301e49d4f37SHong Zhang   PetscFunctionBegin;
3029566063dSJacob Faibussowitsch   PetscCall(TSReset_BasicSymplectic(ts));
3039566063dSJacob Faibussowitsch   PetscCall(PetscFree(ts->data));
304e49d4f37SHong Zhang   PetscFunctionReturn(0);
305e49d4f37SHong Zhang }
306e49d4f37SHong Zhang 
307e49d4f37SHong Zhang static PetscErrorCode TSSetFromOptions_BasicSymplectic(PetscOptionItems *PetscOptionsObject,TS ts)
308e49d4f37SHong Zhang {
309e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic*)ts->data;
310e49d4f37SHong Zhang 
311e49d4f37SHong Zhang   PetscFunctionBegin;
3129566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHead(PetscOptionsObject,"Basic symplectic integrator options"));
313e49d4f37SHong Zhang   {
314e49d4f37SHong Zhang     BasicSymplecticSchemeLink link;
315e49d4f37SHong Zhang     PetscInt                  count,choice;
316e49d4f37SHong Zhang     PetscBool                 flg;
317e49d4f37SHong Zhang     const char                **namelist;
318e49d4f37SHong Zhang 
319e49d4f37SHong Zhang     for (link=BasicSymplecticSchemeList,count=0; link; link=link->next,count++) ;
3209566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(count,(char***)&namelist));
321e49d4f37SHong Zhang     for (link=BasicSymplecticSchemeList,count=0; link; link=link->next,count++) namelist[count] = link->sch.name;
3229566063dSJacob Faibussowitsch     PetscCall(PetscOptionsEList("-ts_basicsymplectic_type","Family of basic symplectic integration method","TSBasicSymplecticSetType",(const char*const*)namelist,count,bsymp->scheme->name,&choice,&flg));
3239566063dSJacob Faibussowitsch     if (flg) PetscCall(TSBasicSymplecticSetType(ts,namelist[choice]));
3249566063dSJacob Faibussowitsch     PetscCall(PetscFree(namelist));
325e49d4f37SHong Zhang   }
3269566063dSJacob Faibussowitsch   PetscCall(PetscOptionsTail());
327e49d4f37SHong Zhang   PetscFunctionReturn(0);
328e49d4f37SHong Zhang }
329e49d4f37SHong Zhang 
330e49d4f37SHong Zhang static PetscErrorCode TSView_BasicSymplectic(TS ts,PetscViewer viewer)
331e49d4f37SHong Zhang {
332e49d4f37SHong Zhang   PetscFunctionBegin;
333e49d4f37SHong Zhang   PetscFunctionReturn(0);
334e49d4f37SHong Zhang }
335e49d4f37SHong Zhang 
336e49d4f37SHong Zhang static PetscErrorCode TSInterpolate_BasicSymplectic(TS ts,PetscReal t,Vec X)
337e49d4f37SHong Zhang {
338e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic*)ts->data;
339e49d4f37SHong Zhang   Vec                update = bsymp->update;
340e49d4f37SHong Zhang   PetscReal          alpha = (ts->ptime - t)/ts->time_step;
341e49d4f37SHong Zhang 
342e49d4f37SHong Zhang   PetscFunctionBegin;
3439566063dSJacob Faibussowitsch   PetscCall(VecWAXPY(X,-ts->time_step,update,ts->vec_sol));
3449566063dSJacob Faibussowitsch   PetscCall(VecAXPBY(X,1.0-alpha,alpha,ts->vec_sol));
345e49d4f37SHong Zhang   PetscFunctionReturn(0);
346e49d4f37SHong Zhang }
347e49d4f37SHong Zhang 
348e49d4f37SHong Zhang static PetscErrorCode TSComputeLinearStability_BasicSymplectic(TS ts,PetscReal xr,PetscReal xi,PetscReal *yr,PetscReal *yi)
349e49d4f37SHong Zhang {
350e49d4f37SHong Zhang   PetscFunctionBegin;
351e49d4f37SHong Zhang   *yr = 1.0 + xr;
352e49d4f37SHong Zhang   *yi = xi;
353e49d4f37SHong Zhang   PetscFunctionReturn(0);
354e49d4f37SHong Zhang }
355e49d4f37SHong Zhang 
356e49d4f37SHong Zhang /*@C
357e49d4f37SHong Zhang   TSBasicSymplecticSetType - Set the type of the basic symplectic method
358e49d4f37SHong Zhang 
359e49d4f37SHong Zhang   Logically Collective on TS
360e49d4f37SHong Zhang 
361d8d19677SJose E. Roman   Input Parameters:
362e49d4f37SHong Zhang +  ts - timestepping context
363e49d4f37SHong Zhang -  bsymptype - type of the symplectic scheme
364e49d4f37SHong Zhang 
365e49d4f37SHong Zhang   Options Database:
366147403d9SBarry Smith .  -ts_basicsymplectic_type <scheme> - select the scheme
367e49d4f37SHong Zhang 
368e49d4f37SHong Zhang   Notes:
369147403d9SBarry Smith     The symplectic solver always expects a two-way splitting with the split names being "position" and "momentum". Each split is associated with an IS object and a sub-TS
370147403d9SBarry Smith     that is intended to store the user-provided RHS function.
371e49d4f37SHong Zhang 
372e49d4f37SHong Zhang   Level: intermediate
373e49d4f37SHong Zhang @*/
374e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticSetType(TS ts,TSBasicSymplecticType bsymptype)
375e49d4f37SHong Zhang {
376e49d4f37SHong Zhang   PetscFunctionBegin;
377e49d4f37SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
378*cac4c232SBarry Smith   PetscTryMethod(ts,"TSBasicSymplecticSetType_C",(TS,TSBasicSymplecticType),(ts,bsymptype));
379e49d4f37SHong Zhang   PetscFunctionReturn(0);
380e49d4f37SHong Zhang }
381e49d4f37SHong Zhang 
382e49d4f37SHong Zhang /*@C
383e49d4f37SHong Zhang   TSBasicSymplecticGetType - Get the type of the basic symplectic method
384e49d4f37SHong Zhang 
385e49d4f37SHong Zhang   Logically Collective on TS
386e49d4f37SHong Zhang 
387d8d19677SJose E. Roman   Input Parameters:
388e49d4f37SHong Zhang +  ts - timestepping context
389e49d4f37SHong Zhang -  bsymptype - type of the basic symplectic scheme
390e49d4f37SHong Zhang 
391e49d4f37SHong Zhang   Level: intermediate
392e49d4f37SHong Zhang @*/
393e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticGetType(TS ts,TSBasicSymplecticType *bsymptype)
394e49d4f37SHong Zhang {
395e49d4f37SHong Zhang   PetscFunctionBegin;
396e49d4f37SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
397*cac4c232SBarry Smith   PetscUseMethod(ts,"TSBasicSymplecticGetType_C",(TS,TSBasicSymplecticType*),(ts,bsymptype));
398e49d4f37SHong Zhang   PetscFunctionReturn(0);
399e49d4f37SHong Zhang }
400e49d4f37SHong Zhang 
401e49d4f37SHong Zhang static PetscErrorCode TSBasicSymplecticSetType_BasicSymplectic(TS ts,TSBasicSymplecticType bsymptype)
402e49d4f37SHong Zhang {
403e49d4f37SHong Zhang   TS_BasicSymplectic        *bsymp = (TS_BasicSymplectic*)ts->data;
404e49d4f37SHong Zhang   BasicSymplecticSchemeLink link;
405e49d4f37SHong Zhang   PetscBool                 match;
406e49d4f37SHong Zhang 
407e49d4f37SHong Zhang   PetscFunctionBegin;
408e49d4f37SHong Zhang   if (bsymp->scheme) {
4099566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(bsymp->scheme->name,bsymptype,&match));
410e49d4f37SHong Zhang     if (match) PetscFunctionReturn(0);
411e49d4f37SHong Zhang   }
412e49d4f37SHong Zhang   for (link = BasicSymplecticSchemeList; link; link=link->next) {
4139566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(link->sch.name,bsymptype,&match));
414e49d4f37SHong Zhang     if (match) {
415e49d4f37SHong Zhang       bsymp->scheme = &link->sch;
416e49d4f37SHong Zhang       PetscFunctionReturn(0);
417e49d4f37SHong Zhang     }
418e49d4f37SHong Zhang   }
41998921bdaSJacob Faibussowitsch   SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",bsymptype);
420e49d4f37SHong Zhang }
421e49d4f37SHong Zhang 
422e49d4f37SHong Zhang static PetscErrorCode  TSBasicSymplecticGetType_BasicSymplectic(TS ts,TSBasicSymplecticType *bsymptype)
423e49d4f37SHong Zhang {
424e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic*)ts->data;
425e49d4f37SHong Zhang 
426e49d4f37SHong Zhang   PetscFunctionBegin;
427e49d4f37SHong Zhang   *bsymptype = bsymp->scheme->name;
428e49d4f37SHong Zhang   PetscFunctionReturn(0);
429e49d4f37SHong Zhang }
430e49d4f37SHong Zhang 
431e49d4f37SHong Zhang /*MC
432e49d4f37SHong Zhang   TSBasicSymplectic - ODE solver using basic symplectic integration schemes
433e49d4f37SHong Zhang 
434e49d4f37SHong Zhang   These methods are intened for separable Hamiltonian systems
435e49d4f37SHong Zhang 
436e49d4f37SHong Zhang $  qdot = dH(q,p,t)/dp
437e49d4f37SHong Zhang $  pdot = -dH(q,p,t)/dq
438e49d4f37SHong Zhang 
439e49d4f37SHong Zhang   where the Hamiltonian can be split into the sum of kinetic energy and potential energy
440e49d4f37SHong Zhang 
441e49d4f37SHong Zhang $  H(q,p,t) = T(p,t) + V(q,t).
442e49d4f37SHong Zhang 
443e49d4f37SHong Zhang   As a result, the system can be genearlly represented by
444e49d4f37SHong Zhang 
445e49d4f37SHong Zhang $  qdot = f(p,t) = dT(p,t)/dp
446e49d4f37SHong Zhang $  pdot = g(q,t) = -dV(q,t)/dq
447e49d4f37SHong Zhang 
448e49d4f37SHong Zhang   and solved iteratively with
449e49d4f37SHong Zhang 
450e49d4f37SHong Zhang $  q_new = q_old + d_i*h*f(p_old,t_old)
451e49d4f37SHong Zhang $  t_new = t_old + d_i*h
452e49d4f37SHong Zhang $  p_new = p_old + c_i*h*g(p_new,t_new)
453e49d4f37SHong Zhang $  i=0,1,...,n.
454e49d4f37SHong Zhang 
455e49d4f37SHong Zhang   The solution vector should contain both q and p, which correspond to (generalized) position and momentum respectively. Note that the momentum component could simply be velocity in some representations.
456e49d4f37SHong Zhang   The symplectic solver always expects a two-way splitting with the split names being "position" and "momentum". Each split is associated with an IS object and a sub-TS that is intended to store the user-provided RHS function.
457e49d4f37SHong Zhang 
458e49d4f37SHong Zhang   Reference: wikipedia (https://en.wikipedia.org/wiki/Symplectic_integrator)
459e49d4f37SHong Zhang 
460e49d4f37SHong Zhang   Level: beginner
461e49d4f37SHong Zhang 
462e49d4f37SHong Zhang .seealso:  TSCreate(), TSSetType(), TSRHSSplitSetIS(), TSRHSSplitSetRHSFunction()
463e49d4f37SHong Zhang 
464e49d4f37SHong Zhang M*/
465e49d4f37SHong Zhang PETSC_EXTERN PetscErrorCode TSCreate_BasicSymplectic(TS ts)
466e49d4f37SHong Zhang {
467e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp;
468e49d4f37SHong Zhang 
469e49d4f37SHong Zhang   PetscFunctionBegin;
4709566063dSJacob Faibussowitsch   PetscCall(TSBasicSymplecticInitializePackage());
4719566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(ts,&bsymp));
472e49d4f37SHong Zhang   ts->data = (void*)bsymp;
473e49d4f37SHong Zhang 
474e49d4f37SHong Zhang   ts->ops->setup           = TSSetUp_BasicSymplectic;
475e49d4f37SHong Zhang   ts->ops->step            = TSStep_BasicSymplectic;
476e49d4f37SHong Zhang   ts->ops->reset           = TSReset_BasicSymplectic;
477e49d4f37SHong Zhang   ts->ops->destroy         = TSDestroy_BasicSymplectic;
478e49d4f37SHong Zhang   ts->ops->setfromoptions  = TSSetFromOptions_BasicSymplectic;
479e49d4f37SHong Zhang   ts->ops->view            = TSView_BasicSymplectic;
480e49d4f37SHong Zhang   ts->ops->interpolate     = TSInterpolate_BasicSymplectic;
481e49d4f37SHong Zhang   ts->ops->linearstability = TSComputeLinearStability_BasicSymplectic;
482e49d4f37SHong Zhang 
4839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts,"TSBasicSymplecticSetType_C",TSBasicSymplecticSetType_BasicSymplectic));
4849566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts,"TSBasicSymplecticGetType_C",TSBasicSymplecticGetType_BasicSymplectic));
485e49d4f37SHong Zhang 
4869566063dSJacob Faibussowitsch   PetscCall(TSBasicSymplecticSetType(ts,TSBasicSymplecticDefault));
487e49d4f37SHong Zhang   PetscFunctionReturn(0);
488e49d4f37SHong Zhang }
489