Swarm-NG  1.1
keplerian.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 
30 #pragma once
31 
32 //#define MINR 1.0e-5 // minimum radius
33 #define MINR_IN_1EM8 0 // minimum radius
34 #define MINDENOM 1e-8 // mininum denominator
35 #define SIGN(a) ((a) < 0 ? -1 : 1)
36 
38 // code adapted from Alice Quillen's Qymsym code
39 // see http://astro.pas.rochester.edu/~aquillen/qymsym/
40 
42 GPUAPI double C_prussing(double y)
43 {
44  if (fabs(y)<1e-4) return 1.0/2.0*(1.0 - y/12.0*(1.0 - y/30.0*(1.0 - y/56.0)));
45  double u = sqrt(fabs(y));
46  if (y>0.0) return (1.0- cos(u))/ y;
47  else return (cosh(u)-1.0)/-y;
48 }
49 
51 GPUAPI double S_prussing(double y)
52 {
53  if (fabs(y)<1e-4) return 1.0/6.0*(1.0 - y/20.0*(1.0 - y/42.0*(1.0 - y/72.0)));
54  double u = sqrt(fabs(y));
55  double u3 = u*u*u;
56  if (y>0.0) return (u - sin(u))/u3;
57  else return (sinh(u) - u)/u3;
58 }
59 
61 GPUAPI void SC_prussing(double y, double& S, double &C)
62 {
63  if (fabs(y)<1e-4)
64  {
65  S = (1.0/6.0)*(1.0 - y*(1.0/20.0)*(1.0 - y*(1.0/42.0)*(1.0 - y*(1.0/72.0))));
66  C = (1.0/2.0)*(1.0 - y*(1.0/12.0)*(1.0 - y*(1.0/30.0)*(1.0 - y*(1.0/56.0))));
67  }
68  else
69  {
70  float absy = y;
71  absy = fabs(y);
72  double u = sqrt(absy);
73  double u3 = u*u*u;
74  if (y>0.0)
75  {
76  sincos(u,&S,&C);
77  S = (u - S)/u3;
78  C = (1.0- C)/ y;
79  }
80  else
81  {
82  S = (sinh(u) - u)/u3;
83  C = (cosh(u)-1.0)/-y;
84  }
85  }
86  return;
87 }
88 
90 __device__ void SC_prussing_fast(double y, double& S, double &C)
91 {
92  if (y*y<1e-8)
93  {
94  S = (1.0/6.0)*(1.0 - y*(1.0/20.0)*(1.0 - y*(1.0/42.0)*(1.0 - y*(1.0/72.0))));
95  C = (1.0/2.0)*(1.0 - y*(1.0/12.0)*(1.0 - y*(1.0/30.0)*(1.0 - y*(1.0/56.0))));
96  }
97  else
98  {
99  float absy = y;
100  absy = fabs(y);
101  float u = sqrtf(absy);
102  float u3 = u*u*u;
103  if (y>0.0)
104  {
105  float Sf, Cf;
106  sincosf(u,&Sf,&Cf);
107  S = (u - Sf)/u3;
108  C = (1.0- Cf)/ y;
109  }
110  else
111  {
112  S = (sinhf(u) - u)/u3;
113  C = (coshf(u)-1.0)/-y;
114  }
115  }
116  return;
117 }
118 
119 
120 GPUAPI double solvex(double r0dotv0, double alpha,
121  double sqrtM1, double r0, double dt)
122 {
123  const double _N_LAG = 5.0;
124 // double smu = sqrt(M1);
125  double smu = sqrtM1;
126  double foo = 1.0 - r0*alpha;
127  double sig0 = r0dotv0/smu;
128  double x = sqrtM1*sqrtM1*dt*dt/r0;
129 // better initial guess depends on rperi which would have to be passed
130 
131  double u=1.0;
132  for(int i=0;(i<7)&&!((i>2)&&(x+u==x));i++){
133  // as it always converges faster than this
134  double x2,x3,alx2,Cp,Sp,F,dF,ddF,z;
135  x2 = x*x;
136  x3 = x2*x;
137  alx2 = alpha*x2;
138  // Cp = C_prussing(alx2);
139  // Sp = S_prussing(alx2);
140 #if 0
141  if(i==0)
142  SC_prussing_fast(alx2,Sp,Cp); // optimization
143  else
144 #endif
145  SC_prussing(alx2,Sp,Cp); // optimization
146  F = sig0*x2*Cp + foo*x3*Sp + r0*x - smu*dt;
147  dF = sig0*x*(1.0 - alx2*Sp) + foo*x2*Cp + r0;
148  ddF = sig0*(1.0-alx2*Cp) + foo*x*(1.0 - alx2*Sp);
149  z = fabs((_N_LAG - 1.0)*((_N_LAG - 1.0)*dF*dF - _N_LAG*F*ddF));
150  z = sqrt(z);
151  double denom = (dF + SIGN(dF)*z); // faster than copysign
152  if (denom ==0.0) denom = MINDENOM;
153  u = _N_LAG*F/denom;
154  x -= u;
155 // if( (i>=2) && (x+u==x) ) break; // optimization to allow to exit loop early
156  }
157 // if (isnan(x)) printf("solvex: is nan\n");
158  return x;
159 }
160 
161 
162 
165 // for differental kepler's equation
166 // has an error catch for r0=0 so can be run with central body
167 // Based on equations by Prussing, J. E. and Conway, B. A.
168 // Orbital Mechanics 1993, Oxford University Press, NY,NY chap 2
169 // npos,nvel are new positions and velocity
170 // pos, vel are old ones
171 // code adapted from Alice Quillen's Qymsym code
172 // see http://astro.pas.rochester.edu/~aquillen/qymsym/
174 //GPUAPI void kepstep(double4 pos, double4 vel, double4* npos, double4* nvel, double deltaTime, double GM)
175 GPUAPI void drift_kepler(double& x_old, double& y_old, double& z_old, double& vx_old, double& vy_old, double& vz_old, const double sqrtGM, const double deltaTime)
176 {
177  double x = x_old, y = y_old, z = z_old, vx = vx_old, vy = vy_old, vz = vz_old;
178 #if (MINR_IN_1EM8>0)
179  // WARNING: Using softened potential
180  double r0 = sqrt(x*x + y*y + z*z + MINR_IN_1EM8*MINR_IN_1EM8*1.e-16);
181 #else
182  double r0 = sqrt(x*x + y*y + z*z ); // current radius
183 #endif
184 // double r0 = sqrt(x*x + y*y + z*z ); // current radius
185  double v2 = (vx*vx + vy*vy + vz*vz); // current velocity
186  double r0dotv0 = (x*vx + y*vy + z*vz);
187  double GM = sqrtGM*sqrtGM;
188  double alpha = (2.0/r0 - v2/GM); // inverse of semi-major eqn 2.134 MD
189 // here alpha=1/a and can be negative
190  double x_p = solvex(r0dotv0, alpha, sqrtGM, r0, deltaTime); // solve universal kepler eqn
191 
192 // double smu = sqrt(GM); // from before we cached sqrt(GM)
193  double smu = sqrtGM;
194  double foo = 1.0 - r0*alpha;
195  double sig0 = r0dotv0/smu;
196  double x2 = x_p*x_p;
197  double x3 = x2*x_p;
198  double alx2 = alpha*x2;
199 // double Cp = C_prussing(alx2);
200 // double Sp = S_prussing(alx2);
201  double Cp, Sp;
202  SC_prussing(alx2,Sp,Cp); // optimization
203  double r = sig0*x_p*(1.0 - alx2*Sp) + foo*x2*Cp + r0; // eqn 2.42 PC
204 
205 #if (MINR_IN_1EM8>0)
206 // WARNING: Using softened potentil
207  if (r < MINR_IN_1EM8*1.e-8) r=MINR_IN_1EM8*1.e-8;
208 #else
209  if(r<0.) r = 0.;
210 #endif
211 
214  double f_p= 1.0 - (x2/r0)*Cp;
215  double g_p= deltaTime - (x3/smu)*Sp;
217  double dfdt;
218  double dgdt = 1.0 - (x2/r)*Cp;
219  if (fabs(g_p) > MINDENOM)
221  dfdt = (f_p*dgdt - 1.0)/g_p;
222  else
224  dfdt = x_p*smu/(r*r0)*(alx2*Sp - 1.0);
225 
226  x = f_p*x_old + g_p*vx_old;
227  y = f_p*y_old + g_p*vy_old;
228  z = f_p*z_old + g_p*vz_old;
229  vx = dfdt*x_old + dgdt*vx_old;
230  vy = dfdt*y_old + dgdt*vy_old;
231  vz = dfdt*z_old + dgdt*vz_old;
232 
234  x_old = x; y_old = y; z_old = z;
235  vx_old = vx; vy_old = vy; vz_old = vz;
236 }