Planetary Orbital Evolution due to Tides
Orbital evolution of two objects experiencing tides
MESAIO.cpp
1 #define BUILDING_LIBRARY
2 #include "MESAIO.h"
3 
4 std::ostream &operator<<(std::ostream &os,
6 {
7  switch(col) {
8  case StellarEvolution::MESA::AGE : os << "AGE"; break;
9  case StellarEvolution::MESA::LOG_RSTAR : os << "LOG_RSTAR"; break;
10  case StellarEvolution::MESA::LOG_LSTAR : os << "LOG_LSTAR"; break;
11  case StellarEvolution::MESA::MRAD : os << "MRAD"; break;
12  case StellarEvolution::MESA::RRAD : os << "RRAD"; break;
13  case StellarEvolution::MESA::ICONV : os << "ICONV"; break;
14  case StellarEvolution::MESA::IRAD : os << "IRAD"; break;
15  default : throw Core::Error::IO("Unrecognized MESA column "
16  "encountered!");
17  };
18  return os;
19 }
20 
21 namespace StellarEvolution {
22  namespace MESA {
23 
26  const double scaling = Yprotosun - Yprimordial + Zprotosun;
27 
28  double metallicity_from_feh(double feh)
29  {
30  return (
31  feh
32  +
33  std::log10(
34  (1 - Yprimordial)
35  /
36  (Xprotosun + scaling * std::pow(10.0, feh))
37  )
38  );
39  }
40 
41  double feh_from_metallicity(double metallicity)
42  {
43  return (
44  metallicity
45  -
46  std::log10(
47  (1.0 - Yprimordial - scaling * std::pow(10.0, metallicity))
48  /
49  Xprotosun
50  )
51  );
52  }
53 
54  const std::vector<QuantityID> Interpolator::__column_to_quantity(
55  {
56  StellarEvolution::NUM_QUANTITIES, //MTRACK - no quantity
57  StellarEvolution::NUM_QUANTITIES, //AGE - no quantity
58  StellarEvolution::RADIUS, //LOG_RSTAR - converted
60  StellarEvolution::LUM, //LOG_LSTAR - converted
61  StellarEvolution::LUM, //LSTAR
66  }
67  );
68 
69  const std::vector<double> Interpolator::__default_smoothing(
70  {
71  Core::NaN, //RADIUS
72  5, //ICONV
73  Core::NaN, //LUM
74  6, //IRAD
75  7, //MRAD
76  6 //RRAD: TBD
77  }
78  );
79 
80  const std::vector<int> Interpolator::__default_nodes(
81  {
82  0, //RADIUS
83  3000, //ICONV
84  0, //LUM
85  3000, //IRAD
86  6000, //MRAD
87  3000 //RRAD: TBD
88  }
89  );
90 
91  const std::vector<bool> Interpolator::__default_vs_log_age(
92  {
93  true, //RADIUS
94  true, //ICONV
95  true, //LUM
96  true, //IRAD
97  true, //MRAD
98  true //RRAD
99  }
100  );
101 
102  const std::vector<bool> Interpolator::__default_log_quantity(
103  {
104  false, //RADIUS
105  false, //ICONV
106  false, //LUM
107  false, //IRAD
108  false, //MRAD
109  false //RRAD
110  }
111  );
112 
114  {
115  __column_names.resize(NUM_COLUMNS);
116  __column_names[MESA::MTRACK] = "M_ini";
117  __column_names[MESA::AGE] = "age";
119  __column_names[MESA::RSTAR] = "R_star";
121  __column_names[MESA::LSTAR] = "L_star";
122  __column_names[MESA::MRAD] = "M_rad";
123  __column_names[MESA::RRAD] = "R_tachocline";
124  __column_names[MESA::ICONV] = "I_conv";
125  __column_names[MESA::IRAD] = "I_rad";
126  }
127 
128  void Header::read_column_numbers(std::istream &track,
129  const std::string &filename,
130  unsigned &line_number)
131  {
132  std::string line="";
133  for(;line==""; ++line_number) {
134  if(!track.good()) {
135  std::ostringstream msg;
136  msg << "Failed to extract line " << line_number
137  << " from " << filename << ".";
138  throw Core::Error::IO(msg.str());
139  }
140  std::getline(track, line);
141  }
142 
143  std::istringstream line_parser(line);
144  std::string column_name;
145  for(
146  int column_number = 0;
147  line_parser.good();
148  ++column_number
149  ) {
150  std::getline(line_parser, column_name, ',');
151  int colname_index = 0;
152  for(
153  ;
154  (
155  colname_index < NUM_COLUMNS
156  &&
157  column_name != __column_names[colname_index]
158  );
159  ++colname_index
160  ) {}
161  if(colname_index < NUM_COLUMNS)
162  __column_numbers[colname_index] = column_number;
163  }
164 
165  }
166 
167  Header::Header(std::ifstream &track, const std::string &filename)
168  {
171 
172  unsigned line_number=0;
173  read_column_numbers(track, filename, line_number);
174 
175  for(int i=0; i<MESA::NUM_COLUMNS; ++i)
176  if(
177  __column_numbers[i]==-1
178  &&
179  !(
180  (
181  i == MESA::LOG_RSTAR
182  &&
184  )
185  ||
186  (
187  i == MESA::RSTAR
188  &&
190  )
191  ||
192  (
193  i == MESA::LOG_LSTAR
194  &&
196  )
197  ||
198  (
199  i == MESA::LSTAR
200  &&
202  )
203  )
204  ) {
205  std::ostringstream message;
206  message << "Failed to find '" << __column_names[i]
207  << "' on line " << line_number << " of " << filename
208  << ".";
209  throw Core::Error::IO(message.str());
210  }
211  }
212 
214  const EvolutionIterator &rhs)
215  {
216  mass_iter = rhs.mass_iter;
217  feh_iter = rhs.feh_iter;
218  age_iter = rhs.age_iter;
219  quantity_iter = rhs.quantity_iter;
220  return *this;
221  }
222 
224  {
225  ++mass_iter;
226  ++feh_iter;
227  ++age_iter;
228  for(size_t i=0; i<quantity_iter.size(); ++i) ++quantity_iter[i];
229  return *this;
230  }
231 
232 #ifndef NDEBUG
234  {
235  assert(__mass_list.size() == __feh_list.size());
236  std::list<double>::const_iterator
237  mass_iter = __mass_list.begin(),
238  feh_iter = __feh_list.begin();
239 
240  std::list< std::valarray<double> >::const_iterator
241  age_iter = __track_ages.begin();
242  while(mass_iter != __mass_list.end()) {
243  assert(feh_iter != __feh_list.end());
244  assert(age_iter != __track_ages.end());
245  ++mass_iter;
246  ++feh_iter;
247  ++age_iter;
248  }
249  }
250 #endif
251 
252  bool Interpolator::parse_model_file_name(const std::string &filename)
253  {
254  const double PRECISION = 1000.0;
255  std::istringstream fname_stream(filename);
256  if(fname_stream.get() != 'M' || !fname_stream.good())
257  return false;
258 
259  double mass = 0;
260  fname_stream >> mass;
261  if(!fname_stream.good() || mass <= 0) return false;
262 
263  if(fname_stream.get() != '_' || !fname_stream.good())
264  return false;
265  if(fname_stream.get() != 'Z' || !fname_stream.good())
266  return false;
267 
268  double metallicity = 0;
269  fname_stream >> metallicity;
270  if(!fname_stream.good() || metallicity <= 0) return false;
271 
272  __feh_list.push_back(
273  std::round(
274  PRECISION
275  *
276  feh_from_metallicity(std::log10(metallicity / Zprotosun))
277  )
278  /
279  PRECISION
280  );
281  __mass_list.push_back(std::round(PRECISION * mass) / PRECISION);
282  return true;
283  }
284 
286  class CompareAges {
287  private:
288  const std::valarray<double> __ages;
289  public:
290  CompareAges(const std::valarray<double> &ages) : __ages(ages) {}
291 
292  bool operator()(size_t i1, size_t i2)
293  {return __ages[i1] < __ages[i2];}
294  };
295 
297  {
298  if(
299  std::is_sorted(std::begin(__track_ages.back()),
300  std::end(__track_ages.back()))
301  )
302  return;
303 
304  std::valarray<size_t> age_sorting_indices(
305  __track_ages.back().size()
306  );
307  for(size_t i = 0; i < __track_ages.back().size(); ++i)
308  age_sorting_indices[i] = i;
309  std::sort(std::begin(age_sorting_indices),
310  std::end(age_sorting_indices),
311  CompareAges(__track_ages.back()));
312 
313  __track_ages.back() = std::valarray<double>(
314  __track_ages.back()[age_sorting_indices]
315  );
316  assert(
317  std::is_sorted(std::begin(__track_ages.back()),
318  std::end(__track_ages.back()))
319  );
320  for(
321  int quantity = 0;
323  ++quantity
324  )
325  __track_quantities[quantity].back() = std::valarray<double>(
326  __track_quantities[quantity].back()[age_sorting_indices]
327  );
328  }
329 
330  void Interpolator::read_model_file(const std::string &filename)
331  {
332  std::ifstream track(filename.c_str());
333  Header header(track, filename);
334  std::vector< std::list<double> > track_columns = parse_columns(
335  track,
336  header.get_all_columns()
337  );
338 
339 #ifndef NDEBUG
340  track_columns[MESA::MTRACK].unique();
341  assert(track_columns[MESA::MTRACK].size() == 1);
342  assert(__mass_list.back()
343  ==
344  track_columns[MESA::MTRACK].front());
345 #endif
346  __track_ages.push_back(
347  Core::list_to_valarray(track_columns[MESA::AGE]) * 1e-9
348  );
349  std::clog
350  << "Model: M = " << __mass_list.back()
351  << ", [Fe/H] = " << __feh_list.back()
352  << ", t_max = "
353  << __track_ages.back()[__track_ages.back().size() - 1]
354  << std::endl;
355  for(int column = 0; column < MESA::NUM_COLUMNS; ++column) {
356  QuantityID quantity = __column_to_quantity[column];
357  if(
359  ||
360  track_columns[column].empty()
361  ) continue;
362 
363  if(column == MESA::LOG_RSTAR || column == MESA::LOG_LSTAR)
364  __track_quantities[quantity].push_back(
365  std::pow(
366  10.0,
367  Core::list_to_valarray(track_columns[column])
368  )
369  );
370  else
371  __track_quantities[quantity].push_back(
372  Core::list_to_valarray(track_columns[column])
373  );
374  }
375  sort_last_track_by_age();
376  }
377 
379  std::valarray<double> &masses,
380  std::valarray<double> &feh
381  )
382  {
383  assert(__mass_list.size() == __feh_list.size());
384  std::list<double>::const_iterator
385  mass_iter = __mass_list.begin(),
386  feh_iter = __feh_list.begin();
387 
388  std::list< std::valarray<double> >::const_iterator
389  age_iter = __track_ages.begin();
390 
391  size_t num_masses = 0;
392  for(
393  double first_feh = *feh_iter;
394  *feh_iter == first_feh;
395  ++feh_iter
396  )
397  ++num_masses;
398  feh_iter = __feh_list.begin();
399  assert(__mass_list.size() % num_masses == 0);
400  size_t num_feh = __mass_list.size() / num_masses;
401 
402  masses.resize(num_masses);
403  feh.resize(num_feh);
404 
405  for(size_t feh_index = 0; feh_index < num_feh; ++feh_index) {
406  for(
407  size_t mass_index = 0;
408  mass_index < num_masses;
409  ++mass_index
410  ) {
411  assert(mass_iter != __mass_list.end());
412  assert(feh_iter != __feh_list.end());
413  std::cerr
414  << "M = " << *mass_iter
415  << ", [Fe/H] = " << *feh_iter
416  << ", age range = " << (*age_iter)[0]
417  << " - " << (*age_iter)[age_iter->size() -1]
418  << std::endl;
419  if(feh_index == 0)
420  masses[mass_index] = *mass_iter;
421  else if(masses[mass_index] != *mass_iter)
422  throw Core::Error::IO(
423  "Input MESA tracks do not lie on a grid of "
424  "masses and [Fe/H]."
425  );
426 
427  if(mass_index == 0)
428  feh[feh_index] = *feh_iter;
429  else if(feh[feh_index] != *feh_iter)
430  throw Core::Error::IO(
431  "Input MESA tracks do not lie on a grid of "
432  "masses and [Fe/H]."
433  );
434 
435  ++mass_iter;
436  ++feh_iter;
437  ++age_iter;
438  }
439  }
440  assert(feh_iter == __feh_list.end());
441  assert(mass_iter == __mass_list.end());
442  }
443 
445  {
446  EvolutionIterator result;
447  result.mass_iter = __mass_list.begin();
448  result.feh_iter = __feh_list.begin();
449  result.age_iter = __track_ages.begin();
450  for(size_t quantity = 0; quantity < NUM_QUANTITIES; ++quantity)
451  result.quantity_iter[quantity] =
452  __track_quantities[quantity].begin();
453  return result;
454  }
455 
457  {
458  EvolutionIterator result;
459  result.mass_iter = __mass_list.end();
460  result.feh_iter = __feh_list.end();
461  result.age_iter = __track_ages.end();
462  for(size_t quantity = 0; quantity < NUM_QUANTITIES; ++quantity)
463  result.quantity_iter[quantity] =
464  __track_quantities[quantity].end();
465  return result;
466  }
467 
469  EvolutionIterator &source)
470  {
471  __mass_list.splice(dest.mass_iter,
472  __mass_list,
473  source.mass_iter);
474 
475  __feh_list.splice(dest.feh_iter,
476  __feh_list,
477  source.feh_iter);
478 
479  __track_ages.splice(dest.age_iter,
480  __track_ages,
481  source.age_iter);
482 
483  for(size_t quantity = 0; quantity < NUM_QUANTITIES; ++quantity)
484  __track_quantities[quantity].splice(
485  dest.quantity_iter[quantity],
486  __track_quantities[quantity],
487  source.quantity_iter[quantity]
488  );
489 #ifndef NDEBUG
490  log_current_age_ranges();
491 #endif
492  }
493 
495  {
496  EvolutionIterator iter = begin(), stop_iter = end();
497  double last_sorted_mass = *iter.mass_iter,
498  last_sorted_feh = *iter.feh_iter;
499  while(iter != stop_iter) {
500  while(
501  iter != stop_iter
502  &&
503  (
504  *iter.feh_iter > last_sorted_feh
505  ||
506  (
507  *iter.feh_iter == last_sorted_feh
508  &&
509  *iter.mass_iter >= last_sorted_mass
510  )
511  )
512  ) {
513  last_sorted_mass = *iter.mass_iter;
514  last_sorted_feh = *iter.feh_iter;
515  ++iter;
516  }
517  if(iter == stop_iter) break;
518  EvolutionIterator dest = begin();
519 
520  while(
521  *(dest.feh_iter) < *(iter.feh_iter)
522  ||
523  (
524  *(dest.feh_iter) == *(iter.feh_iter)
525  &&
526  *(dest.mass_iter) <= *(iter.mass_iter)
527  )
528  )
529  ++dest;
530  EvolutionIterator source = iter++;
531  move(dest, source);
532  }
533  }
534 
535  Interpolator::Interpolator(const std::string &model_directory,
536  unsigned num_threads,
537  const std::vector<double> &smoothing,
538  const std::vector<int> &nodes,
539  const std::vector<bool> &vs_log_age,
540  const std::vector<bool> &log_quantity) :
541  __track_quantities(NUM_QUANTITIES)
542  {
543  std::clog << "Reading tracks from "
544  << model_directory
545  << std::endl;
546  DIR *dirstream = opendir(model_directory.c_str());
547  std::string join;
548  if(model_directory[model_directory.size()-1] == '/') join="";
549  else join = "/";
550  if(dirstream == NULL)
552  "in MESA::Evolution constructor.",
553  model_directory
554  );
555  struct dirent *entry;
556  while((entry = readdir(dirstream))) {
557  std::string fname(entry->d_name);
558  if(
559  fname[0] != '.'
560  &&
561  fname.substr(fname.size() - 4) == ".csv"
562  &&
563  parse_model_file_name(fname)
564  ) {
565  std::cout
566  << "Reading "
567  << model_directory + join + fname
568  << std::endl;
569  read_model_file(model_directory + join + fname);
570  } else
571  std::cout
572  << "Skipping "
573  << model_directory + join + entry->d_name
574  << std::endl;
575  }
576  if(closedir(dirstream)) throw Core::Error::Runtime(
577  "Failed to close directory stream tied to "
578  +
579  model_directory
580  +
581  " in MESA::Evolution constructor."
582  );
583  sort_tracks();
584  std::valarray<double> masses, feh;
585  get_mass_feh_grid(masses, feh);
586  std::cout
587  << "Done reading tracks." << std::endl
588  << "Starting interpolation" << std::endl;
589 
590  create_from(masses,
591  feh,
592  __track_ages,
594  smoothing,
595  nodes,
596  vs_log_age,
597  log_quantity,
598  num_threads);
599  std::cout << "Done with interpolation" << std::endl;
600  }
601  } //End MESA namespace.
602 } // End StellarEvolution namespace.
EvolutionIterator & operator=(const EvolutionIterator &rhs)
Copy rhs to *this.
Definition: MESAIO.cpp:213
The total number of interesting columns.
Definition: MESAIO.h:95
double metallicity_from_feh(double feh)
Return the metallicity interpolation parameter corresponding to the given [Fe/H] value.
Definition: MESAIO.cpp:28
const double Yprotosun
The Helium fraction with which the Sun formed.
Definition: MESAIO.h:43
Used as comparison when sorting quantities by age.
Definition: MESAIO.cpp:286
bool parse_model_file_name(const std::string &filename)
Parse the mass (in ) and [Fe/H] from a track filename.
Definition: MESAIO.cpp:252
RADIUS
The derivative w.r.t. the radius of the body in .
EvolutionIterator & operator++()
Advance all iterators to the next track.
Definition: MESAIO.cpp:223
std::list< std::valarray< double > >::iterator age_iter
Iterator over the array of ages of the tracks.
Definition: MESAIO.h:152
Header(std::ifstream &track, const std::string &filename)
Parse the header information from the given track stream.
Definition: MESAIO.cpp:167
std::vector< int > __column_numbers
The column numbers of the interesting quantities, indexed by MESA::Column.
Definition: MESAIO.h:109
Mass of the radiative core in .
Definition: MESAIO.h:80
static const std::vector< bool > __default_log_quantity
The default selection of interpolation function (quantity vs log(quantity) for each quantity...
Definition: MESAIO.h:219
const double Yprimordial
The primordial Helium fraction of the universe.
Definition: MESAIO.h:40
const double scaling
A scaling constant used when transforming between different metallicity quantities.
Definition: MESAIO.cpp:26
Log10 of the luminosity of the star in .
Definition: MESAIO.h:74
const double Zprotosun
The metal fraction with which the Sun formed.
Definition: MESAIO.h:46
Log10 of the radius of the star in .
Definition: MESAIO.h:68
const int LUM
Identifier for the stellar luminosity as an interpolation quantity.
Definition: CInterface.cpp:13
static const std::vector< bool > __default_vs_log_age
The default selection of interpolation argument (age vs log(age) for each quantity. See StellarEvolution::Interpolator::create_from.
Definition: MESAIO.h:214
const double Xprotosun
The hydrogen fraction with which the Sun formed.
Definition: MESAIO.h:49
The total mass of the star in .
Definition: MESAIO.h:62
void set_column_names()
Sets the column names.
Definition: MESAIO.cpp:113
Any runtime error.
Definition: Error.h:61
void log_current_age_ranges() const
Output the current masses [Fe/H] and age ranges.
Definition: MESAIO.cpp:233
Exception indicating that a file or a directory was not found.
Definition: Error.h:98
Stellar age in years.
Definition: MESAIO.h:65
Column
Names for the interesting columns in a MESA track.
Definition: MESAIO.h:60
std::list< std::valarray< double > > __track_ages
The ages at which each track is tabulated.
Definition: MESAIO.h:228
Defines the classes for generating stellar evolution interpolators from the MESA tracks.
void read_column_numbers(std::istream &track, const std::string &filename, unsigned &line_number)
Checks that the next line in the input stream consists of sequential numbers starting with 1...
Definition: MESAIO.cpp:128
A class which parses the header of a MESA evolution track.
Definition: MESAIO.h:101
Moment of inertia of the convective envelope in .
Definition: MESAIO.h:87
The luminosity of the star in .
Definition: MESAIO.h:77
double feh_from_metallicity(double metallicity)
Return the [Fe/H] value corresponding to the given metallicity.
Definition: MESAIO.cpp:41
void read_model_file(const std::string &filename)
Reads a single evolution track file.
Definition: MESAIO.cpp:330
std::list< double >::iterator feh_iter
Iterator over the masses of the tracks.
Definition: MESAIO.h:149
Input/Output exception.
Definition: Error.h:118
std::vector< std::list< std::valarray< double > > > __track_quantities
A structure holding all interesting quantities from the MESA tracks except age.
Definition: MESAIO.h:242
static const std::vector< QuantityID > __column_to_quantity
The value at the indexed from Column is the StellarEvolution::QuantityID to which this column is conv...
Definition: MESAIO.h:201
EvolutionIterator end()
Returns an EvolutionIterator pointing to the end of all quantities.
Definition: MESAIO.cpp:456
Moment of inertia of the radiative zone of the star (low mass stars only) in .
Definition: IOColumns.h:114
void create_from(const std::valarray< double > &tabulated_masses, const std::valarray< double > &tabulated_feh, const std::list< std::valarray< double > > &tabulated_ages, const std::vector< std::list< std::valarray< double > > > &tabulated_quantities, const std::vector< double > &smoothing, const std::vector< int > &nodes, const std::vector< bool > &vs_log_age, const std::vector< bool > &log_quantity, unsigned num_threads)
Fully setup an object created by the default constructor.
const int NUM_QUANTITIES
The number of interpolation quantities currentyl supported.
Definition: CInterface.cpp:17
Moment of inertia of the convective zone of the star (low mass stars only) in .
Definition: IOColumns.h:110
An iterator over the list of extracted tracks.
Definition: MESAIO.h:139
Radius of the radiative core in .
Definition: MESAIO.h:83
The radius of the star in .
Definition: MESAIO.h:71
std::list< double >::iterator mass_iter
Iterator over the masses of the tracks.
Definition: MESAIO.h:146
QuantityID
Defines the quantities tracked by stellar evolution and their order.
Radius of the stellar core in (low mass stars only).
Definition: IOColumns.h:123
std::vector< std::string > __column_names
The names of the columns in the track, indexed by MESA::Column.
Definition: MESAIO.h:105
std::vector< std::list< std::valarray< double > >::iterator > quantity_iter
Iterators over the arrays of the track quantities.
Definition: MESAIO.h:156
void get_mass_feh_grid(std::valarray< double > &masses, std::valarray< double > &feh)
Verify that the track masses and [Fe/H] form a grid and return the grid.
Definition: MESAIO.cpp:378
Moment of inertia of the radiative core in .
Definition: MESAIO.h:91
The number of significant figures require of the evolution.
Definition: IOColumns.h:81
EvolutionIterator begin()
Returns an EvolutionIterator pointing to the beginning of all quantities.
Definition: MESAIO.cpp:444
void sort_last_track_by_age()
Sorts the quantities read from the last track by age.
Definition: MESAIO.cpp:296
static const std::vector< int > __default_nodes
The default number of node to use for each quantity. See StellarEvolution::Interpolator::create_from...
Definition: MESAIO.h:209
void move(EvolutionIterator &dest, EvolutionIterator &source)
Moves source to right before destination.
Definition: MESAIO.cpp:468
Mass of the stellar core in (low mass stars only).
Definition: IOColumns.h:126
static const std::vector< double > __default_smoothing
The default amount of smoothing to use for each quantity. See StellarEvolution::Interpolator::create_...
Definition: MESAIO.h:205
void sort_tracks()
Sorts the data by mass and [Fe/H].
Definition: MESAIO.cpp:494