Program Listing for File PolynomialEvolution.cpp¶
↰ Return to documentation for file (/home/kpenev/projects/git/poet/poet_src/unit_tests/shared/PolynomialEvolution.cpp)
#include "PolynomialEvolution.h"
namespace StellarEvolution {
double PolynomialEvolutionQuantity::order(unsigned deriv_order) const
{
if(__deriv_x < __xmin || __deriv_x > __xmax) {
std::ostringstream msg;
msg << ("Attempt to evaluate a PolynomialEvolutionQuantity "
"defined over ")
<< __xmin << " < x < " << __xmax << " at x=" << __deriv_x
<< ", polynomial coefficients:" << __poly_coef;
std::cout << msg.str() << std::endl;
// *static_cast<int*>(NULL) = 0;
throw Core::Error::Runtime(msg.str());
}
double xn = 1, result = 0;
for(size_t n = deriv_order; n < __poly_coef.size(); ++n) {
double coef_mod = 1;
for(size_t i = 0; i < deriv_order; ++i) coef_mod *= (n-i);
result += coef_mod * __poly_coef[n] * xn;
xn *= __deriv_x;
}
return result;
}
MockStellarEvolution::MockStellarEvolution(
double core_formation_age,
const std::valarray< std::valarray<double> > &R,
const std::valarray< std::valarray<double> > &Iconv,
const std::valarray< std::valarray<double> > &Irad,
const std::valarray< std::valarray<double> > &Rcore,
const std::valarray< std::valarray<double> > &Mcore,
const std::valarray< std::valarray<double> > &Lum
) :
__R(R),
__Iconv(Iconv),
__Irad(Irad),
__Rcore(Rcore),
__Mcore(Mcore),
__Lum(Lum),
__core_formation_age(core_formation_age)
{
if(std::isnan(__core_formation_age))
__core_formation_age = rand_value(MIN_AGE, 2.1);
if(__R.size() == 0) rand_poly_coef(__R);
if(__Iconv.size()==0) rand_poly_coef(__Iconv);
if(__Irad.size()==0) rand_poly_coef(__Irad);
if(__Rcore.size()==0) rand_poly_coef(__Rcore);
if(__Mcore.size()==0) rand_poly_coef(__Mcore);
if(__Lum.size()==0) rand_poly_coef(__Lum);
if(core_formation_age > 0) {
__Irad[0] = 0;
__Rcore[0] = 0;
__Mcore[0] = 0;
__Irad = offset_age(Irad, core_formation_age);
__Rcore = offset_age(Rcore, core_formation_age);
__Mcore = offset_age(Mcore, core_formation_age);
}
__Menv.resize(
__Mcore.size(),
std::valarray<double>(0.0,
std::max(__Mcore[0].size(), size_t(2)))
);
__Itot.resize(__Iconv.size(),
std::valarray<double>(__Iconv[0].size()));
__Itot = __Iconv + __Irad;
for(size_t mass_i = 0; mass_i < __Mcore.size(); ++mass_i)
for(size_t age_i = 0; age_i < __Mcore[mass_i].size(); ++age_i)
__Menv[mass_i][age_i] = -__Mcore[mass_i][age_i];
__Menv[0][1] += 1;
}
EvolvingStellarQuantity *MockStellarEvolution::operator()(
QuantityID quantity,
double mass,
double
) const
{
switch(quantity) {
case RADIUS: return exact_track(__R, mass);
case ICONV: return exact_track(__Iconv, mass);
case LUM: return exact_track(__Lum, mass);
case IRAD: return exact_track(__Irad, mass);
case MRAD: return exact_track(__Mcore, mass);
case RRAD: return exact_track(__Rcore, mass);
default: throw Core::Error::BadFunctionArguments(
"Unknown quantity ID"
);
};
}
MockStellarEvolution *make_no_evolution(double Rstar, double Iconv)
{
return new StellarEvolution::MockStellarEvolution(
0.0,
std::valarray< std::valarray<double> >(//R
std::valarray<double>(Rstar, 1),
1
),
std::valarray< std::valarray<double> >(//Iconv
std::valarray<double>(Iconv, 1),
1
),
std::valarray< std::valarray<double> >(//Irad
std::valarray<double>(1.0, 1),
1
),
std::valarray< std::valarray<double> >(//Rcore
std::valarray<double>(1.0, 1),
1
),
std::valarray< std::valarray<double> >(//Mcore
std::valarray<double>(1.0, 1),
1
),
std::valarray< std::valarray<double> >(//Lum
std::valarray<double>(1.0, 1),
1
)
);
}
MockStellarEvolution *make_linear_I_evolution()
{
return new StellarEvolution::MockStellarEvolution(
0.0,
std::valarray< std::valarray<double> >(//R
std::valarray<double>(1.0, 1),
1
),
std::valarray< std::valarray<double> >(//Iconv
std::valarray<double>(1.0, 1),
2
),
std::valarray< std::valarray<double> >(//Irad
std::valarray<double>(1.0, 1),
2
),
std::valarray< std::valarray<double> >(//Rcore
std::valarray<double>(1.0, 1),
1
),
std::valarray< std::valarray<double> >(//Mcore
std::valarray<double>(1.0, 1),
1
),
std::valarray< std::valarray<double> >(//Lum
std::valarray<double>(1.0, 1),
1
)
);
}
}//End StellarEvolution namespace.
#if 0
StarData::StarData() :
num_stars_created(0),
Lrad_track(NULL),
Lconv_track(NULL),
evolution_masses(100),
evolution_ages(100),
r_coef(rand_poly_coef()),
Iconv_coef(rand_poly_coef()),
Irad_coef(rand_poly_coef()),
Mrad_coef(rand_poly_coef()),
Rcore_coef(rand_poly_coef())
{
for (size_t age_ind=0; age_ind < evolution_ages.size(); age_ind++) {
evolution_ages[age_ind] = (
MIN_AGE
+
age_ind * (max_age - MIN_AGE) / evolution_ages.size()
);
}
for (
size_t mass_ind = 0;
mass_ind < evolution_masses.size();
++mass_ind
) {
evolution_masses[mass_ind] = (
min_stellar_mass
+
mass_ind
*
(max_stellar_mass - min_stellar_mass)
/
evolution_masses.size()
);
}
}
StarData::~StarData()
{
if(Lrad_track) delete Lrad_track;
if(Lconv_track) delete Lconv_track;
}
void StarData::create_random_star(Star::InterpolatedEvolutionStar **star)
{
mass = rand_value(min_stellar_mass, max_stellar_mass);
feh = rand_value(-1.0, 0.5);
age = rand_value(MIN_AGE, 2.1);
radius = (rand_value(0.9, 1.1)) * eval_poly(r_coef, mass, age);
conv_spin = rand_value(0.0, 1.0);
rad_spin = rand_value(0.0, 1.0);
tidal_Q = std::pow(10.0, rand_value(5.0,10.0));
wind_strength = rand_value(0.0, 1.0);
wind_sat_freq = rand_value(0.0, 1.0);
disk_lock_w = rand_value(0.0, wind_sat_freq);
disk_lock_time = evolution_ages[rand_value(0, evolution_ages.size()-1)];
coupling_timescale = rand_value(0.0, 1.0);
Q_trans_width = 0;
MockStellarEvolution evol(Core::NaN,
r_coef,
Iconv_coef,
Irad_coef,
Rcore_coef,
Mcore_coef);
(*star) = new Star(mass,
feh,
wind_strength,
wind_sat_freq,
coupling_timescale,
evol);
Lconv_track=exact_track(rand_poly_coef(), mass);
Lrad_track=exact_track(rand_poly_coef(), mass);
Lconv.resize(evolution_ages.size());
Lconv = tabulate_track(Lconv_track, evolution_ages);
Lrad.resize(evolution_ages.size());
Lrad = tabulate_track(Lrad_track, evolution_ages);
Iconv.resize(evolution_ages.size());
Iconv = tabulate_track(exact_track(Iconv_coef, mass), evolution_ages);
std::valarray<double> Itot =
tabulate_track(exact_track(Itot_coef, mass), evolution_ages);
std::list<double> Irad_list;
for (size_t i=0; i < evolution_ages.size(); i++)
Irad_list.push_back(Itot[i]-Iconv[i]);
Irad = list_to_valarray(Irad_list);
Mrad_deriv = tabulate_track(exact_track(Mrad_coef, mass),
evolution_ages, 1);
Lconv_deriv = tabulate_track(Lconv_track, evolution_ages, 1);
Lrad_deriv = tabulate_track(Lrad_track, evolution_ages, 1);
Rrad = tabulate_track(exact_track(Rcore_coef, mass), evolution_ages);
all_radii = tabulate_track(exact_track(r_coef, mass), evolution_ages);
std::valarray<double> fake_derivs;
(*star)->set_angular_momentum_evolution(evolution_ages,
tabulate_track(Lrad_track, evolution_ages),
tabulate_track(Lrad_track, evolution_ages, 1), radiative);
(*star)->set_angular_momentum_evolution(evolution_ages,
tabulate_track(Lconv_track, evolution_ages),
tabulate_track(Lconv_track, evolution_ages, 1), convective);
num_stars_created++;
}
void PlanetData::create_random_planet(Planet** planet)
{
mass = rand_value(min_planet_mass, max_planet_mass);
radius = rand_value(min_planet_radius, max_planet_radius);
std::list<double> semis;
std::list<double> ages;
for (double age=0; age < 3; age += 0.1) {
ages.push_back(age);
semis.push_back(get_semi(age));
}
this->ages.resize(ages.size());
this->ages = list_to_valarray(ages);
this->semis.resize(semis.size());
this->semis = list_to_valarray(semis);
std::valarray<double> fakeDerivs;
double curr_semi = get_semi(star->age());
(*planet) = new Planet(*star, mass, radius, curr_semi);
(*planet)->set_semimajor_evolution(this->ages,
this->semis, fakeDerivs);
}
double PlanetData::get_semi(double age)
{
return (-age*age*age + 1.5*age*age + 2*age + 3)/50;
}
PlanetData::~PlanetData()
{
delete sdata;
if(star) delete star;
}
std::ostream &operator<<(std::ostream &os,
const PolynomialEvolutionTrack &track)
{
for(size_t p=0; p<track.poly_coef.size(); p++) {
os << track.poly_coef[p];
if(p) os << "x";
if(p>1) os << "^" << p;
if(p<track.poly_coef.size()-1) os << " + ";
}
os << ", " << track.xmin << " < x < " << track.xmax;
return os;
}
#endif
namespace StellarEvolution {
PolynomialEvolutionQuantity *exact_track(
const std::valarray< std::valarray<double> > &poly_coef,
double mass,
double low_mass_age_scaling,
double high_mass_age_scaling,
double scale_mass
)
{
if(std::isnan(scale_mass)) scale_mass=mass;
std::valarray<double> age_poly_coeff(poly_coef.size());
double age_scaling=(mass <= MAX_LOW_MASS ? low_mass_age_scaling
: high_mass_age_scaling);
for(size_t age_i = 0; age_i < poly_coef.size(); ++age_i) {
double mass_pow=1.0;
age_poly_coeff[age_i]=0.0;
for(size_t mass_i=0; mass_i<poly_coef[age_i].size(); mass_i++) {
age_poly_coeff[age_i]+=mass_pow*poly_coef[age_i][mass_i];
mass_pow*=mass;
}
age_poly_coeff[age_i]*=std::pow(scale_mass, age_scaling*age_i);
}
return new PolynomialEvolutionQuantity(
age_poly_coeff,
MIN_AGE,
std::numeric_limits<double>::max()
);
}
}//End StellarEvolution namespace.
#if 0
double eval_poly(const std::valarray< std::valarray<double> > &poly_coef,
double mass, double age, double low_mass_age_scaling,
double high_mass_age_scaling, double scale_mass)
{
if(std::isnan(scale_mass)) scale_mass=mass;
double age_scaling=(mass<=max_low_mass ? low_mass_age_scaling :
high_mass_age_scaling), result=0.0, age_pow=1.0;
for(size_t age_i=0; age_i<poly_coef.size(); age_i++) {
double mass_pow=1.0, mass_result=0.0;
for(size_t mass_i=0; mass_i<poly_coef[age_i].size(); mass_i++) {
mass_result+=mass_pow*poly_coef[age_i][mass_i];
mass_pow*=mass;
}
result+=mass_result*age_pow*std::pow(scale_mass, age_scaling*age_i);
age_pow*=age;
}
return result;
}
std::valarray<double> tabulate_track(PolynomialEvolutionQuantity *track,
std::valarray<double> ages, unsigned deriv_order)
{
std::valarray<double> data(ages.size());
for(unsigned a=0; a<ages.size(); a++) {
(*track)(ages[a]);
data[a]=track->order(deriv_order);
}
return data;
}
PolynomialStellarEvolution::PolynomialStellarEvolution(
const std::valarray<double> &masses,
const std::valarray<double> &ages,
const std::valarray< std::valarray<double> > &r_coef,
const std::valarray< std::valarray<double> > &Iconv_coef,
const std::valarray< std::valarray<double> > &Itot_coef,
const std::valarray< std::valarray<double> > &Mrad_coef,
const std::valarray< std::valarray<double> > &Rcore_coef,
double low_mass_age_scaling, double high_mass_age_scaling)
{
std::list< std::valarray<double> > r_data, Iconv_data, Irad_data,
Mrad_data, Rcore_data;
PolynomialEvolutionQuantity *track;
for(unsigned i=0; i<masses.size(); i++) {
track=exact_track(r_coef, masses[i], low_mass_age_scaling,
high_mass_age_scaling);
r_data.push_back(tabulate_track(track, ages));
delete track;
track=exact_track(Iconv_coef, masses[i],
low_mass_age_scaling, high_mass_age_scaling);
Iconv_data.push_back(tabulate_track(track, ages));
delete track;
track=exact_track(Itot_coef-Iconv_coef, masses[i],
low_mass_age_scaling, high_mass_age_scaling);
Irad_data.push_back(tabulate_track(track, ages));
delete track;
track=exact_track(Mrad_coef, masses[i],
low_mass_age_scaling, high_mass_age_scaling);
Mrad_data.push_back(tabulate_track(track, ages));
delete track;
track=exact_track(Rcore_coef, masses[i],
low_mass_age_scaling, high_mass_age_scaling);
Rcore_data.push_back(tabulate_track(track, ages));
delete track;
};
interpolate_from(masses,
std::list< std::valarray<double> >(masses.size(), ages),
r_data, Iconv_data, Irad_data, Mrad_data, Rcore_data, NaN, NaN,
NaN, NaN, NaN, 0, 0, 0, 0, 0,
std::list< std::valarray<double> >(), 0,
max_low_mass, low_mass_age_scaling, high_mass_age_scaling);
}
#endif
double ExponentialPlusFunc::order(unsigned deriv_order) const
{
if(deriv_order == 0) return (*this)(__deriv_x);
const Core::FunctionDerivatives *offset_deriv = __offset->deriv(__deriv_x);
double result = (__scale
*
std::pow(__rate, static_cast<int>(deriv_order))
*
std::exp(__rate * __deriv_x)
+
offset_deriv->order(deriv_order));
delete offset_deriv;
return result;
}
double FuncPlusFunc::order(unsigned deriv_order) const
{
if(deriv_order == 0) return (*this)(__deriv_x);
const FunctionDerivatives *f1_deriv = __f1->deriv(__deriv_x),
*f2_deriv = __f2->deriv(__deriv_x);
double result = (f1_deriv->order(deriv_order)
+
f2_deriv->order(deriv_order));
delete f1_deriv;
delete f2_deriv;
return result;
}
PiecewiseFunction::PiecewiseFunction(
const std::list<const OneArgumentDiffFunction *> &pieces,
double deriv_x
) :
__deriv_x(deriv_x),
__range_low(Core::Inf),
__range_high(-Core::Inf),
__pieces(pieces)
{
for(
std::list<const OneArgumentDiffFunction *>::const_iterator
piece_i = __pieces.begin();
piece_i!=__pieces.end();
piece_i++
) {
if((*piece_i)->range_low() < __range_low)
__range_low = (*piece_i)->range_low();
if((*piece_i)->range_high()>__range_high)
__range_high = (*piece_i)->range_high();
}
}
void PiecewiseFunction::add_piece(const OneArgumentDiffFunction *piece)
{
__pieces.push_back(piece);
if(piece->range_low() < __range_low)
__range_low = piece->range_low();
if(piece->range_high() > __range_high)
__range_high = piece->range_high();
}
double PiecewiseFunction::operator()(double x) const
{
double deriv_x = __deriv_x;
const_cast<PiecewiseFunction*>(this)->__deriv_x = x;
double result = order(0);
const_cast<PiecewiseFunction*>(this)->__deriv_x = deriv_x;
return result;
}
double PiecewiseFunction::order(unsigned deriv_order) const
{
unsigned index = 0;
if(std::isnan(__deriv_x)) return Core::NaN;
for(
std::list<const OneArgumentDiffFunction *>::const_iterator
fi = __pieces.begin();
fi != __pieces.end();
++fi
) {
if(
__deriv_x >= (*fi)->range_low()
&&
__deriv_x < (*fi)->range_high()
) {
if(deriv_order == 0) return (**fi)(__deriv_x);
const FunctionDerivatives *df = (*fi)->deriv(__deriv_x);
double result = df->order(deriv_order);
delete df;
return result;
}
++index;
}
if(__deriv_x == __pieces.back()->range_high()) {
if(deriv_order == 0) return (*(__pieces.back()))(__deriv_x);
const FunctionDerivatives *df = __pieces.back()->deriv(__deriv_x);
double result = df->order(deriv_order);
delete df;
return result;
}
std::ostringstream msg;
msg << "Requested derivative or function value at age="
<< __deriv_x
<< ", outside the range of any piece in PiecewiseFunction::order.";
throw Core::Error::BadFunctionArguments(msg.str());
}
double FunctionRatio::order(unsigned deriv_order) const
{
if(deriv_order == 0)
return (*this)(__deriv_x);
else {
const FunctionDerivatives *df1 = __f1->deriv(__deriv_x),
*df2 = __f2->deriv(__deriv_x);
double result;
if(deriv_order == 1)
result = (
df1->order(1) / df2->order(0)
-
df1->order(0) * df2->order(1) / std::pow(df2->order(0), 2)
);
else if(deriv_order == 2)
result = (
df1->order(2) / df2->order(0)
-
(
2.0 * df1->order(1) * df2->order(1)
/
std::pow(df2->order(0), 2)
)
-
df1->order(0) * df2->order(2) / std::pow(df2->order(0), 2)
+
(
df1->order(0) * std::pow(df2->order(1), 2)
/
std::pow(df2->order(0), 3)
)
);
else
throw Core::Error::BadFunctionArguments(
"Function ratio derivatives are only implemneted up to and "
"including order 2."
);
delete df1;
delete df2;
return result;
}
}
double FunctionToPower::order(unsigned deriv_order) const
{
if(deriv_order == 0)
return (*this)(__deriv_x);
else {
const FunctionDerivatives *df = __f->deriv(__deriv_x);
double result;
if(deriv_order == 1)
result = (__power
*
std::pow(df->order(0), __power-1)
*
df->order(1));
else if(deriv_order == 2)
result = (
__power
*
(
(__power-1)
*
std::pow(df->order(0), __power-2)
*
std::pow(df->order(1), 2)
+
std::pow(df->order(0), __power - 1) * df->order(2)
)
);
else
throw Core::Error::BadFunctionArguments(
"Function to power derivatives are only implemneted up to "
"and including order 2."
);
delete df;
return result;
}
}
double ScaledFunction::order(unsigned deriv_order) const
{
if(deriv_order == 0) return (*this)(__deriv_x);
const FunctionDerivatives *f_deriv = __f->deriv(__deriv_x);
double result = __scale*f_deriv->order(deriv_order);
delete f_deriv;
return result;
}
double LogFunction::order(unsigned deriv_order) const
{
if(deriv_order == 0) return (*this)(__deriv_x);
else {
const FunctionDerivatives *f_deriv=__f->deriv(__deriv_x);
double result;
if(deriv_order == 1)
result = f_deriv->order(1) / f_deriv->order(0);
else if(deriv_order == 2)
result = (f_deriv->order(2) / f_deriv->order(0)
-
std::pow(f_deriv->order(1) / f_deriv->order(0), 2));
else
throw Core::Error::BadFunctionArguments(
"Log(Function) derivatives are only implemneted up to and "
"including order 2."
);
delete f_deriv;
return result;
}
}
double CosFunction::order(unsigned deriv_order) const
{
if(deriv_order == 0) return (*this)(__deriv_x);
else {
const FunctionDerivatives *f_deriv=__f->deriv(__deriv_x);
double result;
if(deriv_order == 1)
result = - std::sin(f_deriv->order(0)) * f_deriv->order(1);
else if(deriv_order == 2)
result = - (
std::cos(f_deriv->order(0)) * std::pow(f_deriv->order(1), 2)
+
std::sin(f_deriv->order(1)) * f_deriv->order(2)
);
else
throw Core::Error::BadFunctionArguments(
"Cos(Function) derivatives are only implemneted up to and "
"including order 2."
);
delete f_deriv;
return result;
}
}
double solve(double guess_x,
double abs_precision,
double rel_precision,
double (*f)(double x, void *params),
double (*df) (double x, void *params),
void (*fdf) (double x, void *params, double *f, double *df),
void *params)
{
int status;
int iter = 0;
const gsl_root_fdfsolver_type *T;
gsl_root_fdfsolver *s;
double x0, x = guess_x;
gsl_function_fdf FDF;
FDF.f = f;
FDF.df = df;
FDF.fdf = fdf;
FDF.params = params;
T = gsl_root_fdfsolver_newton;
s = gsl_root_fdfsolver_alloc (T);
gsl_root_fdfsolver_set (s, &FDF, x);
do {
iter++;
status = gsl_root_fdfsolver_iterate (s);
x0 = x;
x = gsl_root_fdfsolver_root (s);
status = gsl_root_test_delta (x, x0, abs_precision, rel_precision);
} while (status == GSL_CONTINUE);
gsl_root_fdfsolver_free (s);
return x;
}