Swarm-NG  1.1
verlet.hpp
Go to the documentation of this file.
1 /*************************************************************************
2  * Copyright (C) 2011 by Saleh Dindar and 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 #include "swarm/swarmplugin.h"
26 
27 namespace swarm { namespace gpu { namespace bppt {
28 
34  double max_timestep, max_timestep_global, timestep_scale;
37  max_timestep_global = cfg.require("max_timestep", 0.0);
38  timestep_scale = cfg.require("timestep_scale", 0.0);
39  }
40 };
41 
50 template<class T,class Gravitation>
53  const static int nbod = T::n;
54 
55  params _params;
56 
57  ensemble::SystemRef& sys;
58  Gravitation& calcForces;
59  int b;
60  int c;
61  int ij;
62  bool body_component_grid;
63  bool first_thread_in_system;
64  double max_timestep, timestep;
65 
67  GPUAPI VerletPropagator(const params& p,ensemble::SystemRef& s,
68  Gravitation& calc)
69  :_params(p),sys(s),calcForces(calc){}
70 
71  static GENERIC int thread_per_system(){
72  return nbod * 3;
73  }
74 
75  static GENERIC int shmem_per_system() {
76  return 0;
77  }
78 
80  GPUAPI void init()
81  {
82  // First half step uses timestep factor from previous itteration,
83  // so need to calculate timestep factor before first call to advance
84  if( is_in_body_component_grid() )
85  {
86  double pos = sys[b][c].pos() , vel = sys[b][c].vel();
87  double acc = calcForces.acc(ij,b,c,pos,vel);
88  timestep = calc_timestep();
89  }
90  max_timestep = _params.max_timestep_global;
91  }
92 
93  GPUAPI void shutdown() { }
94 
95  GPUAPI void convert_internal_to_std_coord() {}
96  GPUAPI void convert_std_to_internal_coord() {}
97 
98  __device__ bool is_in_body_component_grid()
99 // { return body_component_grid; }
100  { return ((b < T::n) && (c < 3)); }
101 
102  __device__ bool is_in_body_component_grid_no_star()
103 // { return ( body_component_grid && (b!=0) ); }
104  { return ( (b!=0) && (b < T::n) && (c < 3) ); }
105 
106  __device__ bool is_first_thread_in_system()
107 // { return first_thread_in_system; }
108  { return (thread_in_system()==0); }
109 
110 
112  GPUAPI double calc_timestep() const
113  {
114  // assumes that calcForces has already been called to fill shared memory
115  // if timestep depended on velocities, then would need to update velocities and syncthreads
116 
117  double factor = 0.;
118  for(int i=0;i<nbod;++i)
119  {
120  double mi = sys[i].mass();
121 
122  for(int j=1;j<nbod;++j)
123  {
124  if(i==j) { continue; }
125  double mj = sys[j].mass();
126  double oor = calcForces.one_over_r(i,j);
127  factor += (mi+mj)*oor*oor*oor;
128  }
129  }
130  factor *= _params.timestep_scale*_params.timestep_scale;
131  factor += 1.;
132  factor = rsqrt(factor);
133  factor *= _params.max_timestep_global;
134  return factor;
135  }
136 
138  GPUAPI void advance(){
139  double h = timestep;
140  double pos = 0.0, vel = 0.0;
141 
142  if( is_in_body_component_grid() )
143  pos = sys[b][c].pos() , vel = sys[b][c].vel();
144 
146 
147  double h_first_half = 0.5 * h;
148 
149  // First half step for positions
150  pos = pos + h_first_half * vel;
151 
152  // Calculate acceleration in the middle
153  double acc = calcForces.acc(ij,b,c,pos,vel);
154 
155  // First half step for velocities
156  vel = vel + h_first_half * acc;
157 
158  // Update timestep with positions (and velocities) at end of half-step
159  timestep = calc_timestep();
160 
161  // Second half step for velocities
162  double h_second_half = 0.5*timestep;
163 
164  // Second half step for positions and velocities
165  vel = vel + h_second_half * acc;
166  pos = pos + h_second_half * vel;
167 
169 
170  // Finalize the step
171  if( is_in_body_component_grid() )
172  sys[b][c].pos() = pos , sys[b][c].vel() = vel;
173  if( is_first_thread_in_system() )
174  sys.time() += h_first_half + h_second_half;
175  }
176 };
177 
178 
179 } } } // End namespace bppt :: gpu :: swarm