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  int stellar_system_jacobian(double age, const double *orbital_parameters,
40  double *param_derivs, double *age_derivs,void *system_mode)
41  {
42  void **input_params = static_cast<void **>(system_mode);
43  BinarySystem &system = *static_cast< BinarySystem* >(input_params[0]);
44  Core::EvolModeType evol_mode = *static_cast< Core::EvolModeType* >(
45  input_params[1]
46  );
47  return system.jacobian(age,
48  orbital_parameters,
49  evol_mode,
50  param_derivs,
51  age_derivs);
52  }
53 
54 #ifndef NDEBUG
56  {
57  // return;
58  std::streamsize orig_precision=os.precision();
59  os.precision(16);
60  std::ios_base::fmtflags orig_flags=os.flags();
61  os.setf(std::ios_base::scientific);
62 
63  os << "Stored stop condition information:" << std::endl
64  << std::setw(20) << "Age:";
65  for(std::list<double>::const_iterator age_i=__stop_history_ages.begin();
66  age_i!=__discarded_stop_ages.end(); age_i++) {
67  if(age_i==__stop_history_ages.end()) {
68  os << "|";
69  age_i=__discarded_stop_ages.begin();
70  }
71  os << std::setw(28) << *age_i;
72  }
73  std::string hline;
74  hline.assign(20+25*(__stop_history_ages.size()
75  +
76  __discarded_stop_ages.size()),
77  '_');
78  os << std::endl << hline << std::endl;
79 
80  for(size_t i=0; i<__stop_cond_discarded.front().size(); i++) {
81  assert(
83  ||
85  );
86  os << std::setw(13) << "Condition["
87  << std::setw(5) << i
88  << "]:"
90  ? " / "
91  : " \\ ");
92  size_t point_num=0;
93  std::list<double>::const_iterator age_i=__stop_history_ages.begin();
94  bool marked_skip_extremum=false;
95  for(std::list< std::valarray<double> >::const_iterator
96  cond_i=__stop_cond_history.begin();
97  cond_i!=__stop_cond_discarded.end(); cond_i++) {
98  if(cond_i==__stop_cond_history.end()) {
99  os << "|";
100  cond_i=__stop_cond_discarded.begin();
101  }
102  bool marked=false;
103  if(point_num==__skip_history_zerocrossing[i]) {
104  os << "z"; marked=true;
105  } else os << " ";
106  if((*age_i)>__skip_history_extremum[i]
107  && !marked_skip_extremum) {
108  os << "e"; marked_skip_extremum=true; marked=true;
109  } else os << (marked ? "-" : " ");
110  os << (marked ? ">" : " ");
111  os << std::setw(25) << (*cond_i)[i];
112  point_num++;
113  age_i++;
114  }
115  os << std::endl;
116  os << std::setw(13) << "Derivative[" << std::setw(5) << i
117  << "]:";
118  for(std::list< std::valarray<double> >::const_iterator
119  deriv_i=__stop_deriv_history.begin();
120  deriv_i!=__stop_deriv_discarded.end(); deriv_i++) {
121  if(deriv_i==__stop_deriv_history.end()) {
122  os << "|";
123  deriv_i=__stop_deriv_discarded.begin();
124  }
125  os << std::setw(28) << (*deriv_i)[i];
126  }
127  os << std::endl;
128  }
129 
130  os.precision(orig_precision);
131  os.flags(orig_flags);
132  }
133 #endif
134 
136  {
137  __discarded_stop_ages.clear();
138  __stop_cond_discarded.clear();
139  __stop_deriv_discarded.clear();
140  }
141 
143  const std::valarray<double> &current_stop_cond,
144  const std::valarray<double> &current_stop_deriv)
145  {
146  std::list<double>::iterator age_i = __discarded_stop_ages.begin();
147  std::list< std::valarray<double> >::iterator
148  cond_i = __stop_cond_discarded.begin(),
149  deriv_i = __stop_deriv_discarded.begin();
150  while(age_i != __discarded_stop_ages.end() && age > (*age_i)) {
151  age_i++; cond_i++; deriv_i++;
152  }
153  __discarded_stop_ages.insert(age_i, age);
154  __stop_cond_discarded.insert(cond_i, current_stop_cond);
155  __stop_deriv_discarded.insert(deriv_i, current_stop_deriv);
156  }
157 
159  Core::EvolModeType evolution_mode,
160  BinarySystem &system)
161  {
162  clear_discarded();
163  system.add_to_evolution();
164  __tabulated_ages.push_back(age);
165  __tabulated_evolution_modes.push_back(evolution_mode);
166  }
167 
168  double OrbitSolver::go_back(double max_age,
169  BinarySystem &system,
170  std::valarray<double> &orbit)
171  {
172  unsigned nsteps = 0;
173  while(!__tabulated_ages.empty() && max_age < __tabulated_ages.back()) {
174  __tabulated_ages.pop_back();
175  __tabulated_evolution_modes.pop_back();
176  ++nsteps;
177  }
178  system.rewind_evolution(nsteps);
179 
180  if(max_age < __stop_history_ages.back()) clear_discarded();
181  while(
182  !__stop_history_ages.empty()
183  &&
184  max_age < __stop_history_ages.back()
185  ) {
186  __stop_history_ages.pop_back();
187  __orbit_history.pop_back();
188  __orbit_deriv_history.pop_back();
189  __stop_cond_history.pop_back();
190  __stop_deriv_history.pop_back();
191  }
192  for(size_t i = 0; i < __skip_history_zerocrossing.size(); ++i) {
193  __skip_history_zerocrossing[i] = std::min(
195  __stop_history_ages.size()
196  );
197  __skip_history_extremum[i] = std::min(
198  __stop_history_ages.back(),
199  __skip_history_extremum[i]
200  );
201  }
202  orbit = __orbit_history.back();
203  return __stop_history_ages.back();
204  }
205 
207  {
208  __orbit_history.clear();
209  __orbit_deriv_history.clear();
210  __stop_history_ages.clear();
211  __stop_cond_history.clear();
212  __stop_deriv_history.clear();
213  clear_discarded();
214  }
215 
217  bool crossing,
218  size_t cond_ind,
219  size_t max_points
220  ) const
221  {
222  if(crossing)
223  assert(
224  __stop_cond_history.size()
225  -
227  >=
228  1
229  );
230  else
231  assert(
232  __stop_cond_history.size()
233  -
235  >=
236  2
237  );
238  size_t num_points = std::min(
239  max_points,
240  (
241  __stop_history_ages.size()
242  +
243  __discarded_stop_ages.size()
244  -
245  (crossing ? __skip_history_zerocrossing[cond_ind] : 0)
246  )
247  );
248  std::list<double>::const_iterator first_age = __stop_history_ages.end();
249  std::list< std::valarray<double> >::const_iterator
250  first_stop_cond = __stop_cond_history.end(),
251  first_stop_deriv = __stop_deriv_history.end();
252  int go_back = (static_cast<int>(num_points)
253  -
254  static_cast<int>(__discarded_stop_ages.size()));
255  go_back = std::max(go_back, (crossing ? 1 : 2));
256  size_t failed_back = 0;
257  for(int i = 0; i < go_back; ++i) {
258  --first_age;
259  --first_stop_cond;
260  --first_stop_deriv;
261  if(!crossing && *first_age < __skip_history_extremum[cond_ind]) {
262  ++failed_back;
263  ++first_age;
264  ++first_stop_cond;
265  ++first_stop_deriv;
266  --num_points;
267  }
268  }
269  if(go_back - failed_back < (crossing ? 1 : 2))
270  return StopHistoryInterval();
271  StopHistoryInterval interval(num_points,
272  first_age,
273  __stop_history_ages.end(),
274  __discarded_stop_ages.begin(),
275  first_stop_cond,
276  __stop_cond_history.end(),
277  __stop_cond_discarded.begin(),
278  first_stop_deriv,
279  __stop_deriv_history.end(),
280  __stop_deriv_discarded.begin()),
281  result = interval;
282  int max_left_shift = std::min(__discarded_stop_ages.size() - 1,
283  num_points - (crossing ? 2 : 3));
284  int history_limit = 0;
285  if(crossing)
286  history_limit = (__stop_history_ages.size()
287  -
288  go_back
289  +
290  failed_back
291  -
292  __skip_history_zerocrossing[cond_ind]);
293  else
294  while(
295  first_age != __stop_history_ages.begin()
296  &&
297  *(--first_age) > __skip_history_extremum[cond_ind]
298  )
299  ++history_limit;
300  max_left_shift = std::min(history_limit, max_left_shift);
301  for(int i = 0; i < max_left_shift; i++) {
302  interval << 1;
303  if(
304  (interval.last_age() - interval.first_age())
305  <
306  result.last_age() - result.first_age()
307  )
308  result = interval;
309  }
310  return result;
311  }
312 
314  size_t condition_index
315  ) const
316  {
317  ExtremumInformation result;
318  if(
319  __stop_history_ages.size()
320  -
321  __skip_history_zerocrossing[condition_index] < 2
322  )
323  return result;
324  std::list< std::valarray<double> >::const_iterator stop_cond_i =
325  __stop_cond_history.end();
326  double pre1_cond = (*(--stop_cond_i))[condition_index],
327  pre2_cond = (*(--stop_cond_i))[condition_index],
328  post_cond = __stop_cond_discarded.front()[condition_index];
329  if(
330  std::abs(pre1_cond) > std::abs(pre2_cond)
331  ||
332  std::abs(pre1_cond) > std::abs(post_cond)
333  ||
334  (
335  !std::isfinite(pre1_cond)
336  &&
337  !std::isfinite(pre2_cond)
338  &&
339  !std::isfinite(post_cond)
340  )
341  )
342  return result;
343 
345  false,
346  condition_index,
347  4
348  );
349  if(stop_interval.num_points() < 3)
350  return result;
351  double t0 = stop_interval.age(),
352  c0 = stop_interval.stop_condition_value(condition_index),
353  t1 = (++stop_interval).age(),
354  c1 = stop_interval.stop_condition_value(condition_index),
355  t2 = (++stop_interval).age(),
356  c2 = stop_interval.stop_condition_value(condition_index),
357  abs_c0 = std::abs(c0),
358  abs_c1 = std::abs(c1),
359  abs_c2 = std::abs(c2);
360 
361  const double min_fractional_diff = (
362  1000.0
363  *
364  std::numeric_limits<double>::epsilon()
365  );
366 
367  bool ignore_10_diff = (std::abs(c1 - c0) / std::max(abs_c0, abs_c1)
368  <
369  min_fractional_diff),
370  ignore_21_diff = (std::abs(c2 - c1) / std::max(abs_c1, abs_c2)
371  <
372  min_fractional_diff);
373 
374 
375  if(stop_interval.num_points() == 3) {
376  if((c1 - c0) * (c2 - c1) > 0 || ignore_10_diff || ignore_21_diff)
377  {
378  return result;
379  }
380  result.x() = Core::quadratic_extremum(t0, c0, t1, c1, t2, c2,
381  &(result.y()));
382  } else {
383  double t3 = (++stop_interval).age(),
384  c3 = stop_interval.stop_condition_value(condition_index),
385  abs_c3 = std::abs(c3);
386  bool ignore_32_diff = (
387  std::abs(c3 - c2) / std::max(abs_c3, abs_c2)
388  <
389  min_fractional_diff
390  );
391  if(
392  (
393  (c1 - c0) * (c2 - c1) > 0
394  ||
395  abs_c1 >= std::max(abs_c0, abs_c2)
396  ||
397  ignore_10_diff
398  ||
399  ignore_21_diff
400  )
401  &&
402  (
403  (c2 - c1) * (c3 - c2) > 0
404  ||
405  abs_c2 >= std::max(abs_c1, abs_c3)
406  ||
407  ignore_21_diff
408  ||
409  ignore_32_diff
410  )
411  ){
412  return result;
413  }
414  double range_low,
415  range_high;
416  if(
417  !ignore_10_diff
418  &&
419  std::abs(c1) <= std::abs(c0)
420  &&
421  std::abs(c1) <= std::abs(c2)
422  ) {
423  range_low = t0;
424  range_high = t2;
425  } else if(
426  !ignore_32_diff
427  &&
428  abs_c2 <= abs_c1
429  &&
430  abs_c2 <= abs_c3
431  ) {
432  range_low = t1;
433  range_high = t3;
435  "Searching for extremum among monotonic stopping condition "
436  "values in OrbitSolver::extremum_from_history_no_deriv."
437  );
438  result.x() = Core::cubic_extremum(t0, c0, t1, c1, t2, c2, t3, c3,
439  &(result.y()),
440  range_low, range_high);
441  }
442  return result;
443  }
444 
446  size_t condition_index) const
447  {
448  ExtremumInformation result;
449  if(
450  __stop_history_ages.size() == 0
451  ||
452  (
453  __stop_history_ages.back()
454  <
455  __skip_history_extremum[condition_index]
456  )
457  )
458  return result;
459  double prev_stop_cond = __stop_cond_history.back()[condition_index],
460  next_stop_cond = __stop_cond_discarded.front()[condition_index];
461  if(next_stop_cond * prev_stop_cond <= 0)
462  return result;
463  if(std::isnan(__stop_deriv_history.back()[condition_index]))
464  return extremum_from_history_no_deriv(condition_index);
465  double prev_stop_deriv = __stop_deriv_history.back()[condition_index],
466  next_stop_deriv = __stop_deriv_discarded.front()[condition_index];
467  if(
468  next_stop_cond * next_stop_deriv < 0
469  ||
470  next_stop_deriv * prev_stop_deriv >= 0
471  )
472  return result;
473  result.x()=Core::estimate_extremum(__stop_history_ages.back(),
474  prev_stop_cond,
475  __discarded_stop_ages.front(),
476  next_stop_cond,
477  prev_stop_deriv,
478  next_stop_deriv,
479  &(result.y()));
480  return result;
481  }
482 
483  double OrbitSolver::crossing_from_history_no_deriv(size_t condition_index)
484  const
485  {
487  true,
488  condition_index,
489  4
490  );
491  if(stop_interval.num_points() < 2) return Core::Inf;
492  double t0 = stop_interval.age(),
493  c0 = stop_interval.stop_condition_value(condition_index),
494  t1 = (++stop_interval).age(),
495  c1 = stop_interval.stop_condition_value(condition_index);
496  if(stop_interval.num_points() == 2)
497  return Core::estimate_zerocrossing(t0, c0, t1, c1);
498  double t2 = (++stop_interval).age(),
499  c2 = stop_interval.stop_condition_value(condition_index);
500  double range_low = Core::NaN,
501  range_high = Core::NaN;
502  short crossing_sign =
504  condition_index
505  );
506  if(c0 * c1 <= 0 && c1 * crossing_sign > 0) {
507  range_low = t0;
508  range_high = t1;
509  } else if(c1 * c2 <= 0 && c2 * crossing_sign > 0) {
510  range_low = t1;
511  range_high = t2;
512  }
513  if(stop_interval.num_points() == 3) {
514  assert(!std::isnan(range_low) && !std::isnan(range_high));
515  return Core::quadratic_zerocrossing(
516  t0, c0, t1, c1, t2, c2, range_low, range_high
517  );
518  }
519  double t3 = (++stop_interval).age(),
520  c3 = stop_interval.stop_condition_value(condition_index);
521  if(std::isnan(range_low)) {
522  range_low = t2;
523  range_high = t3;
524  assert(c2 * c3 < 0);
525  assert(c3 * crossing_sign > 0);
526  }
527  return Core::cubic_zerocrossing(
528  t0, c0, t1, c1, t2, c2, t3, c3, range_low, range_high
529  );
530  }
531 
532  double OrbitSolver::crossing_from_history(size_t condition_index) const
533  {
534  if(
535  __stop_history_ages.size() == 0
536  ||
537  (
538  __stop_history_ages.size()
539  ==
540  __skip_history_zerocrossing[condition_index]
541  )
542  )
543  return Core::Inf;
544  double prev_stop_cond = __stop_cond_history.back()[condition_index];
545  double next_stop_cond = __stop_cond_discarded.front()[condition_index];
546  if(
547  next_stop_cond * prev_stop_cond > 0
548  ||
549  (
550  next_stop_cond
551  *
553  condition_index
554  )
555  <
556  0
557  )
558  ||
559  (
560  next_stop_cond == 0
561  &&
562  prev_stop_cond
563  *
565  condition_index
566  )
567  >=
568  0
569  )
570  )
571  return Core::Inf;
572  if(std::isnan(__stop_deriv_history.back()[condition_index]))
573  return crossing_from_history_no_deriv(condition_index);
574  double
575  prev_stop_deriv = __stop_deriv_history.back()[condition_index],
576  prev_age = __stop_history_ages.back(),
577  next_stop_deriv = __stop_deriv_discarded.front()[condition_index],
578  next_age = __discarded_stop_ages.front();
579  return Core::estimate_zerocrossing(prev_age,
580  prev_stop_cond,
581  next_age,
582  next_stop_cond,
583  prev_stop_deriv,
584  next_stop_deriv);
585  }
586 
588  const StoppingCondition &stop_cond,
589  StoppingConditionType stop_reason
590  )
591  {
592  __skip_history_zerocrossing.resize(stop_cond.num_subconditions(), 0);
593  __skip_history_extremum.resize(stop_cond.num_subconditions(), 0);
594  for(
595  size_t cond_ind=0;
596  cond_ind<stop_cond.num_subconditions();
597  cond_ind++
598  ) {
599  StoppingConditionType stop_cond_type=stop_cond.type(cond_ind);
600  if(
601  (stop_reason==BREAK_LOCK && stop_cond_type==SYNCHRONIZED)
602  ||
603  (stop_reason!=NO_STOP && stop_cond_type==stop_reason)
604  ) {
605  __skip_history_zerocrossing[cond_ind]=1;
606  __skip_history_extremum[cond_ind]=(
607  __stop_history_ages.front()
608  *
609  (1.0+std::numeric_limits<double>::epsilon())
610  );
611  }
612  }
613  }
614 
615  /*
616  void OrbitSolver::update_skip_history(
617  const std::valarray<double> &current_stop_cond,
618  const StopInformation &stop_info)
619  {
620  size_t history_size=__stop_history_ages.size();
621  for(size_t i=0; i<current_stop_cond.size(); i++) {
622  if(__skip_history_zerocrossing[i]==history_size &&
623  std::abs(current_stop_cond[i])<__precision)
624  ++__skip_history_zerocrossing[i];
625  if(stop_info.stop_reason()==__stopping_conditions.type(i) &&
626  !stop_info.is_crossing() &&
627  std::abs(stop_info.stop_condition_precision())<=__precision)
628  __skip_history_extremum[i]=stop_info.stop_age();
629  }
630  }*/
631 
632  bool OrbitSolver::at_exact_condition(double previous_age,
633  const StopInformation &stop_info)
634  {
635  return (
636  (
637  std::abs(stop_info.stop_condition_precision())
638  <=
640  )
641  ||
642  (
643  stop_info.stop_age()
644  <
645  previous_age * MIN_RELATIVE_STEP
646  )
647  );
648  }
649 
650  bool OrbitSolver::acceptable_step(double current_age,
651  double previous_age,
652  const StopInformation &stop_info)
653  {
654 #ifdef VERBOSE_DEBUG
655  std::cerr << "From t = " << previous_age
656  << ", stepped to t = " << current_age
657  << ", stop at t = " << stop_info.stop_age()
658  << ", must be at least: " << previous_age * MIN_RELATIVE_STEP
659  << std::endl;
660  if(
661  at_exact_condition(previous_age, stop_info)
662  &&
663  std::abs(stop_info.stop_condition_precision()) > __precision
664  ) {
665  std::cerr << "Failed to meet precision for "
666  << stop_info
667  << std::endl;
668  }
669 #endif
670  return (
671  stop_info.stop_age() >= current_age
672  ||
673  (
674  at_exact_condition(previous_age, stop_info)
675  &&
676  (stop_info.crossed_zero() || !stop_info.is_crossing())
677  )
678  );
679  }
680 
682  const std::valarray<double> &derivatives,
683  const std::valarray<double> &expansion_errors
684  )
685  {
686  double max_error_ratio = 0.0;
687 #ifndef NDEBUG
688  unsigned max_ratio_index = 0;
689 #endif
690  for(unsigned i = 0; i < derivatives.size(); ++i) {
691  double error_ratio = (
692  std::abs(expansion_errors[i])
693  /
694  (__precision * std::abs(derivatives[i]) + __precision)
695  );
696  assert(error_ratio >= 0);
697  if(error_ratio > 1.0) {
698 #ifndef NDEBUG
699  std::cerr << "Expansion ratio for parameter " << i
700  << " = " << error_ratio
701  << " suggest increasing e order!"
702  << std::endl;
703 #endif
704  return 1;
705  }
706  if(error_ratio > max_error_ratio) {
707  max_error_ratio = error_ratio;
708 #ifndef NDEBUG
709  max_ratio_index = i;
710 #endif
711  }
712  }
713 #ifndef NDEBUG
714  std::cerr << "O(e) downgrade threshold = "
716  << ", max error ratio = "
717  << max_error_ratio
718  << " for parameter "
719  << max_ratio_index
720  << std::endl;
721 #endif
722  if(max_error_ratio < __e_order_downgrade_threshold) {
723 #ifndef NDEBUG
724  std::cerr << "Suggest decreasing e order." << std::endl;
725 #endif
726  return -1;
727  } else {
728 #ifndef NDEBUG
729  std::cerr << "Suggest e order is fine." << std::endl;
730 #endif
731  return 0;
732  }
733  }
734 
736  double age,
737  const std::valarray<double> &orbit,
738  const std::valarray<double> &derivatives,
739  const std::valarray<double> &expansion_errors,
740  Core::EvolModeType evolution_mode,
741  StoppingConditionType stop_reason,
742  bool ignore_e_order_decrease
743  )
744  {
745  for(unsigned i = 0; i < orbit.size(); ++i)
746  if(
747  std::isnan(orbit[i])
748  ||
749  (evolution_mode == Core::BINARY && orbit[0] <= 0)
750  ) {
751 #ifndef NDEBUG
752  std::cerr << "Bad orbit: " << orbit << std::endl;
753 #endif
754  return StopInformation(
755  0.5 * (age + __stop_history_ages.back()),
756  Core::Inf
757  );
758  }
759 
760  int adjust_e_order = 0;
761  if(evolution_mode == Core::BINARY) {
762  adjust_e_order = check_expansion_error(derivatives,
763  expansion_errors);
764  if(adjust_e_order > 0)
765  return StopInformation(
766  0.5 * (age + __stop_history_ages.back()),
767  Core::Inf,
769  );
770  }
771 
772  std::valarray<double> current_stop_cond(
774  );
775  std::valarray<double> current_stop_deriv;
776  current_stop_cond = (*__stopping_conditions)(evolution_mode,
777  orbit,
778  derivatives,
779  current_stop_deriv);
780 
781  if(__stop_history_ages.size() == 0)
783  StopInformation result;
784  insert_discarded(age, current_stop_cond, current_stop_deriv);
785 #ifdef VERBOSE_DEBUG
786  std::cerr << std::string(77, '@') << std::endl;
787  output_history_and_discarded(std::cerr);
788  std::cerr << "Decreasing e_order is "
789  << (ignore_e_order_decrease ? "not" : "")
790  << " allowed"
791  <<std::endl;
792 #endif
793  for(
794  size_t cond_ind = 0;
795  (
796  __stop_cond_history.size() > 0
797  &&
798  cond_ind < current_stop_cond.size()
799  );
800  cond_ind++
801  ) {
802  double stop_cond_value = current_stop_cond[cond_ind],
803  crossing_age = crossing_from_history(cond_ind),
804  crossing_precision =
805  __stop_cond_history.back()[cond_ind];
806  bool crossed_zero = false;
807  if(std::abs(crossing_precision) >= std::abs(stop_cond_value)) {
808  crossing_precision = stop_cond_value;
809  crossed_zero = true;
810  }
811  ExtremumInformation extremum = extremum_from_history(cond_ind);
812  double extremum_precision;
813  if(std::isnan(extremum.y())) extremum_precision = Core::NaN;
814  else
815  extremum_precision = (
816  std::min(
817  std::abs(extremum.y() - stop_cond_value),
818  std::abs(extremum.y()
819  -
820  __stop_cond_history.back()[cond_ind])
821  )
822  /
823  std::abs(extremum.y())
824  );
825  bool is_crossing = crossing_age <= extremum.x();
826  short deriv_sign = 0;
827  if(is_crossing) deriv_sign = (stop_cond_value > 0 ? 1 : -1);
828  StopInformation &stop_info = __stop_info[cond_ind];
829  stop_info.stop_age() = std::min(crossing_age, extremum.x());
830  stop_info.stop_condition_precision() = (is_crossing
831  ? crossing_precision
832  : extremum_precision);
833  stop_info.is_crossing() = is_crossing;
834  stop_info.crossed_zero() = crossed_zero;
835  stop_info.deriv_sign_at_crossing() = (is_crossing
836  ? deriv_sign
837  : 0.0);
838 #ifdef VERBOSE_DEBUG
839  std::cerr << "Condition " << cond_ind << " "
840  << __stopping_conditions->describe(cond_ind)
841  << ": " << stop_info
842  << std::endl;
843 #endif
844  if(
845  (!acceptable_step(age,
846  __stop_history_ages.back(),
847  stop_info) || is_crossing)
848  &&
849  stop_info.stop_age() < result.stop_age()
850  ) {
851  result = stop_info;
852 #ifdef VERBOSE_DEBUG
853  std::cerr << "SELECTED" << std::endl;
854  } else {
855  std::cerr << "NOT SELECTED!" << std::endl;
856 #endif
857  }
858  }
859  if(acceptable_step(age,
860  __stop_history_ages.back(),
861  result)) {
862  // update_skip_history(current_stop_cond, result);
863  __stop_history_ages.push_back(age);
864  __stop_cond_history.push_back(current_stop_cond);
865  __stop_deriv_history.push_back(current_stop_deriv);
866  __orbit_history.push_back(orbit);
867  __orbit_deriv_history.push_back(derivatives);
868 
869  if(
870  result.stop_reason() == NO_STOP
871  &&
872  adjust_e_order < 0
873  &&
874  !ignore_e_order_decrease
875  ) {
876  return StopInformation(Core::Inf,
877  Core::Inf,
879  }
880 
881  } else {
882 #ifndef NDEBUG
883  std::cerr << "Step to age = "
884  << age
885  << " deemed unacceptable: "
886  << result
887  << std::endl;
888 #endif
889  }
890  return result;
891  }
892 
894  double &t,
895  StopInformation &stop,
896  BinarySystem &system,
897  std::valarray<double> &orbit,
898  double &max_next_t,
899  double &step_size
900 #ifndef NDEBUG
901  , std::string reason
902 #endif
903  )
904  {
905  double last_good_t = go_back(stop.stop_age(),
906  system,
907  orbit);
908 #ifndef NDEBUG
909  std::cerr
910  << "Reverting step from t = "
911  << t
912  << " to "
913  << last_good_t
914  << " due to "
915  << reason
916  << "Stop info: "
917  << stop
918  << std::endl;
919 #endif
920 
921  if(
922  t
923  <
924  last_good_t * MIN_RELATIVE_STEP
925  ) {
926 #ifndef NDEBUG
927  std::cerr << "Stepped only "
928  << t - last_good_t
929  << "Gyr, aborting!"
930  << std::endl;
931 #endif
933  }
934  t = last_good_t;
935  if(stop.is_crossing())
936  stop.stop_condition_precision() = (
937  __stop_cond_history.back()[
938  stop.stop_condition_index()
939  ]
940  );
941  max_next_t = stop.stop_age();
942  step_size = 0.1 * (max_next_t - t);
943  }
944 
946  BinarySystem &system,
947  double &max_age,
948  std::valarray<double> &orbit,
949  StoppingConditionType &stop_reason,
950  double max_step,
951  Core::EvolModeType evolution_mode
952  )
953  {
954  size_t nargs = orbit.size();
955 #ifndef NDEBUG
956  std::cerr << "Starting evolution leg in " << evolution_mode
957  << " from t=" << system.age() << " with initial orbit:\n";
958  for(size_t i = 0; i < nargs; ++i) {
959  if(i) std::cerr << ", ";
960  std::cerr << "\t" << orbit[i] << std::endl;
961  }
962  std::cerr << std::endl;
963  std::cerr << "Stopping conditions:" << std::endl
964  << __stopping_conditions->describe() << std::endl;
965 #endif
966 
967  // const gsl_odeiv2_step_type *step_type = gsl_odeiv2_step_bsimp;
968  const gsl_odeiv2_step_type *step_type = gsl_odeiv2_step_rkf45;
969 
970  gsl_odeiv2_step *step = gsl_odeiv2_step_alloc(step_type, nargs);
971  gsl_odeiv2_control *step_control = gsl_odeiv2_control_standard_new(
972  __precision,
973  __precision,
974  1,
975  0
976  );
977  gsl_odeiv2_evolve *evolve = gsl_odeiv2_evolve_alloc(nargs);
978 
979  void *sys_mode[2]={&system, &evolution_mode};
980  gsl_odeiv2_system ode_system={stellar_system_diff_eq,
982  nargs,
983  sys_mode};
984  double t=system.age();
985  std::valarray<double> derivatives(nargs),
986  expansion_errors(nargs),
987  param_derivatives(nargs),
988  age_derivatives(nargs);
989 
990  add_to_evolution(t, evolution_mode, system);
991 
992  /* std::cerr << "Initial state for t=" << t << ": " << std::endl
993  << "\torbit:";
994  for(unsigned i=0; i<orbit.size(); ++i)
995  std::cerr << orbit[i] << " ";
996  std::cerr << std::endl << "\tderiv :";
997  for(unsigned i=0; i<derivatives.size(); ++i)
998  std::cerr << derivatives[i] << " ";
999  std::cerr << std::endl;*/
1000 
1001  clear_discarded();
1002  double step_size = std::min(0.1 * (max_age - t),
1003  max_step);
1004 
1005  stop_reason = NO_STOP;
1006  StopInformation stop;
1007  bool first_step = true;
1008  double from_t;
1009  while(t<max_age) {
1010  double max_next_t = std::min(t + max_step, max_age);
1011  int status=GSL_SUCCESS;
1012  bool step_rejected=false;
1013  do {
1014 #ifndef NDEBUG
1015  std::cerr << "Attempting step from t = " << t
1016  << " not to miss t = " << max_next_t
1017  << ", suggested step = " << step_size
1018  << ", orbit:\n";
1019  for(size_t i=0; i<nargs; ++i) {
1020  if(i) std::cerr << ", ";
1021  std::cerr << "\t" << orbit[i] << std::endl;
1022  }
1023  std::cerr << std::endl;
1024 #endif
1025  from_t = t;
1026  if(!first_step) {
1027  step_size = std::max(step_size,
1028  3.0 * (MIN_RELATIVE_STEP * t - t));
1029  status = gsl_odeiv2_evolve_apply(evolve,
1030  step_control,
1031  step,
1032  &ode_system,
1033  &t,
1034  max_next_t,
1035  &step_size,
1036  &(orbit[0]));
1037  }
1038  if (status == GSL_FAILURE) {
1039 #ifndef NDEBUG
1040  std::cerr << "Failed, (presume zero step size)!"
1041  << std::endl;
1042 #endif
1043  throw Core::Error::GSLZeroStep("rkf45");
1044  } else if (status != GSL_SUCCESS && status != GSL_EDOM) {
1045  std::ostringstream msg;
1046  msg << "GSL signaled failure while evolving (error code " <<
1047  status << ")";
1048  throw Core::Error::Runtime(msg.str());
1049  } else if (
1050  __runtime_limit > 0
1051  &&
1052  difftime(time(NULL), __evolution_start_time)
1053  >
1055  ) {
1056  std::ostringstream msg;
1057  msg << "Exceeded evolution time limit of "
1058  << __runtime_limit
1059  << " seconds!";
1060  throw Core::Error::Runtime(msg.str());
1061  }
1062  if(status == GSL_SUCCESS) {
1063 #ifdef NDEBUG
1064  if(__print_progress)
1065 #endif
1066  std::cerr << "Succeeded! Now t = " << t << std::endl;
1067 #ifdef VERBOSE_DEBUG
1068  std::cerr << "GSL suggested new step size:"
1069  << step_size
1070  << std::endl;
1071 #endif
1072 
1074  &(orbit[0]),
1075  &(derivatives[0]),
1076  sys_mode);
1077 
1078  system.differential_equations(t,
1079  &(orbit[0]),
1080  evolution_mode,
1081  &(expansion_errors[0]),
1082  true);
1083 
1085  t,
1086  orbit,
1087  derivatives,
1088  expansion_errors,
1089  evolution_mode,
1090  stop_reason,
1091  system.eccentricity_order() == 0
1092  );
1093  }
1094  if(status == GSL_EDOM || !acceptable_step(t, from_t, stop)) {
1095  if(!first_step)
1096  reject_step(
1097  t,
1098  stop,
1099  system,
1100  orbit,
1101  max_next_t,
1102  step_size
1103 #ifndef NDEBUG
1104  , (status == GSL_EDOM ? "EDOM error" : "bad step")
1105 #endif
1106  );
1107  gsl_odeiv2_evolve_reset(evolve);
1108  step_rejected = true;
1109  } else {
1110  if(!first_step && t < from_t * MIN_RELATIVE_STEP) {
1111 #ifndef NDEBUG
1112  std::cerr << "Stepped only "
1113  << t - from_t
1114  << "Gyr, aborting!"
1115  << std::endl;
1116 #endif
1117  throw Core::Error::GSLZeroStep("rkf45");
1118  }
1119  step_rejected=false;
1120  }
1121 
1122  } while(
1123  step_rejected
1124  &&
1125  !first_step
1126  &&
1127  (
1128  !at_exact_condition(from_t, stop)
1129  ||
1130  __stop_history_ages.size() == 1
1131  )
1132  &&
1134  );
1135 
1136  first_step = false;
1137  if(!step_rejected) {
1138 #ifndef NDEBUG
1139  std::cerr << "Stepped to t = " << t << std::endl;
1140 #endif
1141  add_to_evolution(t, evolution_mode, system);
1142  }
1143 #ifndef NDEBUG
1144  std::cerr << "Stop: " << stop
1145  << "e-order: " << system.eccentricity_order()
1146  << "last e upgrade at t=" << __last_e_order_upgrade_age
1147  << "max age: " << max_age
1148  << std::endl;
1149 #endif
1150  if(
1151  (stop.is_crossing() && stop.stop_reason() != NO_STOP)
1152  ||
1154  ||
1155  (
1157  &&
1158  system.eccentricity_order() > 0
1159  &&
1160  t > (0.99 * __last_e_order_upgrade_age
1161  +
1162  0.01 * max_age)
1163  )
1164  ) {
1165  stop_reason = stop.stop_reason();
1166 #ifndef NDEBUG
1167  std::cerr << "Breaking for = " << stop << std::endl;
1168 #endif
1169  break;
1170  }
1171  }
1172  max_age=t;
1173  clear_history();
1175  &(orbit[0]),
1176  &(derivatives[0]),
1177  sys_mode);
1178 
1179  gsl_odeiv2_evolve_free(evolve);
1180  gsl_odeiv2_control_free(step_control);
1181  gsl_odeiv2_step_free(step);
1182  return stop;
1183  }
1184 
1186  BinarySystem &system
1187  )
1188  {
1190 #ifdef EXTERNAL_CONDITION
1191  (*result) |= new EXTERNAL_CONDITION;
1192 #endif
1193  __stop_info.clear();
1194  __stop_info.resize(result->num_subconditions());
1195  for(size_t cond_ind = 0; cond_ind < __stop_info.size(); ++cond_ind)
1196  {
1197  __stop_info[cond_ind].stop_reason() = result->type(cond_ind);
1198  __stop_info[cond_ind].stop_condition_index() = cond_ind;
1199  }
1200  return result;
1201  }
1202 
1203  double OrbitSolver::stopping_age(double age,
1204  const BinarySystem &system,
1205  const std::list<double> &required_ages)
1206  {
1207 #ifndef NDEBUG
1208  std::cerr << "Determining next stop age: " << std::endl;
1209 #endif
1210  double result = system.next_stop_age();
1211 #ifndef NDEBUG
1212  std::cerr << "Next system stop age: " << result << std::endl;
1213 #endif
1214  if(required_ages.size() == 0) return result;
1215 
1216  static std::list<double>::const_iterator
1217  next_required_age = required_ages.begin();
1218  if(age <= required_ages.front())
1219  next_required_age = required_ages.begin();
1220  if(
1221  next_required_age != required_ages.end()
1222  &&
1223  age == *next_required_age
1224  )
1225  ++next_required_age;
1226  if(
1227  next_required_age != required_ages.end()
1228  &&
1229  result > *next_required_age
1230  )
1231  result = *next_required_age;
1232 #ifndef NDEBUG
1233  std::cerr << "Required ages change that to: " << result << std::endl;
1234 #endif
1235  return result;
1236  }
1237 
1239  double stop_age,
1240  StoppingConditionType stop_reason
1241  )
1242  {
1243 #ifndef NDEBUG
1244  std::cerr << "Stopped due to condition at t = "
1245  << stop_age
1246  << std::endl;
1247 #endif
1248  for(
1249  std::vector<StopInformation>::const_iterator stop_i =
1250  __stop_info.begin();
1251  stop_i != __stop_info.end();
1252  ++stop_i
1253  ) {
1254  if(
1255  stop_i->is_crossing()
1256  &&
1257  (
1258  stop_i->stop_age() < stop_age
1259  ||
1260  (
1261  stop_i->stop_reason() == stop_reason
1262  &&
1263  at_exact_condition(stop_age, *stop_i)
1264  )
1265  )
1266  ) {
1267 #ifndef NDEBUG
1268  std::cerr << "Triggered condition: "
1270  stop_i->stop_condition_index()
1271  )
1272  << std::endl;
1273 #endif
1275  stop_i->deriv_sign_at_crossing(),
1276  stop_i->stop_condition_index()
1277  );
1278  }
1279  }
1280  }
1281 
1283  BinarySystem &system,
1284  const std::valarray<double> &orbit,
1285  Core::EvolModeType evolution_mode,
1286  bool must_increase
1287  )
1288  {
1289 #ifndef NDEBUG
1290  std::cerr << "Adjusting eccentricity order at t ="
1291  << system.age()
1292  << std::endl;
1293 #endif
1294  assert(evolution_mode == Core::BINARY);
1295 
1296  unsigned e_order = system.eccentricity_order(),
1297  starting_e_order = e_order;
1298  std::valarray<double> expansion_errors(orbit.size()),
1299  derivatives(orbit.size());
1300 
1301 
1302  int adjust_e_order, last_adjustment = 0;
1303  do {
1304  system.differential_equations(system.age(),
1305  &(orbit[0]),
1306  evolution_mode,
1307  &(derivatives[0]));
1308 
1309  system.differential_equations(system.age(),
1310  &(orbit[0]),
1311  evolution_mode,
1312  &(expansion_errors[0]),
1313  true);
1314 
1315  adjust_e_order = check_expansion_error(derivatives,
1316  expansion_errors);
1317 #ifndef NDEBUG
1318  std::cerr << "Suggested adjustment: " << adjust_e_order << std::endl;
1319 #endif
1320 
1321  if(
1323  &&
1324  adjust_e_order > 0
1325  ) {
1326  std::ostringstream msg;
1327  msg << "Maximum available eccentricity expansion order of "
1328  << e_order
1329  << (" is insufficient to ensure evolution to the "
1330  "specified precisoin.");
1331  throw Core::Error::Runtime(msg.str());
1332  }
1333 
1334  if(adjust_e_order || must_increase) {
1335  if(must_increase) {
1336  e_order += 1;
1337  __last_e_order_upgrade_age = system.age();
1338  } else if(e_order == 0 && adjust_e_order < 0)
1339  break;
1340  else {
1341  e_order += adjust_e_order;
1342  if(adjust_e_order > 0)
1343  __last_e_order_upgrade_age = system.age();
1344  }
1345  system.change_e_order(e_order);
1346  if(
1347  e_order == starting_e_order
1348  ||
1349  (
1350  last_adjustment < 0
1351  &&
1352  adjust_e_order > 0
1353  )
1354  ) {
1356 #ifndef NDEBUG
1357  std::cerr << "Reverted to eccentricity expansion order of ";
1358  } else {
1359  std::cerr << "Trying eccentricity expansion order of ";
1360 #endif
1361  }
1362 #ifndef NDEBUG
1363  std::cerr << e_order << std::endl;
1364 #endif
1365  last_adjustment = adjust_e_order;
1366  if(must_increase && adjust_e_order <= 0) break;
1367  }
1368  } while(adjust_e_order && e_order != starting_e_order);
1369 
1370  if(e_order != starting_e_order) {
1372 #ifndef NDEBUG
1373  std::cerr << "Adjusted eccentricity expansion order to "
1374  << e_order
1375  << std::endl;
1376 #endif
1377  }
1378  }
1379 
1381  {
1382  __tabulated_ages.clear();
1384  system.reset_evolution();
1385  }
1386 
1388  double required_precision,
1389  bool print_progress) :
1390  __end_age(max_age),
1391  __precision(required_precision),
1393  __stopping_conditions(NULL),
1394  __print_progress(print_progress)
1395  {
1396 #ifndef NDEBUG
1397  assert(max_age>0);
1398 #endif
1399  }
1400 
1402  double max_step,
1403  const std::list<double> &required_ages,
1404  double max_runtime)
1405  {
1406 #ifndef NDEBUG
1407  std::cerr << "Calculating evolution from t = " << system.age()
1408  << " to t = " << __end_age << std::endl;
1409 #endif
1410  time(&__evolution_start_time);
1411  __runtime_limit = max_runtime;
1412 
1413  double stop_evol_age = __end_age;
1414 
1415  reset(system);
1416  StoppingConditionType stop_reason = NO_STOP;
1417  double last_age = system.age();
1418  std::valarray<double> orbit;
1419 
1420  Core::EvolModeType evolution_mode = system.fill_orbit(orbit);
1421 
1422  if(evolution_mode == Core::BINARY)
1424  orbit,
1425  evolution_mode);
1426 
1427 
1428  while(last_age < stop_evol_age) {
1429  double next_stop_age = std::min(stopping_age(last_age,
1430  system,
1431  required_ages),
1432  stop_evol_age);
1434 #ifndef NDEBUG
1435  std::cerr << "Next stop age: " << next_stop_age << std::endl;
1436  StopInformation stop_information =
1437 #endif
1438  evolve_until(system,
1439  next_stop_age,
1440  orbit,
1441  stop_reason,
1442  max_step,
1443  evolution_mode);
1444 
1445  Core::EvolModeType old_evolution_mode = evolution_mode;
1446 #ifndef NDEBUG
1447  std::cerr << "Stop information: "
1448  << stop_information
1449  << std::endl;
1450  unsigned old_locked_zones = system.number_locked_zones();
1451 #endif
1452  last_age = next_stop_age;
1453  if(last_age < stop_evol_age) {
1454  if(stop_reason == NO_STOP) {
1455  system.reached_critical_age(last_age);
1456  } else if(
1457  stop_reason == LARGE_EXPANSION_ERROR
1458  ||
1459  stop_reason == SMALL_EXPANSION_ERROR
1460  ) {
1462  system,
1463  orbit,
1464  evolution_mode,
1465  stop_reason == LARGE_EXPANSION_ERROR
1466  );
1467  } else
1468  reached_stopping_condition(last_age, stop_reason);
1469  }
1470 #ifndef NDEBUG
1471  std::cerr
1472  << "At t=" << last_age
1473  << ", changing evolution mode from " << old_evolution_mode
1474  << " with " << old_locked_zones
1475  << " zones locked ";
1476 #endif
1477  evolution_mode = system.evolution_mode();
1478 #ifndef NDEBUG
1479  std::cerr
1480  << "to " << evolution_mode
1481  << " with " << system.number_locked_zones()
1482  << " zones locked."
1483  << std::endl
1484  << "Transforming orbit from: ";
1485  std::clog << orbit;
1486 #endif
1487  system.fill_orbit(orbit);
1488 #ifndef NDEBUG
1489  std::cerr << " to " << orbit << std::endl;
1490 #endif
1491 
1492  if(
1493  evolution_mode == Core::BINARY
1494  &&
1495  old_evolution_mode != Core::BINARY
1496  )
1498  orbit,
1499  evolution_mode);
1500 
1501  delete __stopping_conditions;
1502  __stopping_conditions = NULL;
1503  }
1504  }
1505 
1506 } //End Evolve namespace.
double stop_age() const
The target stopping age in Gyr.
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.
int differential_equations(double age, const double *parameters, Core::EvolModeType evolution_mode, double *differential_equations, bool expansion_error=false)
The differential equation and jacobian for the evolution of the system.
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:184
Function arguments do not satisfy some requirement.
Definition: Error.h:73
void operator()(BinarySystem &system, double max_step=Core::Inf, const std::list< double > &required_ages=std::list< double >(), double max_runtime=0)
Actually solves the given differential equation with the given boundary conditions.
void reset(BinarySystem &system)
Clears any previously calculated evolution.
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
ExtremumInformation extremum_from_history(size_t condition_index) const
Estimates the value and age of an extremum of a stopping condition for which derivative information i...
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:136
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:153
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.
void initialize_skip_history(const StoppingCondition &stop_cond, StoppingConditionType stop_reason)
Initializes the skip_history_zerocrossing and skip_history_extremum arrays appropriately after a mode...
double stop_condition_precision() const
The precision up to which the reason to stop is satisfied.
StopInformation update_stop_condition_history(double age, const std::valarray< double > &orbit, const std::valarray< double > &derivatives, const std::valarray< double > &expansion_errors, Core::EvolModeType evolution_mode, StoppingConditionType stop_reason=NO_STOP, bool ignore_e_order_decrease=false)
Updates stop_cond_history and stop_deriv_history after a GSL step, returning if/where the evolution n...
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:181
std::list< std::valarray< double > > __stop_deriv_history
Past values of the stop condition derivatives.
Definition: OrbitSolver.h:153
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...
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:833
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:55
bool at_exact_condition(double previous_age, const StopInformation &stop_info)
Is the condition causing a stop match to within the required precision?
int check_expansion_error(const std::valarray< double > &derivatives, const std::valarray< double > &expansion_errors)
Return -1 if the expansion error is too small (e-order can safely be decreased, 0 if it is within ran...
unsigned number_locked_zones() const
How many zones on either body are currently locked.
Definition: BinarySystem.h:848
virtual void reached_critical_age(double age)
Change the system as necessary at the given age.
static unsigned max_e_order()
The maximum eccentricity expansion order for which the expansion is known.
size_t stop_condition_index() const
The index of the condition which caused us to stop.
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.
double __last_e_order_upgrade_age
The last age at which the eccentricity order was increased.
Definition: OrbitSolver.h:119
No reason to stop.
std::vector< StopInformation > __stop_info
Definition: OrbitSolver.h:175
double x() const
The value of the argument where the extremum occurs.
Definition: OrbitSolver.h:101
double __e_order_downgrade_threshold
If the fractional error due to truncating the eccentricity series falls below this value times the ma...
Definition: OrbitSolver.h:119
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...
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.
int jacobian(double age, const double *parameters, Core::EvolModeType evolution_mode, double *param_derivs, double *age_derivs)
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.
A base class for all stopping conditions.
void clear_history()
Clears the current stopping condition history.
bool __print_progress
See print_progress argument of constructor.
Definition: OrbitSolver.h:178
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:153
Core::EvolModeType evolution_mode()
The evolution mode of last call to configure().
Definition: BinarySystem.h:996
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:146
std::list< std::valarray< double > > __orbit_deriv_history
Past orbital derivatives.
Definition: OrbitSolver.h:153
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:140
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.
int stellar_system_jacobian(double age, const double *orbital_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.
Definition: OrbitSolver.cpp:39
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.
virtual void change_e_order(unsigned new_e_order)
Change the eccentricity expansion order for all dissipative zones.
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
A class combining the the outputs of multiple stopping 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:146
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:143
std::list< double > __tabulated_ages
The ages at which solution is tabulated.
Definition: OrbitSolver.h:133
double age() const
Returns the age of the current point.
std::list< std::valarray< double > > __orbit_history
Past orbits.
Definition: OrbitSolver.h:153
Describes a system of two bodies orbiting each other.
Definition: BinarySystem.h:56
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.
virtual unsigned eccentricity_order() const
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:171
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:153
bool acceptable_step(double current_age, double previous_age, const StopInformation &stop_info)
Updates the skip_history_zerocrossing and skip_history_extremum arrays appropriately after an accepta...
void adjust_eccentricity_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...
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.