File CelestialBody.hpp¶
File List > astrea > astro > astro > systems > CelestialBody.hpp
Go to the documentation of this file
#pragma once
#include <string>
#include <math/chebyshev_util.hpp>
#include <units/units.hpp>
#include <astro/astro.fwd.hpp>
#include <astro/frames/frames.hpp>
#include <astro/systems/CelestialBodyParameters.hpp>
#include <astro/time/Date.hpp>
#include <astro/types/enums.hpp>
#include <astro/utilities/conversions.hpp>
namespace astrea {
namespace astro {
class CelestialBody {
public:
CelestialBody() = default;
virtual ~CelestialBody() = default;
constexpr CelestialBody(const CelestialBodyParameters& data) :
_name(data.name),
_parent(data.parent),
_type(data.type),
_referenceDate(data.referenceDate),
_mu(data.mu),
_mass(data.mass),
_equitorialRadius(data.equitorialRadius),
_polarRadius(data.polarRadius),
_crashRadius(data.crashRadius),
_sphereOfInfluence(data.sphereOfInfluence),
_j2(data.j2),
_j3(data.j3),
_axialTilt(data.axialTilt),
_rotationRate(data.rotationRate),
_siderealPeriod(data.siderealPeriod),
_semimajorAxis(data.semimajorAxis),
_eccentricity(data.eccentricity),
_inclination(data.inclination),
_rightAscension(data.rightAscension),
_longitudeOfPerigee(data.longitudeOfPerigee),
_meanLongitude(data.meanLongitude),
_meanAnomaly(wrap_angle(_meanLongitude - _longitudeOfPerigee)),
_semimajorAxisRate(data.semimajorAxisRate),
_eccentricityRate(data.eccentricityRate),
_inclinationRate(data.inclinationRate),
_rightAscensionRate(data.rightAscensionRate),
_longitudeOfPerigeeRate(data.longitudeOfPerigeeRate),
_meanLongitudeRate(data.meanLongitudeRate)
{
}
CelestialBody(const CelestialBody& other) = default;
constexpr bool operator==(const CelestialBody& other) const { return _mu == other._mu; } // Probably good enough
static constexpr CelestialBodyId get_id() { return CelestialBodyId::UNSET; };
constexpr const std::string& get_name() const { return _name; };
constexpr const CelestialBodyId& get_parent() const { return _parent; };
constexpr const CelestialBodyType& get_type() const { return _type; };
constexpr const GravParam& get_mu() const { return _mu; };
constexpr const Mass& get_mass() const { return _mass; };
constexpr const Distance& get_equitorial_radius() const { return _equitorialRadius; };
constexpr const Distance& get_polar_radius() const { return _polarRadius; };
constexpr const Distance& get_crash_radius() const { return _crashRadius; };
constexpr const Distance& get_sphere_of_influence() const { return _sphereOfInfluence; };
constexpr const Unitless& get_j2() const { return _j2; };
constexpr const Unitless& get_j3() const { return _j3; };
constexpr const Angle& get_axial_tilt() const { return _axialTilt; };
constexpr const AngularRate& get_rotation_rate() const { return _rotationRate; };
constexpr const Time& get_sidereal_period() const { return _siderealPeriod; };
constexpr const Distance& get_semimajor() const { return _semimajorAxis; };
constexpr const Unitless& get_eccentricity() const { return _eccentricity; };
constexpr const Angle& get_inclination() const { return _inclination; };
constexpr const Angle& get_right_ascension() const { return _rightAscension; };
constexpr const Angle& get_longitude_of_perigee() const { return _longitudeOfPerigee; };
constexpr const Angle& get_mean_longitude() const { return _meanLongitude; };
Angle get_true_anomaly() const
{
return wrap_angle(convert_mean_anomaly_to_true_anomaly(_meanAnomaly, _eccentricity));
};
constexpr const Angle& get_mean_anomaly() const { return _meanAnomaly; };
constexpr const InterplanetaryVelocity& get_semimajor_rate() const { return _semimajorAxisRate; };
constexpr const BodyUnitlessPerTime& get_eccentricity_rate() const { return _eccentricityRate; };
constexpr const BodyAngularRate& get_inclination_rate() const { return _inclinationRate; };
constexpr const BodyAngularRate& get_right_ascension_rate() const { return _rightAscensionRate; };
constexpr const BodyAngularRate& get_longitude_of_perigee_rate() const { return _longitudeOfPerigeeRate; };
constexpr const BodyAngularRate& get_mean_longitude_rate() const { return _meanLongitudeRate; };
virtual Density find_atmospheric_density(const Date& date, const Distance& altitude) const;
Keplerian get_keplerian_elements_at(const Date& date) const;
virtual CartesianVector<Distance, frames::solar_system_barycenter::icrf> get_position_at(const Date& date) const;
protected:
std::string _name;
CelestialBodyId _parent;
CelestialBodyType _type;
Date _referenceDate;
GravParam _mu;
GravParam _parentMu;
Mass _mass;
Distance _equitorialRadius;
Distance _polarRadius;
Distance _crashRadius;
Distance _sphereOfInfluence;
Unitless _j2;
Unitless _j3;
Angle _axialTilt;
AngularRate _rotationRate;
Time _siderealPeriod;
Distance _semimajorAxis;
Unitless _eccentricity;
Angle _inclination;
Angle _rightAscension;
Angle _longitudeOfPerigee;
Angle _meanLongitude;
Angle _trueAnomaly;
Angle _meanAnomaly;
// These rates need to stay in rate/JC to avoid numerical issues
InterplanetaryVelocity _semimajorAxisRate;
BodyUnitlessPerTime _eccentricityRate;
BodyAngularRate _inclinationRate;
BodyAngularRate _rightAscensionRate;
BodyAngularRate _longitudeOfPerigeeRate;
BodyAngularRate _meanLongitudeRate;
static constexpr double _COEFF_ZERO_FACTOR = 1.0;
template <typename Table_T, typename Frame_T>
CartesianVector<Distance, Frame_T> get_position_at_impl(const Date& date) const
{
using mp_units::si::unit_symbols::km;
// Evaluate Chebyshev polynomials
const auto [xInterp, yInterp, zInterp] = get_chebyshev_table_coefficients<Table_T>(date);
const double mjd = (date.mjd() - Date(J2000).mjd()).count();
Distance x = math::evaluate_chebyshev_polynomial(mjd, xInterp, _COEFF_ZERO_FACTOR) * km;
Distance y = math::evaluate_chebyshev_polynomial(mjd, yInterp, _COEFF_ZERO_FACTOR) * km;
Distance z = math::evaluate_chebyshev_polynomial(mjd, zInterp, _COEFF_ZERO_FACTOR) * km;
return CartesianVector<Distance, Frame_T>(x, y, z);
}
template <typename Table_T, typename Frame_T>
CartesianVector<Velocity, Frame_T> get_velocity_at_impl(const Date& date) const
{
using mp_units::non_si::day;
using mp_units::si::unit_symbols::km;
// Evaluate Chebyshev polynomials
const auto [xInterp, yInterp, zInterp] = get_chebyshev_table_coefficients<Table_T>(date);
const double mjd = (date.mjd() - Date(J2000).mjd()).count();
Velocity vx = math::evaluate_chebyshev_derivative(mjd, xInterp, _COEFF_ZERO_FACTOR) * km / day;
Velocity vy = math::evaluate_chebyshev_derivative(mjd, yInterp, _COEFF_ZERO_FACTOR) * km / day;
Velocity vz = math::evaluate_chebyshev_derivative(mjd, zInterp, _COEFF_ZERO_FACTOR) * km / day;
return CartesianVector<Velocity, Frame_T>(vx, vy, vz);
}
template <typename Table_T>
const auto get_chebyshev_table_coefficients(const Date& date) const
{
static constexpr Time timePerCoefficient = Table_T::TIME_PER_COEFFICIENT;
// Extract components
const std::size_t ind = Table_T::get_index(date, timePerCoefficient);
const auto& xInterp = Table_T::X_INTERP[ind];
const auto& yInterp = Table_T::Y_INTERP[ind];
const auto& zInterp = Table_T::Z_INTERP[ind];
return std::make_tuple(xInterp, yInterp, zInterp);
}
using CoefficientPack = std::tuple<
mp_units::quantity<mp_units::angular::unit_symbols::rad / (JulianCentury * JulianCentury)>,
mp_units::quantity<mp_units::angular::unit_symbols::rad>,
mp_units::quantity<mp_units::angular::unit_symbols::rad>,
mp_units::quantity<mp_units::angular::unit_symbols::rad / JulianCentury>>;
virtual constexpr CoefficientPack get_linear_expansion_coefficients() const
{
using mp_units::angular::unit_symbols::rad;
return std::make_tuple(0.0 * rad / (JulianCentury * JulianCentury), 0.0 * rad, 0.0 * rad, 0.0 * rad / JulianCentury);
}
};
using CelestialBodyUniquePtr = std::unique_ptr<CelestialBody>;
} // namespace astro
} // namespace astrea
template <>
struct std::hash<astrea::astro::CelestialBody> {
std::size_t operator()(astrea::astro::CelestialBody const& body) const noexcept
{
std::size_t h = std::hash<double>{}(body.get_mu().numerical_value_in(
mp_units::pow<3>(mp_units::si::unit_symbols::km) / mp_units::pow<2>(mp_units::si::unit_symbols::s)
));
h ^= (std::hash<double>{}(body.get_mass().numerical_value_in((mp_units::mag_power<10, 24> * mp_units::si::unit_symbols::kg))) << 1);
/* // These are probably overkill
h ^= (std::hash<double>{}(body.get_equitorial_radius()) << 1);
h ^= (std::hash<double>{}(body.get_polar_radius()) << 1);
h ^= (std::hash<double>{}(body.get_crash_radius()) << 1);
h ^= (std::hash<double>{}(body.get_sphere_of_influence()) << 1);
h ^= (std::hash<double>{}(body.get_j2()) << 1);
h ^= (std::hash<double>{}(body.get_j3()) << 1);
h ^= (std::hash<double>{}(body.get_axial_tilt()) << 1);
h ^= (std::hash<double>{}(body.get_rotation_rate()) << 1);
h ^= (std::hash<double>{}(body.get_sidereal_period()) << 1);
h ^= (std::hash<double>{}(body.get_semimajor()) << 1);
h ^= (std::hash<double>{}(body.get_eccentricity()) << 1);
h ^= (std::hash<double>{}(body.get_inclination()) << 1);
h ^= (std::hash<double>{}(body.get_right_ascension()) << 1);
h ^= (std::hash<double>{}(body.get_longitude_of_perigee()) << 1);
h ^= (std::hash<double>{}(body.get_mean_longitude()) << 1);
*/
return h;
}
};