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 #ifndef NDEBUG
398  if(age < __min_age || age > __max_age)
399  std::cerr << "Age: " << age
400  << " not in [" << __min_age << ", " << __max_age << "]"
401  << std::endl;
402 #endif
403  assert(__min_age <= age && age <= __max_age);
405 #ifndef NDEBUG
406  std::vector<double>::const_iterator
407  lower_age = __next_grid_change_age;
408  --lower_age;
409  assert(*lower_age <= age && age <= *__next_grid_change_age);
410 #endif
411 
412  double interp_param = age_to_interp_param(age);
413  size_t num_interp_tracks = (
415  *
417  );
418  alglib::real_1d_array track_values;
419  track_values.setlength(num_interp_tracks);
420  std::vector<const FunctionDerivatives *>
421  *track_derivatives
422  =
423  new std::vector<const FunctionDerivatives *>(num_interp_tracks);
424  size_t value_index = 0;
425  for(
426  size_t feh_index = __min_interp_feh_index;
427  feh_index < __max_interp_feh_index;
428  ++feh_index
429  ) {
430  double
431  track_feh = __track_feh[feh_index];
432  for(
433  size_t mass_index = __min_interp_mass_index;
434  mass_index < __max_interp_mass_index;
435  ++mass_index
436  ) {
437  double track_mass = __track_masses[mass_index];
438  double track_age = interp_param_to_age(interp_param,
439  track_mass,
440  track_feh);
441  track_values[value_index] = evaluate_track(
442  track_age,
443  *__evolution_tracks[track_index(mass_index,
444  feh_index)],
445  (derivatives
446  ? &((*track_derivatives)[value_index])
447  : NULL)
448  );
449  ++value_index;
450  }
451  }
452  if(derivatives == NULL) {
453  double result = mass_feh_interp(__interp_masses,
454  __interp_feh,
455  track_values,
456  __mass,
457  __feh);
458  delete track_derivatives;
459  return (__log_quantity ? std::exp(result) : result);
460  } else {
461  *derivatives = new InterpolatedDerivatives(
462  __mass,
463  __feh,
464  track_derivatives,
466  __interp_feh,
467  NaN,
469  true
470  );
471  return (*derivatives)->order(0);
472  }
473  }
474 
476  double age,
477  double mass,
478  double feh
479  ) const
480  {
481  //t * (1.0 + (t / 5.0) * m**5 * 10.0**(-0.2*feh))* m**2.3 * 10.0**(-0.4*feh)
482  double feh_factor = std::pow(10.0, -feh / 5.0);
483  return std::log(
484  age
485  *
486  (1.0 + age / 5.0 * std::pow(mass, 5) * feh_factor)
487  *
488  std::pow(mass, 2.3)
489  *
490  std::pow(feh_factor, 2)
491  );
492  }
493 
495  double interp_param,
496  double mass,
497  double feh
498  ) const
499  {
500  double feh_factor = std::pow(10.0, -feh / 5.0),
501  c = (std::exp(interp_param)
502  *
503  std::pow(mass, -2.3)
504  /
505  std::pow(feh_factor, 2)),
506  a = 0.2 * std::pow(mass, 5) * feh_factor,
507  discr = 1.0 + 4.0 * a * c;
508  return (std::sqrt(discr) - 1.0) / (2.0 * a);
509  }
510 
512  double mass,
513  double feh,
514  const std::valarray<double> &track_masses,
515  const std::valarray<double> &track_feh,
516  const std::vector<const OneArgumentDiffFunction *> &evolution_tracks,
517  bool log_age,
518  bool log_quantity,
519  bool starts_zero
520  ) :
521  __mass(mass),
522  __feh(feh),
523  __log_age(log_age),
524  __log_quantity(log_quantity),
525  __initially_zero(starts_zero),
526  __track_masses(track_masses),
527  __track_feh(track_feh),
528  __min_interp_ages(evolution_tracks.size()),
529  __max_interp_ages(evolution_tracks.size()),
530  __evolution_tracks(evolution_tracks)
531  {
532 #ifndef NDEBUG
533  std::cerr << "Creating quantity with mass: " << mass
534  << ", [Fe/H]: " << feh << std::endl
535  << ", with track masses: " << track_masses << std::endl
536  << " and track [Fe/H]: " << track_feh << std::endl
537  << " with " << evolution_tracks.size() << " tracks"
538  << std::endl;
539 #endif
540 
541  assert(evolution_tracks.size() == (track_masses.size()
542  *
543  track_feh.size()));
546 
547  if(starts_zero) {
548  __interp_grid_change_ages.reserve(2 * evolution_tracks.size()
549  +
550  1);
552  -Core::Inf);
553 
554  } else {
555  __interp_grid_change_ages.reserve(2 * evolution_tracks.size());
556  }
559  &__min_interp_ages[0],
561  );
564  &__max_interp_ages[0],
566  );
567 
568  std::sort(__interp_grid_change_ages.begin(),
570  std::unique(__interp_grid_change_ages.begin(),
573 
575  mass,
579  feh,
582 
585  ];
588  ];
589  __min_age = std::max(
590  __min_age,
593  );
594  __max_age = std::min(
595  __max_age,
598  );
599 
600  __min_age = std::max(
601  __min_age,
604  );
605  __max_age = std::min(
606  __max_age,
609  );
610 
611  __min_age = std::max(
612  __min_age,
615  );
616  __max_age = std::min(
617  __max_age,
620  );
621  }
622 
624  const
625  {
626 #ifndef NDEBUG
627  std::cerr << "Finding interpolation region for age = "
628  << age
629  << ", grid change ages: "
630  << std::endl;
631  for(
632  std::vector<double>::const_iterator
633  change_age_i = __interp_grid_change_ages.begin();
634  change_age_i != __interp_grid_change_ages.end();
635  ++change_age_i
636  )
637  std::cerr << "\t" << *change_age_i << std::endl;
638 #endif
639 
640 
641  std::vector<double>::const_iterator new_grid_change_age =
642  std::upper_bound(
645  age
646  );
647  if(__next_grid_change_age != new_grid_change_age) {
648  __next_grid_change_age = new_grid_change_age;
650  !=
653  }
654  }
655 
657  const
658  {
659  const FunctionDerivatives *deriv;
660  interpolate(age, &deriv);
661  return deriv;
662  }
663 
664  double EvolvingStellarQuantity::previous_discontinuity() const
665  {
667  assert(__initially_zero);
668  return -Core::Inf;
669  }
670  std::vector<double>::const_iterator result = __next_grid_change_age;
671  return *(--result);
672  }
673 
674  void EvolvingStellarQuantity::enable_next_interpolation_region() const
675  {
679  }
680 
681 } //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.