PaGMO  1.1.5
mga_part.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_part.h"
36 
37 
38 #define ASTRO_JR 71492000.0 //m
39 
40 namespace pagmo { namespace problem {
41 
42 
44 
56 mga_part::mga_part(const std::vector<kep_toolbox::planet::planet_ptr> seq,
57  const std::vector<std::vector<double> > tof,
58  const kep_toolbox::epoch t0,
59  const kep_toolbox::array3D vinf_in
60  ):
61  base(4*(seq.size()-1)), m_tof(tof), m_t0(t0), m_vinf_in(vinf_in)
62 {
63  // We check that all planets have equal central body
64  std::vector<double> mus(seq.size());
65  for (std::vector<kep_toolbox::planet::planet_ptr>::size_type i = 0; i< seq.size(); ++i) {
66  mus[i] = seq[i]->get_mu_central_body();
67  }
68  if ((unsigned int)std::count(mus.begin(), mus.end(), mus[0]) != mus.size()) {
69  pagmo_throw(value_error,"The planets do not all have the same mu_central_body");
70  }
71  // We check the consistency of the time of flights
72  if (tof.size() != (seq.size()-1)) {
73  pagmo_throw(value_error,"The time-of-flight vector (tof) has the wrong length");
74  }
75  for (size_t i = 0; i < tof.size(); ++i) {
76  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)");
77  }
78  //We check the sequence contains at least two planets
79  if (seq.size() < 2) {
80  pagmo_throw(value_error,"The sequence must contain at least 2 planets");
81  }
82 
83  // Filling in the planetary sequence data member. This requires to construct the polymorphic planets via their clone method
84  for (std::vector<kep_toolbox::planet::planet_ptr>::size_type i = 0; i < seq.size(); ++i) {
85  m_seq.push_back(seq[i]->clone());
86  }
87 
88  // Now setting the problem bounds
89  size_type dim(4*(seq.size()-1));
90  decision_vector lb(dim), ub(dim);
91 
92 
93  // all legs
94  for (std::vector<kep_toolbox::planet::planet_ptr>::size_type i = 0; i < (m_seq.size() - 1); ++i) {
95  lb[4*i] = - 2 * boost::math::constants::pi<double>(); ub[4*i] = 2 * boost::math::constants::pi<double>();
96  lb[4*i+1] = 1.1; ub[4*i+1] = 30;
97  lb[4*i+2] = 1e-5; ub[4*i+2] = 1-1e-5;
98  lb[4*i+3] = m_tof[i][0]; ub[4*i+3] = m_tof[i][1];
99  }
100 
101  // Adjusting the minimum and maximum allowed fly-by rp to the one defined in the kep_toolbox::planet class
102  for (std::vector<kep_toolbox::planet::planet_ptr>::size_type i = 0; i < (m_seq.size() - 1); ++i) {
103  lb[4*i+1] = m_seq[i]->get_safe_radius() / m_seq[i]->get_radius();
104  ub[4*i+1] = (m_seq[i]->get_radius() + 2000000) / m_seq[i]->get_radius(); //from gtoc6 problem description
105  }
106  set_bounds(lb,ub);
107 }
108 
110 mga_part::mga_part(const mga_part &p) : base(p.get_dimension()), m_tof(p.m_tof), m_t0(p.m_t0), m_vinf_in(p.m_vinf_in)
111 {
112  for (std::vector<kep_toolbox::planet::planet_ptr>::size_type i = 0; i < p.m_seq.size();++i) {
113  m_seq.push_back(p.m_seq[i]->clone());
114  }
115  set_bounds(p.get_lb(),p.get_ub());
116 }
117 
120 {
121  return base_ptr(new mga_part(*this));
122 }
123 
126 {
127 try {
128  double d,ra,d2,ra2;
129  double common_mu = m_seq[0]->get_mu_central_body();
130  // 1 - we 'decode' the chromosome recording the various times of flight (days) in the list T
131  std::vector<double> T(m_seq.size()-1,0.0);
132 
133  for (size_t i = 0; i < (m_seq.size()-1); ++i) {
134  T[i] = x[4*i+3];
135  }
136  // 2 - We compute the epochs and ephemerides of the planetary encounters
137  std::vector<kep_toolbox::epoch> t_P(m_seq.size());
138  std::vector<kep_toolbox::array3D> r_P(m_seq.size());
139  std::vector<kep_toolbox::array3D> v_P(m_seq.size());
140  std::vector<double> DV(m_seq.size() - 1);
141  for (size_t i = 0; i<m_seq.size(); ++i) {
142  t_P[i] = kep_toolbox::epoch(m_t0.mjd2000() + std::accumulate(T.begin(),T.begin()+i,0.0));
143  m_seq[i]->eph(t_P[i], r_P[i], v_P[i]);
144  }
145 
146  // 3 - We loop over the legs
147  kep_toolbox::array3D v_out,r,v;
148  kep_toolbox::array3D v_beg_l,v_end_l;
149  kep_toolbox::sum(v_end_l, m_vinf_in, v_P[0]);
150  for (size_t i = 0; i<(m_seq.size()-1); ++i) {
151  // Fly-by
152  kep_toolbox::fb_prop(v_out, v_end_l, v_P[i], x[4*i+1] * m_seq[i]->get_radius(), x[4*i], m_seq[i]->get_mu_self());
153  // s/c propagation before the DSM
154  r = r_P[i];
155  v = v_out;
156 
157  kep_toolbox::propagate_lagrangian(r,v,x[4*i+2]*T[i]*ASTRO_DAY2SEC,common_mu);
158  kep_toolbox::closest_distance(d, ra, r_P[i], v_out, r, v, common_mu);
159 
160  // Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
161  double dt = (1-x[4*i+2])*T[i]*ASTRO_DAY2SEC;
162  kep_toolbox::lambert_problem l2(r,r_P[i+1],dt,common_mu,false,false);
163  v_end_l = l2.get_v2()[0];
164  v_beg_l = l2.get_v1()[0];
165  kep_toolbox::closest_distance(d2,ra2,r,v_beg_l, r_P[i+1], v_end_l, common_mu);
166 
167  if (d < d2)
168  {
169  d = d/ASTRO_JR;
170  } else {
171  d = d2/ASTRO_JR;
172  }
173 
174  // DSM occuring at time nu2*T2
175  kep_toolbox::diff(v_out, v_beg_l, v);
176  // Penalized if the JR is too small (<0.2)
177  DV[i] = kep_toolbox::norm(v_out) + std::max((2.0-d),0.0) * 1000.0;
178  }
179  // Now we return the objective(s) function
180  f[0] = std::accumulate(DV.begin(),DV.end(),0.0);
181 //Here the lambert solver or the lagrangian propagator went wrong
182 } catch (...) {
183  f[0] = boost::numeric::bounds<double>::highest();
184 }
185 }
186 
188 
197 std::string mga_part::pretty(const std::vector<double> &x) const {
198 
199  // We set the std output format
200  std::ostringstream s;
201  s.precision(15);
202  s << std::scientific;
203 
204  double d,ra,d2,ra2;
205 
206  double common_mu = m_seq[0]->get_mu_central_body();
207  // 1 - we 'decode' the chromosome recording the various times of flight (days) in the list T
208  std::vector<double> T(m_seq.size()-1,0.0);
209 
210  for (size_t i = 0; i<m_seq.size()-1; ++i) {
211  T[i] = x[4*i+3];
212  }
213  // 2 - We compute the epochs and ephemerides of the planetary encounters
214  std::vector<kep_toolbox::epoch> t_P(m_seq.size());
215  std::vector<kep_toolbox::array3D> r_P(m_seq.size());
216  std::vector<kep_toolbox::array3D> v_P(m_seq.size());
217  std::vector<double> DV(m_seq.size() - 1);
218  for (size_t i = 0; i<m_seq.size(); ++i) {
219  t_P[i] = kep_toolbox::epoch(m_t0.mjd2000() + std::accumulate(T.begin(),T.begin()+i,0.0));
220  m_seq[i]->eph(t_P[i], r_P[i], v_P[i]);
221  }
222 
223  // 4 - And we proceed with each successive leg (if any)
224  kep_toolbox::array3D v_out,r,v,mem_vin,mem_vout,mem_vP;
225  kep_toolbox::array3D v_beg_l,v_end_l;
226  kep_toolbox::sum(v_end_l, m_vinf_in, v_P[0]);
227  for (size_t i = 0; i<m_seq.size()-1; ++i) {
228  // Fly-by
229  kep_toolbox::fb_prop(v_out, v_end_l, v_P[i], x[4*i+1] * m_seq[i]->get_radius(), x[4*i], m_seq[i]->get_mu_self());
230  // s/c propagation before the DSM
231  r = r_P[i];
232  v = v_out;
233 
234  mem_vout = v_out;
235  mem_vin = v_end_l;
236  mem_vP = v_P[i];
237 
238  kep_toolbox::propagate_lagrangian(r,v,x[4*i+2]*T[i]*ASTRO_DAY2SEC,common_mu);
239  kep_toolbox::closest_distance(d, ra, r_P[i], v_out, r, v, common_mu);
240 
241  // Lambert arc to reach Earth during (1-nu2)*T2 (second segment)
242  double dt = (1-x[4*i+2])*T[i]*ASTRO_DAY2SEC;
243  kep_toolbox::lambert_problem l2(r,r_P[i+1],dt,common_mu,false,false);
244  v_end_l = l2.get_v2()[0];
245  v_beg_l = l2.get_v1()[0];
246  kep_toolbox::closest_distance(d2,ra2,r,v_beg_l, r_P[i+1], v_end_l, common_mu);
247 
248  if (d < d2)
249  {
250  d = d/ASTRO_JR;
251  ra = ra/ASTRO_JR;
252  } else {
253  d = d2/ASTRO_JR;
254  ra = ra2/ASTRO_JR;
255  }
256  // DSM occuring at time nu2*T2
257  // DSM occuring at time nu2*T2
258  kep_toolbox::diff(v_out, v_beg_l, v);
259  DV[i] = kep_toolbox::norm(v_out);
260  s << "\nleg no. " << i+1 << ": " << m_seq[i]->get_name() << " to " << m_seq[i+1]->get_name() << std::endl;
261  s << "\tDuration: (days)" << T[i] << std::endl;
262  s << "\tFly-by epoch: " << t_P[i] << " (" << t_P[i].mjd2000() << " mjd2000) " << std::endl;
263  s << "\tFly-by altitude (km): " << (x[4*i+1]*m_seq[i]->get_radius()-m_seq[i]->get_radius())/1000.0 << std::endl;
264  s << "\tPlanet position (m): " << r_P[i] << std::endl;
265  s << "\tPlanet velocity (m/s): " << mem_vP << std::endl;
266  s << "\tV in (m/s): " << mem_vin << std::endl;
267  s << "\tV out (m/s): " << mem_vout << std::endl << std::endl;
268 
269  s << "\tDSM after (days): " << x[4*i+2]*T[i] << std::endl;
270  s << "\tDSM magnitude (m/s): " << DV[i] << std::endl;
271  s << "\tClosest distance (JR): " << d << std::endl;
272  s << "\tApoapsis at closest distance (JR): " << ra << std::endl;
273 
274  }
275 
276  s << "\nArrival at " << m_seq[m_seq.size()-1]->get_name() << std::endl;
277  kep_toolbox::diff(v_out, v_end_l, v_P[m_seq.size()-1]);
278  s << "Arrival epoch: " << t_P[m_seq.size()-1] << " (" << t_P[m_seq.size()-1].mjd2000() << " mjd2000) " << std::endl;
279  s << "Arrival Vinf (m/s): " << v_out << " - " << kep_toolbox::norm(v_out) << std::endl;
280  s << "Total mission time (days): " << std::accumulate(T.begin(),T.end(),0.0) << std::endl;
281  return s.str();
282 }
283 std::string mga_part::get_name() const
284 {
285  return "MGA-PART (a part of the jupiter moon tour)";
286 }
287 
289 
294 void mga_part::set_tof(const std::vector<std::vector<double> >& tof) {
295  if (tof.size() != (m_seq.size()-1)) {
296  pagmo_throw(value_error,"The time-of-flight vector (tof) has the wrong length");
297  }
298  m_tof = tof;
299  for (size_t i=0; i< (m_seq.size()-1); ++i) {
300  set_bounds(3+4*i,tof[i][0],tof[i][1]);
301  }
302 }
303 
305 
308 const std::vector<std::vector<double> >& mga_part::get_tof() const {
309  return m_tof;
310 }
311 
313 
319 void mga_part::set_betas(const std::vector<std::vector<double> >& betas) {
320  if (betas.size() != (m_seq.size()-1)) {
321  pagmo_throw(value_error,"The betas vector (betas) has the wrong length");
322  }
323  for (size_t i=0; i< (m_seq.size()-1); ++i) {
324  if (betas[i].size() !=2) {
325  pagmo_throw(value_error,"Lower and upper bound vector needs to have dimension 2");
326  }
327  set_bounds(4*i,betas[i][0],betas[i][1]);
328  }
329 }
330 
332 
335 std::vector<std::vector<double> > mga_part::get_betas() const {
336  std::vector<std::vector<double> > retval;
337  std::vector<double> tmp(2);
338  for (size_t i=0; i< (m_seq.size()-1); ++i) {
339  tmp[0] = get_lb()[4*i];
340  tmp[1] = get_ub()[4*i];
341  retval.push_back(tmp);
342  }
343  return retval;
344 }
345 
347 
352 void mga_part::set_rps(const std::vector<std::vector<double> >& rps) {
353  if (rps.size() != (m_seq.size()-1)) {
354  pagmo_throw(value_error,"The periplanets vector (rps) has the wrong length");
355  }
356  for (size_t i=0; i< (m_seq.size()-1); ++i) {
357  if (rps[i].size() !=2) {
358  pagmo_throw(value_error,"Lower and upper bound vector needs to have dimension 2");
359  }
360  set_bounds(1+4*i,(rps[i][0]*1000+m_seq[i]->get_radius())/m_seq[i]->get_radius(),(rps[i][1]*1000+m_seq[i]->get_radius())/m_seq[i]->get_radius());
361  }
362 }
363 
365 
368 std::vector<std::vector<double> > mga_part::get_rps() const {
369  std::vector<std::vector<double> > retval;
370  std::vector<double> tmp(2);
371  for (size_t i=0; i< (m_seq.size()-1); ++i) {
372  tmp[0] = ((get_lb()[4*i+1]*m_seq[i]->get_radius())-m_seq[i]->get_radius())/1000.0;
373  tmp[1] = ((get_ub()[4*i+1]*m_seq[i]->get_radius())-m_seq[i]->get_radius())/1000.0;
374  retval.push_back(tmp);
375  }
376  return retval;
377 }
378 
380 
385 void mga_part::set_t0(const kep_toolbox::epoch& t0) {
386  m_t0 = t0;
387 }
388 
390 
393 const kep_toolbox::epoch& mga_part::get_t0() const {
394  return m_t0;
395 }
396 
398 
403 void mga_part::set_vinf_in(const kep_toolbox::array3D& vinf_in) {
404  m_vinf_in = vinf_in;
405 }
406 
408 
411 const kep_toolbox::array3D& mga_part::get_vinf_in() const {
412  return m_vinf_in;
413 }
414 
415 
417 
420 std::vector<kep_toolbox::planet::planet_ptr> mga_part::get_sequence() const {
421  return m_seq;
422 }
423 
425 
430 {
431  std::ostringstream oss;
432  oss << "\n\tSequence: ";
433  for (size_t i = 0; i<m_seq.size() ;++i) {
434  oss << m_seq[i]->get_name() << " ";
435  }
436  oss << "\n\tTime of flights: ";
437  for (size_t i=0; i<(m_seq.size()-1); ++i) {
438  oss << m_tof[i]<<' ';
439  }
440  oss << "\n\tStarting epoch: " << m_t0;
441  oss << "\n\tStarting Vinf in: " << m_vinf_in << std::endl;
442  return oss.str();
443 }
444 
445 }} //namespaces
446 
447 BOOST_CLASS_EXPORT_IMPLEMENT(pagmo::problem::mga_part)
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
mga_part(const std::vector< kep_toolbox::planet::planet_ptr >=construct_default_sequence(), const std::vector< std::vector< double > > tof=construct_default_tofs(), const kep_toolbox::epoch t0=kep_toolbox::epoch(11000), const kep_toolbox::array3D vinf_in=construct_default_v())
Constructor.
Definition: mga_part.cpp:56
void objfun_impl(fitness_vector &, const decision_vector &) const
Implementation of the objective function.
Definition: mga_part.cpp:125
const kep_toolbox::epoch & get_t0() const
Gets the start epoch.
Definition: mga_part.cpp:393
std::vector< std::vector< double > > get_betas() const
Gets the betas.
Definition: mga_part.cpp:335
base_ptr clone() const
Clone method.
Definition: mga_part.cpp:119
Base problem class.
Definition: problem/base.h:148
void set_tof(const std::vector< std::vector< double > > &)
Sets the times of flight.
Definition: mga_part.cpp:294
std::string human_readable_extra() const
Extra human readable info for the problem.
Definition: mga_part.cpp:429
A part of the GTOC6 Jupiter Capture Trajectory.
Definition: mga_part.h:52
std::string pretty(const std::vector< double > &x) const
Outputs a stream with the trajectory data.
Definition: mga_part.cpp:197
std::string get_name() const
Get problem's name.
Definition: mga_part.cpp:283
std::vector< kep_toolbox::planet::planet_ptr > get_sequence() const
Gets the planetary sequence defining the interplanetary mga-1dsm mission.
Definition: mga_part.cpp:420
void set_t0(const kep_toolbox::epoch &)
Sets the start epoch.
Definition: mga_part.cpp:385
const kep_toolbox::array3D & get_vinf_in() const
Gets the start velocity.
Definition: mga_part.cpp:411
void set_vinf_in(const kep_toolbox::array3D &)
Sets the start velocity.
Definition: mga_part.cpp:403
std::vector< double > fitness_vector
Fitness vector type.
Definition: types.h:42
void set_rps(const std::vector< std::vector< double > > &)
Sets the peri-planet bounds.
Definition: mga_part.cpp:352
const decision_vector & get_ub() const
Upper bounds getter.
void set_betas(const std::vector< std::vector< double > > &)
Sets the betas.
Definition: mga_part.cpp:319
const decision_vector & get_lb() const
Lower bounds getter.
void set_bounds(const decision_vector &, const decision_vector &)
Bounds setter from pagmo::decision_vector.
decision_vector::size_type size_type
Problem's size type: the same as pagmo::decision_vector's size type.
Definition: problem/base.h:160
const std::vector< std::vector< double > > & get_tof() const
Gets the times of flight.
Definition: mga_part.cpp:308
std::vector< std::vector< double > > get_rps() const
Gets the peri-planet bounds.
Definition: mga_part.cpp:368