PaGMO  1.1.5
mga_dsm.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 <cmath>
26 #include "Astro_Functions.h"
27 #include "Lambert.h"
28 #include "mga_dsm.h"
29 #include "propagateKEP.h"
30 #include "time2distance.h"
31 
32 using namespace std;
33 
34 // [MR] TODO: exctract these somewhere...
35 const double MU[9] = {
36  1.32712428e11, // SUN = 0
37  22321, // Gravitational constant of Mercury = 1
38  324860, // Gravitational constant of Venus = 2
39  398601.19, // Gravitational constant of Earth = 3
40  42828.3, // Gravitational constant of Mars = 4
41  126.7e6, // Gravitational constant of Jupiter = 5
42  0.37939519708830e8, // Gravitational constant of Saturn = 6
43  5.78e6, // Gravitational constant of Uranus = 7
44  6.8e6 // Gravitational constant of Neptune = 8
45 };
46 
47 // Definition of planetari radii
48 // TODO: maybe put missing values here so that indices correspond to those from MU[]?
49 const double RPL[6] = {
50  2440, // Mercury
51  6052, // Venus
52  6378, // Earth
53  3397, // Mars
54  71492, // Jupiter
55  60330 // Saturn
56 };
57 
58 //TODO: move somewhere else
59 void vector_normalize(const double in[3], double out[3])
60 {
61  double norm = norm2(in);
62  for(int i = 0; i < 3; i++) {
63  out[i] = in[i] / norm;
64  }
65 }
66 
76 void get_celobj_r_and_v(const mgadsmproblem& problem, const double T, const int i_count, double* r, double* v)
77 {
78  if (problem.sequence[i_count] < 10) { //normal planet
79  Planet_Ephemerides_Analytical (T, problem.sequence[i_count],
80  r, v); // r and v in heliocentric coordinate system
81  } else { //asteroid
82  Custom_Eph(T + 2451544.5, problem.asteroid.epoch, problem.asteroid.keplerian,
83  r, v);
84  }
85 }
86 
95 void precalculate_ers_and_vees(const vector<double>& t, const mgadsmproblem& problem, std::vector<double*>& r, std::vector<double*>& v)
96 {
97  double T = t[0]; //time of departure
98 
99  for(unsigned int i_count = 0; i_count < problem.sequence.size(); i_count++) {
100  get_celobj_r_and_v(problem, T, i_count, r[i_count], v[i_count]);
101  T += t[4 + i_count]; //time of flight
102  }
103 }
104 
111 double get_celobj_mu(const mgadsmproblem& problem, const int i_count)
112 {
113  if (problem.sequence[i_count] < 10) { //normal planet
114  return MU[problem.sequence[i_count]];
115  } else { //asteroid
116  return problem.asteroid.mu;
117  }
118 }
119 
120 // FIRST BLOCK (P1 to P2)
129 void first_block(const vector<double>& t, const mgadsmproblem& problem, const std::vector<double*>& r, std::vector<double*>& v, std::vector<double>& DV, double v_sc_nextpl_in[3])
130 {
131  //First, some helper constants to make code more readable
132  const int n = problem.sequence.size();
133  const double VINF = t[1]; // Hyperbolic escape velocity (km/sec)
134  const double udir = t[2]; // Hyperbolic escape velocity var1 (non dim)
135  const double vdir = t[3]; // Hyperbolic escape velocity var2 (non dim)
136  // [MR] {LITTLE HACKER TRICK} Instead of copying (!) arrays let's just introduce pointers to appropriate positions in the decision vector.
137  const double *tof = &t[4];
138  const double *alpha = &t[n+3];
139 
140  int i; //loop counter
141 
142  // Spacecraft position and velocity at departure
143  double vtemp[3];
144  cross(r[0], v[0], vtemp);
145 
146  double zP1[3];
147  vector_normalize(vtemp, zP1);
148 
149  double iP1[3];
150  vector_normalize(v[0], iP1);
151 
152  double jP1[3];
153  cross(zP1, iP1, jP1);
154 
155  double theta, phi;
156  theta = 2 * M_PI * udir; // See Picking a Point on a Sphere
157  phi = acos(2 * vdir - 1) - M_PI / 2; // In this way: -pi/2<phi<pi/2 so phi can be used as out-of-plane rotation
158 
159  double vinf[3];
160  for (i = 0; i < 3; i++)
161  vinf[i] = VINF * (cos(theta) * cos(phi) * iP1[i] + sin(theta) * cos(phi) * jP1[i] + sin(phi) * zP1[i]);
162 
163  //double v_sc_pl_in[3]; // Spacecraft absolute incoming velocity at P1 [MR] not needed?
164  double v_sc_pl_out[3]; // Spacecraft absolute outgoing velocity at P1
165 
166  for (i = 0; i < 3; i++)
167  {
168  //v_sc_pl_in[i] = v[0][i];
169  v_sc_pl_out[i] = v[0][i] + vinf[i];
170  }
171 
172  // Computing S/C position and absolute incoming velocity at DSM1
173  double rd[3], v_sc_dsm_in[3];
174 
175  propagateKEP(r[0], v_sc_pl_out, alpha[0] * tof[0] * 86400, MU[0],
176  rd, v_sc_dsm_in); // [MR] last two are output.
177 
178  // Evaluating the Lambert arc from DSM1 to P2
179  double Dum_Vec[3]; // [MR] Rename it to something sensible...
180  vett(rd, r[1], Dum_Vec);
181 
182  int lw = (Dum_Vec[2] > 0) ? 0 : 1;
183  double a, p, theta2;
184  int iter_unused; // [MR] unused variable
185 
186  double v_sc_dsm_out[3]; // DSM output speed
187 
188  LambertI(rd, r[1], tof[0] * (1 - alpha[0]) * 86400, MU[0], lw,
189  v_sc_dsm_out, v_sc_nextpl_in, a, p, theta2, iter_unused); // [MR] last 6 are output
190 
191  // First Contribution to DV (the 1st deep space maneuver)
192  for (i = 0; i < 3; i++)
193  {
194  Dum_Vec[i] = v_sc_dsm_out[i] - v_sc_dsm_in[i]; // [MR] Temporary variable reused. Dirty.
195  }
196 
197  DV[0] = norm2(Dum_Vec);
198 }
199 
200 // ------
201 // INTERMEDIATE BLOCK
202 // WARNING: i_count starts from 0
203 double intermediate_block(const vector<double>& t, const mgadsmproblem& problem, const std::vector<double*>& r, const std::vector<double*>& v, int i_count, const double v_sc_pl_in[], std::vector<double>& DV, double* v_sc_nextpl_in)
204 {
205  //[MR] A bunch of helper variables to simplify the code
206  const int n = problem.sequence.size();
207  // [MR] {LITTLE HACKER TRICK} Instead of copying (!) arrays let's just introduce pointers to appropriate positions in the decision vector.
208  const double *tof = &t[4];
209  const double *alpha = &t[n+3];
210  const double *rp_non_dim = &t[2*n+2]; // non-dim perigee fly-by radius of planets P2..Pn(-1) (i=1 refers to the second planet)
211  const double *gamma = &t[3*n]; // rotation of the bplane-component of the swingby outgoing
212  const vector<int>& sequence = problem.sequence;
213 
214  int i; //loop counter
215 
216  // Evaluation of the state immediately after Pi
217  double v_rel_in[3];
218  double vrelin = 0.0;
219 
220  for (i = 0; i < 3; i++)
221  {
222  v_rel_in[i] = v_sc_pl_in[i] - v[i_count+1][i];
223  vrelin += v_rel_in[i] * v_rel_in[i];
224  }
225 
226  // Hop object's gravitional constant
227  double hopobj_mu = get_celobj_mu(problem, i_count + 1);
228 
229  double e = 1.0 + rp_non_dim[i_count] * RPL[sequence[i_count + 1] - 1] * vrelin / hopobj_mu;
230 
231  double beta_rot = 2 * asin(1 / e); // velocity rotation
232 
233  double ix[3];
234  vector_normalize(v_rel_in, ix);
235 
236  double vpervnorm[3];
237  vector_normalize(v[i_count+1], vpervnorm);
238 
239  double iy[3];
240  vett(ix, vpervnorm, iy);
241  vector_normalize(iy, iy); // [MR]this *might* not work properly...
242 
243  double iz[3];
244  vett(ix, iy, iz);
245 
246  double v_rel_in_norm = norm2(v_rel_in);
247 
248  double v_sc_pl_out[3]; // TODO: document me!
249 
250  for (i = 0; i < 3; i++)
251  {
252  double iVout = cos(beta_rot) * ix[i] + cos(gamma[i_count]) * sin(beta_rot) * iy[i] + sin(gamma[i_count]) * sin(beta_rot) * iz[i];
253  double v_rel_out = v_rel_in_norm * iVout;
254  v_sc_pl_out[i] = v[i_count + 1][i] + v_rel_out;
255  }
256 
257  // Computing S/C position and absolute incoming velocity at DSMi
258  double rd[3], v_sc_dsm_in[3];
259 
260  propagateKEP(r[i_count + 1], v_sc_pl_out, alpha[i_count+1] * tof[i_count+1] * 86400, MU[0],
261  rd, v_sc_dsm_in); // [MR] last two are output
262 
263  // Evaluating the Lambert arc from DSMi to Pi+1
264  double Dum_Vec[3]; // [MR] Rename it to something sensible...
265  vett(rd, r[i_count + 2], Dum_Vec);
266 
267  int lw = (Dum_Vec[2] > 0) ? 0 : 1;
268  double a, p, theta;
269  int iter_unused; // [MR] unused variable
270 
271  double v_sc_dsm_out[3]; // DSM output speed
272 
273  LambertI(rd, r[i_count + 2], tof[i_count + 1] * (1 - alpha[i_count + 1]) * 86400, MU[0], lw,
274  v_sc_dsm_out, v_sc_nextpl_in, a, p, theta, iter_unused); // [MR] last 6 are output.
275 
276  // DV contribution
277  for (i = 0; i < 3; i++) {
278  Dum_Vec[i] = v_sc_dsm_out[i] - v_sc_dsm_in[i]; // [MR] Temporary variable reused. Dirty.
279  }
280 
281  DV[i_count + 1] = norm2(Dum_Vec);
282 
283  return vrelin;
284 }
285 
286 // FINAL BLOCK
287 //
288 void final_block(const mgadsmproblem& problem, const std::vector<double*>& , const std::vector<double*>& v, const double v_sc_pl_in[], std::vector<double>& DV)
289 {
290  //[MR] A bunch of helper variables to simplify the code
291  const int n = problem.sequence.size();
292  const double rp_target = problem.rp;
293  const double e_target = problem.e;
294  const vector<int>& sequence = problem.sequence;
295 
296  int i; //loop counter
297 
298  // Evaluation of the arrival DV
299  double Dum_Vec[3];
300  for (i = 0; i < 3; i++) {
301  Dum_Vec[i] = v[n-1][i] - v_sc_pl_in[i];
302  }
303 
304  double DVrel, DVarr;
305  DVrel = norm2(Dum_Vec); // Relative velocity at target planet
306 
307  if ((problem.type == orbit_insertion) || (problem.type == total_DV_orbit_insertion)) {
308  double DVper = sqrt(DVrel * DVrel + 2 * MU[sequence[n - 1]] / rp_target); //[MR] should MU be changed to get_... ?
309  double DVper2 = sqrt(2 * MU[sequence[n - 1]] / rp_target - MU[sequence[n - 1]] / rp_target * (1 - e_target));
310  DVarr = fabs(DVper - DVper2);
311  } else if (problem.type == rndv){
312  DVarr = DVrel;
313  } else if (problem.type == total_DV_rndv){
314  DVarr = DVrel;
315  } else {
316  DVarr = 0.0; // no DVarr is considered
317  }
318 
319  DV[n - 1] = DVarr;
320 }
321 
322 
323 int MGA_DSM(
324  /* INPUT values: */ //[MR] make this parameters const, if they are not modified and possibly references (especially 'problem').
325  const vector<double> &t, // it is the vector which provides time in modified julian date 2000. [MR] ??? Isn't it the decision vetor ???
326  const mgadsmproblem& problem,
327 
328  /* OUTPUT values: */
329  double &J // output
330  )
331 {
332  //[MR] A bunch of helper variables to simplify the code
333  const int n = problem.sequence.size();
334 
335  int i; //loop counter
336 
337  //References to objects pre-allocated in the mgadsm struct
338  std::vector<double*>& r = problem.r;
339  std::vector<double*>& v = problem.v;
340 
341  std::vector<double>& DV = problem.DV; //DV contributions
342 
343  precalculate_ers_and_vees(t, problem, r, v);
344 
345  double inter_pl_in_v[3], inter_pl_out_v[3]; //inter-hop velocities
346 
347  // FIRST BLOCK
348  first_block(t, problem, r, v,
349  DV, inter_pl_out_v); // [MR] output
350 
351  // INTERMEDIATE BLOCK
352 
353  for (int i_count=0; i_count < n - 2; i_count++) {
354  //copy previous output velocity to current input velocity
355  inter_pl_in_v[0] = inter_pl_out_v[0]; inter_pl_in_v[1] = inter_pl_out_v[1]; inter_pl_in_v[2] = inter_pl_out_v[2];
356 
357  problem.vrelin_vec[i_count] = intermediate_block(t, problem, r, v, i_count, inter_pl_in_v,DV, inter_pl_out_v);
358  }
359 
360  //copy previous output velocity to current input velocity
361  inter_pl_in_v[0] = inter_pl_out_v[0]; inter_pl_in_v[1] = inter_pl_out_v[1]; inter_pl_in_v[2] = inter_pl_out_v[2];
362  // FINAL BLOCK
363  final_block(problem, r, v, inter_pl_in_v,
364  DV);
365 
366  // **************************************************************************
367  // Evaluation of total DV spent by the propulsion system
368  // **************************************************************************
369  double DVtot = 0.0;
370 
371  for (i = 0; i < n; i++) {
372  DVtot += DV[i];
373  }
374 
375  // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376  //[MR] Calculation of the actual procedure output (DVvec and J)
377 
378  const double& VINF = t[1]; // Variable renaming: Hyperbolic escape velocity (km/sec)
379 
380  for (i = n; i > 0; i--) {
381  DV[i] = DV[i - 1];
382  }
383  DV[0] = VINF;
384 
385 
386  // Finally our objective function (J) is:
387 
388  if (problem.type == orbit_insertion) {
389  J = DVtot;
390  } else if (problem.type == total_DV_orbit_insertion) {
391  J = DVtot + VINF;
392  } else if (problem.type == rndv) {
393  J = DVtot;
394  } else if (problem.type == total_DV_rndv) {
395  J = DVtot + VINF;
396  } else if (problem.type == time2AUs) { // [MR] TODO: extract method
397  // [MR] helper constants
398  const vector<int>& sequence = problem.sequence;
399  const double *rp_non_dim = &t[2*n+2]; // non-dim perigee fly-by radius of planets P2..Pn(-1) (i=1 refers to the second planet)
400  const double *gamma = &t[3*n]; // rotation of the bplane-component of the swingby outgoing
401  const double AUdist = problem.AUdist;
402  const double DVtotal = problem.DVtotal;
403  const double DVonboard = problem.DVonboard;
404  const double *tof = &t[4];
405 
406  // non dimensional units
407  const double AU = 149597870.66;
408  const double V = sqrt(MU[0] / AU);
409  const double T = AU / V;
410 
411  //evaluate the state of the spacecraft after the last fly-by
412  double vrelin = 0.0;
413  double v_rel_in[3];
414  for (i=0; i<3; i++)
415  {
416  v_rel_in[i] = inter_pl_in_v[i] - v[n-1][i];
417  vrelin += v_rel_in[i] * v_rel_in[i];
418  }
419 
420  double e = 1.0 + rp_non_dim[n - 2] * RPL[sequence[n - 2 + 1] - 1] * vrelin / get_celobj_mu(problem, n - 1); //I hope the planet index (n - 1) is OK
421 
422  double beta_rot=2*asin(1/e); // velocity rotation
423 
424  double vrelinn = norm2(v_rel_in);
425  double ix[3];
426  for (i=0; i<3; i++)
427  ix[i] = v_rel_in[i]/vrelinn;
428  // ix=r_rel_in/norm(v_rel_in); // activating this line and disactivating the one above
429  // shifts the singularity for r_rel_in parallel to v_rel_in
430 
431  double vnorm = norm2(v[n-1]);
432 
433  double vtemp[3];
434  for (i=0; i<3; i++)
435  vtemp[i] = v[n-1][i]/vnorm;
436 
437  double iy[3];
438  vett(ix, vtemp, iy);
439 
440  double iynorm = norm2(iy);
441  for (i=0; i<3; i++)
442  iy[i] = iy[i]/iynorm;
443 
444  double iz[3];
445  vett(ix, iy, iz);
446  double v_rel_in_norm = norm2(v_rel_in);
447 
448  double v_sc_pl_out[3]; // TODO: document me!
449  for (i = 0; i < 3; i++)
450  {
451  double iVout = cos(beta_rot) * ix[i] + cos(gamma[n - 2]) * sin(beta_rot) * iy[i] + sin(gamma[n - 2]) * sin(beta_rot) * iz[i];
452  double v_rel_out = v_rel_in_norm * iVout;
453  v_sc_pl_out[i] = v[n - 1][i] + v_rel_out;
454  }
455 
456  double r_per_AU[3];
457  double v_sc_pl_out_per_V[3];
458  for (i = 0; i < 3; i++)
459  {
460  r_per_AU[i] = r[n - 1][i] / AU;
461  v_sc_pl_out_per_V[i] = v_sc_pl_out[i] / V;
462  }
463 
464  double time = time2distance(r_per_AU, v_sc_pl_out_per_V, AUdist);
465  // if (time == -1) cout << " ERROR" << endl;
466 
467  if (time != -1)
468  {
469  double DVpen=0;
470  double sum = 0.0;
471 
472  for (i=0; i<n+1; i++)
473  sum += DV[i];
474 
475  if (sum > DVtotal)
476  DVpen += DVpen+(sum-DVtotal);
477 
478  sum = 0.0;
479  for (i=1; i<n+1; i++)
480  sum+=DV[i];
481 
482  if (sum > DVonboard)
483  DVpen = DVpen + (sum - DVonboard);
484 
485  sum = 0.0;
486  for (i=0; i<n-1; i++)
487  sum += tof[i];
488 
489  J= (time*T/60/60/24 + sum)/365.25 + DVpen*100;
490  }
491  else
492  J = 100000; // there was an ERROR in time2distance
493  } // time2AU
494 
495  return 0;
496 }
STL namespace.