8 #define BUILDING_LIBRARY 16 for(
short body_ind = 0; body_ind < 2; ++body_ind) {
19 unsigned zone_ind = 0;
32 double *evolution_rates,
36 if(!expansion_error) {
45 unsigned zone_index = 1;
49 evolution_rates[zone_index - 1] = (
56 evolution_rates[zone_index - 1],
69 double *age_derivs)
const 75 for(
unsigned row = 0; row < num_param; ++row) {
76 double dIbelow_dt = 0;
89 if(row < num_param - 1) {
138 for(
unsigned col = 0; col < num_param; ++col) {
139 double &dest = *(param_derivs + row * num_param + col);
140 if(std::abs(static_cast<int>(row) -
static_cast<int>(col)) < 1)
164 double *evolution_rates,
170 *inclination_evol = evolution_rates,
171 *periapsis_evol = evolution_rates + (nzones - 1),
172 *angmom_evol = periapsis_evol+(nzones - 1);
174 if(expansion_error) {
175 angmom_evol[0] = 0.0;
177 unsigned zone_index = 0;
178 zone_index < nzones - 1;
181 inclination_evol[zone_index] = (
182 periapsis_evol[zone_index] = (
183 angmom_evol[zone_index + 1] = 0.0
189 Eigen::Vector3d reference_torque;
190 for(
unsigned zone_index = 0; zone_index < nzones; ++zone_index) {
192 angmom_evol[zone_index] = torque[2];
209 }
else reference_torque = torque;
213 angmom_evol[zone_index],
214 (zone_index ? inclination_evol[zone_index - 1] : 0.0),
215 (zone_index ? periapsis_evol[zone_index -1] : 0.0)
219 std::cerr <<
"rates: ";
220 for(
unsigned i = 0; i < 3 * nzones - 2; ++i) {
221 if(i) std::cerr <<
", ";
222 std::cerr << evolution_rates[i];
224 std::cerr << std::endl;
230 double *inclination_param_derivs,
231 double *periapsis_param_derivs,
232 double *angmom_param_derivs,
233 double *inclination_age_derivs,
234 double *periapsis_age_derivs,
235 double *angmom_age_derivs
266 unsigned deriv_zone_ind = 0;
267 deriv_zone_ind < nzones;
270 angmom_param_derivs[deriv_zone_ind - 1] =
271 (deriv_zone_ind == 1 ? dref_torque_dincl[2] : 0);
272 angmom_param_derivs[nzones+deriv_zone_ind - 2] =
273 (deriv_zone_ind == 1 ? dref_torque_dperi[2] : 0);
274 double &angmom_angmom_deriv =
275 angmom_param_derivs[2 * nzones+deriv_zone_ind - 2];
276 if(deriv_zone_ind==0) angmom_angmom_deriv = dref_torque_dangmom0[2];
277 else if(deriv_zone_ind == 1)
278 angmom_angmom_deriv = dref_torque_dangmom1[2];
279 else angmom_angmom_deriv = 0;
281 angmom_age_derivs[0] = dref_torque_dage[2];
283 for(
unsigned zone_ind = 1; zone_ind < nzones; ++zone_ind) {
296 inclination_age_derivs[zone_ind - 1] =
300 ref_torque_age_deriv,
301 zone_torque_age_deriv);
302 periapsis_age_derivs[zone_ind - 1] =
306 ref_torque_age_deriv,
307 zone_torque_age_deriv);
308 angmom_age_derivs[zone_ind] = zone_torque_age_deriv[2];
310 unsigned quantity_ind = 0;
311 quantity_ind < nparams;
314 unsigned offset = (zone_ind - 1) * nparams + quantity_ind;
315 double &inclination_dest = inclination_param_derivs[offset],
316 &periapsis_dest = periapsis_param_derivs[offset],
317 &angmom_dest = angmom_param_derivs[offset+nparams];
318 unsigned quantity_zone = quantity_ind;
319 Dissipation::QuantityEntry with_respect_to;
320 Eigen::Vector3d ref_torque_deriv(0, 0, 0);
321 if(quantity_ind > 2 * nzones - 2) {
322 quantity_zone -= 2 * nzones - 2;
324 if(quantity_zone == 0)
325 ref_torque_deriv = dref_torque_dangmom0;
326 else if(quantity_zone == 1)
327 ref_torque_deriv = dref_torque_dangmom1;
328 if(quantity_zone <= 1)
335 if(quantity_ind >= nzones - 1) {
336 quantity_zone -= nzones - 2;
338 if(quantity_zone == 1)
339 ref_torque_deriv = dref_torque_dperi;
343 if(quantity_zone == 1)
344 ref_torque_deriv = dref_torque_dincl;
346 if(quantity_zone == 1)
357 Eigen::Vector3d zone_torque_deriv;
358 if(quantity_zone == zone_ind) {
375 if(std::abs(static_cast<int>(quantity_zone-zone_ind)) == 1) {
379 quantity_zone - zone_ind
381 }
else zone_torque_deriv = zero3d;
389 angmom_dest = zone_torque_deriv[2];
395 double *age_derivs)
const 400 param_derivs + (nzones - 1) * nparams,
401 param_derivs + 2 * (nzones - 1) * nparams,
403 age_derivs + (nzones - 1),
404 age_derivs + 2 * (nzones - 1));
409 double orbit_power_deriv
412 if(std::isnan(orbit_power_deriv))
413 return (orbit_power == 0
417 else if(orbit_power == 0 && orbit_power_deriv == 0)
431 double orbit_angmom_gain,
432 double orbit_power_deriv,
433 double orbit_angmom_gain_deriv,
434 bool semimajor_deriv)
const 440 if(std::isnan(orbit_power_deriv))
444 else if(semimajor_deriv)
458 2.0 * orbit_angmom_gain_deriv
502 Dissipation::QuantityEntry entry,
504 Eigen::MatrixXd &matrix,
508 unsigned deriv_zone_index = (body1_deriv
526 unsigned locked_ind = 0;
529 unsigned zone_ind = 0;
530 zone_ind < body->number_zones();
546 if(body->zone(zone_ind).locked()) {
547 matrix.col(locked_ind).array() += (
551 body->tidal_power(zone_ind,
true)
553 body->tidal_power(zone_ind,
false)
566 }
else if(deriv_zone.
locked()) {
577 matrix(deriv_zone_index, deriv_zone_index) -=(
582 rhs(deriv_zone_index) -= (
588 rhs(deriv_zone_index) -= (
598 Eigen::VectorXd &fractions,
599 Dissipation::QuantityEntry entry,
609 if(num_locked_zones == 0) {
613 std::valarray<double> nontidal_torque(num_locked_zones),
614 tidal_torque_z_above(num_locked_zones),
615 tidal_torque_z_below(num_locked_zones),
616 tidal_power_difference(num_locked_zones);
617 unsigned locked_zone_ind = 0;
628 nontidal_torque[locked_zone_ind] =
630 tidal_torque_z_above[locked_zone_ind] =
632 tidal_torque_z_below[locked_zone_ind] =
634 if(!zone_specific(entry) || *zi == 0) {
635 tidal_power_difference[locked_zone_ind] = (
643 Eigen::MatrixXd matrix(num_locked_zones, num_locked_zones);
644 Eigen::VectorXd rhs(num_locked_zones);
656 std::list<unsigned>::const_iterator
661 if(!zone_specific(entry) || *zi == 0)
662 matrix.col(i).setConstant(1.5
664 tidal_power_difference[i]
667 else matrix.col(i).setZero();
672 (tidal_torque_z_above[i] - tidal_torque_z_below[i])
684 rhs(i) -= ((nontidal_torque[i] + tidal_torque_z_below[i])
701 Dissipation::QuantityEntry entry,
712 assert(zone_index > 0 || &body == &
__body2);
719 if(num_locked_zones == 0)
return Eigen::VectorXd();
721 unsigned locked_zone_index=(&body == &
__body1 725 for(
unsigned i = 0; i < zone_index; ++i)
726 if(body.
zone(i).
locked()) ++locked_zone_index;
732 -1.5 * (above_frac*body.
tidal_power(zone_index,
true, entry)
740 rhs(locked_zone_index) -=
741 above_frac*body.
tidal_torque(zone_index,
true, entry)[2]
747 rhs(locked_zone_index) -= (
753 rhs(locked_zone_index) += (
763 rhs.setConstant(num_locked_zones,
764 -1.5 * body.
tidal_power(zone_index,
false, entry));
766 if(zone_index > 0 && body.
zone(zone_index - 1).
locked())
795 unsigned body_zone_ind = 0;
796 for(
unsigned zone_ind = 1; zone_ind < num_zones; ++zone_ind) {
823 std::valarray<Eigen::VectorXd>
832 static_cast<Dissipation::QuantityEntry>(deriv)
834 if(!zone_specific(static_cast < Dissipation::QuantityEntry>(deriv)))
837 body2_above_lock_fractions[deriv],
838 static_cast<Dissipation::QuantityEntry>(deriv),
903 double *inclination_rates = differential_equations + 2,
904 *periapsis_rates = inclination_rates + num_total_zones,
905 *angmom_rates = periapsis_rates + num_total_zones - 1;
906 unsigned angmom_skipped = 0;
907 double reference_periapsis_rate = Core::NaN;
908 for(
unsigned zone_ind = 0; zone_ind < num_total_zones; ++zone_ind) {
912 unsigned body_zone_ind = zone_ind;
913 if(zone_ind >= num_body1_zones)
914 body_zone_ind -= num_body1_zones;
916 Eigen::Vector3d zone_orbit_torque,
919 total_zone_torque.setZero();
926 zone_orbit_torque = (zone_ind
932 Dissipation::QuantityEntry entry = (
941 total_zone_torque += (
951 }
else total_zone_torque += body.
tidal_torque(body_zone_ind,
959 assert(!std::isnan(inclination_rates[zone_ind]));
965 ) - reference_periapsis_rate;
966 assert(!std::isnan(periapsis_rates[zone_ind - 1]));
974 reference_periapsis_rate = -std::abs(
975 reference_periapsis_rate
977 assert(!std::isnan(reference_periapsis_rate));
981 angmom_rates[zone_ind - angmom_skipped] = total_zone_torque[2];
982 assert(!std::isnan(angmom_rates[zone_ind - angmom_skipped]));
987 total_zone_torque[2],
988 inclination_rates[zone_ind],
989 (zone_ind ? periapsis_rates[zone_ind - 1] : 0.0)
993 std::cerr <<
"Zone " << zone_ind
994 <<
" torque: " << total_zone_torque
995 <<
" inclination rate";
997 std::cerr <<
" error";
998 std::cerr <<
": " << inclination_rates[zone_ind];
1000 std::cerr <<
" periapsis rate: " 1001 << periapsis_rates[zone_ind - 1];
1003 std::cerr << std::endl;
1005 assert(!std::isnan(total_zone_torque.sum()));
1008 differential_equations[0] = (
1013 differential_equations[1] = (
1019 if(!expansion_error) {
1025 differential_equations[0] *= 6.5 * std::pow(
__semimajor, 5.5);
1027 #ifdef VERBOSE_DEBUG 1029 std::cerr <<
"rate errors: ";
1031 std::cerr <<
"rates: ";
1037 if(i) std::cerr <<
", ";
1038 std::cerr << differential_equations[i];
1040 std::cerr << std::endl;
1046 template<
typename VALUE_TYPE>
1051 const Eigen::VectorXd &)
const,
1052 std::valarray<VALUE_TYPE> &orbit_rate_deriv,
1057 num_param = orbit_rate_deriv.size() - 1;
1064 orbit_rate_deriv[num_param] += (
1072 for(
unsigned zone_ind = 0; zone_ind < body.
number_zones(); ++zone_ind) {
1073 orbit_rate_deriv[zone_ind+2+offset] =
1079 if(zone_ind+offset > 0)
1080 orbit_rate_deriv[zone_ind + 1 + num_zones + offset] =
1087 if(zone.
locked()) ++locked_zone_count;
1088 else orbit_rate_deriv[
1089 zone_ind + 1 + 2 * num_zones - locked_zone_count
1095 orbit_rate_deriv[num_param] += (
1108 std::valarray<double> &orbit_power_deriv)
const 1110 orbit_power_deriv[0] = 0;
1111 orbit_power_deriv[1] = 0;
1112 orbit_power_deriv[orbit_power_deriv.size() - 1] = 0;
1123 std::valarray<double> &orbit_angmom_gain_deriv
1126 std::valarray<Eigen::Vector3d>
1127 body1_orbit_torque_deriv(orbit_angmom_gain_deriv.size()),
1128 body2_orbit_torque_deriv(orbit_angmom_gain_deriv.size());
1129 body1_orbit_torque_deriv[0] =
1130 body1_orbit_torque_deriv[1] =
1131 body2_orbit_torque_deriv[0] =
1132 body2_orbit_torque_deriv[1] = Eigen::Vector3d(0, 0, 0);
1135 body1_orbit_torque_deriv,
1138 body2_orbit_torque_deriv,
1144 for(
unsigned i = 0; i < orbit_angmom_gain_deriv.size(); ++i)
1145 orbit_angmom_gain_deriv[i] = (
1146 body1_sin_inc * body1_orbit_torque_deriv[i][0]
1148 body1_cos_inc * body1_orbit_torque_deriv[i][2]
1150 body2_sin_inc * body2_orbit_torque_deriv[i][0]
1152 body2_cos_inc * body2_orbit_torque_deriv[i][2]
1156 orbit_angmom_gain_deriv[2] +=(body1_cos_inc * body1_orbit_torque[0]
1158 body1_sin_inc * body1_orbit_torque[2]
1160 body2_cos_inc * body2_orbit_torque[0]
1162 body2_sin_inc * body2_orbit_torque[2]);
1166 const std::valarray<double> &orbit_power_deriv,
1168 double *param_derivs,
1173 orbit_power_deriv[0]);
1174 if(a6p5) param_derivs[0] +=
1177 for(; i < orbit_power_deriv.size() - 1; ++i)
1183 const std::valarray<double> &orbit_power_deriv,
1184 const std::valarray<double> &orbit_angmom_gain_deriv,
1186 double *param_derivs,
1192 orbit_power_deriv[0],
1193 orbit_angmom_gain_deriv[0],
1195 if(a6p5) param_derivs[0] /= 6.5 * std::pow(
__semimajor, 5.5);
1198 orbit_power_deriv[1],
1199 orbit_angmom_gain_deriv[1],
1202 for(; i < orbit_power_deriv.size() - 1; ++i)
1204 orbit_angmom_gain_deriv[i]);
1206 orbit_angmom_gain_deriv[i]);
1213 unsigned locked_zone_ind,
1214 double &inclination,
1215 double &periapsis)
const 1220 Eigen::Vector3d orbit_torque_age_deriv = (
1230 unsigned body_zone_ind = 0,
1233 unsigned other_zone_ind = 0;
1234 other_zone_ind<num_zones;
1237 orbit_torque_age_deriv += (
1253 periapsis = (orbit_torque_age_deriv[1]
1258 inclination = (orbit_torque_age_deriv[0] * cos_inc
1266 double above_frac_deriv =
1283 inclination += to_add[0];
1284 periapsis -= to_add[1] / sin_inc;
1288 double angmom_deriv,
1293 unsigned locked_zone_ind,
1294 double &inclination,
1295 double &periapsis)
const 1305 orbit_torque_deriv = (
1310 inclination = (orbit_torque_deriv[0] * cos_inc
1312 orbit_torque_deriv[2] * sin_inc
1314 (orbit_torque[0] * cos_inc - orbit_torque[2] * sin_inc)
1323 orbit_torque_deriv[1]
1351 }
else to_add -= body.
tidal_torque(zone_ind,
false, entry);
1353 inclination += to_add[0];
1354 periapsis -= to_add[1] / sin_inc;
1358 Dissipation::QuantityEntry entry,
1361 std::valarray<Eigen::Vector3d> &orbit_torque_deriv
1371 assert(orbit_torque_deriv.size()
1375 unsigned body_deriv_zone_ind = 0,
1376 num_zones = orbit_torque_deriv.size();
1378 const std::valarray<Eigen::VectorXd> *above_frac_deriv;
1390 unsigned deriv_zone_ind = 0;
1391 deriv_zone_ind < num_zones;
1394 orbit_torque_deriv[deriv_zone_ind] =
1398 body_deriv_zone_ind,
1399 (*above_frac_deriv)[deriv_zone_ind]
1410 zone_ind == body_deriv_zone_ind
1415 orbit_torque_deriv[deriv_zone_ind] +=
1422 ++body_deriv_zone_ind;
1423 if(body_deriv_zone_ind == deriv_body->
number_zones()) {
1424 body_deriv_zone_ind = 0;
1431 Dissipation::QuantityEntry entry,
1434 std::valarray<Eigen::Vector3d> &zone_torque_deriv
1439 assert(zone_torque_deriv.size() == 4);
1441 assert(zone_torque_deriv.size() == 3);
1444 zone_torque_deriv[0] = (zone_ind == 0
1445 ? Eigen::Vector3d::Zero()
1450 zone_torque_deriv[1] = (nontidal_torque
1453 zone_torque_deriv[2] = (zone_ind < body.
number_zones() - 1
1455 : Eigen::Vector3d::Zero());
1457 zone_torque_deriv[3] = (nontidal_torque
1463 Dissipation::QuantityEntry entry,
1466 double zone_x_torque_above,
1467 double zone_x_torque_below,
1468 const std::valarray<Eigen::Vector3d> &zone_torque_deriv,
1469 const Eigen::Vector3d &orbit_torque,
1470 const std::valarray<Eigen::Vector3d> &orbit_torque_deriv,
1471 const std::valarray<Eigen::VectorXd> &above_frac_deriv,
1474 unsigned locked_zone_ind,
1483 assert(orbit_torque_deriv.size()
1488 unsigned num_zones = orbit_torque_deriv.size();
1489 unsigned global_zone_ind = zone_ind;
1497 deriv_zone_ind < num_zones;
1501 ? result[deriv_zone_ind - 1]
1502 : result[deriv_zone_ind]);
1504 orbit_torque_deriv[deriv_zone_ind][0] * cos_inc
1506 orbit_torque_deriv[deriv_zone_ind][2] * sin_inc
1509 dest -= (above_frac_deriv[deriv_zone_ind][locked_zone_ind]
1511 (zone_x_torque_above - zone_x_torque_below)
1513 zone.angular_momentum());
1514 if(std::abs(static_cast<int>(deriv_zone_ind - global_zone_ind)) <= 1) {
1515 double torque_deriv=
1516 zone_torque_deriv[deriv_zone_ind + 1 - global_zone_ind][0];
1517 if(zone.locked() && deriv_zone_ind == global_zone_ind) {
1519 above_frac * zone_torque_deriv[3][0]
1521 (1.0 - above_frac) * torque_deriv
1522 ) / zone.angular_momentum();
1523 }
else dest -= torque_deriv / zone.angular_momentum();
1527 result[global_zone_ind] -= (
1528 orbit_torque[0] * sin_inc
1530 orbit_torque[2] * cos_inc
1533 result[global_zone_ind] += (
1535 ? (above_frac * zone_x_torque_above
1537 (1.0 - above_frac) * zone_x_torque_below)
1538 : zone_x_torque_below
1539 ) / std::pow(zone.angular_momentum(), 2);
1543 Dissipation::QuantityEntry entry,
1546 double zone_y_torque_above,
1547 double zone_y_torque_below,
1548 const std::valarray<Eigen::Vector3d> &zone_torque_deriv,
1549 double orbit_y_torque,
1550 const std::valarray<Eigen::Vector3d> &orbit_torque_deriv,
1551 const std::valarray<Eigen::VectorXd> &above_frac_deriv,
1554 unsigned locked_zone_ind,
1565 assert(orbit_torque_deriv.size()
1570 unsigned num_zones = orbit_torque_deriv.size();
1571 unsigned global_zone_ind = zone_ind;
1578 unsigned deriv_zone_ind = 0;
1579 deriv_zone_ind < num_zones;
1584 ? result[deriv_zone_ind - 1]
1585 : result[deriv_zone_ind]);
1586 dest = (-orbit_torque_deriv[deriv_zone_ind][1]
1592 dest += (above_frac_deriv[deriv_zone_ind][locked_zone_ind]
1594 (zone_y_torque_above - zone_y_torque_below)
1596 (sin_inc * zone.angular_momentum()));
1598 std::abs(static_cast<int>(deriv_zone_ind - global_zone_ind))
1602 double torque_deriv =
1603 zone_torque_deriv[deriv_zone_ind + 1 - global_zone_ind][1];
1604 if(zone.locked() && deriv_zone_ind == global_zone_ind) {
1606 above_frac * zone_torque_deriv[3][1]
1608 (1.0 - above_frac) * torque_deriv
1609 ) / (sin_inc * zone.angular_momentum());
1610 }
else dest += (torque_deriv
1612 (sin_inc * zone.angular_momentum()));
1616 if(zone.locked()) zone_torque = (above_frac*zone_y_torque_above
1620 zone_y_torque_below);
1621 else zone_torque = zone_y_torque_below;
1623 result[global_zone_ind] += (
1628 (zone.angular_momentum() * std::pow(sin_inc, 2))
1631 result[global_zone_ind] -=
1632 zone_torque / (std::pow(zone.angular_momentum(), 2) * sin_inc);
1636 Dissipation::QuantityEntry entry,
1639 double zone_z_torque_above,
1640 double zone_z_torque_below,
1641 const std::valarray<Eigen::Vector3d> &zone_torque_deriv,
1642 const std::valarray<Eigen::VectorXd> &above_frac_deriv,
1643 unsigned locked_zone_ind,
1647 unsigned global_zone_ind = zone_ind,
1652 bool zone_is_locked = body.
zone(zone_ind).
locked();
1654 unsigned deriv_zone_ind = 0;
1655 deriv_zone_ind<num_zones;
1659 ? result[deriv_zone_ind - 1]
1660 : result[deriv_zone_ind]);
1662 dest = (above_frac_deriv[deriv_zone_ind][locked_zone_ind]
1664 (zone_z_torque_above - zone_z_torque_below));
1666 if(std::abs(static_cast<int>(deriv_zone_ind
1668 global_zone_ind)) <= 1) {
1669 double torque_deriv =
1670 zone_torque_deriv[deriv_zone_ind + 1 - global_zone_ind][2];
1671 if(zone_is_locked) dest += (above_frac * zone_torque_deriv[3][2]
1673 (1.0 - above_frac) * torque_deriv);
1674 else dest += torque_deriv;
1680 double *age_derivs)
const 1687 num_param = 1 + 6 * num_zones - num_locked_zones;
1694 std::valarray<double> orbit_power_deriv(num_param + 1),
1695 orbit_angmom_gain_deriv(num_param + 1);
1699 num_locked_zones == 0,
1703 orbit_angmom_gain_deriv,
1704 num_locked_zones == 0,
1705 param_derivs + num_param,
1707 unsigned locked_zone_ind = 0;
1709 unsigned body_zone_ind = 0;
1710 static Dissipation::QuantityEntry zone_deriv_list[]={
1715 std::valarray<double> reference_periapsis_param_deriv(num_param);
1716 double reference_periapsis_age_deriv;
1717 const std::valarray<Eigen::VectorXd> *above_frac_deriv[] = {
1722 for(
unsigned zone_ind = 0; zone_ind < num_zones; ++zone_ind) {
1726 double &periapsis_age_deriv = (
1728 ? reference_periapsis_age_deriv
1729 : age_derivs[1 + num_zones + zone_ind]
1736 age_derivs[2 + zone_ind],
1737 periapsis_age_deriv);
1739 double *periapsis_row = (
1741 ? &reference_periapsis_param_deriv[0]
1742 : param_derivs+(1 + zone_ind+num_zones) * num_param
1752 param_derivs[(2 + zone_ind) * num_param],
1761 param_derivs[(2 + zone_ind) * num_param + 1],
1766 zone_torque_below = zone_torque_above,
1768 zone_torque_above += body->
tidal_torque(zone_ind,
true);
1769 zone_torque_below += body->
tidal_torque(zone_ind,
false);
1770 std::valarray<Eigen::Vector3d>
1771 zone_torque_deriv(zone.
locked() ? 4 : 3),
1772 orbit_torque_deriv(num_zones);
1773 unsigned param_offset = (2 + zone_ind) * num_param + 2;
1774 for(
unsigned deriv_ind = 0; deriv_ind < 3; ++deriv_ind) {
1775 Dissipation::QuantityEntry deriv = zone_deriv_list[deriv_ind];
1782 orbit_torque_deriv);
1785 zone_torque_above[0],
1786 zone_torque_below[0],
1790 *(above_frac_deriv[deriv_ind]),
1794 param_derivs + param_offset);
1798 zone_torque_above[1],
1799 zone_torque_below[1],
1803 *(above_frac_deriv[deriv_ind]),
1812 zone_torque_above[2],
1813 zone_torque_below[2],
1815 *(above_frac_deriv[deriv_ind]),
1817 param_derivs + param_offset + 2 * num_zones - 1
1824 if(zone.
locked()) ++locked_zone_ind;
1831 periapsis_age_deriv -= reference_periapsis_age_deriv;
1832 for(
unsigned i = 0; i < num_param; ++i)
1833 periapsis_row[i] -= reference_periapsis_param_deriv[i];
1840 std::valarray<double> &orbit
1866 unsigned inclination_ind = 2,
1869 for(
short body_ind = 0; body_ind < 2; ++body_ind) {
1872 unsigned zone_ind = 0;
1878 if(body_ind || zone_ind)
1879 orbit[periapsis_ind++] = zone.
periapsis();
1896 unsigned inclination_ind = 0,
1900 unsigned zone_ind = 0;
1905 if(zone_ind) orbit[inclination_ind++] = zone.
inclination();
1906 if(zone_ind) orbit[periapsis_ind++] = zone.
periapsis();
1916 const double *spin_angmom,
1917 const double *inclination,
1918 const double *periapsis,
1923 std::cerr <<
"Initializing BinarySystem." << std::endl;
1924 if(evolution_mode != Core::BINARY) {
1925 assert(std::isnan(semimajor));
1926 assert(std::isnan(eccentricity));
1928 if(evolution_mode == Core::LOCKED_SURFACE_SPIN) {
1929 assert(inclination == NULL);
1930 assert(periapsis == NULL);
1933 std::cerr <<
"Configuring binary with a = " << semimajor
1934 <<
", e = " << eccentricity
1935 <<
" in " << evolution_mode <<
" mode" 1940 evolution_mode == Core::BINARY
1964 std::cerr <<
"Configuring primary." << std::endl;
1974 evolution_mode == Core::LOCKED_SURFACE_SPIN,
1975 evolution_mode != Core::BINARY,
1979 if(evolution_mode == Core::BINARY) {
1982 std::cerr <<
"Configuring secondary." << std::endl;
1990 inclination + offset,
1991 periapsis + offset - 1);
2007 const double *parameters,
2012 const double *spin_angmom, *inclination, *periapsis;
2014 if(evolution_mode == Core::BINARY) {
2015 if(parameters[0] < 0) {
2017 std::cerr <<
"At t = " << age <<
" param: ";
2023 if(i) std::cerr <<
", ";
2024 std::cerr << parameters[i];
2026 std::cerr << std::endl;
2031 semimajor = parameters[0];
2033 semimajor = std::pow(parameters[0], 1.0 / 6.5);
2034 eccentricity = parameters[1];
2035 inclination = parameters+2;
2037 semimajor = eccentricity=Core::NaN;
2038 if(evolution_mode == Core::SINGLE) inclination = parameters;
2039 else inclination = NULL;
2042 if(evolution_mode == Core::LOCKED_SURFACE_SPIN) {
2044 spin_angmom = parameters;
2046 assert(inclination != NULL);
2048 periapsis = inclination+num_zones;
2049 if(evolution_mode == Core::SINGLE) --periapsis;
2050 spin_angmom = periapsis + num_zones - 1;
2063 std::valarray<double> &orbit
2074 Dissipation::QuantityEntry entry,
2075 unsigned deriv_zone_index,
2076 bool secondary_radius)
2078 if(zone_specific(entry)) {
2089 [locked_zone_index];
2092 [locked_zone_index];
2095 [locked_zone_index];
2097 [locked_zone_index];
2107 const double *parameters,
2110 bool expansion_error)
2113 if(!expansion_error)
2114 std::cerr <<
"Finding differential equations at t = " << age
2115 <<
" in " << evolution_mode
2116 <<
" mode, with orbit[0] = " << parameters[0]
2119 int status =
configure(
false, age, parameters, evolution_mode);
2120 if(status != GSL_SUCCESS)
return status;
2121 if(!expansion_error)
2123 switch(evolution_mode) {
2124 case Core::LOCKED_SURFACE_SPIN :
2126 differential_equations,
2131 differential_equations,
2139 "Evolution mode other than LOCKED_SURFACE_SPIN, SINGLE or " 2140 "BINARY encountered in " 2141 "BinarySystem::differential_equations!" 2147 const double *parameters,
2149 double *param_derivs,
2152 configure(
false, age, parameters, evolution_mode);
2153 switch(evolution_mode) {
2154 case Core::LOCKED_SURFACE_SPIN :
2162 "Evolution mode other than LOCKED_SURFACE_SPIN, " 2163 "SINGLE or BINARY encountered in " 2164 "BinarySystem::jacobian!" 2171 unsigned short body_index,
2172 unsigned zone_index,
2177 assert(body_index <= 1);
2179 assert(spin_freq_mult);
2182 body.
lock_zone_spin(zone_index, orbital_freq_mult, spin_freq_mult);
2185 locked_zone_ind = 0;
2186 std::vector<double> spin_angmom(num_zones - num_locked_zones),
2187 inclinations(num_zones),
2188 periapses(num_zones);
2189 for(
unsigned zone_ind = 0; zone_ind < num_zones; ++zone_ind) {
2195 if(zone.
locked()) ++locked_zone_ind;
2196 else spin_angmom[zone_ind-locked_zone_ind] = (
2200 if(zone_ind) periapses[zone_ind - 1] = zone.
periapsis();
2202 assert(locked_zone_ind == num_locked_zones);
2216 std::cerr <<
"Holding lock requires above lock fraction of: " 2217 << above_lock_fraction
2220 if(above_lock_fraction > 0 && above_lock_fraction < 1)
return;
2221 std::vector<double>::iterator check_zone_dest = (
2232 spin_angmom.insert(check_zone_dest, original_angmom);
2235 "Crossing spin-orbit synchronization with unspecified direction!" 2274 std::cerr <<
"Handling secondary death!" << std::endl;
2277 std::valarray<double> spin_angmom(num_zones),
2278 inclination(num_zones - 1),
2279 periapsis(num_zones - 1);
2281 double old_surface_inclination = old_surface_zone.
inclination(),
2282 sin_inc = std::sin(old_surface_inclination),
2283 cos_inc = std::cos(old_surface_inclination),
2295 spin_angmom[0] = angmom;
2298 for(
unsigned zone_ind = 1; zone_ind < num_zones; ++zone_ind) {
2301 inclination[zone_ind - 1]=std::abs(zone.
inclination()
2303 old_surface_inclination
2305 new_surface_inclination);
2306 periapsis[zone_ind - 1] = 0;
2327 unsigned zone_ind = 0;
2338 unsigned zone_ind = 0;
2341 if(locked_zone_index == 0)
break;
2342 else --locked_zone_index;
2375 for(
unsigned i = 0; i < nsteps; ++i) {
2416 unsigned zone_ind = 0;
2426 assert(static_cast<unsigned>(result)
double __orbit_angmom_gain_expansion_error
Estimate of the error in __orbit_angmom_gain due to truncating the tidal potential eccentricity expan...
virtual void add_to_evolution()
Appends the state defined by last configure(), to the evolution.
double __age
The present age of the stellar system in Gyrs.
void fill_single_body_jacobian(double *inclination_param_derivs, double *periapsis_param_derivs, double *angmom_param_derivs, double *inclination_age_derivs, double *periapsis_age_derivs, double *angmom_age_derivs) const
Fills the jacobian for a system consisting of one isolated body.
unsigned locked_zone_index() const
The index of this zone in the list of locked zones (valid only if locked).
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.
virtual void rewind_evolution(unsigned nsteps)
Discards the last steps from the evolution.
virtual void reset_evolution()
Discards all evolution.
Eigen::VectorXd __above_lock_fractions_body2_radius_deriv
The derivative of the above lock fractions w.r.t. to the radius of the secondardy.
Function arguments do not satisfy some requirement.
RADIUS
The derivative w.r.t. the radius of the body in .
const std::list< double > & eccentricity_evolution() const
The tabulated evolution of the eccentricity so far.
virtual void add_to_evolution()
Appends the state defined by last configure(), to the evolution.
Eigen::Vector3d __orbit_torque
The torque on the orbit in the coordinate system of the outermost zone of the first body...
void find_locked_zones()
Fills the __locked_zones list.
double angular_momentum() const
The angular momentum of the given zone in .
double __semimajor_rate
The current rate at which the semiamjor axis is changing.
unsigned number_locked_zones() const
The number of zones currently in a spin-orbit lock.
void set_above_lock_fractions(std::valarray< Eigen::VectorXd > &above_lock_fractions)
Corrects the tidal orbit energy gain and angular momentum gain for locked zones.
int single_body_differential_equations(double *evolution_rates, bool expansion_error) const
Differential equations for the rotation of the zones of body 0 if no other body is present...
std::list< double > __eccentricity_evolution
The evolution of the eccentricity recorded by add_to_evolution() so far.
SPIN_FREQUENCY
The derivative w.r.t. the spin frequency of a dissipating zone.
std::list< double > __semimajor_evolution
The evolution of the semimajor axis recorded by add_to_evolution() so far.
A base class for any body contributing to tidal dissipation.
double tidal_power(unsigned zone_index, bool above, Dissipation::QuantityEntry entry=Dissipation::NO_DERIV) const
Tidal power dissipated in the given zone.
virtual double minimum_separation(bool deriv=false) const
Smallest semimajor axis at which the secondary can survive for the latest system configuration.
void fill_above_lock_fractions_deriv()
Fills the __above_lock_fractinos_*_deriv members.
double periapsis(bool evolution_rate=false) const
The argument of periapsis of this zone minus the reference zone's.
int binary_differential_equations(double *differential_equations, bool expansion_error) const
The differential equations for a system with both bodies present.
virtual const DissipatingZone & zone(unsigned zone_index) const =0
A modifiable reference to one of the body's zones.
double __semimajor
The current semimajor axis.
void check_for_lock(int orbital_freq_mult, int spin_freq_mult, unsigned short body_index, unsigned zone_index, short direction)
Check if a spin-orbit lock can be held and updates the system as necessary to calculate subsequent ev...
std::valarray< Eigen::VectorXd > __above_lock_fractions
The above lock fractinos for the locked zones and their derivatives.
SEMIMAJOR
The derivative w.r.t. the semimajor axis in AU.
void periapsis_evolution_zone_derivs(Dissipation::QuantityEntry entry, DissipatingBody &body, unsigned zone_ind, double zone_y_torque_above, double zone_y_torque_below, const std::valarray< Eigen::Vector3d > &zone_torque_deriv, double orbit_y_torque, const std::valarray< Eigen::Vector3d > &orbit_torque_deriv, const std::valarray< Eigen::VectorXd > &above_frac_deriv, double sin_inc, double cos_inc, unsigned locked_zone_ind, double *result) const
Computes the derivatives of the periapsis evolution w.r.t. a zone specific quantity for all zones...
void unlock_zone_spin(unsigned zone_index, short direction)
Releases the given zone from a spin-orbit lock.
void inclination_evolution_zone_derivs(Dissipation::QuantityEntry entry, DissipatingBody &body, unsigned zone_ind, double zone_x_torque_above, double zone_x_torque_below, const std::valarray< Eigen::Vector3d > &zone_torque_deriv, const Eigen::Vector3d &orbit_torque, const std::valarray< Eigen::Vector3d > &orbit_torque_deriv, const std::valarray< Eigen::VectorXd > &above_frac_deriv, double sin_inc, double cos_inc, unsigned locked_zone_ind, double *result) const
Calculates the derivatives of an inclination evolution equation w.r.t. a zone specific quentity...
virtual void reached_critical_age(double)
Change the body as necessary at the given age.
virtual double next_stop_age() const
The next age when the evolution needs to be stopped for a system change.
Eigen::Vector3d zone_to_zone_transform(const ZoneOrientation &from_zone, const ZoneOrientation &to_zone, const Eigen::Vector3d &vector, Dissipation::QuantityEntry deriv, bool with_respect_to_from)
Transforms a vector betwen the coordinates systems of two zones.
double above_lock_fraction(unsigned locked_zone_index, Dissipation::QuantityEntry entry=Dissipation::NO_DERIV, unsigned deriv_zone_index=0, bool secondary_radius=false)
The fraction of an infinitesimal timestep that a zone spends spinning faster than the lock it is in...
Orientations of zones of bodies in a binary system.
const std::list< double > & semimajor_evolution() const
The tabulated evolution of the semimajor axis so far.
NUM_DERIVATIVES
The total number of derivatives supported.
double __orbit_power
The rate at which the orbit gains energy due to tides.
void fill_orbit_angmom_gain_deriv(std::valarray< double > &orbit_angmom_gain_deriv) const
Computes the derivatives w.r.t. the evolution quantities of the orbit angular momentum gain...
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...
virtual void reset_evolution()
Resets the evolution of the system.
double mass() const
The mass of the body (constant with age).
void add_body_rate_deriv(const DissipatingBody &body, VALUE_TYPE(DissipatingBody::*func)(Dissipation::QuantityEntry, unsigned, const Eigen::VectorXd &) const, std::valarray< VALUE_TYPE > &orbit_rate_deriv, unsigned offset) const
Adds the derivatives of a rate by which the orbit is changing due to tidal interactions with a single...
double age() const
Returns the present age of the system in Gyr.
virtual void configure(bool initialize, double age, double companion_mass, double semimajor, double eccentricity, const double *spin_angmom, const double *inclination=NULL, const double *periapsis=NULL, bool locked_surface=false, bool zero_outer_inclination=false, bool zero_outer_periapsis=false)
Defines the orbit this body is in.
virtual CombinedStoppingCondition * stopping_conditions(BinarySystem &system, bool primary)
Conditions detecting the next possible discontinuities in the evolution due to this body...
void fill_locked_surface_orbit(std::valarray< double > &orbit) const
Implements fill_orbit() for LOCKED_SURFACE_SPIN evolution mode.
double radius(int deriv_order=0) const
The current radius or its derivative with age of the body.
Eigen::Vector3d nontidal_torque(unsigned zone_index, Dissipation::QuantityEntry deriv=Dissipation::NO_DERIV, int deriv_zone=0) const
External torque acting on a single zone (last calculate_torques_power()).
virtual void spin_jumped()
Notifies the body that its spin just discontinously jumped.
void fill_orbit_torque_deriv(Dissipation::QuantityEntry entry, DissipatingBody &body, unsigned zone_ind, std::valarray< Eigen::Vector3d > &orbit_torque_deriv) const
A layer of a system body for which the tidal bulge is not exactly in phase with the tidal potential...
std::valarray< Eigen::VectorXd > __above_lock_fractions_angmom_deriv
The derivatives of the above lock fractions w.r.t. the angular momenta of the zones.
unsigned number_locked_zones() const
How many zones on either body are currently locked.
double __orbit_power_expansion_error
Estimate of the error in __orbit_power due to truncating the tidal potential eccentricity expansion...
std::list< double > __semimajor_rate_evolution
The rate at which the semimajor axis evolved at each.
DissipatingBody & __body2
The second body in the system.
virtual void reached_critical_age(double age)
Change the system as necessary at the given age.
void calculate_above_lock_fractions(Eigen::VectorXd &fractions, Dissipation::QuantityEntry entry=Dissipation::NO_DERIV, bool body1_deriv=true)
Calculates the fraction of a timestep above spin-orbit lock for all locked zones. ...
double __eccentricity
The current eccentricity.
virtual double next_stop_age() const
The next age when the evolution needs to be stopped for a change in one of the bodies.
void fill_binary_orbit(std::valarray< double > &orbit) const
Implements fill_orbit() for BINARY evolution mode.
Satisfied when the planet enters below either the roche sphere or the stellar photosphere.
std::list< unsigned > __locked_zones
A list of indices of locked zones.
double __orbit_angmom_gain
The rate at which the orbit gains angular momentum due to tides.
void fill_single_orbit(std::valarray< double > &orbit) const
Implements fill_orbit() for SINGLE evolution mode.
std::list< double > __eccentricity_rate_evolution
The rate at which the eccentricity evolved at each.
Core::EvolModeType __evolution_mode
The evolution mode from the last call to configure();.
virtual void secondary_died()
Update the system to account for the death of the secondary.
Eigen::ColPivHouseholderQR< Eigen::MatrixXd > __above_lock_fractions_decomp
The matrix that defines the problem to solve for __above_lock_fractions.
void fill_zone_torque_deriv(Dissipation::QuantityEntry entry, DissipatingBody &body, unsigned zone_ind, std::valarray< Eigen::Vector3d > &zone_torque_deriv) const
Calculates the derivatives of the torque on a zone w.r.t. a zone-specific quantity.
virtual unsigned eccentricity_order() const
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's equatorial plane is changi...
ECCENTRICITY
The derivative w.r.t. the eccentricity.
void spin_angmom_evolution_zone_derivs(Dissipation::QuantityEntry entry, DissipatingBody &body, unsigned zone_ind, double zone_z_torque_above, double zone_z_torque_below, const std::valarray< Eigen::Vector3d > &zone_torque_deriv, const std::valarray< Eigen::VectorXd > &above_frac_deriv, unsigned locked_zone_ind, double *result) const
int jacobian(double age, const double *parameters, Core::EvolModeType evolution_mode, double *param_derivs, double *age_derivs)
void set_evolution_rates(double angular_momentum, double inclination, double periapsis)
Set evolution rates for this zone's properties for storing in the eveloution.
void set_reference_zone_angmom(double reference_angmom)
Defines the angular momentum of the reference zone for single body evolution.
void single_body_jacobian(double *param_derivs, double *age_derivs) const
Jacobian for the evolution of the rotation of the zones of body 0 if no other body is present...
std::valarray< Eigen::VectorXd > __above_lock_fractions_inclination_deriv
The derivatives of the above lock fractions w.r.t. the inclinations of the zones. ...
void binary_jacobian(double *param_derivs, double *age_derivs) const
Calculates the jacobian for the evolution of a system of two bodies.
AGE
The derivative w.r.t. age, excluding the dependence through the body's radius and the moments of iner...
void fill_orbit_power_deriv(std::valarray< double > &orbit_power_deriv) const
Computes the derivatives w.r.t. the evolution quantities of the orbit energy gain.
Defines the BinarySystem class.
virtual void rewind_evolution(unsigned nsteps)
Discards the last steps from the evolution.
Core::EvolModeType evolution_mode()
The evolution mode of last call to configure().
void update_above_lock_fractions()
Solves for and sets the above lock fractions and their derivatives.
virtual bool locked(int orbital_frequency_multiplier, int spin_frequency_multiplier) const
Should return true iff the given term is presently locked.
double inclination(bool evolution_rate=false) const
The angle between the angular momenta of the zone and the orbit.
NO_DERIV
The quantity itself, undifferentiated.
Eigen::Vector3d __orbit_torque_expansion_error
An estiamte of the error in ::__orbit_torque due to truncating the eccentricity series of the tidal p...
void eccentricity_jacobian(const std::valarray< double > &orbit_power_deriv, const std::valarray< double > &orbit_angmom_gain_deriv, bool a6p5, double *param_derivs, double &age_deriv) const
Computes the row of the jacobian corresponding to the eccentricity.
EvolModeType
The various evolution modes.
ORBITAL_FREQUENCY
The derivative w.r.t. the orbital frequency.
std::valarray< Eigen::VectorXd > __above_lock_fractions_inertia_deriv
The derivatives of the above lock fractions w.r.t. the moments of inertia of the zones.
void lock_zone_spin(unsigned zone_index, int orbital_frequency_multiplier, int spin_frequency_multiplier)
double semimajor() const
The current semimajor axis of the system.
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.
double eccentricity_evolution_expansion_error() const
Estimate of the error in the value returned by eccentricity_evolution() due to truncating the tidal p...
double tidal_orbit_power(Dissipation::QuantityEntry entry=Dissipation::NO_DERIV, unsigned deriv_zone_index=0, const Eigen::VectorXd &above_lock_fraction_deriv=Eigen::VectorXd()) const
Rate of increase of the orbital energy due to tides in this body (last calculate_torques_power()).
const Eigen::Vector3d & tidal_torque(unsigned zone_index, bool above, Dissipation::QuantityEntry entry=Dissipation::NO_DERIV) const
Tidal torque acting on the given zone (last calculate_torques_power()).
void locked_surface_jacobian(double *param_derivs, double *age_derivs) const
Jacobian for the evolution of the rotation of the zones of body 0 with the topmost zone rotating with...
DissipatingBody & __body1
The first body in the system.
Eigen::VectorXd above_lock_fractions_deriv(Dissipation::QuantityEntry entry, DissipatingBody &body, unsigned zone_index)
Calculates derivatives of the above lock fractions w.r.t. quantities of non-surface zones...
std::valarray< Eigen::VectorXd > __above_lock_fractions_periapsis_deriv
The derivatives of the above lock fractions w.r.t. the periapses of the zones.
A class combining the the outputs of multiple stopping conditions.
double __eccentricity_rate
The current rate at which the eccentricity is changing.
virtual bool dissipative() const =0
Should return true iff the zone has some non-zero dissipation.
unsigned number_zones() const
The total number of zones in both system bodies.
void above_lock_problem_deriv_correction(Dissipation::QuantityEntry entry, bool body1_deriv, Eigen::MatrixXd &matrix, Eigen::VectorXd &rhs) const
Makes corrections to the matrix and RHS to accomodate the given derivative for the linear problem tha...
double semimajor_evolution_expansion_error() const
Estimate of the error in the value returned by semimajor_evolution() due to truncating the tidal pote...
void angle_evolution_orbit_deriv(Dissipation::QuantityEntry entry, double angmom_deriv, DissipatingBody &body, unsigned zone_ind, double sin_inc, double cos_inc, unsigned locked_zone_ind, double &inclination, double &periapsis) const
Computes the partial derivatives w.r.t. semimamjor axis or eccentricity of the inclination and periap...
void semimajor_jacobian(const std::valarray< double > &orbit_power_deriv, bool a6p5, double *param_derivs, double &age_deriv) const
Computes the row of the jacobian corresponding to the semimajor axis.
virtual void release_lock(unsigned locked_zone_index, short direction)
Releases the lock to one of the locked zones.
double __orbital_angmom
The current orbital angular momentum.
double eccentricity() const
The current eccentricity of the system.
virtual CombinedStoppingCondition * stopping_conditions()
Conditions detecting the next possible doscontinuity in the evolution.
virtual int configure(bool initialize, double age, double semimajor, double eccentricity, const double *spin_angmom, const double *inclination, const double *periapsis, Core::EvolModeType evolution_mode)
Sets the current state of the system.
double __orbital_energy
The current orbital energy.
void fill_orbit_torque_and_power()
Update the values of ::__orbit_power, ::__orbit_torque, ::__orbit_angmom_gain and their associated ex...
virtual unsigned eccentricity_order() const
Eigen::Vector3d tidal_orbit_torque(Dissipation::QuantityEntry deriv=Dissipation::NO_DERIV, unsigned deriv_zone_index=0, const Eigen::VectorXd &above_lock_fraction_deriv=Eigen::VectorXd()) const
The torque on the orbit due to tidal dissipation in the body.
int locked_surface_differential_equations(double *evolution_rates, bool expansion_error) const
Differential equations for the rotation of the zones of body 0 with the topmost zone rotating with a ...
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.
double spin_frequency() const
The spin frequency of the given zone.
virtual unsigned number_zones() const =0
The number of zones the body consists of.
void angle_evolution_age_deriv(DissipatingBody &body, unsigned zone_ind, double sin_inc, double cos_inc, unsigned locked_zone_ind, double &inclination, double &periapsis) const
Computes the partial age derivatives of the inclination or periapsis evolutiono equations.