PaGMO  1.1.5
mga_incipit.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 #include <string>
26 #include <boost/math/constants/constants.hpp>
27 #include <vector>
28 #include <numeric>
29 #include <cmath>
30 #include <keplerian_toolbox/core_functions/propagate_lagrangian.h>
31 #include <keplerian_toolbox/core_functions/fb_prop.h>
32 #include <keplerian_toolbox/core_functions/closest_distance.h>
33 #include <keplerian_toolbox/lambert_problem.h>
34 
35 #include "mga_incipit.h"
36 
37 
38 namespace pagmo { namespace problem {
39 
40 
42 
54 mga_incipit::mga_incipit(const std::vector<kep_toolbox::planet::planet_ptr> seq,
55  const kep_toolbox::epoch t0_l, const kep_toolbox::epoch t0_u,
56  const std::vector<std::vector<double> > tof
57  ):
58  base(4*seq.size()), m_tof(tof)
59 {
60  // We check that all planets have equal central body
61  std::vector<double> mus(seq.size());
62  for (std::vector<kep_toolbox::planet::planet_ptr>::size_type i = 0; i< seq.size(); ++i) {
63  mus[i] = seq[i]->get_mu_central_body();
64  }
65  if ((unsigned int)std::count(mus.begin(), mus.end(), mus[0]) != mus.size()) {
66  pagmo_throw(value_error,"The planets do not all have the same mu_central_body");
67  }
68  // We check the consistency of the time of flights
69  if (tof.size() != seq.size()) {
70  pagmo_throw(value_error,"The time-of-flight vector (tof) has the wrong length");
71  }
72  for (size_t i = 0; i < tof.size(); ++i) {
73  if (tof[i].size()!=2) pagmo_throw(value_error,"Each element of the time-of-flight vector (tof) needs to have dimension 2 (lower and upper bound)");
74  }
75 
76  // Filling in the planetary sequence data member. This requires to construct the polymorphic planets via their clone method
77  for (std::vector<kep_toolbox::planet::planet_ptr>::size_type i = 0; i < seq.size(); ++i) {
78  m_seq.push_back(seq[i]->clone());
79  }
80 
81  // Now setting the problem bounds
82  size_type dim(4*m_tof.size());
83  decision_vector lb(dim), ub(dim);
84 
85  // First leg
86  lb[0] = t0_l.mjd2000(); ub[0] = t0_u.mjd2000();
87  lb[1] = 0; lb[2] = 0; ub[1] = 1; ub[2] = 1;
88  lb[3] = m_tof[0][0]; ub[3] = m_tof[0][1];
89 
90  // Successive legs
91  for (std::vector<kep_toolbox::planet::planet_ptr>::size_type i = 1; i < m_tof.size(); ++i) {
92  lb[4*i] = - 2 * boost::math::constants::pi<double>(); ub[4*i] = 2 * boost::math::constants::pi<double>();
93  lb[4*i+1] = 1.1; ub[4*i+1] = 30;
94  lb[4*i+2] = 1e-5; ub[4*i+2] = 1-1e-5;
95  lb[4*i+3] = m_tof[i][0]; ub[4*i+3] = m_tof[i][1];
96  }
97 
98  // Adjusting the minimum and maximum allowed fly-by rp to the one defined in the kep_toolbox::planet class
99  for (std::vector<kep_toolbox::planet::planet_ptr>::size_type i = 0; i < m_tof.size()-1; ++i) {
100  lb[4*i+5] = m_seq[i]->get_safe_radius() / m_seq[i]->get_radius();
101  ub[4*i+5] = (m_seq[i]->get_radius() + 2000000) / m_seq[i]->get_radius(); //from gtoc6 problem description
102  }
103  set_bounds(lb,ub);
104 }
105 
107 mga_incipit::mga_incipit(const mga_incipit &p) : base(p.get_dimension()), m_tof(p.m_tof)
108 {
109  for (std::vector<kep_toolbox::planet::planet_ptr>::size_type i = 0; i < p.m_seq.size();++i) {
110  m_seq.push_back(p.m_seq[i]->clone());
111  }
112  set_bounds(p.get_lb(),p.get_ub());
113 }
114 
117 {
118  return base_ptr(new mga_incipit(*this));
119 }
120 
123 {
124 try {
125  double common_mu = m_seq[0]->get_mu_central_body();
126  // 1 - we 'decode' the chromosome recording the various times of flight (days) in the list T
127  std::vector<double> T(m_seq.size(),0.0);
128 
129  for (size_t i = 0; i<m_seq.size(); ++i) {
130  T[i] = x[4*i+3];
131  }
132  // 2 - We compute the epochs and ephemerides of the planetary encounters
133  std::vector<kep_toolbox::epoch> t_P(m_seq.size());
134  std::vector<kep_toolbox::array3D> r_P(m_seq.size());
135  std::vector<kep_toolbox::array3D> v_P(m_seq.size());
136  std::vector<double> DV(m_seq.size());
137  for (size_t i = 0; i<r_P.size(); ++i) {
138  t_P[i] = kep_toolbox::epoch(x[0] + std::accumulate(T.begin(),T.begin()+1+i,0.0));
139  m_seq[i]->eph(t_P[i], r_P[i], v_P[i]);
140  }
141 
142  // 3 - We start with the first leg
143  double theta = 2*boost::math::constants::pi<double>()*x[1];
144  double phi = acos(2*x[2]-1)-boost::math::constants::pi<double>() / 2;
145  double d,d2,ra,ra2;
146  kep_toolbox::array3D r = { {ASTRO_JR*1000*cos(phi)*sin(theta), ASTRO_JR*1000*cos(phi)*cos(theta), ASTRO_JR*1000*sin(phi)} };
147  kep_toolbox::array3D v;
148  kep_toolbox::lambert_problem l(r,r_P[0],T[0]*ASTRO_DAY2SEC,common_mu,false,false);
149  kep_toolbox::array3D v_beg_l = l.get_v1()[0];
150  kep_toolbox::array3D v_end_l = l.get_v2()[0];
151 
152  DV[0] = std::abs(kep_toolbox::norm(v_beg_l)-3400.0);
153 
154  // 4 - And we proceed with each successive leg (if any)
155  kep_toolbox::array3D v_out;
156  for (size_t i = 1; i<m_seq.size(); ++i) {
157  // Fly-by
158  kep_toolbox::fb_prop(v_out, v_end_l, v_P[i-1], x[4*i+1] * m_seq[i-1]->get_radius(), x[4*i], m_seq[i-1]->get_mu_self());
159  r = r_P[i-1];
160  v = v_out;
161  // s/c propagation before the DSM
162  kep_toolbox::propagate_lagrangian(r,v,x[4*i+2]*T[i]*ASTRO_DAY2SEC,common_mu);
163  kep_toolbox::closest_distance(d, ra, r_P[i-1], v_out, r, v, common_mu);
164 
165  // Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
166  double dt = (1-x[4*i+2])*T[i]*ASTRO_DAY2SEC;
167  kep_toolbox::lambert_problem l2(r,r_P[i],dt,common_mu,false,false);
168  v_end_l = l2.get_v2()[0];
169  v_beg_l = l2.get_v1()[0];
170  kep_toolbox::closest_distance(d2,ra2,r,v_beg_l, r_P[i], v_end_l, common_mu);
171  if (d < d2)
172  {
173  d = d/ASTRO_JR;
174  } else {
175  d = d2/ASTRO_JR;
176  }
177 
178  // DSM occuring at time nu2*T2
179  kep_toolbox::diff(v_out, v_beg_l, v);
180  DV[i] = kep_toolbox::norm(v_out) + std::max((2.0-d),0.0) * 1000.0;
181  }
182  // Now we return the objective(s) function
183  f[0] = std::accumulate(DV.begin(),DV.end(),0.0);
184 //Here the lambert solver or the lagrangian propagator went wrong
185 } catch (...) {
186  f[0] = boost::numeric::bounds<double>::highest();
187 }
188 }
189 
191 
200 std::string mga_incipit::pretty(const std::vector<double> &x) const {
201 
202  // We set the std output format
203  std::ostringstream s;
204  s.precision(15);
205  s << std::scientific;
206 
207  double d,ra,d2,ra2;
208 
209  double common_mu = m_seq[0]->get_mu_central_body();
210  // 1 - we 'decode' the chromosome recording the various times of flight (days) in the list T
211  std::vector<double> T(m_seq.size(),0.0);
212 
213  for (size_t i = 0; i<m_seq.size(); ++i) {
214  T[i] = x[4*i+3];
215  }
216  // 2 - We compute the epochs and ephemerides of the planetary encounters
217  std::vector<kep_toolbox::epoch> t_P(m_seq.size());
218  std::vector<kep_toolbox::array3D> r_P(m_seq.size());
219  std::vector<kep_toolbox::array3D> v_P(m_seq.size());
220  std::vector<double> DV(m_seq.size());
221  for (size_t i = 0; i<r_P.size(); ++i) {
222  t_P[i] = kep_toolbox::epoch(x[0] + std::accumulate(T.begin(),T.begin()+1+i,0.0));
223  m_seq[i]->eph(t_P[i], r_P[i], v_P[i]);
224  }
225 
226  // 3 - We start with the first leg
227  double theta = 2*boost::math::constants::pi<double>()*x[1];
228  double phi = acos(2*x[2]-1)-boost::math::constants::pi<double>() / 2;
229  kep_toolbox::array3D r = { {ASTRO_JR * 1000*cos(phi)*sin(theta), ASTRO_JR * 1000*cos(phi)*cos(theta), ASTRO_JR * 1000*sin(phi)} };
230  kep_toolbox::array3D v;
231 
232  kep_toolbox::lambert_problem l(r,r_P[0],T[0]*ASTRO_DAY2SEC,common_mu,false,false);
233  kep_toolbox::array3D v_beg_l = l.get_v1()[0];
234  kep_toolbox::array3D v_end_l = l.get_v2()[0];
235  kep_toolbox::closest_distance(d,ra,r,v_beg_l, r_P[0], v_end_l, common_mu);
236 
237  DV[0] = std::abs(kep_toolbox::norm(v_beg_l)-3400.0);
238  kep_toolbox::array3D v_out,mem_vin,mem_vout,mem_vP;
239 
240  s << "\nFirst Leg: 1000JR to " << m_seq[0]->get_name() << std::endl;
241  s << "\tDeparture: " << kep_toolbox::epoch(x[0]) << " (" << x[0] << " mjd2000) " << std::endl;
242  s << "\tDuration: " << T[0] << "days" << std::endl;
243  s << "\tInitial Velocity Increment (m/s): " << DV[0] << std::endl;
244  kep_toolbox::diff(v_out, v_end_l, v_P[0]);
245  s << "\tArrival relative velocity at " << m_seq[0]->get_name() << " (m/s): " << kep_toolbox::norm(v_out) << std::endl;
246  s << "\tClosest distance: " << d / ASTRO_JR;
247 
248  // 4 - And we proceed with each successive leg (if any)
249  for (size_t i = 1; i<m_seq.size(); ++i) {
250  // Fly-by
251  kep_toolbox::fb_prop(v_out, v_end_l, v_P[i-1], x[4*i+1] * m_seq[i-1]->get_radius(), x[4*i], m_seq[i-1]->get_mu_self());
252  // s/c propagation before the DSM
253  r = r_P[i-1];
254  v = v_out;
255  mem_vout = v_out;
256  mem_vin = v_end_l;
257  mem_vP = v_P[i-1];
258 
259  kep_toolbox::propagate_lagrangian(r,v,x[4*i+2]*T[i]*ASTRO_DAY2SEC,common_mu);
260  kep_toolbox::closest_distance(d, ra, r_P[i-1], v_out, r, v, common_mu);
261 
262  // Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
263  double dt = (1-x[4*i+2])*T[i]*ASTRO_DAY2SEC;
264  kep_toolbox::lambert_problem l2(r,r_P[i],dt,common_mu,false,false);
265  v_end_l = l2.get_v2()[0];
266  v_beg_l = l2.get_v1()[0];
267  kep_toolbox::closest_distance(d2,ra2,r,v_beg_l, r_P[i], v_end_l, common_mu);
268 
269  if (d < d2)
270  {
271  d = d/ASTRO_JR;
272  ra = ra/ASTRO_JR;
273  } else {
274  d = d2/ASTRO_JR;
275  ra = ra2/ASTRO_JR;
276  }
277  // DSM occuring at time nu2*T2
278  kep_toolbox::diff(v_out, v_beg_l, v);
279  DV[i] = kep_toolbox::norm(v_out);
280  s << "\nleg no. " << i+1 << ": " << m_seq[i-1]->get_name() << " to " << m_seq[i]->get_name() << std::endl;
281  s << "\tDuration: (days)" << T[i] << std::endl;
282  s << "\tFly-by epoch: " << t_P[i-1] << " (" << t_P[i-1].mjd2000() << " mjd2000) " << std::endl;
283  s << "\tFly-by altitude (km): " << (x[4*i+1]*m_seq[i-1]->get_radius()-m_seq[i-1]->get_radius())/1000.0 << std::endl;
284  s << "\tPlanet position (m): " << r_P[i-1] << std::endl;
285  s << "\tPlanet velocity (m/s): " << mem_vP << std::endl;
286  s << "\tV in (m/s): " << mem_vin << std::endl;
287  s << "\tV out (m/s): " << mem_vout << std::endl << std::endl;
288 
289  s << "\tDSM after (days): " << x[4*i+2]*T[i] << std::endl;
290  s << "\tDSM magnitude (m/s): " << DV[i] << std::endl;
291  s << "\tClosest distance (JR): " << d << std::endl;
292  s << "\tApoapsis at closest distance (JR): " << ra << std::endl;
293  }
294 
295  s << "\nArrival at " << m_seq[m_seq.size()-1]->get_name() << std::endl;
296  kep_toolbox::diff(v_out, v_end_l, v_P[m_seq.size()-1]);
297  s << "Arrival epoch: " << t_P[m_seq.size()-1] << " (" << t_P[m_seq.size()-1].mjd2000() << " mjd2000) " << std::endl;
298  s << "Arrival Vinf (m/s): " << v_out << " - " << kep_toolbox::norm(v_out) << std::endl;
299  s << "Total mission time (days): " << std::accumulate(T.begin(),T.end(),0.0) << std::endl;
300  return s.str();
301 }
302 std::string mga_incipit::get_name() const
303 {
304  return "MGA-INCIPIT (CAPTURE AT JUPITER)";
305 }
306 
307 
309 
312 const std::vector<std::vector<double> >& mga_incipit::get_tof() const {
313  return m_tof;
314 }
315 
317 
322 void mga_incipit::set_tof(const std::vector<std::vector<double> >& tof) {
323  if (tof.size() != (m_seq.size())) {
324  pagmo_throw(value_error,"The time-of-flight vector (tof) has the wrong length");
325  }
326  m_tof = tof;
327  for (size_t i=0; i< m_seq.size(); ++i) {
328  set_bounds(3+4*i,tof[i][0],tof[i][1]);
329  }
330 }
331 
333 
336 std::vector<kep_toolbox::planet::planet_ptr> mga_incipit::get_sequence() const {
337  return m_seq;
338 }
339 
341 
346 {
347  std::ostringstream oss;
348  oss << "\n\tSequence: ";
349  for (size_t i = 0; i<m_seq.size() ;++i) {
350  oss << m_seq[i]->get_name() << " ";
351  }
352  oss << "\n\tTime of flights?: ";
353  for (size_t i=0; i<m_seq.size(); ++i) {
354  oss << m_tof[i]<<' ';
355  }
356  return oss.str();
357 }
358 
359 }} //namespaces
360 
361 BOOST_CLASS_EXPORT_IMPLEMENT(pagmo::problem::mga_incipit)
Root PaGMO namespace.
boost::shared_ptr< base > base_ptr
Alias for shared pointer to base problem.
Definition: problem/base.h:62
std::vector< double > decision_vector
Decision vector type.
Definition: types.h:40
std::string get_name() const
Get problem's name.
std::string pretty(const std::vector< double > &x) const
Outputs a stream with the trajectory data.
Base problem class.
Definition: problem/base.h:148
void set_tof(const std::vector< std::vector< double > > &)
Sets the times of flight.
void objfun_impl(fitness_vector &, const decision_vector &) const
Implementation of the objective function.
const std::vector< std::vector< double > > & get_tof() const
Gets the times of flight.
std::vector< kep_toolbox::planet::planet_ptr > get_sequence() const
Gets the planetary sequence defining the interplanetary mga-1dsm mission.
std::vector< double > fitness_vector
Fitness vector type.
Definition: types.h:42
const decision_vector & get_ub() const
Upper bounds getter.
base_ptr clone() const
Clone method.
const decision_vector & get_lb() const
Lower bounds getter.
void set_bounds(const decision_vector &, const decision_vector &)
Bounds setter from pagmo::decision_vector.
The beginning of the GTOC6 Jupiter Capture Trajectory.
Definition: mga_incipit.h:50
std::string human_readable_extra() const
Extra human readable info for the problem.
decision_vector::size_type size_type
Problem's size type: the same as pagmo::decision_vector's size type.
Definition: problem/base.h:160
mga_incipit(const std::vector< kep_toolbox::planet::planet_ptr >=construct_default_sequence(), const kep_toolbox::epoch t0_l=kep_toolbox::epoch(7305.0), const kep_toolbox::epoch t0_u=kep_toolbox::epoch(11323.0), const std::vector< std::vector< double > > tof=construct_default_tofs())
Constructor.
Definition: mga_incipit.cpp:54