Swarm-NG  1.1
tutorial_propagator.hpp
Go to the documentation of this file.
1 /*************************************************************************
2  * Copyright (C) 2009-2010 by Eric Ford & the Swarm-NG Development Team *
3  * *
4  * This program is free software; you can redistribute it and/or modify *
5  * it under the terms of the GNU General Public License as published by *
6  * the Free Software Foundation; either version 3 of the License. *
7  * *
8  * This program is distributed in the hope that it will be useful, *
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
11  * GNU General Public License for more details. *
12  * *
13  * You should have received a copy of the GNU General Public License *
14  * along with this program; if not, write to the *
15  * Free Software Foundation, Inc., *
16  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
17  ************************************************************************/
18 
25 /*
26  * This is a simple tutorial used in doxygen pages
27  * should go through program2doxygen before it
28  * can be used by doxygen.
29  *
30  *
31  */
32 // \page TutorialPropagator Tutorial for Making a Propagator
33 //
34 // A propagator class implements a device function that advance
35 // one system by one time step for one system (or at least attempts one
36 // timestep). These can be readily combined with the generic_integrator
37 // to quickly provide a new GPU-based integration algorithm.
38 //
39 // This is the header file where you define the new propagator
40 //
41 #include "swarm/swarmplugin.h"
42 
43 // We have to create a separate data structure that holds the parameters
44 // for the propagator. This data structure is initialized with the
45 // configuration object when the propagator plugin is loaded.
46 //
49  double time_step;
52  time_step = cfg.require("time_step", 0.0);
53  }
54 };
55 
56 // This is the actual class that represents our propagator, we cannot
57 // initialize variables in the class because this class is instantiated
58 // at the place when it needs to be used. The propagator class is
59 // parametrized by number of bodies (class T contains it) and an
60 // implementation of Gravitational force calculation algorithm.
62 template<class T,class Gravitation>
64  public:
65 
66  // This will give the Generic integrator an idea about the struct
67  // type we used for the parameters
70 
71  // We get the number of bodies at the compile-time. The propagator
72  // should use this value for number of bodies instead of getting
73  // it from the ensemble.
74  const static int nbod = T::n;
75 
76  // We define variables that we use throughout the integration
77  // _params contains all the parameters from the configuration.
78  // sys is the system that we have to operate on. and calcForces
79  // is the implementation of force calculation algorithm
80  //
81  // The constructure initializez these member variables from what
82  // is provided.
83  private:
84  params _params;
85  ensemble::SystemRef& sys;
86  Gravitation& calcForces;
88  GPUAPI TutorialPropagator(const params& p,ensemble::SystemRef& s,
89  Gravitation& calc)
90  :_params(p),sys(s),calcForces(calc){}
91 
92  // These are the variables that are generally used in the
93  // integrators, we receive these variable in this way from
94  // the integrator.
95  // b, c and ij are define our work based on the thread id. b is
96  // the number of body, c is the component number (0,1,2). and
97  // ij is the pair number that is passed to calcForces
98  public:
99  int b;
100  int c;
101  int ij;
102 
103  // body_component_grid and first_thread_in_system are useful
104  // predicates when we want to exclude some threads from updating
105  // the data structures.
106  bool body_component_grid;
107  bool first_thread_in_system;
108 
109  // max_timestep is set by the generic_integrator, this is the biggest
110  // time step that we are allowed to take. Usually it is only bound
111  // by the destination_time and the default implementation uses
112  // destination_time - sys.time().(but it can be used otherwise).
113  double max_timestep;
114 
115 
116 
117  // init function is executed before entering the integration loop
118  // a propagator can set-up data structure if needed.
119  // shutdown is executed right after the integration loop. So it
120  // do the clean-up.
121  GPUAPI void init() { }
122  GPUAPI void shutdown() { }
123 
124  // These functions are only used if the propagator uses a coordinate
125  // system other than the default.
127  GPUAPI void convert_internal_to_std_coord() {}
129  GPUAPI void convert_std_to_internal_coord() {}
130 
131  // propagator can use arbitrary number of systems and may use
132  // some shared memory, but it should be reported here so the
133  // launcher can initialize it.
134  static GENERIC int thread_per_system(){ return nbod * 3; }
135  static GENERIC int shmem_per_system() { return 0; }
136 
137 
138 
139  // The advance function is called within the integration loop
140  // The main purpose of the advance function is to integrate
141  // the system and advance the system in time.
142  //
143  // The usual implemnation consist of sampling accleration (and jerk
144  // if needed) at one or more points around the current system time
145  // and extrapolate position and velocities.
147  GPUAPI void advance(){
148  // we define the local values just for more readable code.
149  double pos = 0.0, vel = 0.0;
150  double acc = 0.0, jerk = 0.0;
151 
152  // we have to use the predicate so we do not go out of bounds
153  // of the array.
154  if( body_component_grid ) pos = sys[b][c].pos() , vel = sys[b][c].vel();
155 
156 
157  // First step of integration: calculate the accelartion
158  // (second derivative of position) and jerk (third derivative
159  // of position). The gravitation
160  // algorithm needs all the specified parameters. The acceleration and
161  // jerk are returned in the last two variables (acc,jerk).
162  calcForces(ij,b,c,pos,vel,acc,jerk);
163 
164  // For more precise integrations, we want to end exactly at
165  // the destination_time, that means that h cannot be
166  // greater than max_timestep that is allowed by the wrapper.
167  double h = min(_params.time_step, max_timestep);
168 
169  // For this simple integrator, we use explicit Euler integration
170  // equations. More complex equations can be used in practice.
171  pos = pos + h * ( vel + (h*0.5) * (acc + (h/3.0)*jerk ) );
172  vel = vel + h * ( acc + (h*0.5) * jerk );
173 
174 
175  // Finalize the step: save the position and velocities back to the ensemble
176  // data structure and advance the system time.
177  if( body_component_grid ) sys[b][c].pos() = pos , sys[b][c].vel() = vel;
178  if( first_thread_in_system ) sys.time() += h;
179  }
180 };
181