Planetary Orbital Evolution due to Tides
Orbital evolution of two objects experiencing tides
DissipatingZone.cpp
1 #define BUILDING_LIBRARY
2 #include "DissipatingZone.h"
3 #include "BinarySystem.h"
4 
5 namespace Evolve {
6 
7  std::ostream &operator<<(std::ostream &os,
8  const ZoneEvolutionQuantities &evol_var)
9  {
10  switch(evol_var) {
11  case ANGULAR_MOMENTUM : os << "ANGULAR_MOMENTUM"; break;
12  case ANGULAR_MOMENTUM_DERIV : os << "ANGULAR_MOMENTUM_DERIV"; break;
13  case INCLINATION : os << "INCLINATION"; break;
14  case INCLINATION_DERIV : os << "INCLINATION_DERIV"; break;
15  case PERIAPSIS : os << "PERIAPSIS"; break;
16  case PERIAPSIS_DERIV : os << "PERIAPSIS_DERIV"; break;
17  case MOMENT_OF_INERTIA : os << "MOMENT_OF_INERTIA"; break;
19  os << "DMOMENT_OF_INERTIA_DT"; break;
21  os << "D2MOMENT_OF_INERTIA_DT2"; break;
22  case OUTER_RADIUS : os << "OUTER_RADIUS"; break;
23  case OUTER_RADIUS_FIRST_DERIV : os << "DOUTER_RADIUS_DT"; break;
24  case OUTER_RADIUS_SECOND_DERIV : os << "D2OUTER_RADIUS_DT2"; break;
25  case OUTER_MASS : os << "OUTER_MASS"; break;
26  case OUTER_MASS_DERIV : os << "DOUTER_MASS_DT"; break;
27  case E_ORDER : os << "E_ORDER"; break;
28  case ORBITAL_FREQ_MULTIPLIER : os << "ORBITAL_FREQ_MULTIPLIER";
29  break;
30  case SPIN_FREQ_MULTIPLIER : os << "SPIN_FREQ_MULTIPLIER"; break;
31  default : assert(false);
32  };
33  return os;
34  }
35 
36  const double DissipatingZone::__torque_x_plus_coef[]={1.0,
37  std::sqrt(1.5),
38  std::sqrt(1.5),
39  1.0,
40  0.0};
41 
42  const double DissipatingZone::__torque_x_minus_coef[]={0.0, //m=-2
43  1.0, //m=-1
44  std::sqrt(1.5),//m=0
45  std::sqrt(1.5),//m=1
46  1.0}; //m=2
47 
49  const SpinOrbitLockInfo &limit,
50  int orbital_frequency_multiplier,
51  int spin_frequency_multiplier,
52  double &forcing_frequency
53  ) const
54  {
55  if(__initializing || !can_lock()) return;
56  assert(limit.spin_frequency_multiplier() == 1
57  ||
58  limit.spin_frequency_multiplier() == 2);
59 
60  if(
61  limit.term(orbital_frequency_multiplier,
62  spin_frequency_multiplier)
63  ) {
64  if(
65  spin_frequency_multiplier
66  *
67  limit.lock_direction()
68  *
69  forcing_frequency
70  >
71  0
72  )
73  forcing_frequency = (
74  (
75  spin_frequency_multiplier*limit.lock_direction() > 0
76  ? -1
77  : 1
78  )
79  *
80  std::numeric_limits<double>::epsilon()
81  );
82  return;
83  }
84  int expected_sign = boost::math::sign(
86  *
87  (
88  orbital_frequency_multiplier
89  *
91  -
93  *
94  spin_frequency_multiplier
95  )
96  );
97  if(
98  expected_sign * limit.lock_direction() * spin_frequency_multiplier
99  >
100  0
101  ) return;
102  if(forcing_frequency * expected_sign > 0) return;
103 
104  assert(limit.lock_direction());
105 
106  forcing_frequency = (
107  std::numeric_limits<double>::epsilon()
108  *
109  expected_sign
110  );
111  }
112 
114  {
115  if(__initializing) return;
116  int max_abs_orb_mult = static_cast<int>(__e_order + 2);
117  if(
118  (!__lock)
119  &&
121  ) {
122  throw Core::Error::Runtime(
123  "Inconsistent lock state encountered for a zone. Likely related "
124  "to initial conditions with a tidal term too close to zero."
125  );
126  }
127  assert(__lock.spin_frequency_multiplier() == 1
128  ||
131  &&
133  if(__lock) return;
134  return;//<++>
135  assert(
136  (
138  *
140  *
142  +
143  1.0e-5 * __orbital_frequency
144  )
145  >=
146  (
148  *
150  *
152  )
153  );
155  assert(
156  (
158  *
160  *
162  )
163  >
164  (
166  *
168  *
170  )
171  );
172  } else assert(
174  >
175  0
176  );
177  }
178 
180  {
181  assert(lock.lock_direction());
183  if(
184  static_cast<unsigned>(std::abs(lock.orbital_frequency_multiplier()))
185  >
186  __e_order+2
187  &&
188  lock.spin_frequency_multiplier()==2
189  )
190  lock.set_lock(
191  (
193  -
194  lock.lock_direction()
195  )/2,
196  1,
197  lock.lock_direction()
198  );
199 
200  if(
202  >
203  static_cast<int>(__e_order + 2)
204  ) {
205  if(lock.lock_direction() > 0)
206  lock.set_lock(__e_order + 2, 1, 1);
207  else
208  lock.set_lock(1, 0, -1);
209  } else if(
211  <
212  -static_cast<int>(__e_order)-2
213  ) {
214  if(lock.lock_direction() > 0)
215  lock.set_lock(-1, 0, 1);
216  else
217  lock.set_lock(-static_cast<int>(__e_order) - 2, 1, -1);
218  }
220  }
221 
223  {
224  if(!can_lock()) {
225  __lock.set_lock(-1, 0, 1);
226  __other_lock.set_lock(1, 0, -1);
227  return;
228  }
229 #ifndef NDEBUG
230  std::cerr << "Initializing locks for Worb = "
232  << ", W* = "
234  << "." << std::endl;
235 #endif
236  int below_orb_mult = std::floor(2.0
237  *
239  /
241  max_abs_orb_mult=static_cast<int>(__e_order + 2);
242  if(below_orb_mult % 2) {
243  if(
244  std::abs(below_orb_mult)
245  <=
246  max_abs_orb_mult
247  ) {
248  __lock.set_lock(below_orb_mult, 2, 1);
249  __other_lock.set_lock((below_orb_mult + 1) / 2, 1, -1);
250  } else if(
251  std::abs((below_orb_mult - 1) / 2)
252  <=
253  max_abs_orb_mult
254  ) {
255  __lock.set_lock((below_orb_mult - 1) / 2, 1, 1);
256  if((below_orb_mult + 1) / 2 > max_abs_orb_mult)
257  __other_lock.set_lock(1, 0, -1);
258  else
259  __other_lock.set_lock((below_orb_mult + 1) / 2, 1, -1);
260  } else {
261  if(__spin_frequency > 0) {
262  __lock.set_lock(max_abs_orb_mult, 1, 1);
263  __other_lock.set_lock(1, 0, -1);
264  } else {
265  __lock.set_lock(-max_abs_orb_mult, 1, -1);
266  __other_lock.set_lock(-1, 0, 1);
267  }
268  }
269  } else if(std::abs(below_orb_mult / 2) <= max_abs_orb_mult) {
270  __lock.set_lock(below_orb_mult / 2, 1, 1);
271  if(std::abs(below_orb_mult + 1) <= max_abs_orb_mult)
272  __other_lock.set_lock(below_orb_mult + 1, 2, -1);
273  else if(std::abs(below_orb_mult / 2 + 1) <= max_abs_orb_mult)
274  __other_lock.set_lock(below_orb_mult / 2 + 1, 1, -1);
275  else
276  __other_lock.set_lock(1, 0, -1);
277  } else {
278  if(__spin_frequency > 0) {
279  __lock.set_lock(max_abs_orb_mult, 1, 1);
280  __other_lock.set_lock(1, 0, -1);
281  } else {
282  __lock.set_lock(-max_abs_orb_mult, 1, -1);
283  __other_lock.set_lock(-1, 0, 1);
284  }
285 
286  }
288  }
289 
291  int mp,
292  double tidal_frequency,
293  const TidalTermTriplet &U_value,
294  const TidalTermTriplet &U_i_deriv,
295  const TidalTermTriplet &U_e_deriv,
296  const TidalTermTriplet &U_error)
297  {
298  int m_ind = m + 2;
299 
300  bool locked_term = locked(mp, m);
301 
302  bool has_error = true;
303 
304  for(
305  int deriv = Dissipation::NO_DERIV;
306  (
307  (m != 0 || mp != 0)
308  &&
310  );
311  ++deriv
312  ) {
313  Dissipation::QuantityEntry phase_lag_deriv = (
315  ? static_cast<Dissipation::QuantityEntry>(deriv)
317  );
318  double mod_phase_lag_above,
319  mod_phase_lag_below = modified_phase_lag(
320  mp,
321  m,
322  tidal_frequency,
323  phase_lag_deriv,
324  mod_phase_lag_above
325  ),
326  love_coef = love_coefficient(
327  mp,
328  m,
329  (
330  phase_lag_deriv == Dissipation::AGE
333  )
334  );
335 
338  U = U_value;
339  else if(deriv == Dissipation::INCLINATION)
340  U = U_i_deriv;
341  else
342  U = U_e_deriv;
343 
344  double U_mmp_squared = std::pow(U.m, 2),
345  U_mmp_squared_error = (has_error
346  ? (2.0 * std::abs(U.m * U_error.m)
347  +
348  std::pow(U_error.m, 2))
349  : 0.0),
350  term_power = U_mmp_squared * mp,
351  term_power_error = U_mmp_squared_error * mp,
352  term_torque_z = U_mmp_squared * m,
353  term_torque_z_error = U_mmp_squared_error * m,
354  term_torque_x = U.m * (
356  +
358  ),
359  term_torque_x_error = 0.0;
360  if(has_error) {
361  double common_error_term = (
362  __torque_x_minus_coef[m_ind] * U_error.m_minus_one
363  +
364  __torque_x_plus_coef[m_ind] * U_error.m_plus_one
365  );
366  term_torque_x_error = (
367  (
368  U_error.m
369  ? U_error.m * (term_torque_x / U.m + common_error_term)
370  : 0.0
371  )
372  +
373  U.m * common_error_term
374  );
375  }
376  if(
377  !locked_term
378  &&
379  (tidal_frequency != 0 || __lock.lock_direction() < 0)
380  )
381  mod_phase_lag_above = mod_phase_lag_below;
382  else if(
383  !locked_term
384  &&
385  tidal_frequency == 0
386  &&
387  __lock.lock_direction() > 0
388  )
389  mod_phase_lag_below = mod_phase_lag_above;
390  int deriv_ind = 2 * deriv;
391  __power[deriv_ind] += term_power * mod_phase_lag_below;
392  __torque_z[deriv_ind] += (term_torque_z
393  *
394  mod_phase_lag_below);
395  __torque_x[deriv_ind] += (term_torque_x
396  *
397  mod_phase_lag_below);
398  __torque_y[deriv_ind + 1] = -(
399  __torque_y[deriv_ind] -= term_torque_x * love_coef
400  );
401  __power[deriv_ind + 1] += term_power * mod_phase_lag_above;
402  __torque_z[deriv_ind + 1] += (term_torque_z
403  *
404  mod_phase_lag_above);
405  __torque_x[deriv_ind + 1] += (term_torque_x
406  *
407  mod_phase_lag_above);
408  assert(!std::isnan(__torque_x[deriv_ind]));
409  assert(!std::isnan(__torque_x[deriv_ind + 1]));
410  assert(!std::isnan(__torque_y[deriv_ind]));
411  assert(!std::isnan(__torque_y[deriv_ind + 1]));
412  assert(!std::isnan(__torque_z[deriv_ind]));
413  assert(!std::isnan(__torque_z[deriv_ind + 1]));
414  if(has_error) {
415  has_error = false;
416  const int error_ind = 2 * Dissipation::END_DIMENSIONLESS_DERIV;
417  __power[error_ind] += term_power_error * mod_phase_lag_below;
418  __torque_z[error_ind] += (term_torque_z_error
419  *
420  mod_phase_lag_below);
421  __torque_x[error_ind] += (term_torque_x_error
422  *
423  mod_phase_lag_below);
424  __torque_y[error_ind + 1] = -(
425  __torque_y[error_ind] -= term_torque_x_error * love_coef
426  );
427  __power[error_ind + 1] += (term_power_error
428  *
429  mod_phase_lag_above);
430  __torque_z[error_ind + 1] += (term_torque_z_error
431  *
432  mod_phase_lag_above);
433  __torque_x[error_ind + 1] += (term_torque_x_error
434  *
435  mod_phase_lag_above);
436 
437  assert(!std::isnan(__torque_x[error_ind]));
438  assert(!std::isnan(__torque_x[error_ind + 1]));
439  assert(!std::isnan(__torque_y[error_ind]));
440  assert(!std::isnan(__torque_y[error_ind + 1]));
441  assert(!std::isnan(__torque_z[error_ind]));
442  assert(!std::isnan(__torque_z[error_ind + 1]));
443  }
444 #if 0
445  if(deriv == Dissipation::NO_DERIV)
446  std::cerr << ", Wzone = "
447  << spin_frequency()
448  << ", U(" << m << ", " << mp << ") = "
449  << U.m
450  << ", term_power="
451  << term_power
452  << ", mod_phase_lag(above="
453  << mod_phase_lag_above
454  << ", below="
455  << mod_phase_lag_below
456  << ")";
457 #endif
458  }
459  }
460 
462  bool spin_is_frequency)
463  {
464  if(spin_is_frequency) {
466  __spin_frequency = spin;
467  } else {
468  __angular_momentum = spin;
469  if(spin == 0 && moment_of_inertia() == 0) __spin_frequency = 0;
470  else __spin_frequency = spin / moment_of_inertia();
471  }
472  }
473 
474  DissipatingZone::DissipatingZone() :
475  __e_order(0),
482  __initializing(false)
483  {}
484 
485  void DissipatingZone::configure(bool initialize,
486  double
487 #ifndef NDEBUG
488  age
489 #endif
490  ,
491  double orbital_frequency,
492  double eccentricity,
493  double orbital_angmom,
494  double spin,
495  double inclination,
496  double periapsis,
497  bool spin_is_frequency)
498  {
499  assert(age >= 0);
500 
501  if(initialize) {
502  __initializing = true;
503 #ifndef NDEBUG
504  std::cerr << "Initializing DissipatingZone" << std::endl;
505 #endif
506  }
507 #ifndef NDEBUG
508  std::cerr << "At t = " << age << ", configuring zone with "
509  << (spin_is_frequency ? "w" : "L") << " = " << spin
510  << ", inclination = " << inclination
511  << ", periapsis = " << periapsis
512  << std::endl;
513 
514 #endif
515  ZoneOrientation::configure(inclination, periapsis);
516  __orbital_angmom = orbital_angmom;
517  __orbital_frequency = orbital_frequency;
518  if(__lock && !initialize) {
519  __spin_frequency = __lock.spin(orbital_frequency);
521  } else
522  configure_spin(spin, spin_is_frequency);
523 
524  if(initialize) {
526  __initializing = false;
527  }
528  if(std::isnan(orbital_frequency)) return;
529 
530  __potential_term.configure(inclination, periapsis);
531  __power = 0;
532  __torque_x = 0;
533  __torque_y = 0;
534  __torque_z = 0;
535 
536  if(!dissipative()) return;
537 
538  double esquared = std::pow(eccentricity, 2);
539 
540  for(
541  int mp = -static_cast<int>(__e_order) - 2;
542  mp <= static_cast<int>(__e_order) + 2;
543  ++mp
544  ) {
545  TidalTermTriplet U_value,
546  U_error,
547  U_i_deriv,
548  U_e_deriv;
549  __potential_term(eccentricity,
550  -2,
551  mp,
552  U_value.m_plus_one,
553  U_i_deriv.m_plus_one,
554  U_e_deriv.m_plus_one,
555  U_error.m_plus_one);
556  U_error.m_plus_one *= esquared;
557 
558  for(int m = -2; m <= 2; ++m) {
559 #if 0
560  std::cerr << "Term: m' = "
561  << mp
562  << ", m = "
563  << m;
564 #endif
565 
566  U_value.m = U_value.m_plus_one;
567  U_error.m = U_error.m_plus_one;
568  U_i_deriv.m = U_i_deriv.m_plus_one;
569  U_e_deriv.m = U_e_deriv.m_plus_one;
570  if(m < 2) {
571  __potential_term(eccentricity,
572  m + 1,
573  mp,
574  U_value.m_plus_one,
575  U_i_deriv.m_plus_one,
576  U_e_deriv.m_plus_one,
577  U_error.m_plus_one);
578  U_error.m_plus_one *= esquared;
579  } else {
580  U_value.m_plus_one = 0;
581  U_error.m_plus_one = 0;
582  U_i_deriv.m_plus_one = 0;
583  U_e_deriv.m_plus_one = 0;
584  }
585 
587  m,
588  mp,
589  forcing_frequency(mp, m, orbital_frequency),
590  U_value,
591  U_i_deriv,
592  U_e_deriv,
593  U_error
594  );
595 
596  U_value.m_minus_one = U_value.m;
597  U_error.m_minus_one = U_error.m;
598  U_i_deriv.m_minus_one = U_i_deriv.m;
599  U_e_deriv.m_minus_one = U_e_deriv.m;
600 #ifdef VERBOSE_DEBUG
601  std::cerr << std::endl;
602 #endif
603  }
604  }
605  }
606 
608  int orbital_frequency_multiplier,
609  int spin_frequency_multiplier,
610  double orbital_frequency
611  ) const
612  {
613  if(
615  ||
617 
618  )
620  if(__lock(orbital_frequency_multiplier, spin_frequency_multiplier))
621  return 0;
622  double forcing_freq = (
623  orbital_frequency_multiplier * orbital_frequency
624  -
625  spin_frequency_multiplier * spin_frequency()
626  );
627  assert(!std::isnan(forcing_freq));
628 
629 #ifdef VERBOSE_DEBUG
630  std::cerr << "Worb = " << orbital_frequency << ", "
631  << "Wspin = " << spin_frequency() << " -> "
632  << "Wtide = " << forcing_freq << " -> ";
633 #endif
634 
635  if(
637  ||
639 
640  )
642  orbital_frequency_multiplier,
643  spin_frequency_multiplier,
644  forcing_freq);
647  orbital_frequency_multiplier,
648  spin_frequency_multiplier,
649  forcing_freq);
650 #ifdef VERBOSE_DEBUG
651  std::cerr << forcing_freq << std::endl;
652 #endif
653  return forcing_freq;
654  }
655 
656 
657 
659  const Eigen::Vector3d &orbit_torque,
660  const Eigen::Vector3d &zone_torque,
661  Dissipation::QuantityEntry entry,
662  const Eigen::Vector3d &orbit_torque_deriv,
663  const Eigen::Vector3d &zone_torque_deriv
664  )
665  {
666  double sin_inc = std::sin(inclination()),
667  cos_inc = std::cos(inclination()),
668  zone_y_torque,
669  orbit_y_torque;
670  if(entry == Dissipation::NO_DERIV) {
671  orbit_y_torque = orbit_torque[1];
672  zone_y_torque = zone_torque[1];
673  } else if(entry == Dissipation::EXPANSION_ERROR) {
674  return (
675  sin_inc == 0
676  ? 0
677  : (
678  std::abs(orbit_torque[1] * cos_inc
679  /
680  (__orbital_angmom * sin_inc))
681  +
682  std::abs(zone_torque[1]
683  /
684  (__angular_momentum * sin_inc))
685  )
686  );
687  } else {
688  orbit_y_torque = orbit_torque_deriv[1];
689  zone_y_torque = zone_torque_deriv[1];
690  }
691 #ifndef NDEBUG
692  if(sin_inc == 0) {
693  assert(orbit_y_torque == 0 || std::isnan(orbit_y_torque));
694  assert(zone_y_torque == 0 || std::isnan(zone_y_torque));
695  } else {
696  assert(!std::isnan(orbit_y_torque));
697  assert(!std::isnan(zone_y_torque));
698  }
699 #endif
700  double result = (
701  sin_inc == 0
702  ? 0
703  : (
704  -orbit_y_torque * cos_inc / (__orbital_angmom * sin_inc)
705  +
706  zone_y_torque / (__angular_momentum * sin_inc)
707  )
708  );
709  assert(!std::isnan(result));
710 
711  if(
712  entry == Dissipation::NO_DERIV
713  ||
714  entry == Dissipation::AGE
715  ||
717  ||
718  entry == Dissipation::PERIAPSIS
719  ||
720  entry == Dissipation::RADIUS
721  ||
723  ||
724  entry == Dissipation::SEMIMAJOR
725  )
726  return result;
727  else if(
729  ||
730  entry == Dissipation::SPIN_ANGMOM
731  ) {
732  if(sin_inc == 0) return 0.0;
733  else return (
734  result
735  -
736  zone_torque[1]
737  /
738  (std::pow(__angular_momentum, 2) * sin_inc)
739  *
741  );
742  } else if(entry == Dissipation::INCLINATION) {
743  if(sin_inc == 0) return 0.0;
744  else return (
745  result
746  -
747  (
748  orbit_torque[1] / __orbital_angmom
749  +
750  zone_torque[1] * cos_inc / __angular_momentum
751  )
752  /
753  std::pow(sin_inc, 2)
754  );
755  } else {
756  assert(false);
757  }
758 
759  return Core::NaN;
760  }
761 
763  const Eigen::Vector3d &orbit_torque,
764  const Eigen::Vector3d &zone_torque,
765  Dissipation::QuantityEntry entry,
766  const Eigen::Vector3d &orbit_torque_deriv,
767  const Eigen::Vector3d &zone_torque_deriv)
768  {
769  double sin_inc = std::sin(inclination()),
770  cos_inc = std::cos(inclination()),
771  zone_x_torque,
772  orbit_x_torque,
773  orbit_z_torque;
774  assert(!std::isnan(orbit_torque[0]));
775  assert(!std::isnan(orbit_torque[2]));
776  assert(!std::isnan(zone_torque[0]));
777  if(entry == Dissipation::NO_DERIV) {
778  orbit_x_torque = orbit_torque[0];
779  orbit_z_torque = orbit_torque[2];
780  zone_x_torque = zone_torque[0];
781  } else if(entry == Dissipation::EXPANSION_ERROR) {
782  if(orbit_torque[0] == 0 && orbit_torque[2] == 0)
783  return 0;
784 
785  assert(__orbital_angmom > 0);
786  return (
787  (
788  std::abs(orbit_torque[0] * cos_inc)
789  -
790  std::abs(orbit_torque[2] * sin_inc)
791  )
792  /
794  );
795  } else {
796  orbit_x_torque = orbit_torque_deriv[0];
797  orbit_z_torque = orbit_torque_deriv[2];
798  zone_x_torque = zone_torque_deriv[0];
799  }
800 
801  double result;
802  if(orbit_x_torque == 0 && orbit_z_torque == 0)
803  result = 0.0;
804  else
805  result = ((orbit_x_torque * cos_inc - orbit_z_torque * sin_inc)
806  /
808 
809  if(zone_x_torque != 0 && moment_of_inertia() != 0)
810  result -= zone_x_torque / __angular_momentum;
811 
812  assert(!std::isnan(result));
813 
814  if(
815  entry == Dissipation::NO_DERIV
816  ||
817  entry == Dissipation::AGE
818  ||
820  ||
821  entry == Dissipation::PERIAPSIS
822  ||
823  entry == Dissipation::RADIUS
824  ||
826  ||
827  entry == Dissipation::SEMIMAJOR
828  ) {
829  return result;
830  } else if(
832  ||
833  entry == Dissipation::SPIN_ANGMOM
834  ) {
835  assert(std::abs(__angular_momentum) > 0);
836  return (
837  result
838  +
839  zone_torque[0] / std::pow(__angular_momentum, 2)
840  *
842  );
843  } else if(entry == Dissipation::INCLINATION) {
844  assert(std::abs(__angular_momentum) > 0);
845  return (result
846  +
847  (orbit_torque[2] * cos_inc + orbit_torque[0] * sin_inc)
848  /
850  } else
851  assert(false);
852  return Core::NaN;
853  }
854 
856  {
857  assert(can_lock());
858  if(__lock.spin_frequency_multiplier() == 2) {
859  assert(__lock.orbital_frequency_multiplier() % 2 == 1);
862  1,
863  -1
864  );
867  1,
868  -1
869  );
870  }
873  if(__lock.spin_frequency_multiplier() == 0) {
875  __other_lock.set_lock(1, 0, 1);
876  }
877  }
878 
879  void DissipatingZone::release_lock(short direction)
880  {
881  assert(can_lock());
882  assert(__lock);
883  assert(direction == 1 || direction == -1);
884  assert(
886  ||
888  );
889  __lock.lock_direction(direction);
890  int orbit_mult = (
891  (__lock.spin_frequency_multiplier() == 2 ? 1 : 2)
892  *
894  +
895  direction
896  );
897  if(orbit_mult % 2) __other_lock.set_lock(orbit_mult, 2, -direction);
898  else __other_lock.set_lock(orbit_mult/2, 1, -direction);
900  }
901 
903  unsigned new_e_order,
904  BinarySystem &,
905  bool ,
906  unsigned
907  )
908  {
909 #ifndef NDEBUG
910  std::cerr << "Changing eccentricity order to "
911  << new_e_order
912  << std::endl;
913 #endif
914  __potential_term.change_e_order(new_e_order);
915  if(__lock.spin_frequency_multiplier() == 0) {
916  __e_order = new_e_order;
917 #ifdef VERBOSE_DEBUG
918  std::cerr << "No lock defined, simple e-order change." << std::endl;
919 #endif
920  return;
921  }
922 #ifdef VERBOSE_DEBUG
923  std::cerr << "Lock(s) defined, updating." << std::endl;
924 #endif
925  if(__lock) {
926  __e_order = new_e_order;
927  if(
929  >
930  static_cast<int>(__e_order) + 2
931  )
932  release_lock();
933  return;
934  }
936 
937  if(__lock) {
938  __e_order = new_e_order;
939  if(
941  >
942  static_cast<int>(__e_order) + 2
943  )
944  release_lock();
945  return;
946  }
947 
948  __e_order = new_e_order;
950 
952  }
953 
955  {
959  );
960 
963 
964  __evolution_real[PERIAPSIS].push_back(periapsis());
965  __evolution_real[PERIAPSIS_DERIV].push_back(periapsis(true));
966 
968 
971  );
972 
975  );
976 
978 
980 
982 
983  __evolution_real[OUTER_MASS].push_back(outer_mass());
984 
986 
988  __e_order
989  );
990 
991  if(__lock) {
993  .push_back(__lock.orbital_frequency_multiplier());
995  .push_back(__lock.spin_frequency_multiplier());
996  } else {
998  .push_back(0);
1000  .push_back(0);
1001  }
1002  }
1003 
1005  {
1006  for(unsigned i = 0; i < __evolution_real.size(); ++i)
1007  __evolution_real[i].clear();
1008  for(unsigned i = 0; i < __evolution_integer.size(); ++i)
1009  __evolution_integer[i].clear();
1010  }
1011 
1013  {
1014  for(unsigned i = 0; i < nsteps; ++i) {
1015  for(unsigned i = 0; i < __evolution_real.size(); ++i)
1016  __evolution_real[i].pop_back();
1017  for(unsigned i = 0; i < __evolution_integer.size(); ++i)
1018  __evolution_integer[i].pop_back();
1019  }
1020  }
1021 
1023  BinarySystem &system,
1024  bool primary,
1025  unsigned zone_index
1026  )
1027  {
1029  if(!can_lock()) return result;
1030  if(__lock)
1031  (*result) |= new BreakLockCondition(system, __locked_zone_index);
1032  else if(system.evolution_mode() == Core::BINARY) {
1033  (*result) |= new SynchronizedCondition(
1037  primary,
1038  zone_index,
1039  system
1040  );
1041  (*result) |= new SynchronizedCondition(
1045  primary,
1046  zone_index,
1047  system
1048  );
1049  }
1050  return result;
1051  }
1052 
1053 } //End Evolve namespace.
ZoneEvolutionQuantities
IDs for quantities saved as part of the evolution.
double m
The (m, m&#39;) coefficient.
Age derivative of MOMENT_OF_INERTIA.
unsigned __locked_zone_index
If this zone is locked, this is its index in the list of locked zones in the system.
RADIUS
The derivative w.r.t. the radius of the body in .
virtual void configure(bool initialize, double age, double orbital_frequency, double eccentricity, double orbital_angmom, double spin, double inclination, double periapsis, bool spin_is_frequency)
Defines the current orbit, triggering re-calculation of all quantities.
END_PHASE_LAG_DERIV
The above derivatives exist for modified phase lags, below do not.
Inclination of the zone.
The rate at which periapsis changes.
Satisfied when some multiples of the orbit and stellar rotation are synchronized. ...
std::valarray< double > __power
The dimensionless tidal power and its error and derivatives.
Declares a class representing one zone of a body dissipative to tidal distortions.
The total number of quantities whose evolution is tracked.
SPIN_FREQUENCY
The derivative w.r.t. the spin frequency of a dissipating zone.
double __spin_frequency
The current spin frequency of the zone.
std::ostream & operator<<(std::ostream &os, const ZoneEvolutionQuantities &evol_var)
More civilized output for EvolVarType variables.
int orbital_frequency_multiplier() const
The multiplier in front of the orbital frequency in the lock.
virtual void add_to_evolution()
Appends the state defined by last configure(), to the evolution.
double periapsis(bool evolution_rate=false) const
The argument of periapsis of this zone minus the reference zone&#39;s.
Satisfied when the maximum tidal torque that the planet can exert on the star is no longer sufficient...
The rate at which the the inclination changes.
SEMIMAJOR
The derivative w.r.t. the semimajor axis in AU.
void add_tidal_term(int m, int mp, double tidal_frequency, const TidalTermTriplet &U_value, const TidalTermTriplet &U_i_deriv, const TidalTermTriplet &U_e_deriv, const TidalTermTriplet &U_error)
Add a term to the tidal torque and power arrays.
static const double __torque_x_plus_coef[]
as a function of .
unsigned __e_order
The expansion order in eccentricity to use.
std::vector< std::list< double > > __evolution_real
The floating point quantities whose evolution is tracked.
void update_lock_to_lower_e_order(SpinOrbitLockInfo &lock)
Updates a SpinOrbitLockInfo variable as appropriate when decreasing the eccentricity expansion order...
Outer radius boundary of the zone.
MOMENT_OF_INERTIA
virtual double modified_phase_lag(int orbital_frequency_multiplier, int spin_frequency_multiplier, double forcing_frequency, Dissipation::QuantityEntry entry, double &above_lock_value) const =0
Should return the tidal phase lag time the love number for the given tidal term (or one of its deriva...
virtual double love_coefficient(int orbital_frequency_multiplier, int spin_frequency_multiplier, Dissipation::QuantityEntry entry) const =0
Should return the corresponding component of the love coefficient (Lai 2012 Equation 24)...
Any runtime error.
Definition: Error.h:61
Orientations of zones of bodies in a binary system.
double spin(double orbital_frequency) const
Spin frequency at exactly the lock that corresponds to the given orbital frequency.
Number of real values evolution quantities.
Eccentricity expansion order.
void release_lock()
Update the zone as necessary when the held lock disappears from the expansion.
First age derivative of OUTER_MASS.
virtual double moment_of_inertia(int deriv_order=0) const =0
Moment of inertia of the zone or its age derivative at the age of last configure() call...
std::valarray< double > __torque_x
The dimensionless tidal torque in the x direction and its derivatives.
double __angular_momentum_evolution_rate
The current rate of angular momentum evolution of the zone.
double m_minus_one
The (m-1, m&#39;) coefficient.
Periapsis of the zone.
int spin_frequency_multiplier() const
The multiplier in front of the spin frequency in the lock.
void configure(double inclination, double arg_of_periapsis=0)
Set the inclination relative to the orbit.
virtual void reset_evolution()
Discards all evolution.
double __orbital_frequency
The orbital frequency (rad/day).
double m_plus_one
The (m+1, m&#39;) coefficient.
void configure(double inclination, double periapsis)
Changes the zone orientation.
TidalPotentialTerms __potential_term
The expansion of the tidal potential in series.
void change_e_order(unsigned new_e_order)
Change the eccentricity expansion order.
SpinOrbitLockInfo __other_lock
The term closest matched by the current spin-orbit ratio in the other direction from __lock...
double __angular_momentum
The current angular momentum of the zone.
virtual double outer_mass(int deriv_order=0) const =0
Mass coordinate of the zone&#39;s outer ouboundary or its derivative.
double periapsis_evolution(const Eigen::Vector3d &orbit_torque, const Eigen::Vector3d &zone_torque, Dissipation::QuantityEntry entry=Dissipation::NO_DERIV, const Eigen::Vector3d &orbit_torque_deriv=Eigen::Vector3d(), const Eigen::Vector3d &zone_torque_deriv=Eigen::Vector3d())
The rate at which the periapsis of the orbit/reference zone in this zone&#39;s equatorial plane is changi...
ECCENTRICITY
The derivative w.r.t. the eccentricity.
For locked zones this is the orbital frequency multiple of the lock.
END_DIMENSIONLESS_DERIV
void fix_forcing_frequency(const SpinOrbitLockInfo &limit, int orbital_frequency_multiplier, int spin_frequency_multiplier, double &forcing_frequency) const
Ensure the forcing frequency has the correct sign per the given constraint.
Moment of inertia of the zone.
void initialize_locks()
Initializes the locks the first time the zone is configure() -ed.
AGE
The derivative w.r.t. age, excluding the dependence through the body&#39;s radius and the moments of iner...
Defines the BinarySystem class.
Core::EvolModeType evolution_mode()
The evolution mode of last call to configure().
Definition: BinarySystem.h:996
virtual CombinedStoppingCondition * stopping_conditions(BinarySystem &system, bool primary, unsigned zone_index)
Conditions detecting the next possible discontinuities in the evolution due to this zone...
double inclination(bool evolution_rate=false) const
The angle between the angular momenta of the zone and the orbit.
Outer mass boundary of the zone.
NO_DERIV
The quantity itself, undifferentiated.
SpinOrbitLockInfo __lock
The lock the zone is currently held at (disabled if not locked).
Second age deriv of OUTER_RADIUS.
std::vector< std::list< int > > __evolution_integer
The integer quantities whose evolution is tracked.
bool term(int orbital_freq_mult, int spin_freq_mult) const
Angular momentum of the zone.
SPIN_ANGMOM
The derivative w.r.t. the spin angular momentum in .
double inclination_evolution(const Eigen::Vector3d &orbit_torque, const Eigen::Vector3d &zone_torque, Dissipation::QuantityEntry entry=Dissipation::NO_DERIV, const Eigen::Vector3d &orbit_torque_deriv=Eigen::Vector3d(), const Eigen::Vector3d &zone_torque_deriv=Eigen::Vector3d())
The rate at which the inclination between this zone and the orbit is changing.
static const double __torque_x_minus_coef[]
as a function of .
virtual void rewind_evolution(unsigned nsteps)
Discards the last steps from the evolution.
First age deriv of OUTER_RADIUS.
void configure_spin(double spin, bool spin_is_frequency)
Configures only the spin of the zone.
Age second deriv of MOMENT_OF_INERTIA.
std::valarray< double > __torque_y
The dimensionless tidal torque in the y direction and its derivatives.
double forcing_frequency(int orbital_frequency_multiplier, int spin_frequency_multiplier, double orbital_frequency) const
The tidal forcing frequency for the given term and orbital frequency.
std::valarray< double > __torque_z
The dimensionless tidal torque in the z direction and its derivatives.
virtual void change_e_order(unsigned new_e_order, BinarySystem &system, bool primary, unsigned zone_index)
Changes the order of the eccentricity expansion performed.
The rate at which angular momentum changes.
A class combining the the outputs of multiple stopping conditions.
virtual bool dissipative() const =0
Should return true iff the zone has some non-zero dissipation.
bool __initializing
Is the zone in the middle of initializing (disable lock check)?
virtual bool can_lock() const =0
Should return true iff the zone&#39;s dissipation is discontinuous at zero frequency. ...
For locked zones this is the spin frequency multiple of the lock.
double __orbital_angmom
The absolute value of the angular momentum of the orbit.
virtual bool locked() const
Should return true iff any tidal term is locked.
Describes a system of two bodies orbiting each other.
Definition: BinarySystem.h:56
void set_lock(int orbital_freq_mult, int spin_freq_mult, short lock_direction=0)
Define which tidal dissipation term is in a lock.
virtual double outer_radius(int deriv_order=0) const =0
Outer radius of the zone or its derivative (per last.
double spin_frequency() const
The spin frequency of the given zone.
virtual void check_locks_consistency() const
Runs a bunch of asserts to check the consistency of __lock and __other_lock.
Defines a lock between the spin of a dissipating body and the orbit.