Program Listing for File testDifferentialEquations.cpp¶
↰ Return to documentation for file (/home/kpenev/projects/git/poet/poet_src/unit_tests/testEvolve/testDifferentialEquations.cpp)
#include "testDifferentialEquations.h"
namespace Evolve {
void test_DifferentialEquations::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
{
std::cout << std::setw(25) << "eccentricity"
<< std::setw(25) << "semimajor_rate"
<< std::setw(25) << "expected_semimajor_rate"
<< std::setw(25) << "eccentricity_rate"
<< std::setw(25) << "expected_ecc_rate"
<< std::endl;
for(
unsigned e_index = 0;
e_index < eccentricities.length();
++e_index
) {
std::cout << std::setw(25) << eccentricities[e_index]
<< std::setw(25)
<< predicted_semimajor_rate[e_index]
<< std::setw(25)
<< expected_semimajor_rate[e_index]
<< std::setw(25)
<< predicted_eccentricity_rate[e_index]
<< std::setw(25)
<< expected_eccentricity_rate[e_index]
<< std::endl;
}
}
double test_DifferentialEquations::zahn77_semimajor_rate_coef(
int orbital_frequency_multiplier,
int spin_frequency_multiplier,
double eccentricity
) const
{
double e2 = std::pow(eccentricity, 2);
if(orbital_frequency_multiplier == 2 && spin_frequency_multiplier == 2)
return 1.0 - 5.0 * e2;
if(orbital_frequency_multiplier == 1 && spin_frequency_multiplier == 0)
return 3.0 / 4.0 * e2;
if(orbital_frequency_multiplier == 1 && spin_frequency_multiplier == 2)
return 1.0 / 8.0 * e2;
if(orbital_frequency_multiplier == 3 && spin_frequency_multiplier == 2)
return 147.0 / 8.0 * e2;
return 0.0;
}
double test_DifferentialEquations::zahn77_eccentricity_rate_coef(
int orbital_frequency_multiplier,
int spin_frequency_multiplier
) const
{
if(orbital_frequency_multiplier == 2 && spin_frequency_multiplier == 2)
return -1.0;
if(orbital_frequency_multiplier == 1 && spin_frequency_multiplier == 0)
return 1.5;
if(orbital_frequency_multiplier == 1 && spin_frequency_multiplier == 2)
return -1.0 / 4.0;
if(orbital_frequency_multiplier == 3 && spin_frequency_multiplier == 2)
return 49.0 / 4.0;
return 0.0;
}
void test_DifferentialEquations::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
)
{
alglib::real_1d_array difference;
difference.setlength(x.length());
double min_difference = Core::Inf,
max_difference = -Core::Inf,
y_scale = 0;
for(unsigned i = 0; i < x.length(); ++i) {
difference[i] = y2[i] - y1[i];
min_difference = std::min(difference[i], min_difference);
max_difference = std::max(difference[i], max_difference);
y_scale = std::max(std::abs(y1[i]), std::abs(y2[i]));
}
if(
std::max(std::abs(max_difference), std::abs(min_difference))
<
1e-13 * y_scale
)
return;
alglib::ae_int_t fit_info;
alglib::barycentricinterpolant interp;
alglib::polynomialfitreport fit_report;
alglib::polynomialfit(x,
difference,
max_order + 1,
fit_info,
interp,
fit_report);
double max_allowed_residual = 1e-12 * (max_difference - min_difference);
std::ostringstream message;
message << description
<< " too large residual from fit to difference: "
<< fit_report.maxerror
<< " > "
<< max_allowed_residual;
TEST_ASSERT_MSG(fit_report.maxerror <= max_allowed_residual,
message.str().c_str());
alglib::real_1d_array coefficients;
alglib::polynomialbar2pow(interp, coefficients);
double max_allowed_term = 0.0,
max_abs_x = std::max(std::abs(x[0]), x[x.length() - 1]);
for(unsigned power = 0; power < coefficients.length(); ++power)
max_allowed_term = std::max(
max_allowed_term,
std::abs(coefficients[power]) * std::pow(max_abs_x, power)
);
max_allowed_term *= 1e-8;
for(unsigned power = 0; power <= agreement_order; ++power) {
double max_abs_term_value = (std::abs(coefficients[power])
*
std::pow(max_abs_x, power));
message.str("");
message << description
<< " x^" << power << " coefficient too large: |"
<< coefficients[power]
<< " * "
<< max_abs_x << "^" << power
<< "| = "
<< max_abs_term_value
<< " > "
<< max_allowed_term;
TEST_ASSERT_MSG(max_abs_term_value <= max_allowed_term,
message.str().c_str());
}
}
test_DifferentialEquations::test_DifferentialEquations()
{
TEST_ADD(test_DifferentialEquations::test_aligned_equations);
TEST_ADD(test_DifferentialEquations::test_error_estimate);
}
void test_DifferentialEquations::test_aligned_equations()
{
const double MAX_ECCENTRICITY = 0.5;
const unsigned NUM_ECCENTRICITIES = 100;
const double ECCENTRICITY_STEP = (
MAX_ECCENTRICITY / (NUM_ECCENTRICITIES - 1)
);
alglib::real_1d_array eccentricities,
expected_semimajor_rate,
predicted_semimajor_rate,
expected_eccentricity_rate,
predicted_eccentricity_rate;
eccentricities.setlength(NUM_ECCENTRICITIES);
expected_semimajor_rate.setlength(NUM_ECCENTRICITIES);
predicted_semimajor_rate.setlength(NUM_ECCENTRICITIES);
expected_eccentricity_rate.setlength(NUM_ECCENTRICITIES);
predicted_eccentricity_rate.setlength(NUM_ECCENTRICITIES);
eccentricities[0] = 0.0;
for(unsigned e_index = 1; e_index < NUM_ECCENTRICITIES; ++e_index)
eccentricities[e_index] = (eccentricities[e_index - 1]
+
ECCENTRICITY_STEP);
std::valarray<double> one_poly(1.0, 1);
for(
int orbital_frequency_multiplier = 0;
orbital_frequency_multiplier <= 4;
++orbital_frequency_multiplier
) {
for(
int spin_frequency_multiplier = 0;
spin_frequency_multiplier <= 4;
++spin_frequency_multiplier
) {
SingleTidalTermBody primary(0.0,
1.0,
orbital_frequency_multiplier,
spin_frequency_multiplier,
1.0,
one_poly,
one_poly,
one_poly);
Planet::Planet secondary(1.0, 1.0);
BinarySystem binary(primary, secondary);
binary.change_e_order(2);
std::valarray<double> parameters(0.0, 7);
std::valarray<double> evolution_rates(parameters.size());
parameters[0] = 10.0;
parameters[1] = 0.0;
binary.configure(true,
0.0,
&(parameters[0]),
Core::BINARY);
double common_rate_factor = (
-2.4 * M_PI
*
(primary.mass() + secondary.mass()) / primary.mass()
*
Core::AstroConst::G
*
Core::AstroConst::solar_mass * secondary.mass()
/
std::pow(Core::AstroConst::solar_radius, 3)
) * Core::AstroConst::Gyr;
for(double semimajor = 2.0; semimajor <= 10.0; semimajor += 1.0) {
double mean_motion = std::sqrt(
Core::AstroConst::G * Core::AstroConst::solar_mass * (
primary.mass()
+
secondary.mass()
)
/
std::pow(semimajor * Core::AstroConst::solar_radius, 3)
);
double rate_factor = (
common_rate_factor
/
(mean_motion * std::pow(semimajor, 8))
);
for(
double primary_spin_frequency = 0.0;
primary_spin_frequency <= 5.0 * mean_motion;
primary_spin_frequency += 0.2 * mean_motion
) {
for(
unsigned e_index = 0;
e_index < NUM_ECCENTRICITIES;
++e_index
)
{
double age = 1.0,
test_e = eccentricities[e_index];
parameters[0] = std::pow(semimajor, 6.5);
parameters[1] = test_e;
binary.differential_equations(age,
&(parameters[0]),
Core::BINARY,
&(evolution_rates[0]));
expected_semimajor_rate[e_index] = (
6.5 * std::pow(semimajor, 6.5)
*
rate_factor
*
zahn77_semimajor_rate_coef(
orbital_frequency_multiplier,
spin_frequency_multiplier,
test_e
)
);
expected_eccentricity_rate[e_index] = (
test_e
*
rate_factor / 4.0
*
zahn77_eccentricity_rate_coef(
orbital_frequency_multiplier,
spin_frequency_multiplier
)
);
predicted_semimajor_rate[e_index] = evolution_rates[0];
predicted_eccentricity_rate[e_index] =
evolution_rates[1];
}
/* output_rates(eccentricities,
expected_semimajor_rate,
predicted_semimajor_rate,
expected_eccentricity_rate,
predicted_eccentricity_rate);*/
std::ostringstream message;
message << "orbital freq. mult. = "
<< orbital_frequency_multiplier
<< ", spin freq. mult. = "
<< spin_frequency_multiplier
<< " for a = " << semimajor
<< ", W* = " << primary_spin_frequency;
check_agreement(
eccentricities,
expected_semimajor_rate,
predicted_semimajor_rate,
2,
4,
(
"Checking semimajor rate against Zahn (1977)"
+
message.str()
)
);
check_agreement(
eccentricities,
expected_eccentricity_rate,
predicted_eccentricity_rate,
2,
20,
(
"Checking eccentricity rate against Zahn (1977)"
+
message.str()
)
);
}
}
}
}
}
void test_DifferentialEquations::test_error_estimate()
{
const double MAX_ECCENTRICITY = 0.9;
const unsigned NUM_ECCENTRICITIES = 100;
const double ECCENTRICITY_STEP = (
MAX_ECCENTRICITY / (NUM_ECCENTRICITIES - 1)
);
const double a = 10.0;
const double age = 1.0;
StellarEvolution::MockStellarEvolution *no_evol =
StellarEvolution::make_no_evolution();
Star::InterpolatedEvolutionStar *star = make_const_lag_star(
*no_evol,
1.0,
1.0,
1.0,
1.0
);
Planet::Planet planet(1.0, 1.0);
BinarySystem binary(*star, planet);
std::valarray<double> parameters(0.0, 10),
rough_rates(parameters.size()),
fine_rates(parameters.size()),
rate_errors(parameters.size());
parameters[0] = a;
binary.configure(true,
(MIN_AGE + MAX_AGE) / 2.0,
&(parameters[0]),
Core::BINARY);
star->detect_saturation();
std::cout << std::setw(25) << "e_order"
<< std::setw(25) << "e"
<< std::setw(25) << "rough_a_rate"
<< std::setw(25) << "fine_a_rate"
<< std::setw(25) << "a_rate_error"
<< std::setw(25) << "rough_e_rate"
<< std::setw(25) << "fine_e_rate"
<< std::setw(25) << "e_rate_error"
<< std::setw(25) << "rough_inc_rate"
<< std::setw(25) << "fine_inc_rate"
<< std::setw(25) << "inc_rate_error"
<< std::setw(25) << "rough_spin_rate"
<< std::setw(25) << "fine_spin_rate"
<< std::setw(25) << "spin_rate_error"
<< std::endl;
for(unsigned e_order = 5; e_order <= 100; e_order+=5) {
for(double e = 0.0; e <= MAX_ECCENTRICITY; e += ECCENTRICITY_STEP) {
parameters[1] = e;
star->zone(0).change_e_order(e_order, binary, true, 0);
binary.differential_equations(age,
&(parameters[0]),
Core::BINARY,
&(rough_rates[0]));
binary.differential_equations(age,
&(parameters[0]),
Core::BINARY,
&(rate_errors[0]),
true);
star->zone(0).change_e_order(2 * e_order, binary, true, 0);
binary.differential_equations(age,
&(parameters[0]),
Core::BINARY,
&(fine_rates[0]));
std::cout << std::setw(25) << e_order
<< std::setw(25) << e
<< std::setw(25) << rough_rates[0]
<< std::setw(25) << fine_rates[0]
<< std::setw(25) << rate_errors[0]
<< std::setw(25) << rough_rates[1]
<< std::setw(25) << fine_rates[1]
<< std::setw(25) << rate_errors[1]
<< std::setw(25) << rough_rates[2]
<< std::setw(25) << fine_rates[2]
<< std::setw(25) << rate_errors[2]
<< std::setw(25) << rough_rates[7]
<< std::setw(25) << fine_rates[7]
<< std::setw(25) << rate_errors[7]
<< std::endl;
}
}
delete star;
delete no_evol;
}
} //End Envolve namespace.