/* * Copyright (C) 2023 Christopher J. Howard * * This file is part of Antkeeper source code. * * Antkeeper source code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper source code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper source code. If not, see . */ #include #include #include #include #include /// Offset to time data in the JPL DE header, in bytes. static constexpr std::size_t jpl_de_offset_time = 0xA5C; /// Offset to the first coefficient table in the JPL DE header, in bytes. static constexpr std::size_t jpl_de_offset_table1 = 0xA88; /// Offset to the DE version number in the JPL DE header, in bytes. static constexpr std::size_t jpl_de_offset_denum = 0xB18; /// Offset to the second coefficient table in the JPL DE header, in bytes. static constexpr std::size_t jpl_de_offset_table2 = 0xB1C; /// Offset to the third coefficient table in the JPL DE header, in bytes, if the constant limit has not been exceeded. static constexpr std::size_t jpl_de_offset_table3 = 0xB28; /// Mask to detect bytes in the most significant word of the JPL DE version number. static constexpr std::int32_t jpl_de_denum_endian_mask = 0xFFFF0000; /// Number of items in the first coefficient table. static constexpr std::size_t jpl_de_table1_count = 12; /// Number of items in the second coefficient table. static constexpr std::size_t jpl_de_table2_count = 1; /// Number of items in the third coefficient table. static constexpr std::size_t jpl_de_table3_count = 2; /// Maximum number of items in a JPL DE file. static constexpr std::size_t jpl_de_max_item_count = jpl_de_table1_count + jpl_de_table2_count + jpl_de_table3_count; /// Maximum number of constants in the first set of constant names. static constexpr std::size_t jpl_de_constant_limit = 400; /// Length of a constant name, in bytes. static constexpr std::size_t jpl_de_constant_length = 6; /// Enumerated IDs of the JPL DE items. enum { /// Mercury jpl_de_id_mercury, /// Venus jpl_de_id_venus, /// Earth-Moon barycenter jpl_de_id_embary, /// Mars jpl_de_id_mars, /// Jupiter jpl_de_id_jupiter, /// Saturn jpl_de_id_saturn, /// Uranus jpl_de_id_uranus, /// Neptune jpl_de_id_neptune, /// Pluto jpl_de_id_pluto, /// Moon jpl_de_id_moon, /// Sun jpl_de_id_sun, /// Earth nutation jpl_de_id_earth_nutation, /// Lunar mantle libration jpl_de_id_luma_libration, /// Lunar mantle angular velocity jpl_de_id_luma_angular_velocity, /// TT-TDB jpl_de_id_tt_tdb }; /// Number of components for each JPL DE item. static constexpr std::uint8_t jpl_de_component_count[jpl_de_max_item_count] = { 3, // Mercury: x,y,z (km) 3, // Venus: x,y,z (km) 3, // Earth-Moon barycenter: x,y,z (km) 3, // Mars: x,y,z (km) 3, // Jupiter: x,y,z (km) 3, // Saturn: x,y,z (km) 3, // Uranus: x,y,z (km) 3, // Neptune: x,y,z (km) 3, // Pluto: x,y,z (km) 3, // Moon: x,y,z (km) 3, // Sun: x,y,z (km) 2, // Earth nutation: d_psi,d_epsilon (radians) 3, // Lunar mantle libration: phi,theta,ps (radians) 3, // Lunar mantle angular velocity: omega_x,omega_y,omega_z (radians/day) 1 // TT-TDB: t (seconds) }; /** * Deserializes an ephemeris. * * @param[out] file Text file to serialize. * @param[in,out] ctx Deserialize context. * * @throw deserialize_error Read error. */ template <> void deserializer>::deserialize(physics::orbit::ephemeris& ephemeris, deserialize_context& ctx) { ephemeris.trajectories.clear(); // Init file reading function pointers std::size_t (deserialize_context::*read32)(std::byte*, std::size_t) = &deserialize_context::read32; std::size_t (deserialize_context::*read64)(std::byte*, std::size_t) = &deserialize_context::read64; // Read DE version number std::int32_t denum; ctx.seek(jpl_de_offset_denum); ctx.read8(reinterpret_cast(&denum), sizeof(std::int32_t)); // If file endianness does not match host endianness if (denum & jpl_de_denum_endian_mask) { // Use endian-swapping read functions if constexpr (std::endian::native == std::endian::little) { read32 = &deserialize_context::read32; read64 = &deserialize_context::read64; } else { read32 = &deserialize_context::read32; read64 = &deserialize_context::read64; } } // Read ephemeris time double ephemeris_time[3]; ctx.seek(jpl_de_offset_time); std::invoke(read64, ctx, reinterpret_cast(ephemeris_time), 3); // Make time relative to J2000 epoch const double epoch = 2451545.0; ephemeris_time[0] -= epoch; ephemeris_time[1] -= epoch; // Read number of constants std::int32_t constant_count; std::invoke(read32, ctx, reinterpret_cast(&constant_count), 1); // Read first coefficient table std::int32_t coeff_table[jpl_de_max_item_count][3]; ctx.seek(jpl_de_offset_table1); std::invoke(read32, ctx, reinterpret_cast(coeff_table), jpl_de_table1_count * 3); // Read second coefficient table ctx.seek(jpl_de_offset_table2); std::invoke(read32, ctx, reinterpret_cast(&coeff_table[jpl_de_table1_count][0]), jpl_de_table2_count * 3); // Seek past extra constant names if (constant_count > jpl_de_constant_limit) { ctx.seek(jpl_de_offset_table3 + (constant_count - jpl_de_constant_limit) * jpl_de_constant_length); } // Read third coefficient table std::invoke(read32, ctx, reinterpret_cast(&coeff_table[jpl_de_table1_count + jpl_de_table2_count][0]), jpl_de_table3_count * 3); // Calculate number of coefficients per record std::int32_t record_coeff_count = 0; for (int i = 0; i < jpl_de_max_item_count; ++i) { std::int32_t coeff_count = coeff_table[i][0] + coeff_table[i][1] * coeff_table[i][2] * static_cast(jpl_de_component_count[i]) - 1; record_coeff_count = std::max(record_coeff_count, coeff_count); } // Calculate record size and record count std::size_t record_size = record_coeff_count * sizeof(double); std::size_t record_count = static_cast((ephemeris_time[1] - ephemeris_time[0]) / ephemeris_time[2]); // Calculate coefficient strides std::size_t strides[11]; for (int i = 0; i < 11; ++i) { strides[i] = coeff_table[i][2] * coeff_table[i][1] * 3; } // Resize ephemeris to accommodate items 0-10 ephemeris.trajectories.resize(11); // Init trajectories for (int i = 0; i < 11; ++i) { auto& trajectory = ephemeris.trajectories[i]; trajectory.t0 = ephemeris_time[0]; trajectory.t1 = ephemeris_time[1]; trajectory.dt = ephemeris_time[2] / static_cast(coeff_table[i][2]); trajectory.n = coeff_table[i][1]; trajectory.a.resize(record_count * strides[i]); } // Read coefficients for (std::size_t i = 0; i < record_count; ++i) { // Seek to coefficient record ctx.seek((i + 2) * record_size + 2 * sizeof(double)); for (int j = 0; j < 11; ++j) { std::invoke(read64, ctx, reinterpret_cast(&ephemeris.trajectories[j].a[i * strides[j]]), strides[j]); } } } template <> std::unique_ptr> resource_loader>::load(::resource_manager& resource_manager, deserialize_context& ctx) { auto resource = std::make_unique>(); deserializer>().deserialize(*resource, ctx); return resource; }