Program Listing for File MESAIO.cpp¶
↰ Return to documentation for file (/home/kpenev/projects/git/poet/poet_src/StellarEvolution/MESAIO.cpp)
#define BUILDING_LIBRARY
#include "MESAIO.h"
std::ostream &operator<<(std::ostream &os,
StellarEvolution::MESA::Column col)
{
switch(col) {
case StellarEvolution::MESA::AGE : os << "AGE"; break;
case StellarEvolution::MESA::LOG_RSTAR : os << "LOG_RSTAR"; break;
case StellarEvolution::MESA::LOG_LSTAR : os << "LOG_LSTAR"; break;
case StellarEvolution::MESA::MRAD : os << "MRAD"; break;
case StellarEvolution::MESA::RRAD : os << "RRAD"; break;
case StellarEvolution::MESA::ICONV : os << "ICONV"; break;
case StellarEvolution::MESA::IRAD : os << "IRAD"; break;
default : throw Core::Error::IO("Unrecognized MESA column "
"encountered!");
};
return os;
}
namespace StellarEvolution {
namespace MESA {
const double scaling = Yprotosun - Yprimordial + Zprotosun;
double metallicity_from_feh(double feh)
{
return (
feh
+
std::log10(
(1 - Yprimordial)
/
(Xprotosun + scaling * std::pow(10.0, feh))
)
);
}
double feh_from_metallicity(double metallicity)
{
return (
metallicity
-
std::log10(
(1.0 - Yprimordial - scaling * std::pow(10.0, metallicity))
/
Xprotosun
)
);
}
const std::vector<QuantityID> Interpolator::__column_to_quantity(
{
StellarEvolution::NUM_QUANTITIES, //MTRACK - no quantity
StellarEvolution::NUM_QUANTITIES, //AGE - no quantity
StellarEvolution::RADIUS, //LOG_RSTAR - converted
StellarEvolution::RADIUS, //RSTAR
StellarEvolution::LUM, //LOG_LSTAR - converted
StellarEvolution::LUM, //LSTAR
StellarEvolution::MRAD, //MRAD
StellarEvolution::RRAD, //RRAD
StellarEvolution::ICONV, //ICONV
StellarEvolution::IRAD //IRAD
}
);
const std::vector<double> Interpolator::__default_smoothing(
{
Core::NaN, //RADIUS
5, //ICONV
Core::NaN, //LUM
6, //IRAD
7, //MRAD
6 //RRAD: TBD
}
);
const std::vector<int> Interpolator::__default_nodes(
{
0, //RADIUS
3000, //ICONV
0, //LUM
3000, //IRAD
6000, //MRAD
3000 //RRAD: TBD
}
);
const std::vector<bool> Interpolator::__default_vs_log_age(
{
true, //RADIUS
true, //ICONV
true, //LUM
true, //IRAD
true, //MRAD
true //RRAD
}
);
const std::vector<bool> Interpolator::__default_log_quantity(
{
false, //RADIUS
false, //ICONV
false, //LUM
false, //IRAD
false, //MRAD
false //RRAD
}
);
void Header::set_column_names()
{
__column_names.resize(NUM_COLUMNS);
__column_names[MESA::MTRACK] = "M_ini";
__column_names[MESA::AGE] = "age";
__column_names[MESA::LOG_RSTAR] = "";
__column_names[MESA::RSTAR] = "R_star";
__column_names[MESA::LOG_LSTAR] = "";
__column_names[MESA::LSTAR] = "L_star";
__column_names[MESA::MRAD] = "M_rad";
__column_names[MESA::RRAD] = "R_tachocline";
__column_names[MESA::ICONV] = "I_conv";
__column_names[MESA::IRAD] = "I_rad";
}
void Header::read_column_numbers(std::istream &track,
const std::string &filename,
unsigned &line_number)
{
std::string line="";
for(;line==""; ++line_number) {
if(!track.good()) {
std::ostringstream msg;
msg << "Failed to extract line " << line_number
<< " from " << filename << ".";
throw Core::Error::IO(msg.str());
}
std::getline(track, line);
}
std::istringstream line_parser(line);
std::string column_name;
for(
int column_number = 0;
line_parser.good();
++column_number
) {
std::getline(line_parser, column_name, ',');
int colname_index = 0;
for(
;
(
colname_index < NUM_COLUMNS
&&
column_name != __column_names[colname_index]
);
++colname_index
) {}
if(colname_index < NUM_COLUMNS)
__column_numbers[colname_index] = column_number;
}
}
Header::Header(std::ifstream &track, const std::string &filename)
{
set_column_names();
__column_numbers.resize(MESA::NUM_COLUMNS, -1);
unsigned line_number=0;
read_column_numbers(track, filename, line_number);
for(int i=0; i<MESA::NUM_COLUMNS; ++i)
if(
__column_numbers[i]==-1
&&
!(
(
i == MESA::LOG_RSTAR
&&
__column_numbers[MESA::RSTAR] != -1
)
||
(
i == MESA::RSTAR
&&
__column_numbers[MESA::LOG_RSTAR] != -1
)
||
(
i == MESA::LOG_LSTAR
&&
__column_numbers[MESA::LSTAR] != -1
)
||
(
i == MESA::LSTAR
&&
__column_numbers[MESA::LOG_LSTAR] != -1
)
)
) {
std::ostringstream message;
message << "Failed to find '" << __column_names[i]
<< "' on line " << line_number << " of " << filename
<< ".";
throw Core::Error::IO(message.str());
}
}
EvolutionIterator &EvolutionIterator::operator=(
const EvolutionIterator &rhs)
{
mass_iter = rhs.mass_iter;
feh_iter = rhs.feh_iter;
age_iter = rhs.age_iter;
quantity_iter = rhs.quantity_iter;
return *this;
}
EvolutionIterator &EvolutionIterator::operator++()
{
++mass_iter;
++feh_iter;
++age_iter;
for(size_t i=0; i<quantity_iter.size(); ++i) ++quantity_iter[i];
return *this;
}
#ifndef NDEBUG
void Interpolator::log_current_age_ranges() const
{
assert(__mass_list.size() == __feh_list.size());
std::list<double>::const_iterator
mass_iter = __mass_list.begin(),
feh_iter = __feh_list.begin();
std::list< std::valarray<double> >::const_iterator
age_iter = __track_ages.begin();
while(mass_iter != __mass_list.end()) {
assert(feh_iter != __feh_list.end());
assert(age_iter != __track_ages.end());
++mass_iter;
++feh_iter;
++age_iter;
}
}
#endif
bool Interpolator::parse_model_file_name(const std::string &filename)
{
const double PRECISION = 1000.0;
std::istringstream fname_stream(filename);
if(fname_stream.get() != 'M' || !fname_stream.good())
return false;
double mass = 0;
fname_stream >> mass;
if(!fname_stream.good() || mass <= 0) return false;
if(fname_stream.get() != '_' || !fname_stream.good())
return false;
if(fname_stream.get() != 'Z' || !fname_stream.good())
return false;
double metallicity = 0;
fname_stream >> metallicity;
if(!fname_stream.good() || metallicity <= 0) return false;
__feh_list.push_back(
std::round(
PRECISION
*
feh_from_metallicity(std::log10(metallicity / Zprotosun))
)
/
PRECISION
);
__mass_list.push_back(std::round(PRECISION * mass) / PRECISION);
return true;
}
class CompareAges {
private:
const std::valarray<double> __ages;
public:
CompareAges(const std::valarray<double> &ages) : __ages(ages) {}
bool operator()(size_t i1, size_t i2)
{return __ages[i1] < __ages[i2];}
};
void Interpolator::sort_last_track_by_age()
{
if(
std::is_sorted(std::begin(__track_ages.back()),
std::end(__track_ages.back()))
)
return;
std::valarray<size_t> age_sorting_indices(
__track_ages.back().size()
);
for(size_t i = 0; i < __track_ages.back().size(); ++i)
age_sorting_indices[i] = i;
std::sort(std::begin(age_sorting_indices),
std::end(age_sorting_indices),
CompareAges(__track_ages.back()));
__track_ages.back() = std::valarray<double>(
__track_ages.back()[age_sorting_indices]
);
assert(
std::is_sorted(std::begin(__track_ages.back()),
std::end(__track_ages.back()))
);
for(
int quantity = 0;
quantity < StellarEvolution::NUM_QUANTITIES;
++quantity
)
__track_quantities[quantity].back() = std::valarray<double>(
__track_quantities[quantity].back()[age_sorting_indices]
);
}
void Interpolator::read_model_file(const std::string &filename)
{
std::ifstream track(filename.c_str());
Header header(track, filename);
std::vector< std::list<double> > track_columns = parse_columns(
track,
header.get_all_columns()
);
#ifndef NDEBUG
track_columns[MESA::MTRACK].unique();
assert(track_columns[MESA::MTRACK].size() == 1);
assert(__mass_list.back()
==
track_columns[MESA::MTRACK].front());
#endif
__track_ages.push_back(
Core::list_to_valarray(track_columns[MESA::AGE]) * 1e-9
);
std::clog
<< "Model: M = " << __mass_list.back()
<< ", [Fe/H] = " << __feh_list.back()
<< ", t_max = "
<< __track_ages.back()[__track_ages.back().size() - 1]
<< std::endl;
for(int column = 0; column < MESA::NUM_COLUMNS; ++column) {
QuantityID quantity = __column_to_quantity[column];
if(
quantity == StellarEvolution::NUM_QUANTITIES
||
track_columns[column].empty()
) continue;
if(column == MESA::LOG_RSTAR || column == MESA::LOG_LSTAR)
__track_quantities[quantity].push_back(
std::pow(
10.0,
Core::list_to_valarray(track_columns[column])
)
);
else
__track_quantities[quantity].push_back(
Core::list_to_valarray(track_columns[column])
);
}
sort_last_track_by_age();
}
void Interpolator::get_mass_feh_grid(
std::valarray<double> &masses,
std::valarray<double> &feh
)
{
assert(__mass_list.size() == __feh_list.size());
std::list<double>::const_iterator
mass_iter = __mass_list.begin(),
feh_iter = __feh_list.begin();
std::list< std::valarray<double> >::const_iterator
age_iter = __track_ages.begin();
size_t num_masses = 0;
for(
double first_feh = *feh_iter;
*feh_iter == first_feh;
++feh_iter
)
++num_masses;
feh_iter = __feh_list.begin();
assert(__mass_list.size() % num_masses == 0);
size_t num_feh = __mass_list.size() / num_masses;
masses.resize(num_masses);
feh.resize(num_feh);
for(size_t feh_index = 0; feh_index < num_feh; ++feh_index) {
for(
size_t mass_index = 0;
mass_index < num_masses;
++mass_index
) {
assert(mass_iter != __mass_list.end());
assert(feh_iter != __feh_list.end());
std::cerr
<< "M = " << *mass_iter
<< ", [Fe/H] = " << *feh_iter
<< ", age range = " << (*age_iter)[0]
<< " - " << (*age_iter)[age_iter->size() -1]
<< std::endl;
if(feh_index == 0)
masses[mass_index] = *mass_iter;
else if(masses[mass_index] != *mass_iter)
throw Core::Error::IO(
"Input MESA tracks do not lie on a grid of "
"masses and [Fe/H]."
);
if(mass_index == 0)
feh[feh_index] = *feh_iter;
else if(feh[feh_index] != *feh_iter)
throw Core::Error::IO(
"Input MESA tracks do not lie on a grid of "
"masses and [Fe/H]."
);
++mass_iter;
++feh_iter;
++age_iter;
}
}
assert(feh_iter == __feh_list.end());
assert(mass_iter == __mass_list.end());
}
EvolutionIterator Interpolator::begin()
{
EvolutionIterator result;
result.mass_iter = __mass_list.begin();
result.feh_iter = __feh_list.begin();
result.age_iter = __track_ages.begin();
for(size_t quantity = 0; quantity < NUM_QUANTITIES; ++quantity)
result.quantity_iter[quantity] =
__track_quantities[quantity].begin();
return result;
}
EvolutionIterator Interpolator::end()
{
EvolutionIterator result;
result.mass_iter = __mass_list.end();
result.feh_iter = __feh_list.end();
result.age_iter = __track_ages.end();
for(size_t quantity = 0; quantity < NUM_QUANTITIES; ++quantity)
result.quantity_iter[quantity] =
__track_quantities[quantity].end();
return result;
}
void Interpolator::move(EvolutionIterator &dest,
EvolutionIterator &source)
{
__mass_list.splice(dest.mass_iter,
__mass_list,
source.mass_iter);
__feh_list.splice(dest.feh_iter,
__feh_list,
source.feh_iter);
__track_ages.splice(dest.age_iter,
__track_ages,
source.age_iter);
for(size_t quantity = 0; quantity < NUM_QUANTITIES; ++quantity)
__track_quantities[quantity].splice(
dest.quantity_iter[quantity],
__track_quantities[quantity],
source.quantity_iter[quantity]
);
#ifndef NDEBUG
log_current_age_ranges();
#endif
}
void Interpolator::sort_tracks()
{
EvolutionIterator iter = begin(), stop_iter = end();
double last_sorted_mass = *iter.mass_iter,
last_sorted_feh = *iter.feh_iter;
while(iter != stop_iter) {
while(
iter != stop_iter
&&
(
*iter.feh_iter > last_sorted_feh
||
(
*iter.feh_iter == last_sorted_feh
&&
*iter.mass_iter >= last_sorted_mass
)
)
) {
last_sorted_mass = *iter.mass_iter;
last_sorted_feh = *iter.feh_iter;
++iter;
}
if(iter == stop_iter) break;
EvolutionIterator dest = begin();
while(
*(dest.feh_iter) < *(iter.feh_iter)
||
(
*(dest.feh_iter) == *(iter.feh_iter)
&&
*(dest.mass_iter) <= *(iter.mass_iter)
)
)
++dest;
EvolutionIterator source = iter++;
move(dest, source);
}
}
Interpolator::Interpolator(const std::string &model_directory,
unsigned num_threads,
const std::vector<double> &smoothing,
const std::vector<int> &nodes,
const std::vector<bool> &vs_log_age,
const std::vector<bool> &log_quantity) :
__track_quantities(NUM_QUANTITIES)
{
std::clog << "Reading tracks from "
<< model_directory
<< std::endl;
DIR *dirstream = opendir(model_directory.c_str());
std::string join;
if(model_directory[model_directory.size()-1] == '/') join="";
else join = "/";
if(dirstream == NULL)
throw Core::Error::PathNotFound(
"in MESA::Evolution constructor.",
model_directory
);
struct dirent *entry;
while((entry = readdir(dirstream))) {
std::string fname(entry->d_name);
if(
fname[0] != '.'
&&
fname.substr(fname.size() - 4) == ".csv"
&&
parse_model_file_name(fname)
) {
std::cout
<< "Reading "
<< model_directory + join + fname
<< std::endl;
read_model_file(model_directory + join + fname);
} else
std::cout
<< "Skipping "
<< model_directory + join + entry->d_name
<< std::endl;
}
if(closedir(dirstream)) throw Core::Error::Runtime(
"Failed to close directory stream tied to "
+
model_directory
+
" in MESA::Evolution constructor."
);
sort_tracks();
std::valarray<double> masses, feh;
get_mass_feh_grid(masses, feh);
std::cout
<< "Done reading tracks." << std::endl
<< "Starting interpolation" << std::endl;
create_from(masses,
feh,
__track_ages,
__track_quantities,
smoothing,
nodes,
vs_log_age,
log_quantity,
num_threads);
std::cout << "Done with interpolation" << std::endl;
}
} //End MESA namespace.
} // End StellarEvolution namespace.