From fc942786f8554be9b3a3a3b21aac85001057e401 Mon Sep 17 00:00:00 2001 From: pleroy Date: Sun, 26 Nov 2023 17:41:19 +0100 Subject: [PATCH 1/9] Collision computation. --- physics/apsides.hpp | 16 +++++++++++++++ physics/apsides_body.hpp | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/physics/apsides.hpp b/physics/apsides.hpp index 3fa6954fa0..32505461a1 100644 --- a/physics/apsides.hpp +++ b/physics/apsides.hpp @@ -5,8 +5,11 @@ #include "absl/status/status.h" #include "base/constant_function.hpp" #include "geometry/grassmann.hpp" +#include "physics/degrees_of_freedom.hpp" #include "physics/discrete_trajectory.hpp" +#include "physics/rotating_body.hpp" #include "physics/trajectory.hpp" +#include "quantities/quantities.hpp" namespace principia { namespace physics { @@ -15,8 +18,11 @@ namespace internal { using namespace principia::base::_constant_function; using namespace principia::geometry::_grassmann; +using namespace principia::physics::_degrees_of_freedom; using namespace principia::physics::_discrete_trajectory; +using namespace principia::physics::_rotating_body; using namespace principia::physics::_trajectory; +using namespace principia::quantities::_quantities; // Computes the apsides with respect to |reference| for the section given by // |begin| and |end| of |trajectory|. Appends to the given output trajectories @@ -30,6 +36,16 @@ void ComputeApsides(Trajectory const& reference, DiscreteTrajectory& apoapsides, DiscreteTrajectory& periapsides); +//TODO(phl)comment +template +typename DiscreteTrajectory::value_type ComputeCollision( + RotatingBody const& reference_body, + Trajectory const& reference, + Trajectory const& trajectory, + typename DiscreteTrajectory::iterator begin, + typename DiscreteTrajectory::iterator end, + std::function const&)> const& altitude); + // Computes the crossings of the section given by |begin| and |end| of // |trajectory| with the xy plane. Appends the crossings that go towards the // |north| side of the xy plane to |ascending|, and those that go away from the diff --git a/physics/apsides_body.hpp b/physics/apsides_body.hpp index 520c630ca3..734bcd5e83 100644 --- a/physics/apsides_body.hpp +++ b/physics/apsides_body.hpp @@ -134,6 +134,48 @@ void ComputeApsides(Trajectory const& reference, } } +template +typename DiscreteTrajectory::value_type ComputeCollision( + RotatingBody const& reference_body, + Trajectory const& reference, + Trajectory const& trajectory, + typename DiscreteTrajectory::iterator const begin, + typename DiscreteTrajectory::iterator const end, + std::function const&)> const& altitude) { + auto const last = std::prev(end); + DCHECK_LE(altitude(last->time), Length{}); + DCHECK_LE(Length{}, altitude(begin->time)); + + Square max_radius² = Pow<2>(reference_body.max_radius()); + + std::optional::iterator> + last_above_max_radius; + for (auto it = begin; it != end; ++it) { + auto const& [time, degrees_of_freedom] = *it; + DegreesOfFreedom const body_degrees_of_freedom = + reference.EvaluateDegreesOfFreedom(time); + RelativeDegreesOfFreedom const relative = + degrees_of_freedom - body_degrees_of_freedom; + Square const squared_distance = relative.displacement().Norm²(); + if (squared_distance <= max_radius²) { + break; + } else { + last_above_max_radius = it; + } + } + + Instant const collision_time = Brent( + [&altitude, &trajectory](Instant const& t) { + return altitude(trajectory.EvaluateDegreesOfFreedom(t)); + }, + last_above_max_radius.value_or(begin)->time, + last->time); + + return {.time = collision_time, + .degrees_of_freedom = + trajectory.EvaluateDegreesOfFreedom(collision_time)}; +} + template absl::Status ComputeNodes( Trajectory const& trajectory, From 09692a569f59070bd5c5568007467281d0d3edef Mon Sep 17 00:00:00 2001 From: pleroy Date: Mon, 27 Nov 2023 23:12:43 +0100 Subject: [PATCH 2/9] We don't like rotations from a frame to itself. --- physics/rotating_body.hpp | 3 --- physics/rotating_body_body.hpp | 5 ----- 2 files changed, 8 deletions(-) diff --git a/physics/rotating_body.hpp b/physics/rotating_body.hpp index 8528089523..f3ea2cc795 100644 --- a/physics/rotating_body.hpp +++ b/physics/rotating_body.hpp @@ -139,9 +139,6 @@ class RotatingBody : public MassiveBody { template Rotation ToCelestialFrame() const; - // Returns the rotation at time |t|. - Rotation RotationAt(Instant const& t) const; - // Returns false. bool is_massless() const override; diff --git a/physics/rotating_body_body.hpp b/physics/rotating_body_body.hpp index 70b629cce6..401362b217 100644 --- a/physics/rotating_body_body.hpp +++ b/physics/rotating_body_body.hpp @@ -143,11 +143,6 @@ Angle RotatingBody::AngleAt(Instant const& t) const { (t - parameters_.reference_instant_) * parameters_.angular_frequency_; } -template -Rotation RotatingBody::RotationAt(Instant const& t) const { - return Exp((t - parameters_.reference_instant_) * angular_velocity_); -} - template bool RotatingBody::is_massless() const { return false; From 69351c92a01a09bda52a6dc3940ef16c548a53ed Mon Sep 17 00:00:00 2001 From: pleroy Date: Mon, 27 Nov 2023 23:38:26 +0100 Subject: [PATCH 3/9] Computation of collisions. --- physics/apsides.hpp | 5 ++--- physics/apsides_body.hpp | 42 ++++++++++++++++++++++++++++++++-------- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/physics/apsides.hpp b/physics/apsides.hpp index 32505461a1..03fb8bacd7 100644 --- a/physics/apsides.hpp +++ b/physics/apsides.hpp @@ -5,7 +5,6 @@ #include "absl/status/status.h" #include "base/constant_function.hpp" #include "geometry/grassmann.hpp" -#include "physics/degrees_of_freedom.hpp" #include "physics/discrete_trajectory.hpp" #include "physics/rotating_body.hpp" #include "physics/trajectory.hpp" @@ -18,7 +17,6 @@ namespace internal { using namespace principia::base::_constant_function; using namespace principia::geometry::_grassmann; -using namespace principia::physics::_degrees_of_freedom; using namespace principia::physics::_discrete_trajectory; using namespace principia::physics::_rotating_body; using namespace principia::physics::_trajectory; @@ -44,7 +42,8 @@ typename DiscreteTrajectory::value_type ComputeCollision( Trajectory const& trajectory, typename DiscreteTrajectory::iterator begin, typename DiscreteTrajectory::iterator end, - std::function const&)> const& altitude); + std::function const& altitude); // Computes the crossings of the section given by |begin| and |end| of // |trajectory| with the xy plane. Appends the crossings that go towards the diff --git a/physics/apsides_body.hpp b/physics/apsides_body.hpp index 734bcd5e83..4540f4cfa8 100644 --- a/physics/apsides_body.hpp +++ b/physics/apsides_body.hpp @@ -3,12 +3,14 @@ #include "physics/apsides.hpp" #include -#include #include "base/array.hpp" #include "geometry/barycentre_calculator.hpp" +#include "geometry/frame.hpp" #include "geometry/instant.hpp" +#include "geometry/r3_element.hpp" #include "geometry/sign.hpp" +#include "geometry/space.hpp" #include "numerics/hermite3.hpp" #include "numerics/root_finders.hpp" #include "physics/degrees_of_freedom.hpp" @@ -23,7 +25,9 @@ namespace internal { using namespace principia::base::_array; using namespace principia::geometry::_barycentre_calculator; using namespace principia::geometry::_instant; +using namespace principia::geometry::_r3_element; using namespace principia::geometry::_sign; +using namespace principia::geometry::_space; using namespace principia::numerics::_hermite3; using namespace principia::numerics::_root_finders; using namespace principia::physics::_degrees_of_freedom; @@ -141,7 +145,11 @@ typename DiscreteTrajectory::value_type ComputeCollision( Trajectory const& trajectory, typename DiscreteTrajectory::iterator const begin, typename DiscreteTrajectory::iterator const end, - std::function const&)> const& altitude) { + std::function const& altitude) { + // The frame of the surface of the celestial. + using SurfaceFrame = geometry::_frame::Frame; + auto const last = std::prev(end); DCHECK_LE(altitude(last->time), Length{}); DCHECK_LE(Length{}, altitude(begin->time)); @@ -164,12 +172,30 @@ typename DiscreteTrajectory::value_type ComputeCollision( } } - Instant const collision_time = Brent( - [&altitude, &trajectory](Instant const& t) { - return altitude(trajectory.EvaluateDegreesOfFreedom(t)); - }, - last_above_max_radius.value_or(begin)->time, - last->time); + auto altitude_at_time = [&altitude, + &reference, + &reference_body, + &trajectory](Instant const& t) { + auto const reference_position = reference.EvaluatePosition(t); + auto const trajectory_position = trajectory.EvaluatePosition(t); + Displacement const displacement_in_frame = + trajectory_position - reference_position; + + auto const to_surface_frame = reference_body.ToSurfaceFrame(t); + Displacement const displacement_in_surface = + to_surface_frame(displacement_in_frame); + + SphericalCoordinates const spherical_coordinates = + displacement_in_surface.coordinates().ToSpherical(); + + return altitude(spherical_coordinates.latitude, + spherical_coordinates.longitude); + }; + + Instant const collision_time = + Brent(altitude_at_time, + last_above_max_radius.value_or(begin)->time, + last->time); return {.time = collision_time, .degrees_of_freedom = From 2cec0e3db4763f9b19ba4b3371d2db6a7783bc0c Mon Sep 17 00:00:00 2001 From: pleroy Date: Thu, 30 Nov 2023 21:59:11 +0100 Subject: [PATCH 4/9] A test. --- geometry/r3_element.hpp | 5 +++ geometry/r3_element_body.hpp | 10 ++++++ physics/apsides.hpp | 3 +- physics/apsides_body.hpp | 38 +++++++++++++--------- physics/apsides_test.cpp | 61 ++++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 16 deletions(-) diff --git a/geometry/r3_element.hpp b/geometry/r3_element.hpp index eb901bf322..257d6e0ec1 100644 --- a/geometry/r3_element.hpp +++ b/geometry/r3_element.hpp @@ -94,6 +94,11 @@ SphericalCoordinates RadiusLatitudeLongitude(Scalar const& radius, Angle const& latitude, Angle const& longitude); +template +std::ostream& operator<<( + std::ostream& out, + SphericalCoordinates const& spherical_coordinates); + template R3Element operator+(R3Element const& right); template diff --git a/geometry/r3_element_body.hpp b/geometry/r3_element_body.hpp index 5089778d53..f062bec495 100644 --- a/geometry/r3_element_body.hpp +++ b/geometry/r3_element_body.hpp @@ -206,6 +206,16 @@ SphericalCoordinates RadiusLatitudeLongitude(Scalar const& radius, return result; } +template +std::ostream& operator<<( + std::ostream& out, + SphericalCoordinates const& spherical_coordinates) { + out << spherical_coordinates.radius + << ", " << spherical_coordinates.latitude + << ", " << spherical_coordinates.longitude; + return out; +} + template R3Element operator+(R3Element const& right) { return R3Element(+right.x, +right.y, +right.z); diff --git a/physics/apsides.hpp b/physics/apsides.hpp index 03fb8bacd7..24a1093500 100644 --- a/physics/apsides.hpp +++ b/physics/apsides.hpp @@ -43,7 +43,7 @@ typename DiscreteTrajectory::value_type ComputeCollision( typename DiscreteTrajectory::iterator begin, typename DiscreteTrajectory::iterator end, std::function const& altitude); + Angle const& longitude)> const& radius); // Computes the crossings of the section given by |begin| and |end| of // |trajectory| with the xy plane. Appends the crossings that go towards the @@ -75,6 +75,7 @@ void ComputeApsides(Trajectory const& trajectory1, } // namespace internal using internal::ComputeApsides; +using internal::ComputeCollision; using internal::ComputeNodes; } // namespace _apsides diff --git a/physics/apsides_body.hpp b/physics/apsides_body.hpp index 4540f4cfa8..43565efd0b 100644 --- a/physics/apsides_body.hpp +++ b/physics/apsides_body.hpp @@ -146,14 +146,11 @@ typename DiscreteTrajectory::value_type ComputeCollision( typename DiscreteTrajectory::iterator const begin, typename DiscreteTrajectory::iterator const end, std::function const& altitude) { + Angle const& longitude)> const& radius) { // The frame of the surface of the celestial. using SurfaceFrame = geometry::_frame::Frame; auto const last = std::prev(end); - DCHECK_LE(altitude(last->time), Length{}); - DCHECK_LE(Length{}, altitude(begin->time)); - Square max_radius² = Pow<2>(reference_body.max_radius()); std::optional::iterator> @@ -172,34 +169,45 @@ typename DiscreteTrajectory::value_type ComputeCollision( } } - auto altitude_at_time = [&altitude, - &reference, - &reference_body, - &trajectory](Instant const& t) { + auto radius_at_time = [&radius, + &reference, + &reference_body, + &trajectory](Instant const& t) { auto const reference_position = reference.EvaluatePosition(t); auto const trajectory_position = trajectory.EvaluatePosition(t); + LOG(ERROR)< const displacement_in_frame = trajectory_position - reference_position; + LOG(ERROR)<(t); Displacement const displacement_in_surface = to_surface_frame(displacement_in_frame); + LOG(ERROR)< const spherical_coordinates = displacement_in_surface.coordinates().ToSpherical(); - return altitude(spherical_coordinates.latitude, - spherical_coordinates.longitude); + LOG(ERROR)<time)); + CHECK_LT(radius_at_time(last->time), Length{}); + Instant const collision_time = - Brent(altitude_at_time, + Brent(radius_at_time, last_above_max_radius.value_or(begin)->time, last->time); - return {.time = collision_time, - .degrees_of_freedom = - trajectory.EvaluateDegreesOfFreedom(collision_time)}; + return typename DiscreteTrajectory::value_type( + collision_time, + trajectory.EvaluateDegreesOfFreedom(collision_time)); } template diff --git a/physics/apsides_test.cpp b/physics/apsides_test.cpp index 167d3e28fe..3352be0981 100644 --- a/physics/apsides_test.cpp +++ b/physics/apsides_test.cpp @@ -23,12 +23,14 @@ #include "physics/kepler_orbit.hpp" #include "physics/massive_body.hpp" #include "physics/massless_body.hpp" +#include "physics/rotating_body.hpp" #include "quantities/astronomy.hpp" #include "quantities/elementary_functions.hpp" #include "quantities/named_quantities.hpp" #include "quantities/quantities.hpp" #include "quantities/si.hpp" #include "testing_utilities/almost_equals.hpp" +#include "testing_utilities/discrete_trajectory_factories.hpp" #include "testing_utilities/matchers.hpp" // 🧙 For EXPECT_OK. namespace principia { @@ -51,12 +53,14 @@ using namespace principia::physics::_ephemeris; using namespace principia::physics::_kepler_orbit; using namespace principia::physics::_massive_body; using namespace principia::physics::_massless_body; +using namespace principia::physics::_rotating_body; using namespace principia::quantities::_astronomy; using namespace principia::quantities::_elementary_functions; using namespace principia::quantities::_named_quantities; using namespace principia::quantities::_quantities; using namespace principia::quantities::_si; using namespace principia::testing_utilities::_almost_equals; +using namespace principia::testing_utilities::_discrete_trajectory_factories; class ApsidesTest : public ::testing::Test { protected: @@ -162,6 +166,63 @@ TEST_F(ApsidesTest, ComputeApsidesDiscreteTrajectory) { } } +TEST_F(ApsidesTest, ComputeCollision) { + Instant const t0; + DiscreteTrajectory reference_trajectory; + DiscreteTrajectory vessel_trajectory; + AppendTrajectoryTimeline( + NewLinearTrajectoryTimeline( + DegreesOfFreedom( + World::origin + + Displacement({0 * Metre, -1 * Metre, 0 * Metre}), + Velocity({1 * Metre / Second, + 0 * Metre / Second, + 0 * Metre / Second})), + /*Δt=*/1 * Second, + t0, + /*t1=*/t0 - 10 * Second, + /*t2=*/t0 + 10 * Second), + reference_trajectory); + AppendTrajectoryTimeline( + NewLinearTrajectoryTimeline( + DegreesOfFreedom( + World::origin + + Displacement({1 * Metre, -1 * Metre, 0 * Metre}), + Velocity({0 * Metre / Second, + -1 * Metre / Second, + 0 * Metre / Second})), + /*Δt=*/1 * Second, + t0, + /*t1=*/t0 - 10 * Second, + /*t2=*/t0 + 1 * Second), + vessel_trajectory); + + RotatingBody const body( + 1 * Kilogram, + RotatingBody::Parameters( + /*min_radius=*/1 * Metre, + /*mean_radius=*/2 * Metre, + /*max_radius=*/3 * Metre, + /*reference_angle=*/0 * Radian, + /*reference_instant=*/t0, + /*angular_frequency=*/2 * π * Radian / Second, + /*right_ascension_of_pole=*/0 * Radian, + /*declination_of_pole=*/π / 2 * Radian)); + + auto radius = [](Angle const& latitude, Angle const& longitude) { + return (Cos(4 * longitude) + 2) * Metre; + }; + + auto const collision = ComputeCollision(body, + reference_trajectory, + vessel_trajectory, + vessel_trajectory.begin(), + vessel_trajectory.end(), + radius); + + LOG(ERROR)< Date: Sat, 2 Dec 2023 14:12:51 +0100 Subject: [PATCH 5/9] A test. --- physics/apsides_test.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/physics/apsides_test.cpp b/physics/apsides_test.cpp index 3352be0981..55d006960d 100644 --- a/physics/apsides_test.cpp +++ b/physics/apsides_test.cpp @@ -30,7 +30,10 @@ #include "quantities/quantities.hpp" #include "quantities/si.hpp" #include "testing_utilities/almost_equals.hpp" +#include "testing_utilities/approximate_quantity.hpp" +#include "testing_utilities/componentwise.hpp" #include "testing_utilities/discrete_trajectory_factories.hpp" +#include "testing_utilities/is_near.hpp" #include "testing_utilities/matchers.hpp" // 🧙 For EXPECT_OK. namespace principia { @@ -59,8 +62,11 @@ using namespace principia::quantities::_elementary_functions; using namespace principia::quantities::_named_quantities; using namespace principia::quantities::_quantities; using namespace principia::quantities::_si; +using namespace principia::testing_utilities::_approximate_quantity; using namespace principia::testing_utilities::_almost_equals; +using namespace principia::testing_utilities::_componentwise; using namespace principia::testing_utilities::_discrete_trajectory_factories; +using namespace principia::testing_utilities::_is_near; class ApsidesTest : public ::testing::Test { protected: @@ -170,6 +176,9 @@ TEST_F(ApsidesTest, ComputeCollision) { Instant const t0; DiscreteTrajectory reference_trajectory; DiscreteTrajectory vessel_trajectory; + + // At |t0| the vessel is inside the celestial, so we expect the collision at a + // negative time. AppendTrajectoryTimeline( NewLinearTrajectoryTimeline( DegreesOfFreedom( @@ -209,6 +218,8 @@ TEST_F(ApsidesTest, ComputeCollision) { /*right_ascension_of_pole=*/0 * Radian, /*declination_of_pole=*/π / 2 * Radian)); + // The celestial is infinite in the z direction and has four lobes in the x-y + // plane. Think of a LEGO® axle. auto radius = [](Angle const& latitude, Angle const& longitude) { return (Cos(4 * longitude) + 2) * Metre; }; @@ -220,7 +231,17 @@ TEST_F(ApsidesTest, ComputeCollision) { vessel_trajectory.end(), radius); - LOG(ERROR)<({0 * Metre / Second, + -1 * Metre / Second, + 0 * Metre / Second}), 0)); } TEST_F(ApsidesTest, ComputeNodes) { From e6a02dde859107fe396ca28c25995cd84253ead6 Mon Sep 17 00:00:00 2001 From: pleroy Date: Sat, 2 Dec 2023 14:14:02 +0100 Subject: [PATCH 6/9] IWYUsing. --- physics/apsides_body.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/physics/apsides_body.hpp b/physics/apsides_body.hpp index 43565efd0b..7278b50ea9 100644 --- a/physics/apsides_body.hpp +++ b/physics/apsides_body.hpp @@ -6,7 +6,6 @@ #include "base/array.hpp" #include "geometry/barycentre_calculator.hpp" -#include "geometry/frame.hpp" #include "geometry/instant.hpp" #include "geometry/r3_element.hpp" #include "geometry/sign.hpp" @@ -15,7 +14,6 @@ #include "numerics/root_finders.hpp" #include "physics/degrees_of_freedom.hpp" #include "quantities/named_quantities.hpp" -#include "quantities/quantities.hpp" namespace principia { namespace physics { @@ -32,7 +30,6 @@ using namespace principia::numerics::_hermite3; using namespace principia::numerics::_root_finders; using namespace principia::physics::_degrees_of_freedom; using namespace principia::quantities::_named_quantities; -using namespace principia::quantities::_quantities; template void ComputeApsides(Trajectory const& reference, From f7152a316b373753d21d1f70de648d00a363e062 Mon Sep 17 00:00:00 2001 From: pleroy Date: Sat, 2 Dec 2023 14:16:15 +0100 Subject: [PATCH 7/9] Comment. --- physics/apsides.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/physics/apsides.hpp b/physics/apsides.hpp index 24a1093500..ff8051dee7 100644 --- a/physics/apsides.hpp +++ b/physics/apsides.hpp @@ -34,7 +34,10 @@ void ComputeApsides(Trajectory const& reference, DiscreteTrajectory& apoapsides, DiscreteTrajectory& periapsides); -//TODO(phl)comment +// Computes a collision between a vessel and a rotating body. |begin| and |end| +// must be on opposite sides of the surface of the body (that is, a collision +// must exist). |radius| gives the radius of the celestial at a particular +// position given by its latitude and longitude. template typename DiscreteTrajectory::value_type ComputeCollision( RotatingBody const& reference_body, From a6ef04885fe9e67fca9031d98575151b8fb5aa15 Mon Sep 17 00:00:00 2001 From: pleroy Date: Sat, 2 Dec 2023 14:28:11 +0100 Subject: [PATCH 8/9] Remove logging. --- physics/apsides_body.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/physics/apsides_body.hpp b/physics/apsides_body.hpp index 7278b50ea9..21f52a4df6 100644 --- a/physics/apsides_body.hpp +++ b/physics/apsides_body.hpp @@ -172,23 +172,17 @@ typename DiscreteTrajectory::value_type ComputeCollision( &trajectory](Instant const& t) { auto const reference_position = reference.EvaluatePosition(t); auto const trajectory_position = trajectory.EvaluatePosition(t); - LOG(ERROR)< const displacement_in_frame = trajectory_position - reference_position; - LOG(ERROR)<(t); Displacement const displacement_in_surface = to_surface_frame(displacement_in_frame); - LOG(ERROR)< const spherical_coordinates = displacement_in_surface.coordinates().ToSpherical(); - LOG(ERROR)< Date: Sat, 2 Dec 2023 17:55:38 +0100 Subject: [PATCH 9/9] After egg's review. --- physics/apsides.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/physics/apsides.hpp b/physics/apsides.hpp index ff8051dee7..c30fe281d4 100644 --- a/physics/apsides.hpp +++ b/physics/apsides.hpp @@ -35,9 +35,10 @@ void ComputeApsides(Trajectory const& reference, DiscreteTrajectory& periapsides); // Computes a collision between a vessel and a rotating body. |begin| and |end| -// must be on opposite sides of the surface of the body (that is, a collision -// must exist). |radius| gives the radius of the celestial at a particular -// position given by its latitude and longitude. +// must be on opposite sides of the surface of the body (in particular, a +// collision must exist). |radius| gives the radius of the celestial at a +// particular position given by its latitude and longitude. It must never +// exceed the |max_radius| of the body. template typename DiscreteTrajectory::value_type ComputeCollision( RotatingBody const& reference_body,