Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: c1edd32e5843
Choose a base ref
...
head repository: mockingbirdnest/Principia
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 051e7aa0c6c1
Choose a head ref
  • 6 commits
  • 9 files changed
  • 1 contributor

Commits on Mar 4, 2017

  1. Serialization compiles.

    pleroy committed Mar 4, 2017
    Copy the full SHA
    e178953 View commit details
  2. Serialization test.

    pleroy committed Mar 4, 2017
    Copy the full SHA
    5068f71 View commit details
  3. Test passes.

    pleroy committed Mar 4, 2017
    Copy the full SHA
    50cdbc3 View commit details
  4. Use fixed32.

    pleroy committed Mar 4, 2017
    Copy the full SHA
    0dff9fd View commit details
  5. Copy the full SHA
    4f5c7a6 View commit details
  6. Merge pull request #1224 from pleroy/Serialization

    Serialization of pile-ups
    pleroy authored Mar 4, 2017
    Copy the full SHA
    051e7aa View commit details
17 changes: 17 additions & 0 deletions ksp_plugin/identification.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <limits>

namespace principia {
namespace ksp_plugin {

// Corresponds to KSP's |Part.flightID|, *not* to |Part.uid|. C#'s |uint|
// corresponds to |uint32_t|.
using PartId = std::uint32_t;

// An ID given to dummy parts used by vessels that appear unloaded. Note that
// nothing prevents an actual part from having this ID.
constexpr PartId DummyPartId = std::numeric_limits<PartId>::max();

} // namespace ksp_plugin
} // namespace principia
1 change: 1 addition & 0 deletions ksp_plugin/ksp_plugin.vcxproj
Original file line number Diff line number Diff line change
@@ -331,6 +331,7 @@ copy /Y "$(OutDir)$(TargetName).pdb" "$(SolutionDir)$(Configuration)\GameData\Pr
<ClInclude Include="burn.hpp" />
<ClInclude Include="celestial.hpp" />
<ClInclude Include="celestial_body.hpp" />
<ClInclude Include="identification.hpp" />
<ClInclude Include="part_subsets.hpp" />
<ClInclude Include="pile_up.hpp" />
<ClInclude Include="flight_plan.hpp" />
3 changes: 3 additions & 0 deletions ksp_plugin/ksp_plugin.vcxproj.filters
Original file line number Diff line number Diff line change
@@ -56,6 +56,9 @@
<ClInclude Include="part_subsets.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="identification.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="interface.cpp">
11 changes: 1 addition & 10 deletions ksp_plugin/part.hpp
Original file line number Diff line number Diff line change
@@ -3,14 +3,14 @@

#include <experimental/optional>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <memory>

#include "base/container_iterator.hpp"
#include "base/disjoint_sets.hpp"
#include "ksp_plugin/frames.hpp"
#include "ksp_plugin/identification.hpp"
#include "ksp_plugin/part_subsets.hpp"
#include "ksp_plugin/pile_up.hpp"
#include "geometry/grassmann.hpp"
@@ -35,13 +35,6 @@ using physics::DiscreteTrajectory;
using quantities::Force;
using quantities::Mass;

// Corresponds to KSP's |Part.flightID|, *not* to |Part.uid|. C#'s |uint|
// corresponds to |uint32_t|.
using PartId = std::uint32_t;
// An ID given to dummy parts used by vessels that appear unloaded. Note that
// nothing prevents an actual part from having this ID.
constexpr PartId DummyPartId = std::numeric_limits<PartId>::max();

// Represents a KSP part.
class Part final {
public:
@@ -137,10 +130,8 @@ using IdAndOwnedPart = PartIdToOwnedPart::value_type;

} // namespace internal_part

using internal_part::DummyPartId;
using internal_part::IdAndOwnedPart;
using internal_part::Part;
using internal_part::PartId;
using internal_part::PartIdToOwnedPart;

} // namespace ksp_plugin
85 changes: 73 additions & 12 deletions ksp_plugin/pile_up.cpp
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ namespace ksp_plugin {
namespace internal_pile_up {

using base::FindOrDie;
using base::make_not_null_unique;
using geometry::AngularVelocity;
using geometry::BarycentreCalculator;
using geometry::Identity;
@@ -24,7 +25,8 @@ using physics::RigidMotion;
using physics::RigidTransformation;

PileUp::PileUp(std::list<not_null<Part*>>&& parts, Instant const& t)
: parts_(std::move(parts)) {
: parts_(std::move(parts)),
psychohistory_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()) {
BarycentreCalculator<DegreesOfFreedom<Barycentric>, Mass> calculator;
Vector<Force, Barycentric> total_intrinsic_force;
for (not_null<Part*> const part : parts_) {
@@ -34,7 +36,7 @@ PileUp::PileUp(std::list<not_null<Part*>>&& parts, Instant const& t)
mass_ = calculator.weight();
intrinsic_force_ = total_intrinsic_force;
DegreesOfFreedom<Barycentric> const barycentre = calculator.Get();
psychohistory_.Append(t, barycentre);
psychohistory_->Append(t, barycentre);

RigidMotion<Barycentric, RigidPileUp> const barycentric_to_pile_up{
RigidTransformation<Barycentric, RigidPileUp>{
@@ -125,20 +127,20 @@ void PileUp::AdvanceTime(
Ephemeris<Barycentric>::FixedStepParameters const& fixed_step_parameters,
Ephemeris<Barycentric>::AdaptiveStepParameters const&
adaptive_step_parameters) {
CHECK_EQ(psychohistory_.Size(), 1);
CHECK_EQ(psychohistory_->Size(), 1);

DiscreteTrajectory<Barycentric> prolongation;

if (intrinsic_force_ == Vector<Force, Barycentric>{}) {
ephemeris.FlowWithFixedStep(
{&psychohistory_},
{psychohistory_.get()},
Ephemeris<Barycentric>::NoIntrinsicAccelerations,
t,
fixed_step_parameters);
if (psychohistory_.last().time() < t) {
if (psychohistory_->last().time() < t) {
// TODO(phl): Consider using forks.
prolongation.Append(psychohistory_.last().time(),
psychohistory_.last().degrees_of_freedom());
prolongation.Append(psychohistory_->last().time(),
psychohistory_->last().degrees_of_freedom());
CHECK(ephemeris.FlowWithAdaptiveStep(
&prolongation,
Ephemeris<Barycentric>::NoIntrinsicAcceleration,
@@ -152,29 +154,29 @@ void PileUp::AdvanceTime(
auto const a = intrinsic_force_ / mass_;
auto const intrinsic_acceleration = [a](Instant const& t) { return a; };
CHECK(ephemeris.FlowWithAdaptiveStep(
&psychohistory_,
psychohistory_.get(),
intrinsic_acceleration,
t,
adaptive_step_parameters,
Ephemeris<Barycentric>::unlimited_max_ephemeris_steps,
/*last_point_only=*/false));
}
auto it = psychohistory_.Begin();
auto it = psychohistory_->Begin();
++it;
for (; it != psychohistory_.End(); ++it) {
for (; it != psychohistory_->End(); ++it) {
AppendToPartTails(it, /*authoritative=*/true);
}
// TODO(phl): you have reinvented the map. Now I want an empty :-p
if (prolongation.Size() != 0) {
CHECK_EQ(prolongation.Size(), 2);
AppendToPartTails(prolongation.last(), /*authoritative=*/false);
}
psychohistory_.ForgetBefore(psychohistory_.last().time());
psychohistory_->ForgetBefore(psychohistory_->last().time());
}

void PileUp::NudgeParts() const {
auto const actual_centre_of_mass =
psychohistory_.last().degrees_of_freedom();
psychohistory_->last().degrees_of_freedom();

RigidMotion<Barycentric, RigidPileUp> const barycentric_to_pile_up{
RigidTransformation<Barycentric, RigidPileUp>{
@@ -190,6 +192,65 @@ void PileUp::NudgeParts() const {
}
}

void PileUp::WriteToMessage(not_null<serialization::PileUp*> message) const {
for (auto const part : parts_) {
message->add_part_id(part->part_id());
}
mass_.WriteToMessage(message->mutable_mass());
intrinsic_force_.WriteToMessage(message->mutable_intrinsic_force());
psychohistory_->WriteToMessage(message->mutable_psychohistory(),
/*forks=*/{});
for (auto const& pair : actual_part_degrees_of_freedom_) {
auto const part = pair.first;
auto const& degrees_of_freedom = pair.second;
degrees_of_freedom.WriteToMessage(&(
(*message->mutable_actual_part_degrees_of_freedom())[part->part_id()]));
}
for (auto const& pair : apparent_part_degrees_of_freedom_) {
auto const part = pair.first;
auto const& degrees_of_freedom = pair.second;
degrees_of_freedom.WriteToMessage(&(
(*message
->mutable_apparent_part_degrees_of_freedom())[part->part_id()]));
}
}

not_null<std::unique_ptr<PileUp>> PileUp::ReadFromMessage(
serialization::PileUp const& message,
std::function<not_null<Part*>(PartId)> const& part_id_to_part) {
std::list<not_null<Part*>> parts;
for (auto const part_id : message.part_id()) {
parts.push_back(part_id_to_part(part_id));
}
not_null<std::unique_ptr<PileUp>> pile_up =
std::unique_ptr<PileUp>(new PileUp(std::move(parts)));
pile_up->mass_ = Mass::ReadFromMessage(message.mass());
pile_up->intrinsic_force_ =
Vector<Force, Barycentric>::ReadFromMessage(message.intrinsic_force());
pile_up->psychohistory_ =
DiscreteTrajectory<Barycentric>::ReadFromMessage(message.psychohistory(),
/*forks=*/{});
for (auto const& pair : message.actual_part_degrees_of_freedom()) {
std::uint32_t const part_id = pair.first;
serialization::Pair const& degrees_of_freedom = pair.second;
pile_up->actual_part_degrees_of_freedom_.emplace(
part_id_to_part(part_id),
DegreesOfFreedom<RigidPileUp>::ReadFromMessage(degrees_of_freedom));
}
for (auto const& pair : message.apparent_part_degrees_of_freedom()) {
std::uint32_t const part_id = pair.first;
serialization::Pair const& degrees_of_freedom = pair.second;
pile_up->apparent_part_degrees_of_freedom_.emplace(
part_id_to_part(part_id),
DegreesOfFreedom<ApparentBubble>::ReadFromMessage(degrees_of_freedom));
}
return pile_up;
}

PileUp::PileUp(std::list<not_null<Part*>>&& parts)
: parts_(std::move(parts)),
psychohistory_(make_not_null_unique<DiscreteTrajectory<Barycentric>>()) {}

void PileUp::AppendToPartTails(
DiscreteTrajectory<Barycentric>::Iterator const it,
bool const authoritative) const {
11 changes: 10 additions & 1 deletion ksp_plugin/pile_up.hpp
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
#include "physics/ephemeris.hpp"
#include "physics/massless_body.hpp"
#include "ksp_plugin/frames.hpp"
#include "ksp_plugin/identification.hpp"

namespace principia {
namespace ksp_plugin {
@@ -78,7 +79,15 @@ class PileUp {
// |DeformPileUpIfNeeded|.
void NudgeParts() const;

void WriteToMessage(not_null<serialization::PileUp*> message) const;
static not_null<std::unique_ptr<PileUp>> ReadFromMessage(
serialization::PileUp const& message,
std::function<not_null<Part*>(PartId)> const& part_id_to_part);

private:
// For deserialization.
explicit PileUp::PileUp(std::list<not_null<Part*>>&& parts);

void AppendToPartTails(DiscreteTrajectory<Barycentric>::Iterator it,
bool authoritative) const;

@@ -93,7 +102,7 @@ class PileUp {
// with nonzero intrinsic force), or a fixed step instance otherwise (with the
// prolongation being computed by an instance local to the body of
// |AdvanceTime|).
DiscreteTrajectory<Barycentric> psychohistory_;
not_null<std::unique_ptr<DiscreteTrajectory<Barycentric>>> psychohistory_;

// The |PileUp| is seen as a (currently non-rotating) rigid body; the degrees
// of freedom of the parts in the frame of that body can be set, however their
35 changes: 34 additions & 1 deletion ksp_plugin_test/pile_up_test.cpp
Original file line number Diff line number Diff line change
@@ -74,7 +74,7 @@ class TestablePileUp : public PileUp {
}

DiscreteTrajectory<Barycentric> const& psychohistory() const {
return psychohistory_;
return *psychohistory_;
}

std::map<not_null<Part*>, DegreesOfFreedom<RigidPileUp>> const&
@@ -489,6 +489,39 @@ TEST_F(PileUpTest, LifecycleWithoutIntrinsicForce) {
890.6 / 9.0 * Metre / Second}), 1)));
}

TEST_F(PileUpTest, Serialization) {
p1_.increment_intrinsic_force(
Vector<Force, Barycentric>({1 * Newton, 2 * Newton, 3 * Newton}));
p2_.increment_intrinsic_force(
Vector<Force, Barycentric>({11 * Newton, 21 * Newton, 31 * Newton}));
TestablePileUp pile_up({&p1_, &p2_}, astronomy::J2000);

serialization::PileUp message;
pile_up.WriteToMessage(&message);

EXPECT_EQ(2, message.part_id_size());
EXPECT_EQ(part_id1_, message.part_id(0));
EXPECT_EQ(part_id2_, message.part_id(1));
EXPECT_EQ(1, message.psychohistory().timeline_size());
EXPECT_EQ(2, message.actual_part_degrees_of_freedom().size());
EXPECT_TRUE(message.apparent_part_degrees_of_freedom().empty());

auto const part_id_to_part = [this](PartId const part_id) {
if (part_id == part_id1_) {
return &p1_;
}
if (part_id == part_id2_) {
return &p2_;
}
LOG(FATAL) << "Unexpected part id " << part_id;
};
auto const p = PileUp::ReadFromMessage(message, part_id_to_part);

serialization::PileUp second_message;
p->WriteToMessage(&second_message);
EXPECT_EQ(message.SerializeAsString(), second_message.SerializeAsString());
}

} // namespace internal_pile_up
} // namespace ksp_plugin
} // namespace principia
63 changes: 36 additions & 27 deletions serialization/ksp_plugin.proto
Original file line number Diff line number Diff line change
@@ -19,14 +19,42 @@ message CelestialJacobiKeplerian {
required MassiveBody body = 4;
}

message FlightPlan {
required Quantity initial_mass = 1;
required Point initial_time = 2;
optional Pair initial_degrees_of_freedom = 12; // required.
required Point desired_final_time = 3;
repeated Manoeuvre manoeuvre = 8;
optional Ephemeris.AdaptiveStepParameters
adaptive_step_parameters = 11; // required

// Pre-Буняковский.
optional Quantity length_integration_tolerance = 4;
optional Quantity speed_integration_tolerance = 5;
optional AdaptiveStepSizeIntegrator integrator = 6;
repeated DiscreteTrajectory.Pointer segment = 7;
reserved 9, 10;
reserved "anomalous_segments", "max_steps";
}

// Pre-Буняковский.
message HistoryAndProlongation {
required DiscreteTrajectory history = 1;
required DiscreteTrajectory.Pointer prolongation = 2;
}

message Manoeuvre {
required Quantity thrust = 1;
required Quantity initial_mass = 2;
required Quantity specific_impulse = 3;
required Multivector direction = 4;
required Quantity duration = 5;
required Point initial_time = 6;
required DynamicFrame frame = 7;
}

message Part {
required uint32 part_id = 4;
required fixed32 part_id = 4;
required Quantity mass = 2;
required Multivector intrinsic_force = 5;
optional int32 containing_pile_up = 6; // TODO(phl): Do the right thing.
@@ -39,32 +67,13 @@ message Part {
reserved "gravitational_acceleration_to_be_applied_by_ksp";
}

message Manoeuvre {
required Quantity thrust = 1;
required Quantity initial_mass = 2;
required Quantity specific_impulse = 3;
required Multivector direction = 4;
required Quantity duration = 5;
required Point initial_time = 6;
required DynamicFrame frame = 7;
}

message FlightPlan {
required Quantity initial_mass = 1;
required Point initial_time = 2;
optional Pair initial_degrees_of_freedom = 12; // required.
required Point desired_final_time = 3;
repeated Manoeuvre manoeuvre = 8;
optional Ephemeris.AdaptiveStepParameters
adaptive_step_parameters = 11; // required

// Pre-Буняковский.
optional Quantity length_integration_tolerance = 4;
optional Quantity speed_integration_tolerance = 5;
optional AdaptiveStepSizeIntegrator integrator = 6;
repeated DiscreteTrajectory.Pointer segment = 7;
reserved 9, 10;
reserved "anomalous_segments", "max_steps";
message PileUp {
repeated fixed32 part_id = 1;
required Quantity mass = 2;
required Multivector intrinsic_force = 3;
required DiscreteTrajectory psychohistory = 4;
map<uint32, Pair> actual_part_degrees_of_freedom = 5;
map<uint32, Pair> apparent_part_degrees_of_freedom = 6;
}

message Plugin {
Loading