void Plugin::UpdateCelestialHierarchy(Index const celestial_index, Index const parent_index) const { VLOG(1) << __FUNCTION__ << '\n' << NAMED(celestial_index) << '\n' << NAMED(parent_index); CHECK(!initializing_); FindOrDie(celestials_, celestial_index)->set_parent( FindOrDie(celestials_, parent_index).get()); }
void Plugin::EndInitialization() { CHECK(initializing_); if (hierarchical_initialization_) { std::uint64_t system_fingerprint = 0; for (std::uint64_t fingerprint : celestial_jacobi_keplerian_fingerprints_) { system_fingerprint = FingerprintCat2011(system_fingerprint, fingerprint); } LOG(INFO) << "System fingerprint is " << std::hex << system_fingerprint; if (system_fingerprint == ksp_stock_system_fingerprint) { is_ksp_stock_system_ = true; LOG(WARNING) << "This appears to be the dreaded KSP stock system!"; } else if (system_fingerprint == ksp_fixed_system_fingerprint) { LOG(INFO) << "This is the fixed KSP system, all hail retrobop!"; } HierarchicalSystem<Barycentric>::BarycentricSystem system = hierarchical_initialization_->system.ConsumeBarycentricSystem(); std::map<not_null<MassiveBody const*>, Index> bodies_to_indices; for (auto const& index_body : hierarchical_initialization_->indices_to_bodies) { bodies_to_indices[index_body.second] = index_body.first; } auto const parents = std::move(hierarchical_initialization_->parents); hierarchical_initialization_ = std::experimental::nullopt; for (int i = 0; i < system.bodies.size(); ++i) { Index const celestial_index = bodies_to_indices[system.bodies[i].get()]; InsertCelestialAbsoluteCartesian( celestial_index, FindOrDie(parents, celestial_index), system.degrees_of_freedom[i], std::move(system.bodies[i])); } } CHECK(absolute_initialization_); CHECK_NOTNULL(sun_); main_body_ = CHECK_NOTNULL( dynamic_cast<RotatingBody<Barycentric> const*>(&*sun_->body())); initializing_.Flop(); InitializeEphemerisAndSetCelestialTrajectories(); // Log the serialized ephemeris. serialization::Ephemeris ephemeris_message; ephemeris_->WriteToMessage(&ephemeris_message); std::string const bytes = ephemeris_message.SerializeAsString(); base::UniqueArray<std::uint8_t> const hex((bytes.size() << 1) + 1); base::HexadecimalEncode( base::Array<std::uint8_t const>( reinterpret_cast<std::uint8_t const*>(bytes.data()), bytes.size()), hex.get()); hex.data[hex.size - 1] = 0; // Begin and end markers to make sure the hex did not get clipped (this might // happen if the message is very big). LOG(INFO) << "Ephemeris at initialization:\nbegin\n" << reinterpret_cast<char const*>(hex.data.get()) << "\nend"; }
Rotation<BodyWorld, World> Plugin::CelestialRotation( Index const index) const { // |BodyWorld| with its y and z axes swapped (so that z is the polar axis). // The basis is right-handed. struct BodyFixed; Permutation<BodyWorld, BodyFixed> const body_mirror( Permutation<BodyWorld, BodyFixed>::XZY); auto const& body = dynamic_cast<RotatingBody<Barycentric> const&>( *FindOrDie(celestials_, index)->body()); Bivector<double, BodyFixed> z({0, 0, 1}); Bivector<double, BodyFixed> x({1, 0, 0}); Rotation<BodyFixed, Barycentric> body_orientation( π / 2 * Radian + body.right_ascension_of_pole(), π / 2 * Radian - body.declination_of_pole(), body.AngleAt(current_time_), EulerAngles::ZXZ, DefinesFrame<BodyFixed>{});
void Plugin::SetMainBody(Index const index) { main_body_ = dynamic_cast<RotatingBody<Barycentric> const*>( &*FindOrDie(celestials_, index)->body()); LOG_IF(FATAL, main_body_ == nullptr) << index; }
void GenerateKopernicusForSlippist1( std::string const& gravity_model_stem, std::string const& initial_state_stem) { std::filesystem::path const directory = SOLUTION_DIR / "astronomy"; SolarSystem<Sky> solar_system( (directory / gravity_model_stem).replace_extension(proto_txt), (directory / initial_state_stem).replace_extension(proto_txt), /*ignore_frame=*/true); std::ofstream kopernicus_cfg( (directory / (gravity_model_stem + "_slippist1")).replace_extension(cfg)); CHECK(kopernicus_cfg.good()); // Find the star. This is needed to construct Kepler orbits below. std::optional<serialization::GravityModel::Body> star; for (std::string const& name : solar_system.names()) { serialization::GravityModel::Body const& body = solar_system.gravity_model_message(name); bool const is_star = !solar_system.keplerian_initial_state_message(name).has_parent(); if (is_star) { star = body; } } kopernicus_cfg << "@Kopernicus:AFTER[aSLIPPIST-1] {\n"; for (std::string const& name : solar_system.names()) { serialization::GravityModel::Body const& body = solar_system.gravity_model_message(name); serialization::InitialState::Keplerian::Body::Elements const& elements = solar_system.keplerian_initial_state_message(name).elements(); bool const is_star = !solar_system.keplerian_initial_state_message(name).has_parent(); bool const is_kerbin = FindOrDie(body_name_map, name) == kerbin; kopernicus_cfg << " @Body[" << FindOrDie(body_name_map, name) << "] {\n"; if (is_kerbin) { kopernicus_cfg << " %cbNameLater = " << name << "\n"; } else if (!is_star) { kopernicus_cfg << " @name = " << name << "\n"; } kopernicus_cfg << " @Properties {\n"; if (is_star) { kopernicus_cfg << " !mass = delete\n"; } else { kopernicus_cfg << " !geeASL = delete\n"; } kopernicus_cfg << " @displayName = " << name << "\n"; kopernicus_cfg << " %gravParameter = " << DebugString(ParseQuantity<GravitationalParameter>( body.gravitational_parameter()) / SIUnit<GravitationalParameter>()) << "\n"; kopernicus_cfg << " %radius = " << DebugString(ParseQuantity<Length>(body.mean_radius()) / Metre) << "\n"; kopernicus_cfg << " %description = " << FindOrDie(body_description_map, name) << "\n"; if (!is_star) { kopernicus_cfg << " %tidallyLocked = false\n"; } kopernicus_cfg << " }\n"; if (is_star) { kopernicus_cfg << " @ScaledVersion {\n"; kopernicus_cfg << " @Light {\n"; for (char const* const curve : {"ScaledIntensityCurve", "IntensityCurve", "IVAIntensityCurve"}) { kopernicus_cfg << " @" << curve << " {\n"; kopernicus_cfg << " @key,*[0, ] *= 10\n"; kopernicus_cfg << " }\n"; } kopernicus_cfg << " }\n"; kopernicus_cfg << " }\n"; } else { CHECK(star.has_value()); auto const keplerian_elements = solar_system.MakeKeplerianElements(elements); KeplerOrbit<Sky> const kepler_orbit(*solar_system.MakeMassiveBody(*star), *solar_system.MakeMassiveBody(body), keplerian_elements, solar_system.epoch()); kopernicus_cfg << " @Orbit {\n"; kopernicus_cfg << " %semiMajorAxis = " << DebugString( *kepler_orbit.elements_at_epoch().semimajor_axis / Metre) << "\n"; kopernicus_cfg << " %eccentricity = " << DebugString(elements.eccentricity()) << "\n"; kopernicus_cfg << " %longitudeOfAscendingNode = " << DebugString( ParseQuantity<Angle>( elements.longitude_of_ascending_node()) / Degree) << "\n"; kopernicus_cfg << " %argumentOfPeriapsis = " << DebugString(ParseQuantity<Angle>( elements.argument_of_periapsis()) / Degree) << "\n"; kopernicus_cfg << " %meanAnomalyAtEpoch = " << DebugString(ParseQuantity<Angle>( elements.mean_anomaly()) / Radian) << "\n"; kopernicus_cfg << " }\n"; kopernicus_cfg << " @Atmosphere {\n"; kopernicus_cfg << " @altitude *= 2\n"; for (char const* const curve : {"temperatureCurve", "temperatureSunMultCurve", "pressureCurve"}) { kopernicus_cfg << " @" << curve << " {\n"; kopernicus_cfg << " @key,*[0, ] *= 2\n"; kopernicus_cfg << " }\n"; } kopernicus_cfg << " }\n"; } kopernicus_cfg << " }\n"; } kopernicus_cfg << "}\n"; kopernicus_cfg << "@principia_gravity_model:FOR[Principia] {\n"; for (std::string const& name : solar_system.names()) { serialization::GravityModel::Body const& body = solar_system.gravity_model_message(name); serialization::InitialState::Keplerian::Body::Elements const& elements = solar_system.keplerian_initial_state_message(name).elements(); bool const is_star = !solar_system.keplerian_initial_state_message(name).has_parent(); kopernicus_cfg << " @body[" << name << "] {\n"; if (!is_star) { kopernicus_cfg << " @reference_angle = " << Mod(FindOrDie(body_angle, name) + ParseQuantity<Angle>( elements.argument_of_periapsis()) + ParseQuantity<Angle>(elements.mean_anomaly()), 2 * π * Radian) << "\n"; } kopernicus_cfg << " }\n"; } kopernicus_cfg << "}\n"; for (std::string const& name : solar_system.names()) { bool const is_star = !solar_system.keplerian_initial_state_message(name).has_parent(); if (!is_star) { kopernicus_cfg << "@Scatterer_atmosphere:HAS[@Atmo[" << body_name_map.at(name) << "]]:AFTER[aSLIPPIST-1] {\n"; kopernicus_cfg << " @Atmo[" << body_name_map.at(name) << "] {\n"; kopernicus_cfg << " @name = " << name << "\n"; kopernicus_cfg << " @configPoints {\n"; kopernicus_cfg << " @Item,* {\n"; kopernicus_cfg << " @altitude *= 2\n"; kopernicus_cfg << " }\n"; kopernicus_cfg << " }\n"; kopernicus_cfg << " }\n"; kopernicus_cfg << "}\n"; kopernicus_cfg << "@Scatterer_ocean:HAS[@Ocean[" << body_name_map.at(name) << "]]:AFTER[aSLIPPIST-1] {\n"; kopernicus_cfg << " @Ocean[" << body_name_map.at(name) << "] {\n"; kopernicus_cfg << " @name = " << name << "\n"; kopernicus_cfg << " }\n"; kopernicus_cfg << "}\n"; } } kopernicus_cfg << "@Scatterer_planetsList:AFTER[aSLIPPIST-1] {\n"; kopernicus_cfg << " @scattererCelestialBodies {\n"; for (std::string const& name : solar_system.names()) { bool const is_star = !solar_system.keplerian_initial_state_message(name).has_parent(); bool const is_kerbin = body_name_map.at(name) == kerbin; std::string const slippist_name = is_kerbin ? "Echo" : body_name_map.at(name); if (!is_star) { kopernicus_cfg << " @Item[" << slippist_name << "] {\n"; kopernicus_cfg << " @celestialBodyName = " << name << "\n"; kopernicus_cfg << " @transformName = " << name << "\n"; kopernicus_cfg << " }\n"; } } kopernicus_cfg << " }\n"; kopernicus_cfg << "}\n"; kopernicus_cfg << "@EVE_CLOUDS:AFTER[aSLIPPIST-1] {\n"; for (std::string const& name : solar_system.names()) { bool const is_star = !solar_system.keplerian_initial_state_message(name).has_parent(); if (!is_star) { kopernicus_cfg << " @OBJECT:HAS[#body[" << body_name_map.at(name) << "]] {\n"; kopernicus_cfg << " @body = " << name << "\n"; kopernicus_cfg << " @altitude *= 2\n"; kopernicus_cfg << " }\n"; } } kopernicus_cfg << "}\n"; kopernicus_cfg << "@EVE_SHADOWS:AFTER[aSLIPPIST-1] {\n"; for (std::string const& name : solar_system.names()) { bool const is_star = !solar_system.keplerian_initial_state_message(name).has_parent(); if (!is_star) { kopernicus_cfg << " @OBJECT:HAS[#body[" << body_name_map.at(name) << "]] {\n"; kopernicus_cfg << " @body = " << name << "\n"; kopernicus_cfg << " !caster,* = delete\n"; auto const elements = SolarSystem<Sky>::MakeKeplerianElements( solar_system.keplerian_initial_state_message(name).elements()); for (std::string const& caster_name : solar_system.names()) { bool const caster_is_star = !solar_system.keplerian_initial_state_message(caster_name) .has_parent(); if (!caster_is_star) { auto const caster_elements = SolarSystem<Sky>::MakeKeplerianElements( solar_system.keplerian_initial_state_message(caster_name) .elements()); if (caster_elements.period < elements.period) { kopernicus_cfg << " caster = " << caster_name << "\n"; } } } kopernicus_cfg << " }\n"; } } kopernicus_cfg << "}\n"; }
int Ephemeris<Frame>::serialization_index_for_body( not_null<MassiveBody const*> const body) const { return FindOrDie(unowned_bodies_indices_, body); }
not_null<ContinuousTrajectory<Frame> const*> Ephemeris<Frame>::trajectory( not_null<MassiveBody const*> body) const { return FindOrDie(bodies_to_trajectories_, body).get(); }
serialization::GravityModel::Body const& SolarSystem<Frame>::gravity_model_message(std::string const& name) const { return *FindOrDie(gravity_model_map_, name); }
serialization::InitialState::Body const& SolarSystem<Frame>::initial_state_message(std::string const& name) const { return *FindOrDie(initial_state_map_, name); }