Program Listing for File DissipatingZone.cpp¶
↰ Return to documentation for file (/home/kpenev/projects/git/poet/poet_src/Evolve/DissipatingZone.cpp)
#define BUILDING_LIBRARY
#include "DissipatingZone.h"
#include "BinarySystem.h"
namespace Evolve {
std::ostream &operator<<(std::ostream &os,
const ZoneEvolutionQuantities &evol_var)
{
switch(evol_var) {
case ANGULAR_MOMENTUM : os << "AGE"; break;
case INCLINATION : os << "INCLINATION"; break;
case PERIAPSIS : os << "PERIAPSIS"; break;
case MOMENT_OF_INERTIA : os << "MOMENT_OF_INERTIA"; break;
case MOMENT_OF_INERTIA_FIRST_DERIV :
os << "DMOMENT_OF_INERTIA_DT"; break;
case MOMENT_OF_INERTIA_SECOND_DERIV :
os << "D2MOMENT_OF_INERTIA_DT2"; break;
case OUTER_RADIUS : os << "OUTER_RADIUS"; break;
case OUTER_RADIUS_FIRST_DERIV : os << "DOUTER_RADIUS_DT"; break;
case OUTER_RADIUS_SECOND_DERIV : os << "D2OUTER_RADIUS_DT2"; break;
case OUTER_MASS : os << "OUTER_MASS"; break;
case OUTER_MASS_DERIV : os << "DOUTER_MASS_DT"; break;
case E_ORDER : os << "E_ORDER"; break;
case ORBITAL_FREQ_MULTIPLIER : os << "ORBITAL_FREQ_MULTIPLIER";
break;
case SPIN_FREQ_MULTIPLIER : os << "SPIN_FREQ_MULTIPLIER"; break;
default : assert(false);
};
return os;
}
const double DissipatingZone::__torque_x_plus_coef[]={1.0,
std::sqrt(1.5),
std::sqrt(1.5),
1.0,
0.0};
const double DissipatingZone::__torque_x_minus_coef[]={0.0, //m=-2
1.0, //m=-1
std::sqrt(1.5),//m=0
std::sqrt(1.5),//m=1
1.0}; //m=2
void DissipatingZone::fix_forcing_frequency(
const SpinOrbitLockInfo &limit,
int orbital_frequency_multiplier,
int spin_frequency_multiplier,
double &forcing_frequency
) const
{
if(__initializing) return;
assert(limit.spin_frequency_multiplier() == 1
||
limit.spin_frequency_multiplier() == 2);
if(
limit.term(orbital_frequency_multiplier,
spin_frequency_multiplier)
) {
if(
spin_frequency_multiplier
*
limit.lock_direction()
*
forcing_frequency
>
0
)
forcing_frequency = (
(
spin_frequency_multiplier*limit.lock_direction() > 0
? -1
: 1
)
*
std::numeric_limits<double>::epsilon()
);
return;
}
int expected_sign = (
limit.spin_frequency_multiplier()
*
(
orbital_frequency_multiplier
*
limit.spin_frequency_multiplier()
-
limit.orbital_frequency_multiplier()
*
spin_frequency_multiplier
)
);
if(expected_sign * limit.lock_direction() > 0) return;
if(forcing_frequency * expected_sign > 0) return;
assert(limit.lock_direction());
forcing_frequency = (std::numeric_limits<double>::epsilon()
*
limit.lock_direction());
}
#ifndef NDEBUG
void DissipatingZone::check_locks_consistency() const
{
if(__initializing) return;
int max_abs_orb_mult = static_cast<int>(__e_order + 2);
if(
!(
__lock
||
(__lock.lock_direction() * __other_lock.lock_direction( )== -1)
||
(
__lock.spin_frequency_multiplier() == 1
&&
(
__lock.orbital_frequency_multiplier()
==
__lock.lock_direction() * max_abs_orb_mult
)
&&
__other_lock.orbital_frequency_multiplier() == 1
&&
__other_lock.spin_frequency_multiplier() == 0
&&
__other_lock.lock_direction() == 1)
)
) {
throw Core::Error::Runtime(
"Incosistent lock state encountered for a zone. Likely related "
"to initial conditions with a tidal term too close to zero."
);
}
assert(__lock.spin_frequency_multiplier() == 1
||
__lock.spin_frequency_multiplier() == 2);
assert(__other_lock.spin_frequency_multiplier() >= 0
&&
__other_lock.spin_frequency_multiplier() <= 2);
if(__lock) return;
return;//<++>
assert(
(
__lock.lock_direction()
*
__lock.spin_frequency_multiplier()
*
spin_frequency()
+
1.0e-5 * __orbital_frequency
)
>=
(
__lock.lock_direction()
*
__lock.orbital_frequency_multiplier()
*
__orbital_frequency
)
);
if(__other_lock.spin_frequency_multiplier()) {
assert(
(
__other_lock.lock_direction()
*
__other_lock.spin_frequency_multiplier()
*
spin_frequency()
)
>
(
__other_lock.lock_direction()
*
__other_lock.orbital_frequency_multiplier()
*
__orbital_frequency
)
);
} else assert(
__lock.lock_direction() * __lock.orbital_frequency_multiplier()
>
0
);
}
#endif
void DissipatingZone::update_lock_to_lower_e_order(SpinOrbitLockInfo &lock)
{
#ifndef NDEBUG
assert(lock.lock_direction());
check_locks_consistency();
#endif
if(
static_cast<unsigned>(std::abs(lock.orbital_frequency_multiplier()))
>
__e_order+2
&&
lock.spin_frequency_multiplier()==2
)
lock.set_lock(
(
lock.orbital_frequency_multiplier()
-
lock.lock_direction()
)/2,
1,
lock.lock_direction()
);
if(
lock.orbital_frequency_multiplier()
>
static_cast<int>(__e_order + 2)
) {
if(lock.lock_direction() > 0)
lock.set_lock(__e_order + 2, 1, 1);
else
lock.set_lock(1, 0, 1);
} else if(
lock.orbital_frequency_multiplier()
<
-static_cast<int>(__e_order)-2
) {
if(lock.lock_direction() > 0)
lock.set_lock(1, 0, 1);
else
lock.set_lock(-static_cast<int>(__e_order) - 2, 1, -1);
}
#ifndef NDEBUG
check_locks_consistency();
#endif
}
void DissipatingZone::update_locks_to_higher_e_order(unsigned new_e_order)
{
if(__other_lock.spin_frequency_multiplier() == 0) {
int orb_mult = std::ceil(std::abs(2 * spin_frequency())
/
__orbital_frequency);
if(
orb_mult % 2 == 1
&&
static_cast<int>(new_e_order) + 2 >= orb_mult
)
__other_lock.set_lock(__lock.lock_direction() * orb_mult,
2,
-__lock.lock_direction());
else if(static_cast<int>(new_e_order) + 2 >= orb_mult / 2)
__other_lock.set_lock(
__lock.lock_direction() * orb_mult / 2,
1,
-__lock.lock_direction()
);
} else if(
__lock.spin_frequency_multiplier() == 1
&&
__other_lock.spin_frequency_multiplier() == 1
&&
__lock.orbital_frequency_multiplier()
+
__other_lock.orbital_frequency_multiplier()
<=
static_cast<int>(new_e_order) + 2
) {
int mid_mult = (__lock.orbital_frequency_multiplier()
+
__other_lock.orbital_frequency_multiplier());
if(2 * spin_frequency() < mid_mult * __orbital_frequency)
(
__lock.lock_direction() > 0
? __other_lock
: __lock
).set_lock(mid_mult, 2, -1);
else
(
__lock.lock_direction()>0
? __lock
: __other_lock
).set_lock(mid_mult, 2, 1);
}
}
void DissipatingZone::initialize_locks()
{
#ifndef NDEBUG
std::cerr << "Initializing locks" << std::endl;
#endif
int below_orb_mult = std::floor(2.0
*
__spin_frequency
/
__orbital_frequency),
max_abs_orb_mult=static_cast<int>(__e_order + 2);
if(below_orb_mult % 2) {
if(
static_cast<unsigned>(std::abs(below_orb_mult))
<=
__e_order + 2
) {
__lock.set_lock(below_orb_mult, 2, 1);
__other_lock.set_lock((below_orb_mult + 1) / 2, 1, -1);
} else if(
static_cast<unsigned>(std::abs((below_orb_mult - 1) / 2))
<=
__e_order + 2
) {
__lock.set_lock((below_orb_mult - 1) / 2, 1, 1);
if((below_orb_mult + 1) / 2 > max_abs_orb_mult)
__other_lock.set_lock(1, 0, 1);
else
__other_lock.set_lock((below_orb_mult + 1) / 2, 1, -1);
} else {
if(__spin_frequency > 0)
__lock.set_lock(max_abs_orb_mult, 1, 1);
else
__lock.set_lock(-max_abs_orb_mult, 1, -1);
__other_lock.set_lock(1, 0, 1);
}
} else if(std::abs(below_orb_mult / 2) <= max_abs_orb_mult) {
__lock.set_lock(below_orb_mult / 2, 1, 1);
if(std::abs(below_orb_mult + 1) <= max_abs_orb_mult)
__other_lock.set_lock(below_orb_mult + 1, 2, -1);
else if(std::abs(below_orb_mult / 2 + 1) <= max_abs_orb_mult)
__other_lock.set_lock(below_orb_mult / 2 + 1, 1, -1);
else
__other_lock.set_lock(1, 0, 1);
} else {
if(__spin_frequency > 0)
__lock.set_lock(max_abs_orb_mult, 1, 1);
else
__lock.set_lock(-max_abs_orb_mult, 1, -1);
__other_lock.set_lock(1, 0, 1);
}
#ifndef NDEBUG
check_locks_consistency();
#endif
}
void DissipatingZone::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)
{
int m_ind = m + 2;
bool locked_term = locked(mp, m);
bool has_error = true;
for(
int deriv = Dissipation::NO_DERIV;
(
(m != 0 || mp != 0)
&&
deriv < Dissipation::END_DIMENSIONLESS_DERIV
);
++deriv
) {
Dissipation::QuantityEntry phase_lag_deriv = (
deriv < Dissipation::END_PHASE_LAG_DERIV
? static_cast<Dissipation::QuantityEntry>(deriv)
: Dissipation::NO_DERIV
);
double mod_phase_lag_above,
mod_phase_lag_below = modified_phase_lag(
mp,
m,
tidal_frequency,
phase_lag_deriv,
mod_phase_lag_above
),
love_coef = love_coefficient(
mp,
m,
(
phase_lag_deriv == Dissipation::AGE
? Dissipation::AGE
: Dissipation::NO_DERIV
)
);
TidalTermTriplet U;
if(deriv < Dissipation::END_PHASE_LAG_DERIV)
U = U_value;
else if(deriv == Dissipation::INCLINATION)
U = U_i_deriv;
else
U = U_e_deriv;
double U_mmp_squared = std::pow(U.m, 2),
U_mmp_squared_error = (has_error
? (2.0 * std::abs(U.m * U_error.m)
+
std::pow(U_error.m, 2))
: 0.0),
term_power = U_mmp_squared * mp,
term_power_error = U_mmp_squared_error * mp,
term_torque_z = U_mmp_squared * m,
term_torque_z_error = U_mmp_squared_error * m,
term_torque_x = U.m * (
__torque_x_minus_coef[m_ind] * U.m_minus_one
+
__torque_x_plus_coef[m_ind] * U.m_plus_one
),
term_torque_x_error = 0.0;
if(has_error) {
double common_error_term = (
__torque_x_minus_coef[m_ind] * U_error.m_minus_one
+
__torque_x_plus_coef[m_ind] * U_error.m_plus_one
);
term_torque_x_error = (
(
U_error.m
? U_error.m * (term_torque_x / U.m + common_error_term)
: 0.0
)
+
U.m * common_error_term
);
}
if(
!locked_term
&&
(tidal_frequency != 0 || __lock.lock_direction() < 0)
)
mod_phase_lag_above = mod_phase_lag_below;
else if(
!locked_term
&&
tidal_frequency == 0
&&
__lock.lock_direction() > 0
)
mod_phase_lag_below = mod_phase_lag_above;
int deriv_ind = 2 * deriv;
__power[deriv_ind] += term_power * mod_phase_lag_below;
__torque_z[deriv_ind] += (term_torque_z
*
mod_phase_lag_below);
__torque_x[deriv_ind] += (term_torque_x
*
mod_phase_lag_below);
__torque_y[deriv_ind + 1] = -(
__torque_y[deriv_ind] -= term_torque_x * love_coef
);
__power[deriv_ind + 1] += term_power * mod_phase_lag_above;
__torque_z[deriv_ind + 1] += (term_torque_z
*
mod_phase_lag_above);
__torque_x[deriv_ind + 1] += (term_torque_x
*
mod_phase_lag_above);
assert(!std::isnan(__torque_x[deriv_ind]));
assert(!std::isnan(__torque_x[deriv_ind + 1]));
assert(!std::isnan(__torque_y[deriv_ind]));
assert(!std::isnan(__torque_y[deriv_ind + 1]));
assert(!std::isnan(__torque_z[deriv_ind]));
assert(!std::isnan(__torque_z[deriv_ind + 1]));
if(has_error) {
has_error = false;
const int error_ind = 2 * Dissipation::END_DIMENSIONLESS_DERIV;
__power[error_ind] += term_power_error * mod_phase_lag_below;
__torque_z[error_ind] += (term_torque_z_error
*
mod_phase_lag_below);
__torque_x[error_ind] += (term_torque_x_error
*
mod_phase_lag_below);
__torque_y[error_ind + 1] = -(
__torque_y[error_ind] -= term_torque_x_error * love_coef
);
__power[error_ind + 1] += (term_power_error
*
mod_phase_lag_above);
__torque_z[error_ind + 1] += (term_torque_z_error
*
mod_phase_lag_above);
__torque_x[error_ind + 1] += (term_torque_x_error
*
mod_phase_lag_above);
assert(!std::isnan(__torque_x[error_ind]));
assert(!std::isnan(__torque_x[error_ind + 1]));
assert(!std::isnan(__torque_y[error_ind]));
assert(!std::isnan(__torque_y[error_ind + 1]));
assert(!std::isnan(__torque_z[error_ind]));
assert(!std::isnan(__torque_z[error_ind + 1]));
}
#if 0
if(deriv == Dissipation::NO_DERIV)
std::cerr << ", Wzone = "
<< spin_frequency()
<< ", U(" << m << ", " << mp << ") = "
<< U.m
<< ", term_power="
<< term_power
<< ", mod_phase_lag(above="
<< mod_phase_lag_above
<< ", below="
<< mod_phase_lag_below
<< ")";
#endif
}
}
void DissipatingZone::configure_spin(double spin,
bool spin_is_frequency)
{
if(spin_is_frequency) {
__angular_momentum = spin * moment_of_inertia();
__spin_frequency = spin;
} else {
__angular_momentum = spin;
if(spin == 0 && moment_of_inertia() == 0) __spin_frequency = 0;
else __spin_frequency = spin / moment_of_inertia();
}
}
DissipatingZone::DissipatingZone() :
__e_order(0),
__power(0.0, 2 * Dissipation::END_DIMENSIONLESS_DERIV + 2),
__torque_x(0.0, 2 * Dissipation::END_DIMENSIONLESS_DERIV + 2),
__torque_y(0.0, 2 * Dissipation::END_DIMENSIONLESS_DERIV + 2),
__torque_z(0.0, 2 * Dissipation::END_DIMENSIONLESS_DERIV + 2),
__evolution_real(NUM_REAL_EVOL_QUANTITIES),
__evolution_integer(NUM_EVOL_QUANTITIES - NUM_REAL_EVOL_QUANTITIES),
__initializing(false)
{}
void DissipatingZone::configure(bool initialize,
double
#ifndef NDEBUG
age
#endif
,
double orbital_frequency,
double eccentricity,
double orbital_angmom,
double spin,
double inclination,
double periapsis,
bool spin_is_frequency)
{
assert(age >= 0);
if(initialize) {
__initializing = true;
#ifndef NDEBUG
std::cerr << "Initializing DissipatingZone" << std::endl;
#endif
}
#ifndef NDEBUG
std::cerr << "At t = " << age << ", configuring zone with "
<< (spin_is_frequency ? "w" : "L") << " = " << spin
<< ", inclination = " << inclination
<< ", periapsis = " << periapsis
<< std::endl;
#endif
ZoneOrientation::configure(inclination, periapsis);
__orbital_angmom = orbital_angmom;
__orbital_frequency = orbital_frequency;
if(__lock && !initialize) {
__spin_frequency = __lock.spin(orbital_frequency);
__angular_momentum = __spin_frequency*moment_of_inertia();
} else
configure_spin(spin, spin_is_frequency);
if(initialize) {
initialize_locks();
__initializing = false;
}
if(std::isnan(orbital_frequency)) return;
__potential_term.configure(inclination, periapsis);
__power = 0;
__torque_x = 0;
__torque_y = 0;
__torque_z = 0;
if(!dissipative()) return;
double esquared = std::pow(eccentricity, 2);
for(
int mp = -static_cast<int>(__e_order) - 2;
mp <= static_cast<int>(__e_order) + 2;
++mp
) {
TidalTermTriplet U_value,
U_error,
U_i_deriv,
U_e_deriv;
__potential_term(eccentricity,
-2,
mp,
U_value.m_plus_one,
U_i_deriv.m_plus_one,
U_e_deriv.m_plus_one,
U_error.m_plus_one);
U_error.m_plus_one *= esquared;
for(int m = -2; m <= 2; ++m) {
#if 0
std::cerr << "Term: m' = "
<< mp
<< ", m = "
<< m;
#endif
U_value.m = U_value.m_plus_one;
U_error.m = U_error.m_plus_one;
U_i_deriv.m = U_i_deriv.m_plus_one;
U_e_deriv.m = U_e_deriv.m_plus_one;
if(m < 2) {
__potential_term(eccentricity,
m + 1,
mp,
U_value.m_plus_one,
U_i_deriv.m_plus_one,
U_e_deriv.m_plus_one,
U_error.m_plus_one);
U_error.m_plus_one *= esquared;
} else {
U_value.m_plus_one = 0;
U_error.m_plus_one = 0;
U_i_deriv.m_plus_one = 0;
U_e_deriv.m_plus_one = 0;
}
add_tidal_term(
m,
mp,
forcing_frequency(mp, m, orbital_frequency),
U_value,
U_i_deriv,
U_e_deriv,
U_error
);
U_value.m_minus_one = U_value.m;
U_error.m_minus_one = U_error.m;
U_i_deriv.m_minus_one = U_i_deriv.m;
U_e_deriv.m_minus_one = U_e_deriv.m;
#ifdef VERBOSE_DEBUG
std::cerr << std::endl;
#endif
}
}
}
double DissipatingZone::forcing_frequency(
int orbital_frequency_multiplier,
int spin_frequency_multiplier,
double orbital_frequency
) const
{
#ifndef NDEBUG
check_locks_consistency();
#endif
if(__lock(orbital_frequency_multiplier, spin_frequency_multiplier))
return 0;
double forcing_freq = (
orbital_frequency_multiplier * orbital_frequency
-
spin_frequency_multiplier * spin_frequency()
);
assert(!std::isnan(forcing_freq));
#ifdef VERBOSE_DEBUG
std::cerr << "Worb = " << orbital_frequency << ", "
<< "Wspin = " << spin_frequency() << " -> "
<< "Wtide = " << forcing_freq << " -> ";
#endif
fix_forcing_frequency(__lock,
orbital_frequency_multiplier,
spin_frequency_multiplier,
forcing_freq);
if(!__lock && __other_lock.spin_frequency_multiplier() != 0)
fix_forcing_frequency(__other_lock,
orbital_frequency_multiplier,
spin_frequency_multiplier,
forcing_freq);
#ifdef VERBOSE_DEBUG
std::cerr << forcing_freq << std::endl;
#endif
return forcing_freq;
}
double DissipatingZone::periapsis_evolution(
const Eigen::Vector3d &orbit_torque,
const Eigen::Vector3d &zone_torque,
Dissipation::QuantityEntry entry,
const Eigen::Vector3d &orbit_torque_deriv,
const Eigen::Vector3d &zone_torque_deriv
)
{
double sin_inc = std::sin(inclination()),
cos_inc = std::cos(inclination()),
zone_y_torque,
orbit_y_torque;
if(entry == Dissipation::NO_DERIV) {
orbit_y_torque = orbit_torque[1];
zone_y_torque = zone_torque[1];
} else if(entry == Dissipation::EXPANSION_ERROR) {
return (
sin_inc == 0
? 0
: (
std::abs(orbit_torque[1] * cos_inc
/
(__orbital_angmom * sin_inc))
+
std::abs(zone_torque[1]
/
(__angular_momentum * sin_inc))
)
);
} else {
orbit_y_torque = orbit_torque_deriv[1];
zone_y_torque = zone_torque_deriv[1];
}
#ifndef NDEBUG
if(sin_inc == 0) {
assert(orbit_y_torque == 0 || std::isnan(orbit_y_torque));
assert(zone_y_torque == 0 || std::isnan(zone_y_torque));
} else {
assert(!std::isnan(orbit_y_torque));
assert(!std::isnan(zone_y_torque));
}
#endif
double result = (
sin_inc == 0
? 0
: (
-orbit_y_torque * cos_inc / (__orbital_angmom * sin_inc)
+
zone_y_torque / (__angular_momentum * sin_inc)
)
);
assert(!std::isnan(result));
if(
entry == Dissipation::NO_DERIV
||
entry == Dissipation::AGE
||
entry == Dissipation::ECCENTRICITY
||
entry == Dissipation::PERIAPSIS
||
entry == Dissipation::RADIUS
||
entry == Dissipation::MOMENT_OF_INERTIA
||
entry == Dissipation::SEMIMAJOR
)
return result;
else if(
entry == Dissipation::SPIN_FREQUENCY
||
entry == Dissipation::SPIN_ANGMOM
) {
if(sin_inc == 0) return 0.0;
else return (
result
-
zone_torque[1]
/
(std::pow(__angular_momentum, 2) * sin_inc)
*
(entry == Dissipation::SPIN_FREQUENCY ? moment_of_inertia() : 1)
);
} else if(entry == Dissipation::INCLINATION) {
if(sin_inc == 0) return 0.0;
else return (
result
-
(
orbit_torque[1] / __orbital_angmom
+
zone_torque[1] * cos_inc / __angular_momentum
)
/
std::pow(sin_inc, 2)
);
} else {
assert(false);
}
return Core::NaN;
}
double DissipatingZone::inclination_evolution(
const Eigen::Vector3d &orbit_torque,
const Eigen::Vector3d &zone_torque,
Dissipation::QuantityEntry entry,
const Eigen::Vector3d &orbit_torque_deriv,
const Eigen::Vector3d &zone_torque_deriv)
{
double sin_inc = std::sin(inclination()),
cos_inc = std::cos(inclination()),
zone_x_torque,
orbit_x_torque,
orbit_z_torque;
assert(!std::isnan(orbit_torque[0]));
assert(!std::isnan(orbit_torque[2]));
assert(!std::isnan(zone_torque[0]));
if(entry == Dissipation::NO_DERIV) {
orbit_x_torque = orbit_torque[0];
orbit_z_torque = orbit_torque[2];
zone_x_torque = zone_torque[0];
} else if(entry == Dissipation::EXPANSION_ERROR) {
if(orbit_torque[0] == 0 && orbit_torque[2] == 0)
return 0;
assert(__orbital_angmom > 0);
return (
(
std::abs(orbit_torque[0] * cos_inc)
-
std::abs(orbit_torque[2] * sin_inc)
)
/
__orbital_angmom
);
} else {
orbit_x_torque = orbit_torque_deriv[0];
orbit_z_torque = orbit_torque_deriv[2];
zone_x_torque = zone_torque_deriv[0];
}
double result;
if(orbit_x_torque == 0 && orbit_z_torque == 0)
result = 0.0;
else
result = ((orbit_x_torque * cos_inc - orbit_z_torque * sin_inc)
/
__orbital_angmom);
if(zone_x_torque != 0 && moment_of_inertia() != 0)
result -= zone_x_torque / __angular_momentum;
assert(!std::isnan(result));
if(
entry == Dissipation::NO_DERIV
||
entry == Dissipation::AGE
||
entry == Dissipation::ECCENTRICITY
||
entry == Dissipation::PERIAPSIS
||
entry == Dissipation::RADIUS
||
entry == Dissipation::MOMENT_OF_INERTIA
||
entry == Dissipation::SEMIMAJOR
) {
return result;
} else if(
entry == Dissipation::SPIN_FREQUENCY
||
entry == Dissipation::SPIN_ANGMOM
) {
assert(std::abs(__angular_momentum) > 0);
return (
result
+
zone_torque[0] / std::pow(__angular_momentum, 2)
*
(entry == Dissipation::SPIN_FREQUENCY ? moment_of_inertia() : 1)
);
} else if(entry == Dissipation::INCLINATION) {
assert(std::abs(__angular_momentum) > 0);
return (result
+
(orbit_torque[2] * cos_inc + orbit_torque[0] * sin_inc)
/
__angular_momentum);
} else
assert(false);
return Core::NaN;
}
void DissipatingZone::release_lock()
{
if(__lock.spin_frequency_multiplier() == 2) {
assert(__lock.orbital_frequency_multiplier() % 2 == 1);
__other_lock.set_lock(
(__lock.orbital_frequency_multiplier() + 1) / 2,
1,
-1
);
__lock.set_lock(
(__lock.orbital_frequency_multiplier() - 1) / 2,
1,
-1
);
}
update_lock_to_lower_e_order(__lock);
update_lock_to_lower_e_order(__other_lock);
if(__lock.spin_frequency_multiplier() == 0) {
__lock=__other_lock;
__other_lock.set_lock(1, 0, 1);
}
}
void DissipatingZone::release_lock(short direction)
{
assert(__lock);
assert(direction == 1 || direction == -1);
assert(
__lock.spin_frequency_multiplier() == 1
||
__lock.spin_frequency_multiplier() == 2
);
__lock.lock_direction(direction);
int orbit_mult = (
(__lock.spin_frequency_multiplier() == 2 ? 1 : 2)
*
__lock.orbital_frequency_multiplier()
+
direction
);
if(orbit_mult % 2) __other_lock.set_lock(orbit_mult, 2, -direction);
else __other_lock.set_lock(orbit_mult/2, 1, -direction);
update_lock_to_lower_e_order(__other_lock);
}
void DissipatingZone::change_e_order(
unsigned new_e_order,
BinarySystem &,
bool ,
unsigned
)
{
__potential_term.change_e_order(new_e_order);
if(__lock.spin_frequency_multiplier() == 0) {
__e_order = new_e_order;
return;
}
if(__lock) {
__e_order = new_e_order;
if(
__lock.orbital_frequency_multiplier()
>
static_cast<int>(__e_order) + 2
)
release_lock();
return;
}
#ifndef NDEBUG
check_locks_consistency();
#endif
if(new_e_order > __e_order) {
update_locks_to_higher_e_order(new_e_order);
__e_order = new_e_order;
} else {
__e_order = new_e_order;
update_lock_to_lower_e_order(__lock);
update_lock_to_lower_e_order(__other_lock);
if(__lock.spin_frequency_multiplier() == 0) {
__lock = __other_lock;
__other_lock.set_lock(1, 0, 1);
}
}
#ifndef NDEBUG
check_locks_consistency();
#endif
}
void DissipatingZone::add_to_evolution()
{
__evolution_real[ANGULAR_MOMENTUM].push_back(__angular_momentum);
__evolution_real[INCLINATION].push_back(inclination());
__evolution_real[PERIAPSIS].push_back(periapsis());
__evolution_real[MOMENT_OF_INERTIA].push_back(moment_of_inertia());
__evolution_real[MOMENT_OF_INERTIA_FIRST_DERIV].push_back(
moment_of_inertia(1)
);
__evolution_real[MOMENT_OF_INERTIA_SECOND_DERIV].push_back(
moment_of_inertia(2)
);
__evolution_real[OUTER_RADIUS].push_back(outer_radius());
__evolution_real[OUTER_RADIUS_FIRST_DERIV].push_back(outer_radius(1));
__evolution_real[OUTER_RADIUS_SECOND_DERIV].push_back(outer_radius(2));
__evolution_real[OUTER_MASS].push_back(outer_mass());
__evolution_real[OUTER_MASS_DERIV].push_back(outer_mass(1));
__evolution_integer[E_ORDER-NUM_REAL_EVOL_QUANTITIES].push_back(
__e_order
);
if(__lock) {
__evolution_integer[ORBITAL_FREQ_MULTIPLIER-NUM_REAL_EVOL_QUANTITIES]
.push_back(__lock.orbital_frequency_multiplier());
__evolution_integer[SPIN_FREQ_MULTIPLIER-NUM_REAL_EVOL_QUANTITIES]
.push_back(__lock.spin_frequency_multiplier());
} else {
__evolution_integer[ORBITAL_FREQ_MULTIPLIER-NUM_REAL_EVOL_QUANTITIES]
.push_back(0);
__evolution_integer[SPIN_FREQ_MULTIPLIER-NUM_REAL_EVOL_QUANTITIES]
.push_back(0);
}
}
void DissipatingZone::reset_evolution()
{
for(unsigned i = 0; i < __evolution_real.size(); ++i)
__evolution_real[i].clear();
for(unsigned i = 0; i < __evolution_integer.size(); ++i)
__evolution_integer[i].clear();
}
void DissipatingZone::rewind_evolution(unsigned nsteps)
{
for(unsigned i = 0; i < nsteps; ++i) {
for(unsigned i = 0; i < __evolution_real.size(); ++i)
__evolution_real[i].pop_back();
for(unsigned i = 0; i < __evolution_integer.size(); ++i)
__evolution_integer[i].pop_back();
}
}
CombinedStoppingCondition *DissipatingZone::stopping_conditions(
BinarySystem &system,
bool primary,
unsigned zone_index
)
{
CombinedStoppingCondition *result = new CombinedStoppingCondition();
if(!dissipative()) return result;
if(__lock)
(*result) |= new BreakLockCondition(system, __locked_zone_index);
else if(system.evolution_mode() == Core::BINARY) {
(*result) |= new SynchronizedCondition(
__lock.orbital_frequency_multiplier(),
__lock.spin_frequency_multiplier(),
__lock.lock_direction(),
primary,
zone_index,
system
);
(*result) |= new SynchronizedCondition(
__other_lock.orbital_frequency_multiplier(),
__other_lock.spin_frequency_multiplier(),
__other_lock.lock_direction(),
primary,
zone_index,
system
);
}
return result;
}
} //End Evolve namespace.