Planetary Orbital Evolution due to Tides
Orbital evolution of two objects experiencing tides
testDifferentialEquations.cpp
Go to the documentation of this file.
1 
9 
10 namespace Evolve {
11 
13  const alglib::real_1d_array &eccentricities,
14  const alglib::real_1d_array &expected_semimajor_rate,
15  const alglib::real_1d_array &predicted_semimajor_rate,
16  const alglib::real_1d_array &expected_eccentricity_rate,
17  const alglib::real_1d_array &predicted_eccentricity_rate
18  ) const
19  {
20  std::cout << std::setw(25) << "eccentricity"
21  << std::setw(25) << "semimajor_rate"
22  << std::setw(25) << "expected_semimajor_rate"
23  << std::setw(25) << "eccentricity_rate"
24  << std::setw(25) << "expected_ecc_rate"
25  << std::endl;
26  for(
27  unsigned e_index = 0;
28  e_index < eccentricities.length();
29  ++e_index
30  ) {
31  std::cout << std::setw(25) << eccentricities[e_index]
32  << std::setw(25)
33  << predicted_semimajor_rate[e_index]
34  << std::setw(25)
35  << expected_semimajor_rate[e_index]
36  << std::setw(25)
37  << predicted_eccentricity_rate[e_index]
38  << std::setw(25)
39  << expected_eccentricity_rate[e_index]
40  << std::endl;
41  }
42 
43 
44  }
45 
47  int orbital_frequency_multiplier,
48  int spin_frequency_multiplier,
49  double eccentricity
50  ) const
51  {
52 
53  double e2 = std::pow(eccentricity, 2);
54 
55  if(orbital_frequency_multiplier == 2 && spin_frequency_multiplier == 2)
56  return 1.0 - 5.0 * e2;
57 
58  if(orbital_frequency_multiplier == 1 && spin_frequency_multiplier == 0)
59  return 3.0 / 4.0 * e2;
60 
61  if(orbital_frequency_multiplier == 1 && spin_frequency_multiplier == 2)
62  return 1.0 / 8.0 * e2;
63 
64  if(orbital_frequency_multiplier == 3 && spin_frequency_multiplier == 2)
65  return 147.0 / 8.0 * e2;
66 
67  return 0.0;
68  }
69 
71  int orbital_frequency_multiplier,
72  int spin_frequency_multiplier
73  ) const
74  {
75 
76  if(orbital_frequency_multiplier == 2 && spin_frequency_multiplier == 2)
77  return -1.0;
78 
79  if(orbital_frequency_multiplier == 1 && spin_frequency_multiplier == 0)
80  return 1.5;
81 
82  if(orbital_frequency_multiplier == 1 && spin_frequency_multiplier == 2)
83  return -1.0 / 4.0;
84 
85  if(orbital_frequency_multiplier == 3 && spin_frequency_multiplier == 2)
86  return 49.0 / 4.0;
87 
88  return 0.0;
89  }
90 
92  const alglib::real_1d_array& x,
93  const alglib::real_1d_array& y1,
94  const alglib::real_1d_array& y2,
95  unsigned agreement_order,
96  unsigned max_order,
97  const std::string &description
98  )
99  {
100  alglib::real_1d_array difference;
101  difference.setlength(x.length());
102  double min_difference = Core::Inf,
103  max_difference = -Core::Inf,
104  y_scale = 0;
105  for(unsigned i = 0; i < x.length(); ++i) {
106  difference[i] = y2[i] - y1[i];
107  min_difference = std::min(difference[i], min_difference);
108  max_difference = std::max(difference[i], max_difference);
109  y_scale = std::max(std::abs(y1[i]), std::abs(y2[i]));
110  }
111 
112  if(
113  std::max(std::abs(max_difference), std::abs(min_difference))
114  <
115  1e-13 * y_scale
116  )
117  return;
118  alglib::ae_int_t fit_info;
119  alglib::barycentricinterpolant interp;
120  alglib::polynomialfitreport fit_report;
121  alglib::polynomialfit(x,
122  difference,
123  max_order + 1,
124  fit_info,
125  interp,
126  fit_report);
127 
128  double max_allowed_residual = 1e-12 * (max_difference - min_difference);
129 
130  std::ostringstream message;
131  message << description
132  << " too large residual from fit to difference: "
133  << fit_report.maxerror
134  << " > "
135  << max_allowed_residual;
136 
137  TEST_ASSERT_MSG(fit_report.maxerror <= max_allowed_residual,
138  message.str().c_str());
139 
140  alglib::real_1d_array coefficients;
141 
142  alglib::polynomialbar2pow(interp, coefficients);
143 
144  double max_allowed_term = 0.0,
145  max_abs_x = std::max(std::abs(x[0]), x[x.length() - 1]);
146  for(unsigned power = 0; power < coefficients.length(); ++power)
147  max_allowed_term = std::max(
148  max_allowed_term,
149  std::abs(coefficients[power]) * std::pow(max_abs_x, power)
150  );
151  max_allowed_term *= 1e-8;
152 
153  for(unsigned power = 0; power <= agreement_order; ++power) {
154  double max_abs_term_value = (std::abs(coefficients[power])
155  *
156  std::pow(max_abs_x, power));
157  message.str("");
158  message << description
159  << " x^" << power << " coefficient too large: |"
160  << coefficients[power]
161  << " * "
162  << max_abs_x << "^" << power
163  << "| = "
164  << max_abs_term_value
165  << " > "
166  << max_allowed_term;
167 
168  TEST_ASSERT_MSG(max_abs_term_value <= max_allowed_term,
169  message.str().c_str());
170  }
171  }
172 
174  {
177  }
178 
180  {
181  const double MAX_ECCENTRICITY = 0.5;
182  const unsigned NUM_ECCENTRICITIES = 100;
183  const double ECCENTRICITY_STEP = (
184  MAX_ECCENTRICITY / (NUM_ECCENTRICITIES - 1)
185  );
186 
187  alglib::real_1d_array eccentricities,
188  expected_semimajor_rate,
189  predicted_semimajor_rate,
190  expected_eccentricity_rate,
191  predicted_eccentricity_rate;
192  eccentricities.setlength(NUM_ECCENTRICITIES);
193  expected_semimajor_rate.setlength(NUM_ECCENTRICITIES);
194  predicted_semimajor_rate.setlength(NUM_ECCENTRICITIES);
195  expected_eccentricity_rate.setlength(NUM_ECCENTRICITIES);
196  predicted_eccentricity_rate.setlength(NUM_ECCENTRICITIES);
197 
198  eccentricities[0] = 0.0;
199  for(unsigned e_index = 1; e_index < NUM_ECCENTRICITIES; ++e_index)
200  eccentricities[e_index] = (eccentricities[e_index - 1]
201  +
202  ECCENTRICITY_STEP);
203 
204  std::valarray<double> one_poly(1.0, 1);
205  for(
206  int orbital_frequency_multiplier = 0;
207  orbital_frequency_multiplier <= 4;
208  ++orbital_frequency_multiplier
209  ) {
210  for(
211  int spin_frequency_multiplier = 0;
212  spin_frequency_multiplier <= 4;
213  ++spin_frequency_multiplier
214  ) {
215  SingleTidalTermBody primary(0.0,
216  1.0,
217  orbital_frequency_multiplier,
218  spin_frequency_multiplier,
219  1.0,
220  one_poly,
221  one_poly,
222  one_poly);
223  Planet::Planet secondary(1.0, 1.0);
224 
225  BinarySystem binary(primary, secondary);
226 
227  binary.change_e_order(2);
228 
229  std::valarray<double> parameters(0.0, 7);
230  std::valarray<double> evolution_rates(parameters.size());
231  parameters[0] = 10.0;
232  parameters[1] = 0.0;
233  binary.configure(true,
234  0.0,
235  &(parameters[0]),
236  Core::BINARY);
237 
238  double common_rate_factor = (
239  -2.4 * M_PI
240  *
241  (primary.mass() + secondary.mass()) / primary.mass()
242  *
244  *
245  Core::AstroConst::solar_mass * secondary.mass()
246  /
247  std::pow(Core::AstroConst::solar_radius, 3)
249 
250  for(double semimajor = 2.0; semimajor <= 10.0; semimajor += 1.0) {
251 
252  double mean_motion = std::sqrt(
254  primary.mass()
255  +
256  secondary.mass()
257  )
258  /
259  std::pow(semimajor * Core::AstroConst::solar_radius, 3)
260  );
261  double rate_factor = (
262  common_rate_factor
263  /
264  (mean_motion * std::pow(semimajor, 8))
265  );
266  for(
267  double primary_spin_frequency = 0.0;
268  primary_spin_frequency <= 5.0 * mean_motion;
269  primary_spin_frequency += 0.2 * mean_motion
270  ) {
271 
272  for(
273  unsigned e_index = 0;
274  e_index < NUM_ECCENTRICITIES;
275  ++e_index
276  )
277  {
278  double age = 1.0,
279  test_e = eccentricities[e_index];
280  parameters[0] = std::pow(semimajor, 6.5);
281  parameters[1] = test_e;
282  binary.differential_equations(age,
283  &(parameters[0]),
284  Core::BINARY,
285  &(evolution_rates[0]));
286  expected_semimajor_rate[e_index] = (
287  6.5 * std::pow(semimajor, 6.5)
288  *
289  rate_factor
290  *
292  orbital_frequency_multiplier,
293  spin_frequency_multiplier,
294  test_e
295  )
296  );
297  expected_eccentricity_rate[e_index] = (
298  test_e
299  *
300  rate_factor / 4.0
301  *
303  orbital_frequency_multiplier,
304  spin_frequency_multiplier
305  )
306  );
307  predicted_semimajor_rate[e_index] = evolution_rates[0];
308  predicted_eccentricity_rate[e_index] =
309  evolution_rates[1];
310  }
311 /* output_rates(eccentricities,
312  expected_semimajor_rate,
313  predicted_semimajor_rate,
314  expected_eccentricity_rate,
315  predicted_eccentricity_rate);*/
316  std::ostringstream message;
317  message << "orbital freq. mult. = "
318  << orbital_frequency_multiplier
319  << ", spin freq. mult. = "
320  << spin_frequency_multiplier
321  << " for a = " << semimajor
322  << ", W* = " << primary_spin_frequency;
324  eccentricities,
325  expected_semimajor_rate,
326  predicted_semimajor_rate,
327  2,
328  4,
329  (
330  "Checking semimajor rate against Zahn (1977)"
331  +
332  message.str()
333  )
334  );
336  eccentricities,
337  expected_eccentricity_rate,
338  predicted_eccentricity_rate,
339  2,
340  20,
341  (
342  "Checking eccentricity rate against Zahn (1977)"
343  +
344  message.str()
345  )
346  );
347  }
348  }
349  }
350  }
351  }
352 
354  {
355  const double MAX_ECCENTRICITY = 0.9;
356  const unsigned NUM_ECCENTRICITIES = 100;
357  const double ECCENTRICITY_STEP = (
358  MAX_ECCENTRICITY / (NUM_ECCENTRICITIES - 1)
359  );
360  const double a = 10.0;
361  const double age = 1.0;
362 
364  StellarEvolution::make_no_evolution();
365 
367  *no_evol,
368  1.0,
369  1.0,
370  1.0,
371  1.0
372  );
373 
374  Planet::Planet planet(1.0, 1.0);
375 
376  BinarySystem binary(*star, planet);
377 
378  std::valarray<double> parameters(0.0, 10),
379  rough_rates(parameters.size()),
380  fine_rates(parameters.size()),
381  rate_errors(parameters.size());
382 
383  parameters[0] = a;
384 
385  binary.configure(true,
386  (MIN_AGE + MAX_AGE) / 2.0,
387  &(parameters[0]),
388  Core::BINARY);
389  star->detect_saturation();
390 
391  std::cout << std::setw(25) << "e_order"
392  << std::setw(25) << "e"
393  << std::setw(25) << "rough_a_rate"
394  << std::setw(25) << "fine_a_rate"
395  << std::setw(25) << "a_rate_error"
396  << std::setw(25) << "rough_e_rate"
397  << std::setw(25) << "fine_e_rate"
398  << std::setw(25) << "e_rate_error"
399  << std::setw(25) << "rough_inc_rate"
400  << std::setw(25) << "fine_inc_rate"
401  << std::setw(25) << "inc_rate_error"
402  << std::setw(25) << "rough_spin_rate"
403  << std::setw(25) << "fine_spin_rate"
404  << std::setw(25) << "spin_rate_error"
405 
406  << std::endl;
407 
408 
409  for(unsigned e_order = 5; e_order <= 100; e_order+=5) {
410  for(double e = 0.0; e <= MAX_ECCENTRICITY; e += ECCENTRICITY_STEP) {
411  parameters[1] = e;
412 
413  star->zone(0).change_e_order(e_order, binary, true, 0);
414  binary.differential_equations(age,
415  &(parameters[0]),
416  Core::BINARY,
417  &(rough_rates[0]));
418  binary.differential_equations(age,
419  &(parameters[0]),
420  Core::BINARY,
421  &(rate_errors[0]),
422  true);
423 
424  star->zone(0).change_e_order(2 * e_order, binary, true, 0);
425  binary.differential_equations(age,
426  &(parameters[0]),
427  Core::BINARY,
428  &(fine_rates[0]));
429 
430  std::cout << std::setw(25) << e_order
431  << std::setw(25) << e
432  << std::setw(25) << rough_rates[0]
433  << std::setw(25) << fine_rates[0]
434  << std::setw(25) << rate_errors[0]
435  << std::setw(25) << rough_rates[1]
436  << std::setw(25) << fine_rates[1]
437  << std::setw(25) << rate_errors[1]
438  << std::setw(25) << rough_rates[2]
439  << std::setw(25) << fine_rates[2]
440  << std::setw(25) << rate_errors[2]
441  << std::setw(25) << rough_rates[7]
442  << std::setw(25) << fine_rates[7]
443  << std::setw(25) << rate_errors[7]
444  << std::endl;
445  }
446  }
447 
448  delete star;
449  delete no_evol;
450  }
451 
452 } //End Envolve namespace.
Implements a StellarEvolution based on polynomial evolution quantities.
const double MIN_AGE
Most tests start at this age in Gyr.
Definition: Common.h:54
int differential_equations(double age, const double *parameters, Core::EvolModeType evolution_mode, double *differential_equations, bool expansion_error=false)
The differential equation and jacobian for the evolution of the system.
void detect_saturation()
Sets the saturation based on the currently configured spin frequency.
A skumanich wind body with a single zone dissipative to only a single tidal term. ...
double zahn77_semimajor_rate_coef(int orbital_frequency_multiplier, int spin_frequency_multiplier, double eccentricity) const
The Zahn (1977) coefficient for the semimajor evolution rate that corresponds to the given tidal term...
void test_aligned_equations()
Test the a & e differential equations for aligned orbit.
Single zone non-evolving planets with huge dissipation, so they always remain locked to the disk...
Definition: Planet.h:21
Evolve::DissipatingZone & zone(unsigned zone_index)
See Evolve::DissipatingBody::zone().
Definition: EvolvingStar.h:85
const double MAX_AGE
Most tests end at this age in Gyr.
Definition: Common.h:57
Orientations of zones of bodies in a binary system.
double mass() const
The mass of the body (constant with age).
const double solar_radius
Radius of the sun [m].
void check_agreement(const alglib::real_1d_array &x, const alglib::real_1d_array &y1, const alglib::real_1d_array &y2, unsigned agreement_order, unsigned max_order, const std::string &description)
Check if two given dependencies on x agree up to a given order in x.
const double Gyr
Gyr [s].
const double solar_mass
Mass of the sun [kg].
double zahn77_eccentricity_rate_coef(int orbital_frequency_multiplier, int spin_frequency_multiplier) const
Same as zahn77_semimajor_rate_coef() but for the eccentricity evolution.
Unit tests that check the differential equations for eccentricity and semimajor against analytic expr...
void test_error_estimate()
Test the error estimate of the differential equations.
virtual void change_e_order(unsigned new_e_order)
Change the eccentricity expansion order for all dissipative zones.
virtual void change_e_order(unsigned new_e_order, BinarySystem &system, bool primary, unsigned zone_index)
Changes the order of the eccentricity expansion performed.
Star::InterpolatedEvolutionStar * make_const_lag_star(const StellarEvolution::Interpolator &evolution, double wind_strength, double wind_sat_freq, double coupling_timescale, double phase_lag)
Create a star with the given parameters with a constant phase lag.
Definition: MakeStar.cpp:10
virtual int configure(bool initialize, double age, double semimajor, double eccentricity, const double *spin_angmom, const double *inclination, const double *periapsis, Core::EvolModeType evolution_mode)
Sets the current state of the system.
Describes a system of two bodies orbiting each other.
Definition: BinarySystem.h:56
void output_rates(const alglib::real_1d_array &eccentricities, const alglib::real_1d_array &expected_semimajor_rate, const alglib::real_1d_array &predicted_semimajor_rate, const alglib::real_1d_array &expected_eccentricity_rate, const alglib::real_1d_array &predicted_eccentricity_rate) const
Output the predicted/expected semiamjor and eccentricity evolution rates to stdout.
const double G
Gravitational constant in SI.