PaGMO  1.1.5
Lambert.cpp
1 /*****************************************************************************
2  * Copyright (C) 2004-2015 The PaGMO development team, *
3  * Advanced Concepts Team (ACT), European Space Agency (ESA) *
4  * *
5  * https://github.com/esa/pagmo *
6  * *
7  * act@esa.int *
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  * This program is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License *
20  * along with this program; if not, write to the *
21  * Free Software Foundation, Inc., *
22  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
23  *****************************************************************************/
24 
25 /*
26  This routine implements a new algorithm that solves Lambert's problem. The
27  algorithm has two major characteristics that makes it favorable to other
28  existing ones.
29 
30  1) It describes the generic orbit solution of the boundary condition
31  problem through the variable X=log(1+cos(alpha/2)). By doing so the
32  graphs of the time of flight become defined in the entire real axis and
33  resembles a straight line. Convergence is granted within few iterations
34  for all the possible geometries (except, of course, when the transfer
35  angle is zero). When multiple revolutions are considered the variable is
36  X=tan(cos(alpha/2)*pi/2).
37 
38  2) Once the orbit has been determined in the plane, this routine
39  evaluates the velocity vectors at the two points in a way that is not
40  singular for the transfer angle approaching to pi (Lagrange coefficient
41  based methods are numerically not well suited for this purpose).
42 
43  As a result Lambert's problem is solved (with multiple revolutions
44  being accounted for) with the same computational effort for all
45  possible geometries. The case of near 180 transfers is also solved
46  efficiently.
47 
48  We note here that even when the transfer angle is exactly equal to pi
49  the algorithm does solve the problem in the plane (it finds X), but it
50  is not able to evaluate the plane in which the orbit lies. A solution
51  to this would be to provide the direction of the plane containing the
52  transfer orbit from outside. This has not been implemented in this
53  routine since such a direction would depend on which application the
54  transfer is going to be used in.
55 
56  Inputs:
57  r1=Position vector at departure (column)
58  r2=Position vector at arrival (column, same units as r1)
59  t=Transfer time (scalar)
60  mu=gravitational parameter (scalar, units have to be
61  consistent with r1,t units)
62  lw=1 if long way is chosen
63 
64 
65  Outputs:
66  v1=Velocity at departure (consistent units)
67  v2=Velocity at arrival
68  a=semi major axis of the solution
69  p=semi latus rectum of the solution
70  theta=transfer angle in rad
71  iter=number of iteration made by the newton solver (usually 6)
72 */
73 
74 #include <boost/math/special_functions/acosh.hpp>
75 #include <boost/math/special_functions/asinh.hpp>
76 #include <cmath>
77 #include <iostream>
78 
79 #include "Astro_Functions.h"
80 #include "Lambert.h"
81 #include "../exceptions.h"
82 
83 using namespace std;
84 
85 void LambertI (const double *r1_in, const double *r2_in, double t, const double &mu, //INPUT
86  const int &lw, //INPUT
87  double *v1, double *v2, double &a, double &p, double &theta, int &iter)//OUTPUT
88 {
89  double V,T,
90  r2_mod = 0.0, // R2 module
91  dot_prod = 0.0, // dot product
92  c, // non-dimensional chord
93  s, // non dimensional semi-perimeter
94  am, // minimum energy ellipse semi major axis
95  lambda, //lambda parameter defined in Battin's Book
96  x,x1,x2,y1,y2,x_new=0,y_new,err,alfa,beta,psi,eta,eta2,sigma1,vr1,vt1,vt2,vr2,R=0.0;
97  int i_count, i;
98  const double tolerance = 1e-11;
99  double r1[3], r2[3], r2_vers[3];
100  double ih_dum[3], ih[3], dum[3];
101 
102  // Increasing the tolerance does not bring any advantage as the
103  // precision is usually greater anyway (due to the rectification of the tof
104  // graph) except near particular cases such as parabolas in which cases a
105  // lower precision allow for usual convergence.
106 
107  if (t <= 0)
108  {
109  pagmo_throw(value_error,"ERROR in Lambert Solver: Negative Time in input.");
110  }
111 
112  for (i = 0; i < 3; i++)
113  {
114  r1[i] = r1_in[i];
115  r2[i] = r2_in[i];
116  R += r1[i]*r1[i];
117  }
118 
119  R = sqrt(R);
120  V = sqrt(mu/R);
121  T = R/V;
122 
123  // working with non-dimensional radii and time-of-flight
124  t /= T;
125  for (i = 0;i <3;i++) // r1 dimension is 3
126  {
127  r1[i] /= R;
128  r2[i] /= R;
129  r2_mod += r2[i]*r2[i];
130  }
131 
132  // Evaluation of the relevant geometry parameters in non dimensional units
133  r2_mod = sqrt(r2_mod);
134 
135  for (i = 0;i < 3;i++)
136  dot_prod += (r1[i] * r2[i]);
137 
138  theta = acos(dot_prod/r2_mod);
139 
140  if (lw)
141  theta=2*acos(-1.0)-theta;
142 
143  c = sqrt(1 + r2_mod*(r2_mod - 2.0 * cos(theta)));
144  s = (1 + r2_mod + c)/2.0;
145  am = s/2.0;
146  lambda = sqrt (r2_mod) * cos (theta/2.0)/s;
147 
148  // We start finding the log(x+1) value of the solution conic:
149  // NO MULTI REV --> (1 SOL)
150  // inn1=-.5233; //first guess point
151  // inn2=.5233; //second guess point
152  x1=log(0.4767);
153  x2=log(1.5233);
154  y1=log(x2tof(-.5233,s,c,lw))-log(t);
155  y2=log(x2tof(.5233,s,c,lw))-log(t);
156 
157  // Regula-falsi iterations
158  err=1;
159  i_count=0;
160  while ((err>tolerance) && (y1 != y2))
161  {
162  i_count++;
163  x_new=(x1*y2-y1*x2)/(y2-y1);
164  y_new=log(x2tof(exp(x_new)-1,s,c,lw))-log(t);
165  x1=x2;
166  y1=y2;
167  x2=x_new;
168  y2=y_new;
169  err = fabs(x1-x_new);
170  }
171  iter = i_count;
172  x = exp(x_new)-1;
173 
174  // The solution has been evaluated in terms of log(x+1) or tan(x*pi/2), we
175  // now need the conic. As for transfer angles near to pi the lagrange
176  // coefficient technique goes singular (dg approaches a zero/zero that is
177  // numerically bad) we here use a different technique for those cases. When
178  // the transfer angle is exactly equal to pi, then the ih unit vector is not
179  // determined. The remaining equations, though, are still valid.
180 
181  a = am/(1 - x*x);
182 
183  // psi evaluation
184  if (x < 1) // ellipse
185  {
186  beta = 2 * asin (sqrt( (s-c)/(2*a) ));
187  if (lw) beta = -beta;
188  alfa=2*acos(x);
189  psi=(alfa-beta)/2;
190  eta2=2*a*pow(sin(psi),2)/s;
191  eta=sqrt(eta2);
192  }
193  else // hyperbola
194  {
195  beta = 2*boost::math::asinh(sqrt((c-s)/(2*a)));
196  if (lw) beta = -beta;
197  alfa = 2*boost::math::acosh(x);
198  psi = (alfa-beta)/2;
199  eta2 = -2 * a * pow(sinh(psi),2)/s;
200  eta = sqrt(eta2);
201  }
202 
203  // parameter of the solution
204  p = ( r2_mod / (am * eta2) ) * pow (sin (theta/2),2);
205  sigma1 = (1/(eta * sqrt(am)) )* (2 * lambda * am - (lambda + x * eta));
206  vett(r1,r2,ih_dum);
207  vers(ih_dum,ih) ;
208 
209  if (lw)
210  {
211  for (i = 0; i < 3;i++)
212  ih[i]= -ih[i];
213  }
214 
215  vr1 = sigma1;
216  vt1 = sqrt(p);
217  vett(ih,r1,dum);
218 
219  for (i = 0;i < 3 ;i++)
220  v1[i] = vr1 * r1[i] + vt1 * dum[i];
221 
222  vt2 = vt1 / r2_mod;
223  vr2 = -vr1 + (vt1 - vt2)/tan(theta/2);
224  vers(r2,r2_vers);
225  vett(ih,r2_vers,dum);
226  for (i = 0;i < 3 ;i++)
227  v2[i] = vr2 * r2[i] / r2_mod + vt2 * dum[i];
228 
229  for (i = 0;i < 3;i++)
230  {
231  v1[i] *= V;
232  v2[i] *= V;
233  }
234  a *= R;
235  p *= R;
236 }
237 
238 
STL namespace.