Planetary Orbital Evolution due to Tides
Orbital evolution of two objects experiencing tides
OrbitSolver.cpp
Go to the documentation of this file.
1 
10 #define BUILDING_LIBRARY
11 #include "OrbitSolver.h"
12 #include <iostream>
13 #include <iomanip>
14 
15 namespace Evolve {
16 
17  const double MIN_RELATIVE_STEP = (
18  1.0
19  +
20  10.0 * std::numeric_limits<double>::epsilon()
21  );
22 
23  int stellar_system_diff_eq(double age,
24  const double *parameters,
25  double *derivatives,
26  void *system_mode)
27  {
28  void **input_params = static_cast<void **>(system_mode);
29  BinarySystem &system = *static_cast< BinarySystem* >(input_params[0]);
30  Core::EvolModeType evol_mode = *static_cast< Core::EvolModeType* >(
31  input_params[1]
32  );
33  return system.differential_equations(age,
34  parameters,
35  evol_mode,
36  derivatives);
37  }
38 
39 #ifdef ENABLE_DERIVATIVES
40  int stellar_system_jacobian(double age, const double *orbital_parameters,
41  double *param_derivs, double *age_derivs,void *system_mode)
42  {
43  void **input_params = static_cast<void **>(system_mode);
44  BinarySystem &system = *static_cast< BinarySystem* >(input_params[0]);
45  Core::EvolModeType evol_mode = *static_cast< Core::EvolModeType* >(
46  input_params[1]
47  );
48  return system.jacobian(age,
49  orbital_parameters,
50  evol_mode,
51  param_derivs,
52  age_derivs);
53  }
54 #endif
55 
56 #ifndef NDEBUG
58  {
59  assert(
60  !__stop_history_ages.empty()
61  ||
62  !__discarded_stop_ages.empty()
63  );
64  // return;
65  std::streamsize orig_precision=os.precision();
66  os.precision(16);
67  std::ios_base::fmtflags orig_flags=os.flags();
68  os.setf(std::ios_base::scientific);
69 
70  os << "Stored stop condition information:" << std::endl
71  << std::setw(20) << "Age:";
72  bool skip_check = true;
73  std::list<double>::const_iterator age_i;
74  if(__stop_history_ages.size() > 5) {
75  age_i = __stop_history_ages.end();
76  std::advance(age_i, -5);
77  } else
78  age_i = __stop_history_ages.begin();
79  for(
80  ;
81  skip_check || age_i != __discarded_stop_ages.end();
82  ++age_i
83  ) {
84  if(skip_check && age_i == __stop_history_ages.end()) {
85  os << "|";
86  age_i = __discarded_stop_ages.begin();
87  skip_check=false;
88  }
89  os << std::setw(28) << *age_i;
90  }
91  std::string hline;
92  hline.assign(
93  20
94  +
95  25 * (std::min(static_cast<int>(__stop_history_ages.size()), 5)
96  +
97  __discarded_stop_ages.size()),
98  '_'
99  );
100  os << std::endl << hline << std::endl;
101 
102  for(size_t i = 0; i < __stop_cond_discarded.front().size(); i++) {
103  assert(
105  ||
107  );
108  os << std::setw(13) << "Condition["
109  << std::setw(5) << i
110  << "]:"
112  ? " / "
113  : " \\ ");
114  size_t point_num=0;
115  std::list<double>::const_iterator age_i=__stop_history_ages.begin();
116  bool marked_skip_extremum=false;
117  skip_check = true;
118  std::list< std::valarray<double> >::const_iterator cond_i;
119  if(__stop_cond_history.size() > 5) {
120  cond_i = __stop_cond_history.end();
121  std::advance(cond_i, -5);
122  } else
123  cond_i = __stop_cond_history.begin();
124  for(
125  ;
126  skip_check || cond_i != __stop_cond_discarded.end();
127  cond_i++
128  ) {
129  if(skip_check && cond_i == __stop_cond_history.end()) {
130  os << "|";
131  cond_i=__stop_cond_discarded.begin();
132  age_i = __discarded_stop_ages.begin();
133  skip_check = false;
134  }
135  bool marked=false;
136  if(point_num==__skip_history_zerocrossing[i]) {
137  os << "z"; marked=true;
138  } else os << " ";
139  if((*age_i)>__skip_history_extremum[i]
140  && !marked_skip_extremum) {
141  os << "e"; marked_skip_extremum=true; marked=true;
142  } else os << (marked ? "-" : " ");
143  os << (marked ? ">" : " ");
144  os << std::setw(25) << (*cond_i)[i];
145  point_num++;
146  age_i++;
147  }
148  os << std::endl;
149  os << std::setw(13) << "Derivative[" << std::setw(5) << i
150  << "]:";
151  skip_check=true;
152  std::list< std::valarray<double> >::const_iterator deriv_i;
153  if(__stop_deriv_history.size() > 5) {
154  deriv_i = __stop_deriv_history.end();
155  std::advance(deriv_i, -5);
156  } else
157  deriv_i = __stop_deriv_history.begin();
158  for(
159  ;
160  skip_check || deriv_i != __stop_deriv_discarded.end();
161  deriv_i++
162  ) {
163  if(skip_check && deriv_i == __stop_deriv_history.end()) {
164  os << "|";
165  deriv_i=__stop_deriv_discarded.begin();
166  skip_check=false;
167  }
168  os << std::setw(28) << (*deriv_i)[i];
169  }
170  os << std::endl;
171  }
172 
173  os.precision(orig_precision);
174  os.flags(orig_flags);
175  }
176 #endif
177 
179  {
180  __discarded_stop_ages.clear();
181  __stop_cond_discarded.clear();
182  __stop_deriv_discarded.clear();
183  }
184 
186  const std::valarray<double> &current_stop_cond,
187  const std::valarray<double> &current_stop_deriv)
188  {
189  std::list<double>::iterator age_i = __discarded_stop_ages.begin();
190  std::list< std::valarray<double> >::iterator
191  cond_i = __stop_cond_discarded.begin(),
192  deriv_i = __stop_deriv_discarded.begin();
193  while(age_i != __discarded_stop_ages.end() && age > (*age_i)) {
194  age_i++; cond_i++; deriv_i++;
195  }
196  __discarded_stop_ages.insert(age_i, age);
197  __stop_cond_discarded.insert(cond_i, current_stop_cond);
198  __stop_deriv_discarded.insert(deriv_i, current_stop_deriv);
199  }
200 
202  Core::EvolModeType evolution_mode,
203  BinarySystem &system)
204  {
205  clear_discarded();
206  system.add_to_evolution();
207  __tabulated_ages.push_back(age);
208  __tabulated_evolution_modes.push_back(evolution_mode);
209  }
210 
211  double OrbitSolver::go_back(double max_age,
212  BinarySystem &system,
213  std::valarray<double> &orbit)
214  {
215  unsigned nsteps = 0;
216  while(!__tabulated_ages.empty() && max_age < __tabulated_ages.back()) {
217  __tabulated_ages.pop_back();
218  __tabulated_evolution_modes.pop_back();
219  ++nsteps;
220  }
221  system.rewind_evolution(nsteps);
222 
223  if(max_age < __stop_history_ages.back()) clear_discarded();
224  while(
225  !__stop_history_ages.empty()
226  &&
227  max_age < __stop_history_ages.back()
228  ) {
229  __stop_history_ages.pop_back();
230  __orbit_history.pop_back();
231  __orbit_deriv_history.pop_back();
232  __stop_cond_history.pop_back();
233  __stop_deriv_history.pop_back();
234  }
235  for(size_t i = 0; i < __skip_history_zerocrossing.size(); ++i) {
236  __skip_history_zerocrossing[i] = std::min(
238  __stop_history_ages.size()
239  );
240  __skip_history_extremum[i] = std::min(
241  __stop_history_ages.back(),
242  __skip_history_extremum[i]
243  );
244  }
245  orbit = __orbit_history.back();
246  return __stop_history_ages.back();
247  }
248 
250  {
251  __orbit_history.clear();
252  __orbit_deriv_history.clear();
253  __stop_history_ages.clear();
254  __stop_cond_history.clear();
255  __stop_deriv_history.clear();
256  clear_discarded();
257  }
258 
260  bool crossing,
261  size_t cond_ind,
262  size_t max_points
263  ) const
264  {
265  if(crossing)
266  assert(
267  __stop_cond_history.size()
268  -
270  >=
271  1
272  );
273  else
274  assert(
275  __stop_cond_history.size()
276  -
278  >=
279  2
280  );
281  size_t num_points = std::min(
282  max_points,
283  (
284  __stop_history_ages.size()
285  +
286  __discarded_stop_ages.size()
287  -
288  (crossing ? __skip_history_zerocrossing[cond_ind] : 0)
289  )
290  );
291  std::list<double>::const_iterator first_age = __stop_history_ages.end();
292  std::list< std::valarray<double> >::const_iterator
293  first_stop_cond = __stop_cond_history.end(),
294  first_stop_deriv = __stop_deriv_history.end();
295  int go_back = (static_cast<int>(num_points)
296  -
297  static_cast<int>(__discarded_stop_ages.size()));
298  go_back = std::max(go_back, (crossing ? 1 : 2));
299  size_t failed_back = 0;
300  for(int i = 0; i < go_back; ++i) {
301  --first_age;
302  --first_stop_cond;
303  --first_stop_deriv;
304  if(!crossing && *first_age < __skip_history_extremum[cond_ind]) {
305  ++failed_back;
306  ++first_age;
307  ++first_stop_cond;
308  ++first_stop_deriv;
309  --num_points;
310  }
311  }
312  if(go_back - failed_back < (crossing ? 1 : 2))
313  return StopHistoryInterval();
314  StopHistoryInterval interval(num_points,
315  first_age,
316  __stop_history_ages.end(),
317  __discarded_stop_ages.begin(),
318  first_stop_cond,
319  __stop_cond_history.end(),
320  __stop_cond_discarded.begin(),
321  first_stop_deriv,
322  __stop_deriv_history.end(),
323  __stop_deriv_discarded.begin()),
324  result = interval;
325  int max_left_shift = std::min(__discarded_stop_ages.size() - 1,
326  num_points - (crossing ? 2 : 3));
327  int history_limit = 0;
328  if(crossing)
329  history_limit = (__stop_history_ages.size()
330  -
331  go_back
332  +
333  failed_back
334  -
335  __skip_history_zerocrossing[cond_ind]);
336  else
337  while(
338  first_age != __stop_history_ages.begin()
339  &&
340  *(--first_age) > __skip_history_extremum[cond_ind]
341  )
342  ++history_limit;
343  max_left_shift = std::min(history_limit, max_left_shift);
344  for(int i = 0; i < max_left_shift; i++) {
345  interval << 1;
346  if(
347  (interval.last_age() - interval.first_age())
348  <
349  result.last_age() - result.first_age()
350  )
351  result = interval;
352  }
353  return result;
354  }
355 
357  size_t condition_index
358  ) const
359  {
360  ExtremumInformation result;
361  if(
362  __stop_history_ages.size()
363  -
364  __skip_history_zerocrossing[condition_index] < 2
365  )
366  return result;
367  std::list< std::valarray<double> >::const_iterator stop_cond_i =
368  __stop_cond_history.end();
369  double pre1_cond = (*(--stop_cond_i))[condition_index],
370  pre2_cond = (*(--stop_cond_i))[condition_index],
371  post_cond = __stop_cond_discarded.front()[condition_index];
372  if(
373  std::abs(pre1_cond) > std::abs(pre2_cond)
374  ||
375  std::abs(pre1_cond) > std::abs(post_cond)
376  ||
377  (
378  !std::isfinite(pre1_cond)
379  &&
380  !std::isfinite(pre2_cond)
381  &&
382  !std::isfinite(post_cond)
383  )
384  )
385  return result;
386 
388  false,
389  condition_index,
390  4
391  );
392  if(stop_interval.num_points() < 3)
393  return result;
394  double t0 = stop_interval.age(),
395  c0 = stop_interval.stop_condition_value(condition_index),
396  t1 = (++stop_interval).age(),
397  c1 = stop_interval.stop_condition_value(condition_index),
398  t2 = (++stop_interval).age(),
399  c2 = stop_interval.stop_condition_value(condition_index),
400  abs_c0 = std::abs(c0),
401  abs_c1 = std::abs(c1),
402  abs_c2 = std::abs(c2);
403 
404  const double min_fractional_diff = (
405  1000.0
406  *
407  std::numeric_limits<double>::epsilon()
408  );
409 
410  bool ignore_10_diff = (std::abs(c1 - c0) / std::max(abs_c0, abs_c1)
411  <
412  min_fractional_diff),
413  ignore_21_diff = (std::abs(c2 - c1) / std::max(abs_c1, abs_c2)
414  <
415  min_fractional_diff);
416 
417 
418  if(stop_interval.num_points() == 3) {
419  if((c1 - c0) * (c2 - c1) > 0 || ignore_10_diff || ignore_21_diff)
420  {
421  return result;
422  }
423  result.x() = Core::quadratic_extremum(t0, c0, t1, c1, t2, c2,
424  &(result.y()));
425  } else {
426  double t3 = (++stop_interval).age(),
427  c3 = stop_interval.stop_condition_value(condition_index),
428  abs_c3 = std::abs(c3);
429  bool ignore_32_diff = (
430  std::abs(c3 - c2) / std::max(abs_c3, abs_c2)
431  <
432  min_fractional_diff
433  );
434  if(
435  (
436  (c1 - c0) * (c2 - c1) > 0
437  ||
438  abs_c1 >= std::max(abs_c0, abs_c2)
439  ||
440  ignore_10_diff
441  ||
442  ignore_21_diff
443  )
444  &&
445  (
446  (c2 - c1) * (c3 - c2) > 0
447  ||
448  abs_c2 >= std::max(abs_c1, abs_c3)
449  ||
450  ignore_21_diff
451  ||
452  ignore_32_diff
453  )
454  ){
455  return result;
456  }
457  double range_low,
458  range_high;
459  if(
460  !ignore_10_diff
461  &&
462  std::abs(c1) <= std::abs(c0)
463  &&
464  std::abs(c1) <= std::abs(c2)
465  ) {
466  range_low = t0;
467  range_high = t2;
468  } else if(
469  !ignore_32_diff
470  &&
471  abs_c2 <= abs_c1
472  &&
473  abs_c2 <= abs_c3
474  ) {
475  range_low = t1;
476  range_high = t3;
478  "Searching for extremum among monotonic stopping condition "
479  "values in OrbitSolver::extremum_from_history_no_deriv."
480  );
481  result.x() = Core::cubic_extremum(t0, c0, t1, c1, t2, c2, t3, c3,
482  &(result.y()),
483  range_low, range_high);
484  }
485  return result;
486  }
487 
489  size_t condition_index,
490  double min_extremum_x
491  ) const
492  {
493  ExtremumInformation result;
494  if(
495  __stop_history_ages.size() == 0
496  ||
497  (
498  __stop_history_ages.back()
499  <
500  __skip_history_extremum[condition_index]
501  )
502  )
503  return result;
504  double prev_stop_cond = __stop_cond_history.back()[condition_index],
505  next_stop_cond = __stop_cond_discarded.front()[condition_index];
506  if(next_stop_cond * prev_stop_cond <= 0)
507  return result;
508  if(std::isnan(__stop_deriv_history.back()[condition_index])) {
509  result = extremum_from_history_no_deriv(condition_index);
510  } else {
511  double
512  prev_stop_deriv = __stop_deriv_history.back()[
513  condition_index
514  ],
515  next_stop_deriv = __stop_deriv_discarded.front()[
516  condition_index
517  ];
518  if(
519  next_stop_cond * next_stop_deriv < 0
520  ||
521  next_stop_deriv * prev_stop_deriv >= 0
522  )
523  return result;
524  result.x() = Core::estimate_extremum(__stop_history_ages.back(),
525  prev_stop_cond,
526  __discarded_stop_ages.front(),
527  next_stop_cond,
528  prev_stop_deriv,
529  next_stop_deriv,
530  &(result.y()));
531  }
532 
533  if(result.x() < min_extremum_x) {
534  result.x() = min_extremum_x;
535  result.y() = Core::NaN;
536  }
537 
538  return result;
539  }
540 
541  double OrbitSolver::crossing_from_history_no_deriv(size_t condition_index)
542  const
543  {
545  true,
546  condition_index,
547  4
548  );
549  if(stop_interval.num_points() < 2) return Core::Inf;
550  double t0 = stop_interval.age(),
551  c0 = stop_interval.stop_condition_value(condition_index),
552  t1 = (++stop_interval).age(),
553  c1 = stop_interval.stop_condition_value(condition_index);
554  if(stop_interval.num_points() == 2)
555  return Core::estimate_zerocrossing(t0, c0, t1, c1);
556  double t2 = (++stop_interval).age(),
557  c2 = stop_interval.stop_condition_value(condition_index);
558  double range_low = Core::NaN,
559  range_high = Core::NaN;
560  short crossing_sign =
562  condition_index
563  );
564  if(c0 * c1 <= 0 && c1 * crossing_sign > 0) {
565  range_low = t0;
566  range_high = t1;
567  } else if(c1 * c2 <= 0 && c2 * crossing_sign > 0) {
568  range_low = t1;
569  range_high = t2;
570  }
571  if(stop_interval.num_points() == 3) {
572  assert(!std::isnan(range_low) && !std::isnan(range_high));
573  return Core::quadratic_zerocrossing(
574  t0, c0, t1, c1, t2, c2, range_low, range_high
575  );
576  }
577  double t3 = (++stop_interval).age(),
578  c3 = stop_interval.stop_condition_value(condition_index);
579  if(std::isnan(range_low)) {
580  range_low = t2;
581  range_high = t3;
582  assert(c2 * c3 < 0);
583  assert(c3 * crossing_sign > 0);
584  }
585  return Core::cubic_zerocrossing(
586  t0, c0, t1, c1, t2, c2, t3, c3, range_low, range_high
587  );
588  }
589 
590  double OrbitSolver::crossing_from_history(size_t condition_index) const
591  {
592  if(
593  __stop_history_ages.size() == 0
594  ||
595  (
596  __stop_history_ages.size()
597  ==
598  __skip_history_zerocrossing[condition_index]
599  )
600  )
601  return Core::Inf;
602  double prev_stop_cond = __stop_cond_history.back()[condition_index];
603  double next_stop_cond = __stop_cond_discarded.front()[condition_index];
604  if(
605  next_stop_cond * prev_stop_cond > 0
606  ||
607  (
608  next_stop_cond
609  *
611  condition_index
612  )
613  <
614  0
615  )
616  ||
617  (
618  next_stop_cond == 0
619  &&
620  prev_stop_cond
621  *
623  condition_index
624  )
625  >=
626  0
627  )
628  )
629  return Core::Inf;
630  if(std::isnan(__stop_deriv_history.back()[condition_index]))
631  return crossing_from_history_no_deriv(condition_index);
632  double
633  prev_stop_deriv = __stop_deriv_history.back()[condition_index],
634  prev_age = __stop_history_ages.back(),
635  next_stop_deriv = __stop_deriv_discarded.front()[condition_index],
636  next_age = __discarded_stop_ages.front();
637  return Core::estimate_zerocrossing(prev_age,
638  prev_stop_cond,
639  next_age,
640  next_stop_cond,
641  prev_stop_deriv,
642  next_stop_deriv);
643  }
644 
646  const StoppingCondition &stop_cond,
647  const std::valarray<double> &stop_cond_values,
648  StoppingConditionType stop_reason
649  )
650  {
651 #ifndef NDEBUG
652  std::cerr << "Initializing skip history with stop reason: "
653  << stop_reason
654  << std::endl;
655 #endif
656  __skip_history_zerocrossing.resize(stop_cond.num_subconditions(), 0);
657  __skip_history_extremum.resize(stop_cond.num_subconditions(), 0);
658  for(
659  size_t cond_ind = 0;
660  cond_ind < stop_cond.num_subconditions();
661  cond_ind++
662  ) {
663  StoppingConditionType stop_cond_type=stop_cond.type(cond_ind);
664  if(
665  (
666  (
667  stop_reason == BREAK_LOCK
668  &&
669  stop_cond_type == SYNCHRONIZED
670  )
671  ||
672  (
673  stop_reason != NO_STOP
674  &&
675  stop_reason != BREAK_LOCK
676  &&
677  stop_cond_type == stop_reason
678  )
679  )
680  &&
681  std::abs(stop_cond_values[cond_ind]) <= __precision
682  ) {
683 #ifndef NDEBUG
684  std::cerr << "Skipping first step of condition "
685  << cond_ind
686  << "(" << stop_cond_type << ")"
687  << std::endl;
688 #endif
689  __skip_history_zerocrossing[cond_ind]=1;
690  __skip_history_extremum[cond_ind]=(
691  __stop_history_ages.front()
692  *
693  (1.0+std::numeric_limits<double>::epsilon())
694  );
695  }
696 #ifdef VERBOSE_DEBUG
697  else
698  std::cerr << "Not skipping condition "
699  << cond_ind
700  << "(" << stop_cond_type << ")"
701  << std::endl;
702 #endif
703  }
704  }
705 
707  const std::valarray<double> &current_stop_cond,
708  const StopInformation &stop_info)
709  {
710  size_t history_size = __stop_history_ages.size();
711  for(size_t i = 0; i < current_stop_cond.size(); i++) {
712  if(
713  __skip_history_zerocrossing[i] == history_size
714  &&
715  std::abs(current_stop_cond[i]) <= __precision
716  )
718  if(
719  stop_info.stop_reason() == __stopping_conditions->type(i)
720  &&
721  !stop_info.is_crossing()
722  &&
723  (
724  std::abs(stop_info.stop_condition_precision())
725  <=
727  )
728  )
729  __skip_history_extremum[i]=stop_info.stop_age();
730  }
731  }
732 
733  bool OrbitSolver::at_exact_condition(double previous_age,
734  const StopInformation &stop_info)
735  {
736  return (
737  (
738  std::abs(stop_info.stop_condition_precision())
739  <=
741  )
742  ||
743  (
744  stop_info.stop_age()
745  <
746  previous_age * MIN_RELATIVE_STEP
747  )
748  );
749  }
750 
751  bool OrbitSolver::acceptable_step(double current_age,
752  double previous_age,
753  const StopInformation &stop_info)
754  {
755 #ifdef VERBOSE_DEBUG
756  std::cerr << "From t = " << previous_age
757  << ", stepped to t = " << current_age
758  << ", stop at t = " << stop_info.stop_age()
759  << ", must be at least: " << previous_age * MIN_RELATIVE_STEP
760  << std::endl;
761  if(
762  at_exact_condition(previous_age, stop_info)
763  &&
764  std::abs(stop_info.stop_condition_precision()) > __precision
765  ) {
766  std::cerr << "Failed to meet precision for "
767  << stop_info
768  << std::endl;
769  }
770 #endif
771  return (
772  stop_info.stop_age() >= current_age
773  ||
774  (
775  at_exact_condition(previous_age, stop_info)
776  &&
777  (stop_info.crossed_zero() || !stop_info.is_crossing())
778  )
779  );
780  }
781 
783  double age,
784  const std::valarray<double> &orbit,
785  const std::valarray<double> &derivatives,
786  Core::EvolModeType evolution_mode,
787  unsigned current_expansion_order,
788  StoppingConditionType stop_reason
789  )
790  {
791  for(unsigned i = 0; i < orbit.size(); ++i)
792  if(
793  std::isnan(orbit[i])
794  ||
795  (evolution_mode == Core::BINARY && orbit[0] <= 0)
796  ) {
797 #ifndef NDEBUG
798  std::cerr << "Bad orbit: " << orbit << std::endl;
799 #endif
800  return StopInformation(
801  0.5 * (age + __stop_history_ages.back()),
802  Core::Inf
803  );
804  }
805 
806  std::pair<double, double> expansion_range =
807  TidalPotentialTerms::get_expansion_range(current_expansion_order);
808 
809 #ifdef VERBOSE_DEBUG
810  if(evolution_mode == Core::BINARY)
811  std::cerr << "Updating stop condition history. Current e = "
812  << orbit[1]
813  << " current expansion order: "
814  << current_expansion_order
815  << " current expansion range: "
816  << expansion_range.first
817  << " < e < "
818  << expansion_range.second
819  << std::endl;
820 #endif
821 
822 
823  if(
824  evolution_mode == Core::BINARY
825  &&
826  orbit[1] > expansion_range.second
827  ) {
828 #ifdef VERBOSE_DEBUG
829  std::cerr << "Eccentricity ("
830  << orbit[1]
831  << ") exceeds current expansion error limit of "
832  << expansion_range.second
833  << ". Choosing to stop half way between t = "
834  << age
835  << " and t = "
836  << __stop_history_ages.back()
837  << std::endl;
838 #endif
839  return StopInformation(
840  0.5 * (age + __stop_history_ages.back()),
841  Core::Inf,
843  true,
844  true
845  );
846  }
847 
848  std::valarray<double> current_stop_cond(
850  );
851  std::valarray<double> current_stop_deriv;
852  current_stop_cond = (*__stopping_conditions)(evolution_mode,
853  orbit,
854  derivatives,
855  current_stop_deriv);
856 
857  if(__stop_history_ages.empty())
859  current_stop_cond,
860  stop_reason);
861  StopInformation result;
862  insert_discarded(age, current_stop_cond, current_stop_deriv);
863 #ifdef VERBOSE_DEBUG
864  std::cerr << std::string(77, '@') << std::endl;
865  output_history_and_discarded(std::cerr);
866  std::cerr << "Decreasing expansion order is "
867  << (current_expansion_order == 0 ? "not" : "")
868  << " allowed"
869  <<std::endl;
870 #endif
871  for(
872  size_t cond_ind = 0;
873  (
874  __stop_cond_history.size() > 0
875  &&
876  cond_ind < current_stop_cond.size()
877  );
878  cond_ind++
879  ) {
880  double stop_cond_value = current_stop_cond[cond_ind],
881  crossing_age = crossing_from_history(cond_ind),
882  crossing_precision =
883  __stop_cond_history.back()[cond_ind];
884  bool crossed_zero = false;
885  if(std::abs(crossing_precision) >= std::abs(stop_cond_value)) {
886  crossing_precision = stop_cond_value;
887  crossed_zero = true;
888  }
890  cond_ind,
892  );
893  double extremum_precision;
894  if(std::isnan(extremum.y())) extremum_precision = Core::NaN;
895  else
896  extremum_precision = (
897  std::min(
898  std::abs(extremum.y() - stop_cond_value),
899  std::abs(extremum.y()
900  -
901  __stop_cond_history.back()[cond_ind])
902  )
903  /
904  std::abs(extremum.y())
905  );
906  bool is_crossing = crossing_age <= extremum.x();
907  short deriv_sign = 0;
908  if(is_crossing) deriv_sign = (stop_cond_value > 0 ? 1 : -1);
909  StopInformation &stop_info = __stop_info[cond_ind];
910  stop_info.stop_age() = std::min(crossing_age, extremum.x());
911  stop_info.stop_condition_precision() = (is_crossing
912  ? crossing_precision
913  : extremum_precision);
914  stop_info.is_crossing() = is_crossing;
915  stop_info.crossed_zero() = crossed_zero;
916  stop_info.deriv_sign_at_crossing() = (is_crossing
917  ? deriv_sign
918  : 0.0);
919 #ifdef VERBOSE_DEBUG
920  std::cerr << "Condition " << cond_ind << " "
921  << __stopping_conditions->describe(cond_ind)
922  << ": " << stop_info
923  << std::endl;
924 #endif
925  if(
926  !__stop_history_ages.empty()
927  &&
928  (
929  !acceptable_step(age, __stop_history_ages.back(), stop_info)
930  ||
931  is_crossing
932  )
933  &&
934  stop_info.stop_age() < result.stop_age()
935  ) {
936  result = stop_info;
937 #ifdef VERBOSE_DEBUG
938  std::cerr << "SELECTED" << std::endl;
939  } else {
940  std::cerr << "NOT SELECTED!" << std::endl;
941 #endif
942  }
943  }
944  if(
945  __stop_history_ages.empty()
946  ||
947  acceptable_step(age, __stop_history_ages.back(), result)
948  ) {
949  if(!__stop_history_ages.empty())
950  update_skip_history(current_stop_cond, result);
951  __stop_history_ages.push_back(age);
952  __stop_cond_history.push_back(current_stop_cond);
953  __stop_deriv_history.push_back(current_stop_deriv);
954  __orbit_history.push_back(orbit);
955  __orbit_deriv_history.push_back(derivatives);
956 
957  if(
958  result.stop_reason() == NO_STOP
959  &&
960  evolution_mode == Core::BINARY
961  &&
962  orbit[1] < expansion_range.first
963  &&
964  age > (0.99 * __last_order_upgrade_age
965  +
966  0.01 * __end_age)
967  &&
968  current_expansion_order > 0
969  ) {
970 #ifdef VERBOSE_DEBUG
971  std::cerr << "Eccentricity ("
972  << orbit[1]
973  << " is sufficiently small (< "
974  << expansion_range.first
975  << ") to decrease expansion order."
976  << std::endl;
977 #endif
978  return StopInformation(Core::Inf,
979  Core::Inf,
981  true,
982  true);
983  }
984 
985  } else {
986 #ifndef NDEBUG
987  std::cerr << "Step to age = "
988  << age
989  << " deemed unacceptable: "
990  << result
991  << std::endl;
992 #endif
993  }
994  return result;
995  }
996 
998  double &t,
999  StopInformation &stop,
1000  BinarySystem &system,
1001  std::valarray<double> &orbit,
1002  double &max_next_t,
1003  double &step_size
1004 #ifndef NDEBUG
1005  , std::string reason
1006 #endif
1007  )
1008  {
1009  double last_good_t = go_back(stop.stop_age(),
1010  system,
1011  orbit);
1012 #ifndef NDEBUG
1013  std::cerr
1014  << "Reverting step from t = "
1015  << t
1016  << " to "
1017  << last_good_t
1018  << " due to "
1019  << reason
1020  << "Stop info: "
1021  << stop
1022  << std::endl;
1023 #endif
1024 
1025  if(
1026  t
1027  <
1028  last_good_t * MIN_RELATIVE_STEP
1029  ) {
1030 #ifndef NDEBUG
1031  std::cerr << "Stepped only "
1032  << t - last_good_t
1033  << "Gyr, aborting!"
1034  << std::endl;
1035 #endif
1037  }
1038  t = last_good_t;
1039  if(stop.is_crossing())
1040  stop.stop_condition_precision() = (
1041  __stop_cond_history.back()[
1042  stop.stop_condition_index()
1043  ]
1044  );
1045  max_next_t = stop.stop_age();
1046  step_size = 0.1 * (max_next_t - t);
1047  }
1048 
1050  BinarySystem &system,
1051  double &max_age,
1052  std::valarray<double> &orbit,
1053  StoppingConditionType &stop_reason,
1054  double max_step,
1055  Core::EvolModeType evolution_mode
1056  )
1057  {
1058  size_t nargs = orbit.size();
1059 #ifndef NDEBUG
1060  std::cerr << "Starting evolution leg in " << evolution_mode
1061  << " from t=" << system.age() << " with initial orbit:\n";
1062  for(size_t i = 0; i < nargs; ++i) {
1063  if(i) std::cerr << ", ";
1064  std::cerr << "\t" << orbit[i] << std::endl;
1065  }
1066  std::cerr << std::endl;
1067  std::cerr << "Stopping conditions:" << std::endl
1068  << __stopping_conditions->describe() << std::endl;
1069 #endif
1070 
1071  const gsl_odeiv2_step_type *step_type = gsl_odeiv2_step_rkf45;
1072 
1073  gsl_odeiv2_step *step = gsl_odeiv2_step_alloc(step_type, nargs);
1074  gsl_odeiv2_control *step_control = gsl_odeiv2_control_standard_new(
1075  __precision,
1076  __precision,
1077  1,
1078  0
1079  );
1080  gsl_odeiv2_evolve *evolve = gsl_odeiv2_evolve_alloc(nargs);
1081 
1082  void *sys_mode[2]={&system, &evolution_mode};
1083  gsl_odeiv2_system ode_system={stellar_system_diff_eq,
1084 #ifdef ENABLE_DERIVATIVES
1086 #else
1087  NULL,
1088 #endif
1089  nargs,
1090  sys_mode};
1091  double t=system.age();
1092  std::valarray<double> derivatives(nargs),
1093  param_derivatives(nargs),
1094  age_derivatives(nargs);
1095 
1096  add_to_evolution(t, evolution_mode, system);
1097 
1098  clear_discarded();
1099  double step_size = std::min(0.1 * (max_age - t),
1100  max_step);
1101 
1102  StopInformation stop;
1103  bool first_step = true;
1104  double from_t;
1105  while(t<max_age) {
1106  double max_next_t = std::min(t + max_step, max_age);
1107  int status=GSL_SUCCESS;
1108  bool step_rejected=false;
1109  do {
1110 #ifndef NDEBUG
1111  std::cerr << "Attempting step from t = " << t
1112  << " not to miss t = " << max_next_t
1113  << ", suggested step = " << step_size
1114  << ", orbit:\n";
1115  for(size_t i=0; i<nargs; ++i) {
1116  if(i) std::cerr << ", ";
1117  std::cerr << "\t" << orbit[i] << std::endl;
1118  }
1119  std::cerr << std::endl;
1120 #endif
1121  from_t = t;
1122  if(!first_step) {
1123  step_size = std::max(step_size,
1124  3.0 * (MIN_RELATIVE_STEP * t - t));
1125  status = gsl_odeiv2_evolve_apply(evolve,
1126  step_control,
1127  step,
1128  &ode_system,
1129  &t,
1130  max_next_t,
1131  &step_size,
1132  &(orbit[0]));
1133  }
1134  if (status == GSL_FAILURE) {
1135 #ifndef NDEBUG
1136  std::cerr << "Failed, (presume zero step size)!"
1137  << std::endl;
1138 #endif
1139  throw Core::Error::GSLZeroStep("rkf45");
1140  } else if (status != GSL_SUCCESS && status != GSL_EDOM) {
1141  std::ostringstream msg;
1142  msg << "GSL signaled failure while evolving (error code " <<
1143  status << ")";
1144  throw Core::Error::Runtime(msg.str());
1145  } else if (
1146  (
1147  __runtime_limit > 0
1148  &&
1149  difftime(time(NULL), __evolution_start_time)
1150  >
1152  )
1153  ||
1154  (
1155  __num_step_limit > 0
1156  &&
1157  (
1158  __tabulated_ages.size()
1159  +
1160  __discarded_stop_ages.size()
1161  >
1163  )
1164  )
1165  ) {
1166  std::ostringstream msg;
1167  msg << "After "
1168  << __tabulated_ages.size()
1169  << "steps (+"
1170  << __discarded_stop_ages.size()
1171  << " discarded), exceeded evolution time limit of "
1172  << __runtime_limit
1173  << " seconds or step limit of "
1174  << __num_step_limit
1175  << " steps!";
1176  throw Core::Error::Runtime(msg.str());
1177  }
1178  if(status == GSL_SUCCESS) {
1179 #ifdef NDEBUG
1180  if(__print_progress)
1181 #endif
1182  std::cerr << "Succeeded! Now t = " << t << std::endl;
1183 #ifdef VERBOSE_DEBUG
1184  std::cerr << "GSL suggested new step size:"
1185  << step_size
1186  << std::endl;
1187 #endif
1188 
1190  &(orbit[0]),
1191  &(derivatives[0]),
1192  sys_mode);
1193 
1195  t,
1196  orbit,
1197  derivatives,
1198  evolution_mode,
1199  system.expansion_order(),
1200  stop_reason
1201  );
1202  stop_reason = NO_STOP;
1203  }
1204  if(
1205  (status == GSL_EDOM || !acceptable_step(t, from_t, stop))
1206  &&
1207  !first_step
1208  ) {
1209  reject_step(
1210  t,
1211  stop,
1212  system,
1213  orbit,
1214  max_next_t,
1215  step_size
1216 #ifndef NDEBUG
1217  , (status == GSL_EDOM ? "EDOM error" : "bad step")
1218 #endif
1219  );
1220  step_rejected = true;
1221  gsl_odeiv2_evolve_reset(evolve);
1222  } else {
1223  if(!first_step && t < from_t * MIN_RELATIVE_STEP) {
1224 #ifndef NDEBUG
1225  std::cerr << "Stepped only "
1226  << t - from_t
1227  << "Gyr, aborting!"
1228  << std::endl;
1229 #endif
1230  throw Core::Error::GSLZeroStep("rkf45");
1231  }
1232  step_rejected=false;
1233  }
1234 
1235  } while(
1236  step_rejected
1237  &&
1238  !first_step
1239  &&
1240  (
1241  !at_exact_condition(from_t, stop)
1242  ||
1243  __stop_history_ages.size() == 1
1244  )
1245  &&
1247  );
1248 
1249  if(!step_rejected) {
1250 #ifndef NDEBUG
1251  std::cerr << "Stepped to t = " << t << std::endl;
1252 #endif
1253  add_to_evolution(t, evolution_mode, system);
1254  }
1255 #ifndef NDEBUG
1256  std::cerr << "Stop: " << stop
1257  << "expansion order: " << system.expansion_order()
1258  << "last order upgrade at t=" << __last_order_upgrade_age
1259  << "max age: " << max_age
1260  << std::endl;
1261 #endif
1262  if(
1263  (stop.is_crossing() && stop.stop_reason() != NO_STOP)
1264  ||
1266  ||
1267  (
1269  &&
1270  system.expansion_order() > 0
1271  &&
1272  !first_step
1273  )
1274  ) {
1275  stop_reason = stop.stop_reason();
1276 #ifndef NDEBUG
1277  std::cerr << "Breaking for = " << stop << std::endl;
1278 #endif
1279  break;
1280  }
1281 
1282  first_step = false;
1283  }
1284  max_age=t;
1285  clear_history();
1287  &(orbit[0]),
1288  &(derivatives[0]),
1289  sys_mode);
1290 
1291  gsl_odeiv2_evolve_free(evolve);
1292  gsl_odeiv2_control_free(step_control);
1293  gsl_odeiv2_step_free(step);
1294  return stop;
1295  }
1296 
1298  BinarySystem &system
1299  )
1300  {
1302 #ifdef EXTERNAL_CONDITION
1303  (*result) |= new EXTERNAL_CONDITION;
1304 #endif
1305  __stop_info.clear();
1306  __stop_info.resize(result->num_subconditions());
1307  for(size_t cond_ind = 0; cond_ind < __stop_info.size(); ++cond_ind)
1308  {
1309  __stop_info[cond_ind].stop_reason() = result->type(cond_ind);
1310  __stop_info[cond_ind].stop_condition_index() = cond_ind;
1311  }
1312  return result;
1313  }
1314 
1315  double OrbitSolver::stopping_age(double age,
1316  const BinarySystem &system,
1317  const std::list<double> &required_ages)
1318  {
1319 #ifndef NDEBUG
1320  std::cerr << "Determining next stop age: " << std::endl;
1321 #endif
1322  double result = system.next_stop_age();
1323 #ifndef NDEBUG
1324  std::cerr << "Next system stop age: " << result << std::endl;
1325 #endif
1326  if(required_ages.size() == 0) return result;
1327 
1328  static std::list<double>::const_iterator
1329  next_required_age = required_ages.begin();
1330  if(age <= required_ages.front())
1331  next_required_age = required_ages.begin();
1332  if(
1333  next_required_age != required_ages.end()
1334  &&
1335  age == *next_required_age
1336  )
1337  ++next_required_age;
1338  if(
1339  next_required_age != required_ages.end()
1340  &&
1341  result > *next_required_age
1342  )
1343  result = *next_required_age;
1344 #ifndef NDEBUG
1345  std::cerr << "Required ages change that to: " << result << std::endl;
1346 #endif
1347  return result;
1348  }
1349 
1351  double stop_age,
1352  StoppingConditionType stop_reason
1353  )
1354  {
1355 #ifndef NDEBUG
1356  std::cerr << "Stopped due to condition at t = "
1357  << stop_age
1358  << std::endl;
1359 #endif
1360  for(
1361  std::vector<StopInformation>::const_iterator stop_i =
1362  __stop_info.begin();
1363  stop_i != __stop_info.end();
1364  ++stop_i
1365  ) {
1366  if(
1367  stop_i->is_crossing()
1368  &&
1369  (
1370  stop_i->stop_age() < stop_age
1371  ||
1372  (
1373  stop_i->stop_reason() == stop_reason
1374  &&
1375  at_exact_condition(stop_age, *stop_i)
1376  )
1377  )
1378  ) {
1379 #ifndef NDEBUG
1380  std::cerr << "Triggered condition: "
1382  stop_i->stop_condition_index()
1383  )
1384  << std::endl;
1385 #endif
1387  stop_i->deriv_sign_at_crossing(),
1388  stop_i->stop_condition_index()
1389  );
1390  }
1391  }
1392  }
1393 
1396  BinarySystem &system,
1397  const std::valarray<double> &orbit,
1398  Core::EvolModeType evolution_mode,
1399  bool must_increase
1400  )
1401  {
1402 #ifndef NDEBUG
1403  std::cerr << "Adjusting expansion order at t ="
1404  << system.age();
1405  if(must_increase)
1406  std::cerr << " upward!";
1407  std::cerr << std::endl;
1408 #endif
1409  assert(evolution_mode == Core::BINARY);
1410 
1411  unsigned
1412  current_expansion_order = system.expansion_order(),
1413  required_expansion_order =
1415 
1416  if(must_increase)
1417  required_expansion_order = std::max(required_expansion_order,
1418  current_expansion_order + 1);
1419 
1420  if(required_expansion_order != current_expansion_order) {
1421  if(required_expansion_order > current_expansion_order)
1422  __last_order_upgrade_age = system.age();
1423  system.change_expansion_order(required_expansion_order);
1424  }
1425 
1426 #ifdef NDEBUG
1427  if(__print_progress)
1428 #endif
1429  std::cerr << "At e(t = "
1430  << system.age()
1431  << ") = "
1432  << orbit[1]
1433  << " adjusted expansion order from "
1434  << current_expansion_order
1435  << " to "
1436  << required_expansion_order
1437  << std::endl;
1438  }
1439 
1441  {
1442  __tabulated_ages.clear();
1444  system.reset_evolution();
1445  }
1446 
1448  double required_precision,
1449  bool print_progress) :
1450  __end_age(max_age),
1451  __precision(required_precision),
1453  __stopping_conditions(NULL),
1454  __print_progress(print_progress)
1455  {
1456 #ifndef NDEBUG
1457  assert(max_age>0);
1458 #endif
1459  }
1460 
1462  double max_step,
1463  const std::list<double> &required_ages,
1464  double max_runtime,
1465  unsigned max_time_steps,
1466  double min_extremum_search_step)
1467  {
1468 #ifndef NDEBUG
1469  std::cerr << "Calculating evolution from t = " << system.age()
1470  << " to t = " << __end_age << std::endl;
1471 #endif
1472  time(&__evolution_start_time);
1473  __runtime_limit = max_runtime;
1474  __num_step_limit = max_time_steps;
1475 
1476  __min_extremum_search_step = min_extremum_search_step;
1477 
1478  double stop_evol_age = __end_age;
1479 
1480  reset(system);
1481  StoppingConditionType stop_reason = NO_STOP;
1482  double last_age = system.age();
1483  std::valarray<double> orbit;
1484 
1485  Core::EvolModeType evolution_mode = system.fill_orbit(orbit);
1486 
1487  if(evolution_mode == Core::BINARY) {
1488  adjust_expansion_order(system,
1489  orbit,
1490  evolution_mode);
1491  __last_order_upgrade_age = -Core::Inf;
1492  }
1493 
1494  while(last_age < stop_evol_age) {
1495  double next_stop_age = std::min(stopping_age(last_age,
1496  system,
1497  required_ages),
1498  stop_evol_age);
1500  last_age = next_stop_age;
1501 #ifndef NDEBUG
1502  std::cerr << "Next stop age: " << next_stop_age << std::endl;
1503  StopInformation stop_information =
1504 #endif
1505  evolve_until(system,
1506  last_age,
1507  orbit,
1508  stop_reason,
1509  max_step,
1510  evolution_mode);
1511 
1512  Core::EvolModeType old_evolution_mode = evolution_mode;
1513 #ifndef NDEBUG
1514  std::cerr << "Stop information: "
1515  << stop_information
1516  << std::endl;
1517  unsigned old_locked_zones = system.number_locked_zones();
1518 #endif
1519  if(last_age < stop_evol_age) {
1520  if(stop_reason == NO_STOP || last_age == next_stop_age) {
1521  system.reached_critical_age(last_age);
1522  } else if(
1523  stop_reason == LARGE_EXPANSION_ERROR
1524  ||
1525  stop_reason == SMALL_EXPANSION_ERROR
1526  ) {
1528  system,
1529  orbit,
1530  evolution_mode,
1531  stop_reason == LARGE_EXPANSION_ERROR
1532  );
1533  } else
1534  reached_stopping_condition(last_age, stop_reason);
1535  }
1536  evolution_mode = system.evolution_mode();
1537 #ifndef NDEBUG
1538  std::valarray<double> old_orbit(orbit);
1539 #endif
1540  system.fill_orbit(orbit);
1541 
1542  if(evolution_mode == Core::BINARY) {
1543  if(old_evolution_mode != Core::BINARY) {
1544  adjust_expansion_order(system,
1545  orbit,
1546  evolution_mode);
1547  __last_order_upgrade_age = -Core::Inf;
1548  }
1549  if(
1550  stop_reason != SMALL_EXPANSION_ERROR
1551  &&
1552  stop_reason != BREAK_LOCK
1553  &&
1554  stop_reason != WIND_SATURATION
1555  ) {
1556  system.initialize_locks(__precision);
1557  system.fill_orbit(orbit);
1558  }
1559  }
1560 
1561 #ifndef NDEBUG
1562  std::cerr
1563  << "At t=" << last_age
1564  << ", changing evolution mode from " << old_evolution_mode
1565  << " with " << old_locked_zones
1566  << " zones locked to " << evolution_mode
1567  << " with " << system.number_locked_zones()
1568  << " zones locked."
1569  << std::endl
1570  << "Transforming orbit from: " << old_orbit
1571  << " to " << orbit << std::endl;
1572 #endif
1573  delete __stopping_conditions;
1574  __stopping_conditions = NULL;
1575  }
1576  }
1577 
1578 } //End Evolve namespace.
double stop_age() const
The target stopping age in Gyr.
void adjust_expansion_order(BinarySystem &system, const std::valarray< double > &orbit, Core::EvolModeType evolution_mode, bool must_increase=false)
Increase/decrease the eccentricity expansion order until error is acceptable and return the new order...
Maximum allowed step size decreased below machine precision.
Definition: Error.h:167
virtual void add_to_evolution()
Appends the state defined by last configure(), to the evolution.
double __min_extremum_search_step
Extremum searching cannot limit the step size below this.
Definition: OrbitSolver.h:119
void initialize_locks(double sync_precision)
Identify and lock all zones within precision of a lock that can hold the lock at the current configur...
OrbitSolver(double max_age, double required_precision, bool print_progress=false)
Prepare to solve for the orbital evolution.
double __runtime_limit
Max number of seconds current evolution is allowed to run.
Definition: OrbitSolver.h:182
Function arguments do not satisfy some requirement.
Definition: Error.h:73
double __last_order_upgrade_age
The last age at which the eccentricity order was increased.
Definition: OrbitSolver.h:119
void reset(BinarySystem &system)
Clears any previously calculated evolution.
virtual unsigned expansion_order() const
ExtremumInformation extremum_from_history_no_deriv(size_t condition_index) const
Estimates the value and age of an extremum of a stopping condition for which no derivative informatio...
double __precision
The precision required of the solution.
Definition: OrbitSolver.h:119
LIB_LOCAL int stellar_system_jacobian(double age, const double *parameters, double *param_derivs, double *age_derivs, void *system_mode)
A wrapper tha allows the stellar system jacobian to be passed to the GSL ODE solver.
The spin-orbit lock can no longer be maintaned.
void reject_step(double &age, StopInformation &stop, BinarySystem &system, std::valarray< double > &orbit, double &max_next_t, double &step_size, std::string reason)
Handle the situation when the last step has to be rejected.
std::list< Core::EvolModeType > __tabulated_evolution_modes
The evolution mode corresponding to the matching tabulated age.
Definition: OrbitSolver.h:134
virtual StoppingConditionType type(unsigned index=0) const =0
What event is the index-th stopping sub-condition associated with.
std::list< std::valarray< double > > __stop_cond_history
Past values of the stop conditions.
Definition: OrbitSolver.h:151
The error due to truncating the eccentricity expansion is too small.
virtual size_t num_subconditions() const
The number of subconditions in the current condition.
Infomation about an extremum of a function.
Definition: OrbitSolver.h:84
virtual double next_stop_age() const
The next age when the evolution needs to be stopped for a system change.
double stop_condition_precision() const
The precision up to which the reason to stop is satisfied.
StoppingConditionType
The reasons for stopping the evolution currently supported.
Any runtime error.
Definition: Error.h:61
Orientations of zones of bodies in a binary system.
time_t __evolution_start_time
When did the currently running evolution start.
Definition: OrbitSolver.h:179
std::list< std::valarray< double > > __stop_deriv_history
Past values of the stop condition derivatives.
Definition: OrbitSolver.h:151
Defines the OrbitSolver class, the various stopping conditions and a number of other classes used whi...
double go_back(double max_age, BinarySystem &system, std::valarray< double > &orbit)
Rewinds the evlution to the last step before the given age and returns the age of that step...
int differential_equations(double age, const double *parameters, Core::EvolModeType evolution_mode, double *differential_equations)
The differential equation and jacobian for the evolution of the system.
void add_to_evolution(double age, Core::EvolModeType evolution_mode, BinarySystem &system)
Adds the last step to the evolution.
short deriv_sign_at_crossing() const
The sign of the derivative at zero-crossing.
virtual void reset_evolution()
Resets the evolution of the system.
double age() const
Returns the present age of the system in Gyr.
Definition: BinarySystem.h:914
double crossing_from_history(size_t condition_index) const
Estimates the age at which a stopping condition with derivative information crossed zero...
CombinedStoppingCondition * get_stopping_condition(BinarySystem &system)
Returns the stopping conditions which end the given evolution mode and update __stop_info.
The information about why and where the evolution should stop.
void output_history_and_discarded(std::ostream &os)
Generates a nicely formatted table of the contents of the discarded and history stopping condition in...
Definition: OrbitSolver.cpp:57
bool at_exact_condition(double previous_age, const StopInformation &stop_info)
Is the condition causing a stop match to within the required precision?
unsigned number_locked_zones() const
How many zones on either body are currently locked.
Definition: BinarySystem.h:929
virtual void reached_critical_age(double age)
Change the system as necessary at the given age.
size_t stop_condition_index() const
The index of the condition which caused us to stop.
StopInformation update_stop_condition_history(double age, const std::valarray< double > &orbit, const std::valarray< double > &derivatives, Core::EvolModeType evolution_mode, unsigned current_expansion_order, StoppingConditionType stop_reason=NO_STOP)
Updates stop_cond_history and stop_deriv_history after a GSL step, returning if/where the evolution n...
double stopping_age(double age, const BinarySystem &system, const std::list< double > &required_ages)
The age at which the evolution should stop next if no other stopping condition occurs.
The error due to truncating the eccentricity expansion is too large.
No reason to stop.
std::vector< StopInformation > __stop_info
Definition: OrbitSolver.h:173
double x() const
The value of the argument where the extremum occurs.
Definition: OrbitSolver.h:101
bool crossed_zero() const
Did we stop after the stopping condition crossed zero (always false for extrema). ...
StopInformation evolve_until(BinarySystem &system, double &max_age, std::valarray< double > &orbit, StoppingConditionType &stop_reason, double max_step, Core::EvolModeType evolution_mode)
Evolves a system until either some age cut-off is reached or some stopping condition crosses zero...
static std::pair< double, double > get_expansion_range(int max_mp)
Return the range of eccentricities (min, max) over which an expansion going up to given max m&#39; is val...
void reached_stopping_condition(double stop_age, StoppingConditionType stop_reason)
Handle a stop in the evolution due to at least one condition reaching a critical value.
virtual short expected_crossing_deriv_sign(unsigned index=0) const
The expected sign of the derivative at the next zero-crossing.
virtual std::string describe(int index=-1) const =0
Overwrite with something returning a description of what the stopping condition is monitoring...
size_t num_points()
Returns the number of points in the interval.
unsigned __num_step_limit
Max number of steps allowed to be stored in history and/or discarded.
Definition: OrbitSolver.h:185
A base class for all stopping conditions.
void clear_history()
Clears the current stopping condition history.
static unsigned required_expansion_order(double e)
The maximum orbital frequency multiplier to include in the potential Fourier expansion in order to ac...
bool __print_progress
See print_progress argument of constructor.
Definition: OrbitSolver.h:176
virtual void rewind_evolution(unsigned nsteps)
Discards the last steps from the evolution.
std::list< std::valarray< double > > __stop_deriv_discarded
Discarded derivatives of the stop conditions.
Definition: OrbitSolver.h:151
Core::EvolModeType evolution_mode()
The evolution mode of last call to configure().
void initialize_skip_history(const StoppingCondition &stop_cond, const std::valarray< double > &stop_cond_values, StoppingConditionType stop_reason)
Initializes the skip_history_zerocrossing and skip_history_extremum arrays appropriately after a mode...
std::list< double > __discarded_stop_ages
The ages of steps which were discarded becauset they are past a zero or an extremum of a stopping con...
Definition: OrbitSolver.h:144
std::list< std::valarray< double > > __orbit_deriv_history
Past orbital derivatives.
Definition: OrbitSolver.h:151
EvolModeType
The various evolution modes.
Definition: Common.h:42
virtual size_t num_subconditions() const
The number of subconditions in the current condition.
std::valarray< size_t > __skip_history_zerocrossing
The number of points at the start of the history to skip when lookng for a zero crossing for each con...
Definition: OrbitSolver.h:138
StopHistoryInterval select_stop_condition_interval(bool crossing, size_t cond_ind, size_t max_points) const
Selects a history interval for interpolating to a reason to stop the evolution.
void update_skip_history(const std::valarray< double > &current_stop_cond, const StopInformation &stop_info)
Updates the skip_history_zerocrossing and skip_history_extremum arrays appropriately after an accepta...
double crossing_from_history_no_deriv(size_t condition_index) const
Estimates the age at which a stopping condition with no derivative information crossed zero...
double stop_condition_value(size_t condition_index) const
Returns the value of the stop condition with the given index for the current point.
double __end_age
The last age for which evolution is required.
Definition: OrbitSolver.h:119
double y() const
The value of the function at the extremum.
Definition: OrbitSolver.h:106
ExtremumInformation extremum_from_history(size_t condition_index, double min_extremum_x) const
Estimates the value and age of an extremum of a stopping condition for which derivative information i...
virtual void change_expansion_order(unsigned new_expansion_order)
Change the tidal potential expansion order for all dissipative zones.
A class combining the the outputs of multiple stopping conditions.
void operator()(BinarySystem &system, double max_step=Core::Inf, const std::list< double > &required_ages=std::list< double >(), double max_runtime=0, unsigned max_time_steps=0, double min_extremum_search_step=1e-5)
Actually solves the given differential equation with the given boundary conditions.
StoppingConditionType type(unsigned index=0) const
What event is the index-th stopping sub-condition associated with.
bool is_crossing() const
Is the reason for stopping that a condition actually crossed zero?
std::list< double > __stop_history_ages
The ages at which the stop condition history is kept.
Definition: OrbitSolver.h:144
StoppingConditionType stop_reason() const
The reason for stopping.
GSL step size decreased below machine precision.
Definition: Error.h:154
void clear_discarded()
Removes all stored discarded stop condition information.
virtual CombinedStoppingCondition * stopping_conditions()
Conditions detecting the next possible doscontinuity in the evolution.
std::valarray< double > __skip_history_extremum
The age after which to look for extrema for each condition.
Definition: OrbitSolver.h:141
std::list< double > __tabulated_ages
The ages at which solution is tabulated.
Definition: OrbitSolver.h:131
double age() const
Returns the age of the current point.
std::list< std::valarray< double > > __orbit_history
Past orbits.
Definition: OrbitSolver.h:151
Describes a system of two bodies orbiting each other.
Definition: BinarySystem.h:57
void insert_discarded(double age, const std::valarray< double > &current_stop_cond, const std::valarray< double > &current_stop_deriv)
Adds an entry in the discarded ages, stop conditions and derivatives.
A collection of accepted and discarded evolution steps which contain some reason to stop...
StoppingCondition * __stopping_conditions
The current set of stopping conditions.
Definition: OrbitSolver.h:169
Core::EvolModeType fill_orbit(std::valarray< double > &orbit) const
Fills an array with the parameters expected by differential_equations() and jacobian(), returning the evolution mode.
std::list< std::valarray< double > > __stop_cond_discarded
Discarded values of the stop conditions.
Definition: OrbitSolver.h:151
bool acceptable_step(double current_age, double previous_age, const StopInformation &stop_info)
Return true iff the step with the given stop information is acceptable.
int stellar_system_diff_eq(double age, const double *parameters, double *derivatives, void *system_mode)
A wrapper tha allows the stellar system differential equation to be passed to the GSL ODE solver...
Definition: OrbitSolver.cpp:23
virtual void reached(short deriv_sign, unsigned index=0)
Called when a stopping condition has been reached by the evolution.