xref: /petsc/src/ts/impls/symplectic/basicsymplectic/basicsymplectic.c (revision 8a690491e6c6c591ad1bff5657f43271c38b9863)
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 .keywords: TS, TSBASICSYMPLECTIC, register, all
52e49d4f37SHong Zhang 
53e49d4f37SHong Zhang .seealso:  TSBasicSymplecticRegisterDestroy()
54e49d4f37SHong Zhang @*/
55e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticRegisterAll(void)
56e49d4f37SHong Zhang {
57e49d4f37SHong Zhang   PetscErrorCode ierr;
58e49d4f37SHong Zhang 
59e49d4f37SHong Zhang   PetscFunctionBegin;
60e49d4f37SHong Zhang   if (TSBasicSymplecticRegisterAllCalled) PetscFunctionReturn(0);
61e49d4f37SHong Zhang   TSBasicSymplecticRegisterAllCalled = PETSC_TRUE;
62e49d4f37SHong Zhang   {
63e49d4f37SHong Zhang     PetscReal c[1] = {1.0},d[1] = {1.0};
64e49d4f37SHong Zhang     ierr = TSBasicSymplecticRegister(TSBASICSYMPLECTICSIEULER,1,1,c,d);CHKERRQ(ierr);
65e49d4f37SHong Zhang   }
66e49d4f37SHong Zhang   {
67e49d4f37SHong Zhang     PetscReal c[2] = {0,1.0},d[2] = {0.5,0.5};
68e49d4f37SHong Zhang     ierr = TSBasicSymplecticRegister(TSBASICSYMPLECTICVELVERLET,2,2,c,d);CHKERRQ(ierr);
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};
72e49d4f37SHong Zhang     ierr = TSBasicSymplecticRegister(TSBASICSYMPLECTIC3,3,3,c,d);CHKERRQ(ierr);
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};
77e49d4f37SHong Zhang     ierr = TSBasicSymplecticRegister(TSBASICSYMPLECTIC4,4,4,c,d);CHKERRQ(ierr);
78e49d4f37SHong Zhang   }
79e49d4f37SHong Zhang   PetscFunctionReturn(0);
80e49d4f37SHong Zhang }
81e49d4f37SHong Zhang 
82e49d4f37SHong Zhang /*@C
83e49d4f37SHong Zhang    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 
89e49d4f37SHong Zhang .keywords: TSBasicSymplectic, register, destroy
90e49d4f37SHong Zhang .seealso: TSBasicSymplecticRegister(), TSBasicSymplecticRegisterAll()
91e49d4f37SHong Zhang @*/
92e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticRegisterDestroy(void)
93e49d4f37SHong Zhang {
94e49d4f37SHong Zhang   PetscErrorCode            ierr;
95e49d4f37SHong Zhang   BasicSymplecticSchemeLink link;
96e49d4f37SHong Zhang 
97e49d4f37SHong Zhang   PetscFunctionBegin;
98e49d4f37SHong Zhang   while ((link = BasicSymplecticSchemeList)) {
99e49d4f37SHong Zhang     BasicSymplecticScheme scheme = &link->sch;
100e49d4f37SHong Zhang     BasicSymplecticSchemeList = link->next;
101e49d4f37SHong Zhang     ierr = PetscFree2(scheme->c,scheme->d);CHKERRQ(ierr);
102e49d4f37SHong Zhang     ierr = PetscFree(scheme->name);CHKERRQ(ierr);
103e49d4f37SHong Zhang     ierr = PetscFree(link);CHKERRQ(ierr);
104e49d4f37SHong Zhang   }
105e49d4f37SHong Zhang   TSBasicSymplecticRegisterAllCalled = PETSC_FALSE;
106e49d4f37SHong Zhang   PetscFunctionReturn(0);
107e49d4f37SHong Zhang }
108e49d4f37SHong Zhang 
109e49d4f37SHong Zhang /*@C
110e49d4f37SHong Zhang   TSBasicSymplecticInitializePackage - This function initializes everything in the TSBasicSymplectic package. It is called
111*8a690491SBarry Smith   from TSInitializePackage().
112e49d4f37SHong Zhang 
113e49d4f37SHong Zhang   Level: developer
114e49d4f37SHong Zhang 
115e49d4f37SHong Zhang .keywords: TS, TSBasicSymplectic, initialize, package
116e49d4f37SHong Zhang .seealso: PetscInitialize()
117e49d4f37SHong Zhang @*/
118e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticInitializePackage(void)
119e49d4f37SHong Zhang {
120e49d4f37SHong Zhang   PetscErrorCode ierr;
121e49d4f37SHong Zhang 
122e49d4f37SHong Zhang   PetscFunctionBegin;
123e49d4f37SHong Zhang   if (TSBasicSymplecticPackageInitialized) PetscFunctionReturn(0);
124e49d4f37SHong Zhang   TSBasicSymplecticPackageInitialized = PETSC_TRUE;
125e49d4f37SHong Zhang   ierr = TSBasicSymplecticRegisterAll();CHKERRQ(ierr);
126e49d4f37SHong Zhang   ierr = PetscRegisterFinalize(TSBasicSymplecticFinalizePackage);CHKERRQ(ierr);
127e49d4f37SHong Zhang   PetscFunctionReturn(0);
128e49d4f37SHong Zhang }
129e49d4f37SHong Zhang 
130e49d4f37SHong Zhang /*@C
131e49d4f37SHong Zhang   TSBasicSymplecticFinalizePackage - This function destroys everything in the TSBasicSymplectic package. It is
132e49d4f37SHong Zhang   called from PetscFinalize().
133e49d4f37SHong Zhang 
134e49d4f37SHong Zhang   Level: developer
135e49d4f37SHong Zhang 
136e49d4f37SHong Zhang .keywords: Petsc, destroy, package
137e49d4f37SHong Zhang .seealso: PetscFinalize()
138e49d4f37SHong Zhang @*/
139e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticFinalizePackage(void)
140e49d4f37SHong Zhang {
141e49d4f37SHong Zhang   PetscErrorCode ierr;
142e49d4f37SHong Zhang 
143e49d4f37SHong Zhang   PetscFunctionBegin;
144e49d4f37SHong Zhang   TSBasicSymplecticPackageInitialized = PETSC_FALSE;
145e49d4f37SHong Zhang   ierr = TSBasicSymplecticRegisterDestroy();CHKERRQ(ierr);
146e49d4f37SHong Zhang   PetscFunctionReturn(0);
147e49d4f37SHong Zhang }
148e49d4f37SHong Zhang 
149e49d4f37SHong Zhang /*@C
150e49d4f37SHong Zhang    TSBasicSymplecticRegister - register a basic symplectic integration scheme by providing the coefficients.
151e49d4f37SHong Zhang 
152e49d4f37SHong Zhang    Not Collective, but the same schemes should be registered on all processes on which they will be used
153e49d4f37SHong Zhang 
154e49d4f37SHong Zhang    Input Parameters:
155e49d4f37SHong Zhang +  name - identifier for method
156e49d4f37SHong Zhang .  order - approximation order of method
157e49d4f37SHong Zhang .  s - number of stages, this is the dimension of the matrices below
158e49d4f37SHong Zhang .  c - coefficients for updating generalized position (dimension s)
159e49d4f37SHong Zhang -  d - coefficients for updating generalized momentum (dimension s)
160e49d4f37SHong Zhang 
161e49d4f37SHong Zhang    Notes:
162e49d4f37SHong Zhang    Several symplectic methods are provided, this function is only needed to create new methods.
163e49d4f37SHong Zhang 
164e49d4f37SHong Zhang    Level: advanced
165e49d4f37SHong Zhang 
166e49d4f37SHong Zhang .keywords: TS, register
167e49d4f37SHong Zhang 
168e49d4f37SHong Zhang .seealso: TSBasicSymplectic
169e49d4f37SHong Zhang @*/
170e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticRegister(TSRosWType name,PetscInt order,PetscInt s,PetscReal c[],PetscReal d[])
171e49d4f37SHong Zhang {
172e49d4f37SHong Zhang   BasicSymplecticSchemeLink link;
173e49d4f37SHong Zhang   BasicSymplecticScheme     scheme;
174e49d4f37SHong Zhang   PetscErrorCode  ierr;
175e49d4f37SHong Zhang 
176e49d4f37SHong Zhang   PetscFunctionBegin;
177e49d4f37SHong Zhang   PetscValidCharPointer(name,1);
178e49d4f37SHong Zhang   PetscValidPointer(c,4);
179e49d4f37SHong Zhang   PetscValidPointer(d,4);
180e49d4f37SHong Zhang 
1811d36bdfdSBarry Smith   ierr = TSBasicSymplecticInitializePackage();CHKERRQ(ierr);
182e49d4f37SHong Zhang   ierr = PetscCalloc1(1,&link);CHKERRQ(ierr);
183e49d4f37SHong Zhang   scheme = &link->sch;
184e49d4f37SHong Zhang   ierr = PetscStrallocpy(name,&scheme->name);CHKERRQ(ierr);
185e49d4f37SHong Zhang   scheme->order = order;
186e49d4f37SHong Zhang   scheme->s = s;
187e49d4f37SHong Zhang   ierr = PetscMalloc2(s,&scheme->c,s,&scheme->d);CHKERRQ(ierr);
188e49d4f37SHong Zhang   ierr = PetscMemcpy(scheme->c,c,s*sizeof(c[0]));CHKERRQ(ierr);
189e49d4f37SHong Zhang   ierr = PetscMemcpy(scheme->d,d,s*sizeof(d[0]));CHKERRQ(ierr);
190e49d4f37SHong Zhang   link->next = BasicSymplecticSchemeList;
191e49d4f37SHong Zhang   BasicSymplecticSchemeList = link;
192e49d4f37SHong Zhang   PetscFunctionReturn(0);
193e49d4f37SHong Zhang }
194e49d4f37SHong Zhang 
195e49d4f37SHong Zhang /*
196e49d4f37SHong Zhang The simplified form of the equations are:
197e49d4f37SHong Zhang 
198e49d4f37SHong Zhang $ p_{i+1} = p_i + c_i*g(q_i)*h
199e49d4f37SHong Zhang $ q_{i+1} = q_i + d_i*f(p_{i+1},t_{i+1})*h
200e49d4f37SHong Zhang 
201e49d4f37SHong Zhang Several symplectic integrators are given below. An illustrative way to use them is to consider a particle with position q and velocity p.
202e49d4f37SHong Zhang 
203e49d4f37SHong Zhang To apply a timestep with values c_{1,2},d_{1,2} to the particle, carry out the following steps:
204e49d4f37SHong Zhang 
205e49d4f37SHong Zhang - Update the velocity of the particle by adding to it its acceleration multiplied by c_1
206e49d4f37SHong Zhang - Update the position of the particle by adding to it its (updated) velocity multiplied by d_1
207e49d4f37SHong Zhang - Update the velocity of the particle by adding to it its acceleration (at the updated position) multiplied by c_2
208e49d4f37SHong Zhang - Update the position of the particle by adding to it its (double-updated) velocity multiplied by d_2
209e49d4f37SHong Zhang 
210e49d4f37SHong Zhang */
211e49d4f37SHong Zhang static PetscErrorCode TSStep_BasicSymplectic(TS ts)
212e49d4f37SHong Zhang {
213e49d4f37SHong Zhang   TS_BasicSymplectic    *bsymp = (TS_BasicSymplectic*)ts->data;
214e49d4f37SHong Zhang   BasicSymplecticScheme scheme = bsymp->scheme;
215e49d4f37SHong Zhang   Vec                   solution = ts->vec_sol,update = bsymp->update,q,p,q_update,p_update;
216e49d4f37SHong Zhang   IS                    is_q = bsymp->is_q,is_p = bsymp->is_p;
217e49d4f37SHong Zhang   TS                    subts_q = bsymp->subts_q,subts_p = bsymp->subts_p;
218e49d4f37SHong Zhang   PetscBool             stageok;
219e49d4f37SHong Zhang   PetscReal             next_time_step = ts->time_step;
220e49d4f37SHong Zhang   PetscInt              iter;
221e49d4f37SHong Zhang   PetscErrorCode        ierr;
222e49d4f37SHong Zhang 
223e49d4f37SHong Zhang   PetscFunctionBegin;
224e49d4f37SHong Zhang   ierr = VecGetSubVector(solution,is_q,&q);CHKERRQ(ierr);
225e49d4f37SHong Zhang   ierr = VecGetSubVector(solution,is_p,&p);CHKERRQ(ierr);
226e49d4f37SHong Zhang   ierr = VecGetSubVector(update,is_q,&q_update);CHKERRQ(ierr);
227e49d4f37SHong Zhang   ierr = VecGetSubVector(update,is_p,&p_update);CHKERRQ(ierr);
228e49d4f37SHong Zhang 
229e49d4f37SHong Zhang   for (iter = 0;iter<scheme->s;iter++) {
230e49d4f37SHong Zhang     ierr = TSPreStage(ts,ts->ptime);CHKERRQ(ierr);
231e49d4f37SHong Zhang     /* update velocity p */
232e49d4f37SHong Zhang     if (scheme->c[iter]) {
233e49d4f37SHong Zhang       ierr = TSComputeRHSFunction(subts_p,ts->ptime,q,p_update);CHKERRQ(ierr);
234e49d4f37SHong Zhang       ierr = VecAXPY(p,scheme->c[iter]*ts->time_step,p_update);CHKERRQ(ierr);
235e49d4f37SHong Zhang     }
236e49d4f37SHong Zhang     /* update position q */
237e49d4f37SHong Zhang     if (scheme->d[iter]) {
238e49d4f37SHong Zhang       ierr = TSComputeRHSFunction(subts_q,ts->ptime,p,q_update);CHKERRQ(ierr);
239e49d4f37SHong Zhang       ierr = VecAXPY(q,scheme->d[iter]*ts->time_step,q_update);CHKERRQ(ierr);
240e49d4f37SHong Zhang       ts->ptime = ts->ptime+scheme->d[iter]*ts->time_step;
241e49d4f37SHong Zhang     }
242e49d4f37SHong Zhang     ierr = TSPostStage(ts,ts->ptime,0,&solution);CHKERRQ(ierr);
243e49d4f37SHong Zhang     ierr = TSAdaptCheckStage(ts->adapt,ts,ts->ptime,solution,&stageok);CHKERRQ(ierr);
244e49d4f37SHong Zhang     if(!stageok) {ts->reason = TS_DIVERGED_STEP_REJECTED; PetscFunctionReturn(0);}
245e49d4f37SHong Zhang     ierr = TSFunctionDomainError(ts,ts->ptime+ts->time_step,update,&stageok);CHKERRQ(ierr);
246e49d4f37SHong Zhang     if(!stageok) {ts->reason = TS_DIVERGED_STEP_REJECTED; PetscFunctionReturn(0);}
247e49d4f37SHong Zhang   }
248e49d4f37SHong Zhang 
249e49d4f37SHong Zhang   ts->time_step = next_time_step;
250e49d4f37SHong Zhang   ierr = VecRestoreSubVector(solution,is_q,&q);CHKERRQ(ierr);
251e49d4f37SHong Zhang   ierr = VecRestoreSubVector(solution,is_p,&p);CHKERRQ(ierr);
252e49d4f37SHong Zhang   ierr = VecRestoreSubVector(update,is_q,&q_update);CHKERRQ(ierr);
253e49d4f37SHong Zhang   ierr = VecRestoreSubVector(update,is_p,&p_update);CHKERRQ(ierr);
254e49d4f37SHong Zhang   PetscFunctionReturn(0);
255e49d4f37SHong Zhang }
256e49d4f37SHong Zhang 
257e49d4f37SHong Zhang static PetscErrorCode DMCoarsenHook_BasicSymplectic(DM fine,DM coarse,void *ctx)
258e49d4f37SHong Zhang {
259e49d4f37SHong Zhang   PetscFunctionBegin;
260e49d4f37SHong Zhang   PetscFunctionReturn(0);
261e49d4f37SHong Zhang }
262e49d4f37SHong Zhang 
263e49d4f37SHong Zhang static PetscErrorCode DMRestrictHook_BasicSymplectic(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse,void *ctx)
264e49d4f37SHong Zhang {
265e49d4f37SHong Zhang   PetscFunctionBegin;
266e49d4f37SHong Zhang   PetscFunctionReturn(0);
267e49d4f37SHong Zhang }
268e49d4f37SHong Zhang 
269e49d4f37SHong Zhang static PetscErrorCode DMSubDomainHook_BasicSymplectic(DM dm,DM subdm,void *ctx)
270e49d4f37SHong Zhang {
271e49d4f37SHong Zhang   PetscFunctionBegin;
272e49d4f37SHong Zhang   PetscFunctionReturn(0);
273e49d4f37SHong Zhang }
274e49d4f37SHong Zhang 
275e49d4f37SHong Zhang static PetscErrorCode DMSubDomainRestrictHook_BasicSymplectic(DM dm,VecScatter gscat,VecScatter lscat,DM subdm,void *ctx)
276e49d4f37SHong Zhang {
277e49d4f37SHong Zhang 
278e49d4f37SHong Zhang   PetscFunctionBegin;
279e49d4f37SHong Zhang   PetscFunctionReturn(0);
280e49d4f37SHong Zhang }
281e49d4f37SHong Zhang 
282e49d4f37SHong Zhang static PetscErrorCode TSSetUp_BasicSymplectic(TS ts)
283e49d4f37SHong Zhang {
284e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic*)ts->data;
285e49d4f37SHong Zhang   DM                 dm;
286e49d4f37SHong Zhang   PetscErrorCode     ierr;
287e49d4f37SHong Zhang 
288e49d4f37SHong Zhang   PetscFunctionBegin;
289e49d4f37SHong Zhang   ierr = TSRHSSplitGetIS(ts,"position",&bsymp->is_q);CHKERRQ(ierr);
290e49d4f37SHong Zhang   ierr = TSRHSSplitGetIS(ts,"momentum",&bsymp->is_p);CHKERRQ(ierr);
291e49d4f37SHong Zhang   if (!bsymp->is_q || !bsymp->is_p) SETERRQ(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");
292e49d4f37SHong Zhang   ierr = TSRHSSplitGetSubTS(ts,"position",&bsymp->subts_q);CHKERRQ(ierr);
293e49d4f37SHong Zhang   ierr = TSRHSSplitGetSubTS(ts,"momentum",&bsymp->subts_p);CHKERRQ(ierr);
294e49d4f37SHong Zhang   if (!bsymp->subts_q || !bsymp->subts_p) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"Must set up the RHSFunctions for position and momentum using TSRHSSplitSetRHSFunction() or calling TSSetRHSFunction() for each sub-TS");
295e49d4f37SHong Zhang 
296e49d4f37SHong Zhang   ierr = VecDuplicate(ts->vec_sol,&bsymp->update);CHKERRQ(ierr);
297e49d4f37SHong Zhang 
298e49d4f37SHong Zhang   ierr = TSGetAdapt(ts,&ts->adapt);CHKERRQ(ierr);
299e49d4f37SHong Zhang   ierr = TSAdaptCandidatesClear(ts->adapt);CHKERRQ(ierr); /* make sure to use fixed time stepping */
300e49d4f37SHong Zhang   ierr = TSGetDM(ts,&dm);CHKERRQ(ierr);
301e49d4f37SHong Zhang   if (dm) {
302e49d4f37SHong Zhang     ierr = DMCoarsenHookAdd(dm,DMCoarsenHook_BasicSymplectic,DMRestrictHook_BasicSymplectic,ts);CHKERRQ(ierr);
303e49d4f37SHong Zhang     ierr = DMSubDomainHookAdd(dm,DMSubDomainHook_BasicSymplectic,DMSubDomainRestrictHook_BasicSymplectic,ts);CHKERRQ(ierr);
304e49d4f37SHong Zhang   }
305e49d4f37SHong Zhang   PetscFunctionReturn(0);
306e49d4f37SHong Zhang }
307e49d4f37SHong Zhang 
308e49d4f37SHong Zhang static PetscErrorCode TSReset_BasicSymplectic(TS ts)
309e49d4f37SHong Zhang {
310e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic*)ts->data;
311e49d4f37SHong Zhang   PetscErrorCode     ierr;
312e49d4f37SHong Zhang 
313e49d4f37SHong Zhang   PetscFunctionBegin;
314e49d4f37SHong Zhang   ierr = VecDestroy(&bsymp->update);CHKERRQ(ierr);
315e49d4f37SHong Zhang   PetscFunctionReturn(0);
316e49d4f37SHong Zhang }
317e49d4f37SHong Zhang 
318e49d4f37SHong Zhang static PetscErrorCode TSDestroy_BasicSymplectic(TS ts)
319e49d4f37SHong Zhang {
320e49d4f37SHong Zhang   PetscErrorCode ierr;
321e49d4f37SHong Zhang 
322e49d4f37SHong Zhang   PetscFunctionBegin;
323e49d4f37SHong Zhang   ierr = TSReset_BasicSymplectic(ts);CHKERRQ(ierr);
324e49d4f37SHong Zhang   ierr = PetscFree(ts->data);CHKERRQ(ierr);
325e49d4f37SHong Zhang   PetscFunctionReturn(0);
326e49d4f37SHong Zhang }
327e49d4f37SHong Zhang 
328e49d4f37SHong Zhang static PetscErrorCode TSSetFromOptions_BasicSymplectic(PetscOptionItems *PetscOptionsObject,TS ts)
329e49d4f37SHong Zhang {
330e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic*)ts->data;
331e49d4f37SHong Zhang   PetscErrorCode     ierr;
332e49d4f37SHong Zhang 
333e49d4f37SHong Zhang   PetscFunctionBegin;
334e49d4f37SHong Zhang   ierr = PetscOptionsHead(PetscOptionsObject,"Basic symplectic integrator options");CHKERRQ(ierr);
335e49d4f37SHong Zhang   {
336e49d4f37SHong Zhang     BasicSymplecticSchemeLink link;
337e49d4f37SHong Zhang     PetscInt                  count,choice;
338e49d4f37SHong Zhang     PetscBool                 flg;
339e49d4f37SHong Zhang     const char                **namelist;
340e49d4f37SHong Zhang 
341e49d4f37SHong Zhang     for (link=BasicSymplecticSchemeList,count=0; link; link=link->next,count++) ;
342e49d4f37SHong Zhang     ierr = PetscMalloc1(count,(char***)&namelist);CHKERRQ(ierr);
343e49d4f37SHong Zhang     for (link=BasicSymplecticSchemeList,count=0; link; link=link->next,count++) namelist[count] = link->sch.name;
344e49d4f37SHong Zhang     ierr = PetscOptionsEList("-ts_basicsymplectic_type","Family of basic symplectic integration method","TSBasicSymplecticSetType",(const char*const*)namelist,count,bsymp->scheme->name,&choice,&flg);CHKERRQ(ierr);
345e49d4f37SHong Zhang     if (flg) {ierr = TSBasicSymplecticSetType(ts,namelist[choice]);CHKERRQ(ierr);}
346e49d4f37SHong Zhang     ierr = PetscFree(namelist);CHKERRQ(ierr);
347e49d4f37SHong Zhang   }
348e49d4f37SHong Zhang   ierr = PetscOptionsTail();CHKERRQ(ierr);
349e49d4f37SHong Zhang   PetscFunctionReturn(0);
350e49d4f37SHong Zhang }
351e49d4f37SHong Zhang 
352e49d4f37SHong Zhang static PetscErrorCode TSView_BasicSymplectic(TS ts,PetscViewer viewer)
353e49d4f37SHong Zhang {
354e49d4f37SHong Zhang   PetscFunctionBegin;
355e49d4f37SHong Zhang   PetscFunctionReturn(0);
356e49d4f37SHong Zhang }
357e49d4f37SHong Zhang 
358e49d4f37SHong Zhang static PetscErrorCode TSInterpolate_BasicSymplectic(TS ts,PetscReal t,Vec X)
359e49d4f37SHong Zhang {
360e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic*)ts->data;
361e49d4f37SHong Zhang   Vec                update = bsymp->update;
362e49d4f37SHong Zhang   PetscReal          alpha = (ts->ptime - t)/ts->time_step;
363e49d4f37SHong Zhang   PetscErrorCode     ierr;
364e49d4f37SHong Zhang 
365e49d4f37SHong Zhang   PetscFunctionBegin;
366e49d4f37SHong Zhang   ierr = VecWAXPY(X,-ts->time_step,update,ts->vec_sol);CHKERRQ(ierr);
367e49d4f37SHong Zhang   ierr = VecAXPBY(X,1.0-alpha,alpha,ts->vec_sol);CHKERRQ(ierr);
368e49d4f37SHong Zhang   PetscFunctionReturn(0);
369e49d4f37SHong Zhang }
370e49d4f37SHong Zhang 
371e49d4f37SHong Zhang static PetscErrorCode TSComputeLinearStability_BasicSymplectic(TS ts,PetscReal xr,PetscReal xi,PetscReal *yr,PetscReal *yi)
372e49d4f37SHong Zhang {
373e49d4f37SHong Zhang   PetscFunctionBegin;
374e49d4f37SHong Zhang   *yr = 1.0 + xr;
375e49d4f37SHong Zhang   *yi = xi;
376e49d4f37SHong Zhang   PetscFunctionReturn(0);
377e49d4f37SHong Zhang }
378e49d4f37SHong Zhang 
379e49d4f37SHong Zhang /*@C
380e49d4f37SHong Zhang   TSBasicSymplecticSetType - Set the type of the basic symplectic method
381e49d4f37SHong Zhang 
382e49d4f37SHong Zhang   Logically Collective on TS
383e49d4f37SHong Zhang 
384e49d4f37SHong Zhang   Input Parameter:
385e49d4f37SHong Zhang +  ts - timestepping context
386e49d4f37SHong Zhang -  bsymptype - type of the symplectic scheme
387e49d4f37SHong Zhang 
388e49d4f37SHong Zhang   Options Database:
389e49d4f37SHong Zhang .  -ts_basicsymplectic_type <scheme>
390e49d4f37SHong Zhang 
391e49d4f37SHong Zhang   Notes:
392e49d4f37SHong 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.
393e49d4f37SHong Zhang 
394e49d4f37SHong Zhang   Level: intermediate
395e49d4f37SHong Zhang @*/
396e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticSetType(TS ts,TSBasicSymplecticType bsymptype)
397e49d4f37SHong Zhang {
398e49d4f37SHong Zhang   PetscErrorCode ierr;
399e49d4f37SHong Zhang 
400e49d4f37SHong Zhang   PetscFunctionBegin;
401e49d4f37SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
402e49d4f37SHong Zhang   ierr = PetscTryMethod(ts,"TSBasicSymplecticSetType_C",(TS,TSBasicSymplecticType),(ts,bsymptype));CHKERRQ(ierr);
403e49d4f37SHong Zhang   PetscFunctionReturn(0);
404e49d4f37SHong Zhang }
405e49d4f37SHong Zhang 
406e49d4f37SHong Zhang /*@C
407e49d4f37SHong Zhang   TSBasicSymplecticGetType - Get the type of the basic symplectic method
408e49d4f37SHong Zhang 
409e49d4f37SHong Zhang   Logically Collective on TS
410e49d4f37SHong Zhang 
411e49d4f37SHong Zhang   Input Parameter:
412e49d4f37SHong Zhang +  ts - timestepping context
413e49d4f37SHong Zhang -  bsymptype - type of the basic symplectic scheme
414e49d4f37SHong Zhang 
415e49d4f37SHong Zhang   Level: intermediate
416e49d4f37SHong Zhang @*/
417e49d4f37SHong Zhang PetscErrorCode TSBasicSymplecticGetType(TS ts,TSBasicSymplecticType *bsymptype)
418e49d4f37SHong Zhang {
419e49d4f37SHong Zhang   PetscErrorCode ierr;
420e49d4f37SHong Zhang 
421e49d4f37SHong Zhang   PetscFunctionBegin;
422e49d4f37SHong Zhang   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
423e49d4f37SHong Zhang   ierr = PetscUseMethod(ts,"TSBasicSymplecticGetType_C",(TS,TSBasicSymplecticType*),(ts,bsymptype));CHKERRQ(ierr);
424e49d4f37SHong Zhang   PetscFunctionReturn(0);
425e49d4f37SHong Zhang }
426e49d4f37SHong Zhang 
427e49d4f37SHong Zhang static PetscErrorCode TSBasicSymplecticSetType_BasicSymplectic(TS ts,TSBasicSymplecticType bsymptype)
428e49d4f37SHong Zhang {
429e49d4f37SHong Zhang   TS_BasicSymplectic        *bsymp = (TS_BasicSymplectic*)ts->data;
430e49d4f37SHong Zhang   BasicSymplecticSchemeLink link;
431e49d4f37SHong Zhang   PetscBool                 match;
432e49d4f37SHong Zhang   PetscErrorCode            ierr;
433e49d4f37SHong Zhang 
434e49d4f37SHong Zhang   PetscFunctionBegin;
435e49d4f37SHong Zhang   if (bsymp->scheme) {
436e49d4f37SHong Zhang     ierr = PetscStrcmp(bsymp->scheme->name,bsymptype,&match);CHKERRQ(ierr);
437e49d4f37SHong Zhang     if (match) PetscFunctionReturn(0);
438e49d4f37SHong Zhang   }
439e49d4f37SHong Zhang   for (link = BasicSymplecticSchemeList; link; link=link->next) {
440e49d4f37SHong Zhang     ierr = PetscStrcmp(link->sch.name,bsymptype,&match);CHKERRQ(ierr);
441e49d4f37SHong Zhang     if (match) {
442e49d4f37SHong Zhang       bsymp->scheme = &link->sch;
443e49d4f37SHong Zhang       PetscFunctionReturn(0);
444e49d4f37SHong Zhang     }
445e49d4f37SHong Zhang   }
446e49d4f37SHong Zhang   SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_UNKNOWN_TYPE,"Could not find '%s'",bsymptype);
447e49d4f37SHong Zhang   PetscFunctionReturn(0);
448e49d4f37SHong Zhang }
449e49d4f37SHong Zhang 
450e49d4f37SHong Zhang static PetscErrorCode  TSBasicSymplecticGetType_BasicSymplectic(TS ts,TSBasicSymplecticType *bsymptype)
451e49d4f37SHong Zhang {
452e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp = (TS_BasicSymplectic*)ts->data;
453e49d4f37SHong Zhang 
454e49d4f37SHong Zhang   PetscFunctionBegin;
455e49d4f37SHong Zhang   *bsymptype = bsymp->scheme->name;
456e49d4f37SHong Zhang   PetscFunctionReturn(0);
457e49d4f37SHong Zhang }
458e49d4f37SHong Zhang 
459e49d4f37SHong Zhang /*MC
460e49d4f37SHong Zhang   TSBasicSymplectic - ODE solver using basic symplectic integration schemes
461e49d4f37SHong Zhang 
462e49d4f37SHong Zhang   These methods are intened for separable Hamiltonian systems
463e49d4f37SHong Zhang 
464e49d4f37SHong Zhang $  qdot = dH(q,p,t)/dp
465e49d4f37SHong Zhang $  pdot = -dH(q,p,t)/dq
466e49d4f37SHong Zhang 
467e49d4f37SHong Zhang   where the Hamiltonian can be split into the sum of kinetic energy and potential energy
468e49d4f37SHong Zhang 
469e49d4f37SHong Zhang $  H(q,p,t) = T(p,t) + V(q,t).
470e49d4f37SHong Zhang 
471e49d4f37SHong Zhang   As a result, the system can be genearlly represented by
472e49d4f37SHong Zhang 
473e49d4f37SHong Zhang $  qdot = f(p,t) = dT(p,t)/dp
474e49d4f37SHong Zhang $  pdot = g(q,t) = -dV(q,t)/dq
475e49d4f37SHong Zhang 
476e49d4f37SHong Zhang   and solved iteratively with
477e49d4f37SHong Zhang 
478e49d4f37SHong Zhang $  q_new = q_old + d_i*h*f(p_old,t_old)
479e49d4f37SHong Zhang $  t_new = t_old + d_i*h
480e49d4f37SHong Zhang $  p_new = p_old + c_i*h*g(p_new,t_new)
481e49d4f37SHong Zhang $  i=0,1,...,n.
482e49d4f37SHong Zhang 
483e49d4f37SHong 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.
484e49d4f37SHong 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.
485e49d4f37SHong Zhang 
486e49d4f37SHong Zhang   Reference: wikipedia (https://en.wikipedia.org/wiki/Symplectic_integrator)
487e49d4f37SHong Zhang 
488e49d4f37SHong Zhang   Level: beginner
489e49d4f37SHong Zhang 
490e49d4f37SHong Zhang .seealso:  TSCreate(), TSSetType(), TSRHSSplitSetIS(), TSRHSSplitSetRHSFunction()
491e49d4f37SHong Zhang 
492e49d4f37SHong Zhang M*/
493e49d4f37SHong Zhang PETSC_EXTERN PetscErrorCode TSCreate_BasicSymplectic(TS ts)
494e49d4f37SHong Zhang {
495e49d4f37SHong Zhang   TS_BasicSymplectic *bsymp;
496e49d4f37SHong Zhang   PetscErrorCode     ierr;
497e49d4f37SHong Zhang 
498e49d4f37SHong Zhang   PetscFunctionBegin;
499e49d4f37SHong Zhang   ierr = TSBasicSymplecticInitializePackage();CHKERRQ(ierr);
500e49d4f37SHong Zhang   ierr = PetscNewLog(ts,&bsymp);CHKERRQ(ierr);
501e49d4f37SHong Zhang   ts->data = (void*)bsymp;
502e49d4f37SHong Zhang 
503e49d4f37SHong Zhang   ts->ops->setup           = TSSetUp_BasicSymplectic;
504e49d4f37SHong Zhang   ts->ops->step            = TSStep_BasicSymplectic;
505e49d4f37SHong Zhang   ts->ops->reset           = TSReset_BasicSymplectic;
506e49d4f37SHong Zhang   ts->ops->destroy         = TSDestroy_BasicSymplectic;
507e49d4f37SHong Zhang   ts->ops->setfromoptions  = TSSetFromOptions_BasicSymplectic;
508e49d4f37SHong Zhang   ts->ops->view            = TSView_BasicSymplectic;
509e49d4f37SHong Zhang   ts->ops->interpolate     = TSInterpolate_BasicSymplectic;
510e49d4f37SHong Zhang   ts->ops->linearstability = TSComputeLinearStability_BasicSymplectic;
511e49d4f37SHong Zhang 
512e49d4f37SHong Zhang   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSBasicSymplecticSetType_C",TSBasicSymplecticSetType_BasicSymplectic);CHKERRQ(ierr);
513e49d4f37SHong Zhang   ierr = PetscObjectComposeFunction((PetscObject)ts,"TSBasicSymplecticGetType_C",TSBasicSymplecticGetType_BasicSymplectic);CHKERRQ(ierr);
514e49d4f37SHong Zhang 
515e49d4f37SHong Zhang   ierr = TSBasicSymplecticSetType(ts,TSBasicSymplecticDefault);CHKERRQ(ierr);
516e49d4f37SHong Zhang   PetscFunctionReturn(0);
517e49d4f37SHong Zhang }
518