Planetary Orbital Evolution due to Tides
Orbital evolution of two objects experiencing tides
EvolvingStellarQuantity.cpp
Go to the documentation of this file.
1 
9 #define BUILDING_LIBRARY
11 #include <memory>
12 
13 namespace StellarEvolution {
14 
16  {
17  if(
18  __track_masses.size() != 1
19  &&
20  __track_feh.size() != 1
21  &&
22  (
24  ||
26  ||
27  __feh < __track_feh[0]
28  ||
29  __feh > __track_feh[__track_feh.size() - 1]
30  )
31  ) {
32  std::ostringstream msg;
33  msg.precision(16);
34  msg << "Stellar mass: "
35  << __mass
36  << " and [Fe/H]: "
37  << __feh
38  << " are outside the range of masses: "
39  << __track_masses[0]
40  << " - "
41  << __track_masses[__track_masses.size() - 1]
42  << " and [Fe/H]: "
43  << __track_feh[0]
44  << " - "
45  << __track_feh[__track_feh.size() - 1]
46  << " covered by the stellar evolution grid.";
47  throw Core::Error::BadFunctionArguments(msg.str());
48  }
49  }
50 
52  const std::valarray<double> &boundaries,
53  double value,
54  size_t &below_index,
55  size_t &above_index
56  ) const
57  {
58  const double *first_ptr = &boundaries[0],
59  *last_ptr = first_ptr + boundaries.size(),
60  *above_ptr = std::lower_bound(first_ptr,
61  last_ptr,
62  value),
63  *below_ptr = above_ptr;
64  if(boundaries.size() == 1) {
65  below_index = above_index = 0;
66  return;
67  }
68 #ifndef NDEBUG
69  if(above_ptr >= last_ptr )
70  std::cerr << "Value: "
71  << value
72  << " out of bounds: ["
73  << boundaries[0]
74  << ", "
75  << boundaries[boundaries.size() - 1]
76  << "]"
77  << std::endl;
78 #endif
79 
80  assert( above_ptr < last_ptr );
81 
82  if( value < *below_ptr) --below_ptr;
83 #ifndef NDEBUG
84  if(*above_ptr < value)
85  std::cerr << "Value: " << value
86  << " not in [" << *below_ptr << ", " << *above_ptr << "]"
87  << std::endl;
88 #endif
89  assert(*above_ptr >= value);
90  assert(value >= *below_ptr);
91  below_index = below_ptr - first_ptr;
92  above_index = above_ptr - first_ptr;
93  }
94 
96  {
97  size_t track_i = 0;
98  for(
99  size_t feh_i = 0;
100  feh_i < __track_feh.size();
101  ++feh_i
102  ) {
103  double track_feh = __track_feh[feh_i];
104  for(
105  size_t mass_i = 0;
106  mass_i < __track_masses.size();
107  ++mass_i
108  ) {
109  double track_mass = __track_masses[mass_i];
110  double min_track_age =
111  __evolution_tracks[track_i]->range_low(),
112  max_track_age =
113  __evolution_tracks[track_i]->range_high();
114  if(__log_age) {
115  min_track_age = std::exp(min_track_age);
116  max_track_age = std::exp(max_track_age);
117  }
119  age_to_interp_param(min_track_age,
120  track_mass,
121  track_feh)
122  );
124  age_to_interp_param(max_track_age,
125  track_mass,
126  track_feh)
127  );
128 #ifndef NDEBUG
129  std::cerr << "Track "
130  << track_i
131  << " age range: ["
132  << __min_interp_ages[track_i]
133  << ", "
134  << __max_interp_ages[track_i]
135  << "]"
136  << std::endl;
137 #endif
138  ++track_i;
139  }
140  }
141  }
142 
144  double age,
145  const OneArgumentDiffFunction &track,
146  const FunctionDerivatives **derivatives
147  ) const
148  {
149  double track_argument = (__log_age ? std::log(age) : age);
150  if(track_argument < track.range_low()) {
151  assert(std::abs(track_argument - track.range_low())
152  <
153  1e-8 * std::abs(track_argument));
154  track_argument = track.range_low();
155  }
156 
157  if(derivatives) {
158  *derivatives = new RemoveLogDeriv(
159  (__log_age ? age : NaN),
160  false,
161  track.deriv(track_argument),
162  true
163  );
164  return (*derivatives)->order(0);
165  } else return track(track_argument);
166  }
167 
169  AllowedGridGrowth &grow,
170  double age
171  ) const
172  {
173  if(__min_interp_mass_index == 0)
174  grow.block_lighter();
176  grow.block_heavier();
177  if(__min_interp_feh_index == 0)
178  grow.block_poorer();
179  if(__max_interp_feh_index == __track_feh.size())
180  grow.block_richer();
181 
182  for(
183  size_t feh_index = __min_interp_feh_index;
184  (
185  (grow.lighter() || grow.heavier())
186  &&
187  feh_index < __max_interp_feh_index
188  );
189  ++feh_index
190  ) {
191  if(
192  grow.lighter()
193  &&
195  feh_index,
196  age)
197  )
198  grow.block_lighter();
199 
200  if(
201  grow.heavier()
202  &&
204  feh_index,
205  age)
206  )
207  grow.block_heavier();
208  }
209 
210  for(
211  size_t mass_index = __min_interp_mass_index;
212  (
213  (grow.poorer() || grow.richer())
214  &&
215  mass_index < __max_interp_mass_index
216  );
217  ++mass_index
218  ) {
219  if(
220  grow.poorer()
221  &&
222  !track_in_range(mass_index,
224  age)
225  )
226  grow.block_poorer();
227  if(
228  grow.richer()
229  &&
230  !track_in_range(mass_index,
232  age)
233  )
234  grow.block_richer();
235  }
236  }
237 
239  double age) const
240  {
241  if(
242  grow.lighter()
243  &&
245  std::max(size_t(1),
247  age)
248  &&
250  std::min(__track_feh.size() - 1,
252  age)
253  ) {
255  return true;
256  }
257 
258  if(
259  grow.heavier()
260  &&
262  std::max(size_t(1),
264  age)
265  &&
267  std::min(__track_feh.size() - 1,
269  age)
270  ) {
272  return true;
273  }
274 
275  if(
276  grow.poorer()
277  &&
278  track_in_range(std::max(size_t(1), __min_interp_mass_index) - 1,
280  age)
281  &&
283  __track_masses.size() - 1),
285  age)
286  ) {
288  return true;
289  }
290 
291  if(
292  grow.richer()
293  &&
294  track_in_range(std::max(size_t(1), __min_interp_mass_index) - 1,
296  age)
297  &&
299  __track_masses.size() - 1),
301  age)
302  ) {
304  return true;
305  }
306 
307  std::valarray<size_t> padding(4);
309  padding[1] = (__min_interp_feh_index
310  -
312  padding[2] =
314  padding[3] = __max_interp_mass_index - __mass_index_above - 1;
315 
316  if(grow.lighter() && padding[0] == padding.min()) {
318  return true;
319  }
320  padding[0] = std::numeric_limits<size_t>::max();
321  if(grow.poorer() && padding[1] == padding.min()) {
323  return true;
324  }
325  padding[1] = std::numeric_limits<size_t>::max();
326  if(grow.richer() && padding[2] == padding.min()) {
328  return true;
329  }
330  if(grow.heavier()) {
332  return true;
333  }
334  return false;
335  }
336 
338  {
339  std::vector<double>::const_iterator
340  lower_age = __next_grid_change_age;
342  assert(__initially_zero);
347  __interp_masses.setlength(0);
348  __interp_feh.setlength(0);
349  return;
350  }
351  --lower_age;
352  double age = 0.5 * (*lower_age + *__next_grid_change_age);
353 
354  if(__min_interp_ages.max() < age && __max_interp_ages.min() > age) {
359  } else {
360 
361  AllowedGridGrowth grow;
362 
364  grow.block_lighter().block_heavier();
366  grow.block_poorer().block_richer();
367 
372  while(grow) {
374  if(grow && !expand_grid(grow, age)) break;
375  }
376  }
377 
378  __interp_masses.setcontent(
381  );
382  __interp_feh.setcontent(
385  );
386  }
387 
389  double age,
390  const FunctionDerivatives **derivatives
391  ) const
392  {
393  if(age < __min_age && __initially_zero) {
394  if(derivatives) *derivatives=new Core::ZeroDerivatives;
395  return 0.0;
396  }
397  if(age < __min_age || age > __max_age) {
398 #ifndef NDEBUG
399  std::cerr << "Age: " << age
400  << " not in [" << __min_age << ", " << __max_age << "]"
401  << std::endl;
402 #endif
403  return Core::NaN;
404  }
405  assert(__min_age <= age && age <= __max_age);
407 #ifndef NDEBUG
408  std::vector<double>::const_iterator
409  lower_age = __next_grid_change_age;
410  --lower_age;
411  assert(*lower_age <= age && age <= *__next_grid_change_age);
412 #endif
413 
414  double interp_param = age_to_interp_param(age);
415  size_t num_interp_tracks = (
417  *
419  );
420  alglib::real_1d_array track_values;
421  track_values.setlength(num_interp_tracks);
422  std::vector<const FunctionDerivatives *>
423  *track_derivatives
424  =
425  new std::vector<const FunctionDerivatives *>(num_interp_tracks);
426  size_t value_index = 0;
427  for(
428  size_t feh_index = __min_interp_feh_index;
429  feh_index < __max_interp_feh_index;
430  ++feh_index
431  ) {
432  double
433  track_feh = __track_feh[feh_index];
434  for(
435  size_t mass_index = __min_interp_mass_index;
436  mass_index < __max_interp_mass_index;
437  ++mass_index
438  ) {
439  double track_mass = __track_masses[mass_index];
440  double track_age = interp_param_to_age(interp_param,
441  track_mass,
442  track_feh);
443  track_values[value_index] = evaluate_track(
444  track_age,
445  *__evolution_tracks[track_index(mass_index,
446  feh_index)],
447  (derivatives
448  ? &((*track_derivatives)[value_index])
449  : NULL)
450  );
451  ++value_index;
452  }
453  }
454  if(derivatives == NULL) {
455  double result = mass_feh_interp(__interp_masses,
456  __interp_feh,
457  track_values,
458  __mass,
459  __feh);
460  delete track_derivatives;
461  return (__log_quantity ? std::exp(result) : result);
462  } else {
463  *derivatives = new InterpolatedDerivatives(
464  __mass,
465  __feh,
466  track_derivatives,
468  __interp_feh,
469  NaN,
471  true
472  );
473  return (*derivatives)->order(0);
474  }
475  }
476 
478  double age,
479  double mass,
480  double feh
481  ) const
482  {
483  //t * (1.0 + (t / 5.0) * m**5 * 10.0**(-0.2*feh))* m**2.3 * 10.0**(-0.4*feh)
484  double feh_factor = std::pow(10.0, -feh / 5.0);
485  return std::log(
486  age
487  *
488  (1.0 + age / 5.0 * std::pow(mass, 5) * feh_factor)
489  *
490  std::pow(mass, 2.3)
491  *
492  std::pow(feh_factor, 2)
493  );
494  }
495 
497  double interp_param,
498  double mass,
499  double feh
500  ) const
501  {
502  double feh_factor = std::pow(10.0, -feh / 5.0),
503  c = (std::exp(interp_param)
504  *
505  std::pow(mass, -2.3)
506  /
507  std::pow(feh_factor, 2)),
508  a = 0.2 * std::pow(mass, 5) * feh_factor,
509  discr = 1.0 + 4.0 * a * c;
510  return (std::sqrt(discr) - 1.0) / (2.0 * a);
511  }
512 
514  double mass,
515  double feh,
516  const std::valarray<double> &track_masses,
517  const std::valarray<double> &track_feh,
518  const std::vector<const OneArgumentDiffFunction *> &evolution_tracks,
519  bool log_age,
520  bool log_quantity,
521  bool starts_zero
522  ) :
523  __mass(mass),
524  __feh(feh),
525  __log_age(log_age),
526  __log_quantity(log_quantity),
527  __initially_zero(starts_zero),
528  __track_masses(track_masses),
529  __track_feh(track_feh),
530  __min_interp_ages(evolution_tracks.size()),
531  __max_interp_ages(evolution_tracks.size()),
532  __evolution_tracks(evolution_tracks)
533  {
534 #ifndef NDEBUG
535  std::cerr << "Creating quantity with mass: " << mass
536  << ", [Fe/H]: " << feh << std::endl
537  << ", with track masses: " << track_masses << std::endl
538  << " and track [Fe/H]: " << track_feh << std::endl
539  << " with " << evolution_tracks.size() << " tracks"
540  << std::endl;
541 #endif
542 
543  assert(evolution_tracks.size() == (track_masses.size()
544  *
545  track_feh.size()));
548 
549  if(starts_zero) {
550  __interp_grid_change_ages.reserve(2 * evolution_tracks.size()
551  +
552  1);
554  -Core::Inf);
555 
556  } else {
557  __interp_grid_change_ages.reserve(2 * evolution_tracks.size());
558  }
561  &__min_interp_ages[0],
563  );
566  &__max_interp_ages[0],
568  );
569 
570  std::sort(__interp_grid_change_ages.begin(),
572  std::unique(__interp_grid_change_ages.begin(),
575 
577  mass,
581  feh,
584 
587  ];
590  ];
591  __min_age = std::max(
592  __min_age,
595  );
596  __max_age = std::min(
597  __max_age,
600  );
601 
602  __min_age = std::max(
603  __min_age,
606  );
607  __max_age = std::min(
608  __max_age,
611  );
612 
613  __min_age = std::max(
614  __min_age,
617  );
618  __max_age = std::min(
619  __max_age,
622  );
623  }
624 
626  const
627  {
628 #ifndef NDEBUG
629  std::cerr << "Finding interpolation region for age = "
630  << age
631  << ", grid change ages: "
632  << std::endl;
633  for(
634  std::vector<double>::const_iterator
635  change_age_i = __interp_grid_change_ages.begin();
636  change_age_i != __interp_grid_change_ages.end();
637  ++change_age_i
638  )
639  std::cerr << "\t" << *change_age_i << std::endl;
640 #endif
641 
642 
643  std::vector<double>::const_iterator new_grid_change_age =
644  std::upper_bound(
647  age
648  );
649  if(__next_grid_change_age != new_grid_change_age) {
650  __next_grid_change_age = new_grid_change_age;
652  !=
655  }
656  }
657 
659  const
660  {
661  const FunctionDerivatives *deriv;
662  interpolate(age, &deriv);
663  return deriv;
664  }
665 
666  double EvolvingStellarQuantity::previous_discontinuity() const
667  {
669  assert(__initially_zero);
670  return -Core::Inf;
671  }
672  std::vector<double>::const_iterator result = __next_grid_change_age;
673  return *(--result);
674  }
675 
676  void EvolvingStellarQuantity::enable_next_interpolation_region() const
677  {
681  }
682 
683 } //End StellarEvolution namespace
Derivative class for stellar quantities which are interpolated age, mass and [Fe/H].
std::valarray< double > __track_feh
The [Fe/H] of the evolution tracks.
bool poorer() const
Can grow toward lower [Fe/H]?
bool __initially_zero
Should the quantity be assumed zero below the minimum track age.
AllowedGridGrowth & block_heavier()
Disable growth to higher masses.
void check_grid_range() const
Verify that the stellar mass and [Fe/H] are within range of the evolution tracks. ...
Function arguments do not satisfy some requirement.
Definition: Error.h:73
double __min_age
The minimum age for which this quantity is defined in Gyr.
std::vector< const OneArgumentDiffFunction * > __evolution_tracks
The model tracks for the evolution of the quantity on the grid defined by ::__track_masses and ::__tr...
size_t __feh_index_above
The index of the smallest track [Fe/H] not smaller than ::__feh.
AllowedGridGrowth & block_richer()
Disable growth to higher [Fe/H].
size_t __mass_index_below
The index of the largest track mass not exceeding ::__mass.
The derivatives of an identically zero quantity.
Definition: Functions.h:133
double evaluate_track(double age, const OneArgumentDiffFunction &track, const FunctionDerivatives **derivatives) const
Interpolate the quantity for the given track to the given age, returning NaN if out of age range...
size_t track_index(size_t mass_index, size_t feh_index) const
Return the index within ::__evolution_tracks for the given mass and [Fe/H] indices.
A class representing a once differentiable function of a single argument.
Definition: Functions.h:104
Declares a class implementing the intepolation of a single stellar quantity from stellar evolution tr...
size_t __max_interp_feh_index
The index within ::__track_feh of the highest [Fe/H] currently participating in the interpolation...
double __max_age
The maximum age for which this quantity is defined in Gyr.
bool lighter() const
Can grow toward lower masses?
std::vector< double >::const_iterator __next_grid_change_age
The entry in ::__interp_grid_change_ages up to which the current interpolation grid is valid...
size_t __min_interp_feh_index
The index within ::__track_feh of the lowest [Fe/H] currently participating in the interpolation...
size_t __min_interp_mass_index
The index within ::__track_masses of the lowest mass currently participating in the interpolation...
std::valarray< double > __track_masses
The masses of the evolution tracks.
size_t __feh_index_below
The index of the largest track [Fe/H] not exceeding ::__feh.
void update_interpolation_grid() const
Find the best sub-grid of tracks to interpolate on.
double interpolate(double age, const FunctionDerivatives **derivatives=NULL) const
Interpolate the quantity to the desired age.
void select_interpolation_region(const EvolvingStar *star, double age)
Prepare the zone quantities for interpolation around the given age.
Definition: CInterface.cpp:99
double interp_param_to_age(double interp_param) const
Return the age for the given interpoltaion parameter for the current star.
A class representing arbitrary order derivatives of a function.
Definition: Functions.h:66
Return dy/dx given dy/dln(x), dln(y)/dx or dln(y)/dln(x).
std::valarray< double > __max_interp_ages
The maximum interpolation age for the current star to which each track can contribute.
Return the age derivative of the quantity at the given age in virtual Gyr const FunctionDerivatives * deriv(double age) const
Returns a pointer to the derivative of the function.
double __mass
The mass to which to interpolate in .
AllowedGridGrowth & block_lighter()
Disable growth to lower masses.
bool __log_age
Whether the tracks have log(age) instead of age as their argument.
bool heavier() const
Can grow toward higher masses?
double age_to_interp_param(double age) const
Return the interpoltaion parameter for the given age for the current star.
void check_grid_expansion_directions(AllowedGridGrowth &grow, double age) const
Figure out in which directions we can expand a mass-[Fe/H] interpolation grid, assuming a single dire...
bool __log_quantity
Whether the tracks are of log(quantity) instead of the quantity.
EvolvingStellarQuantity()
Default constructor (only useful for derived classes which do not use the interpolation).
size_t __mass_index_above
The index of the smallest track mass not smaller than ::__mass.
std::valarray< double > __min_interp_ages
The minimum interpolation age for the current star to which each track can contribute.
bool richer() const
Can grow toward higher [Fe/H]?
double order(unsigned deriv_order=1) const
Returns the deriv_order-th derivative of the quantity.
bool track_in_range(size_t track_i, double age) const
Answer if a given track can participate in interpolating to the given age.
size_t __max_interp_mass_index
The index within ::__track_masses of the highest mass currently participating in the interpolation...
void set_interp_age_ranges()
Fill the ::__min_interp_ages and ::__max_interp_ages members.
double __feh
The [Fe/H] to which to interpolate.
std::vector< double > __interp_grid_change_ages
The ages at which the interpolation grid needs to be re-determined.
alglib::real_1d_array __interp_feh
The current track [Fe/H] values participating in the interpolation.
bool expand_grid(const AllowedGridGrowth &grow, double age) const
Attempt to expand the current interpolation grid returning true on success.
AllowedGridGrowth & block_poorer()
Disable growth to lower [Fe/H].
virtual const FunctionDerivatives * deriv(double x) const =0
Returns a pointer to the derivative of the function.
alglib::real_1d_array __interp_masses
The current track masses participating in the interpolation.
void find_cell(const std::valarray< double > &boundaries, double value, size_t &below_index, size_t &above_index) const
The two indices within the given sorted array defining the closed internal containing value...
virtual InputDataType range_low() const =0
The upper end of the range over which the function is defined.