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
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" 28 e_index < eccentricities.length();
31 std::cout << std::setw(25) << eccentricities[e_index]
33 << predicted_semimajor_rate[e_index]
35 << expected_semimajor_rate[e_index]
37 << predicted_eccentricity_rate[e_index]
39 << expected_eccentricity_rate[e_index]
47 int orbital_frequency_multiplier,
48 int spin_frequency_multiplier,
53 double e2 = std::pow(eccentricity, 2);
55 if(orbital_frequency_multiplier == 2 && spin_frequency_multiplier == 2)
56 return 1.0 - 5.0 * e2;
58 if(orbital_frequency_multiplier == 1 && spin_frequency_multiplier == 0)
59 return 3.0 / 4.0 * e2;
61 if(orbital_frequency_multiplier == 1 && spin_frequency_multiplier == 2)
62 return 1.0 / 8.0 * e2;
64 if(orbital_frequency_multiplier == 3 && spin_frequency_multiplier == 2)
65 return 147.0 / 8.0 * e2;
71 int orbital_frequency_multiplier,
72 int spin_frequency_multiplier
76 if(orbital_frequency_multiplier == 2 && spin_frequency_multiplier == 2)
79 if(orbital_frequency_multiplier == 1 && spin_frequency_multiplier == 0)
82 if(orbital_frequency_multiplier == 1 && spin_frequency_multiplier == 2)
85 if(orbital_frequency_multiplier == 3 && spin_frequency_multiplier == 2)
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,
97 const std::string &description
100 alglib::real_1d_array difference;
101 difference.setlength(x.length());
102 double min_difference = Core::Inf,
103 max_difference = -Core::Inf,
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]));
113 std::max(std::abs(max_difference), std::abs(min_difference))
118 alglib::ae_int_t fit_info;
119 alglib::barycentricinterpolant interp;
120 alglib::polynomialfitreport fit_report;
121 alglib::polynomialfit(x,
128 double max_allowed_residual = 1e-12 * (max_difference - min_difference);
130 std::ostringstream message;
131 message << description
132 <<
" too large residual from fit to difference: " 133 << fit_report.maxerror
135 << max_allowed_residual;
137 TEST_ASSERT_MSG(fit_report.maxerror <= max_allowed_residual,
138 message.str().c_str());
140 alglib::real_1d_array coefficients;
142 alglib::polynomialbar2pow(interp, coefficients);
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(
149 std::abs(coefficients[power]) * std::pow(max_abs_x, power)
151 max_allowed_term *= 1e-8;
153 for(
unsigned power = 0; power <= agreement_order; ++power) {
154 double max_abs_term_value = (std::abs(coefficients[power])
156 std::pow(max_abs_x, power));
158 message << description
159 <<
" x^" << power <<
" coefficient too large: |" 160 << coefficients[power]
162 << max_abs_x <<
"^" << power
164 << max_abs_term_value
168 TEST_ASSERT_MSG(max_abs_term_value <= max_allowed_term,
169 message.str().c_str());
181 const double MAX_ECCENTRICITY = 0.5;
182 const unsigned NUM_ECCENTRICITIES = 100;
183 const double ECCENTRICITY_STEP = (
184 MAX_ECCENTRICITY / (NUM_ECCENTRICITIES - 1)
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);
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]
204 std::valarray<double> one_poly(1.0, 1);
206 int orbital_frequency_multiplier = 0;
207 orbital_frequency_multiplier <= 4;
208 ++orbital_frequency_multiplier
211 int spin_frequency_multiplier = 0;
212 spin_frequency_multiplier <= 4;
213 ++spin_frequency_multiplier
217 orbital_frequency_multiplier,
218 spin_frequency_multiplier,
229 std::valarray<double> parameters(0.0, 7);
230 std::valarray<double> evolution_rates(parameters.size());
231 parameters[0] = 10.0;
238 double common_rate_factor = (
250 for(
double semimajor = 2.0; semimajor <= 10.0; semimajor += 1.0) {
252 double mean_motion = std::sqrt(
261 double rate_factor = (
264 (mean_motion * std::pow(semimajor, 8))
267 double primary_spin_frequency = 0.0;
268 primary_spin_frequency <= 5.0 * mean_motion;
269 primary_spin_frequency += 0.2 * mean_motion
273 unsigned e_index = 0;
274 e_index < NUM_ECCENTRICITIES;
279 test_e = eccentricities[e_index];
280 parameters[0] = std::pow(semimajor, 6.5);
281 parameters[1] = test_e;
285 &(evolution_rates[0]));
286 expected_semimajor_rate[e_index] = (
287 6.5 * std::pow(semimajor, 6.5)
292 orbital_frequency_multiplier,
293 spin_frequency_multiplier,
297 expected_eccentricity_rate[e_index] = (
303 orbital_frequency_multiplier,
304 spin_frequency_multiplier
307 predicted_semimajor_rate[e_index] = evolution_rates[0];
308 predicted_eccentricity_rate[e_index] =
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;
325 expected_semimajor_rate,
326 predicted_semimajor_rate,
330 "Checking semimajor rate against Zahn (1977)" 337 expected_eccentricity_rate,
338 predicted_eccentricity_rate,
342 "Checking eccentricity rate against Zahn (1977)" 355 const double MAX_ECCENTRICITY = 0.9;
356 const unsigned NUM_ECCENTRICITIES = 100;
357 const double ECCENTRICITY_STEP = (
358 MAX_ECCENTRICITY / (NUM_ECCENTRICITIES - 1)
360 const double a = 10.0;
361 const double age = 1.0;
364 StellarEvolution::make_no_evolution();
378 std::valarray<double> parameters(0.0, 10),
379 rough_rates(parameters.size()),
380 fine_rates(parameters.size()),
381 rate_errors(parameters.size());
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" 409 for(
unsigned e_order = 5; e_order <= 100; e_order+=5) {
410 for(
double e = 0.0; e <= MAX_ECCENTRICITY; e += ECCENTRICITY_STEP) {
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]
Implements a StellarEvolution based on polynomial evolution quantities.
const double MIN_AGE
Most tests start at this age in Gyr.
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.
test_DifferentialEquations()
Create the test suite.
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...
Evolve::DissipatingZone & zone(unsigned zone_index)
See Evolve::DissipatingBody::zone().
const double MAX_AGE
Most tests end at this age in Gyr.
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 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.
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.
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.