Program Listing for File clock.cc

Return to documentation for file (devices/clock.cc)

#include "lupnt/devices/clock.h"

#include "lupnt/agents/agent.h"
#include "lupnt/conversions/frame_converter.h"
#include "lupnt/core/asset_factory.h"
#include "lupnt/core/data_logger.h"
#include "lupnt/core/definitions.h"
#include "lupnt/core/error.h"
#include "lupnt/core/logger.h"
#include "lupnt/environment/body.h"

namespace lupnt {

  // Clock
  Clock::Clock() : Device() {
    Logger::Debug(fmt::format("Creating {}", name_), "Clock");
    dynamics_ = MakePtr<ClockDynamics>();
    ApplyClockStateUnits();
  }

  // Constructor
  Clock::Clock(Config& config) : Device(config) {
    Logger::Debug(fmt::format("Creating {}", name_), "Clock");
    dynamics_ = MakePtr<ClockDynamics>();
    if (config["model"]) {
      model_ = enum_cast<ClockModel>(config["model"].as<std::string>()).value();
      dynamics_->SetModel(model_);
    }
    if (config["clock_bias_unit"]) {
      SetClockBiasUnit(
          enum_cast<ClockBiasUnit>(config["clock_bias_unit"].as<std::string>()).value());
    } else if (config["bias_unit"]) {
      SetClockBiasUnit(enum_cast<ClockBiasUnit>(config["bias_unit"].as<std::string>()).value());
    } else {
      ApplyClockStateUnits();
    }
    if (config["use_relativity"]) use_relativity_ = config["use_relativity"].as<bool>();
    if (config["relativity_center_body"]) {
      SetRelativityCenterBody(
          enum_cast<BodyId>(config["relativity_center_body"].as<std::string>()).value());
    }
  }

  void Clock::ApplyClockStateUnits() {
    state_.SetUnits(ClockDynamics::GetStateUnits(state_.size(), bias_unit_));
  }

  void Clock::SetModel(ClockModel model) {
    model_ = model;
    if (dynamics_) dynamics_->SetModel(model_);
  }

  void Clock::SetClockBiasUnit(ClockBiasUnit unit) {
    bias_unit_ = unit;
    if (dynamics_) dynamics_->SetClockBiasUnit(unit);
    ApplyClockStateUnits();
  }

  void Clock::SetDynamics(Ptr<ClockDynamics> dynamics) {
    dynamics_ = std::move(dynamics);
    if (dynamics_) {
      dynamics_->SetModel(model_);
      dynamics_->SetClockBiasUnit(bias_unit_);
    }
  }

  ClockRelativityContext Clock::BuildRelativityContext(Real t0, Real tf) const {
    LUPNT_CHECK(agent_ != nullptr, "Relativistic clock propagation requires an owning agent",
                "Clock");

    Cart6 rv0 = agent_->GetStateAt(t0);
    Cart6 rvf = agent_->GetStateAt(tf);
    BodyId center_body
        = relativity_center_body_set_ ? relativity_center_body_ : GetFrameCenter(rvf.GetFrame());
    BodyData center_data = GetBodyData(center_body, relativity_units_);
    Frame center_inertial_frame = center_data.inertial_frame;

    Cart6 rv0_centered = rv0;
    if (rv0.GetFrame() != center_inertial_frame) {
      rv0_centered = Cart6(ConvertFrame(t0, rv0, center_inertial_frame));
    }
    Cart6 rvf_centered = rvf;
    if (rvf.GetFrame() != center_inertial_frame) {
      rvf_centered = Cart6(ConvertFrame(tf, rvf, center_inertial_frame));
    }

    PhysicalConstants constants = GetPhysicalConstants(relativity_units_);
    ClockRelativityContext context;
    context.rv0_centered = rv0_centered;
    context.rvf_centered = rvf_centered;
    context.GM = center_data.GM;
    context.c = constants.C;
    return context;
  }

  // ReadTime
  Real Clock::Read(Real t) {
    Logger::Debug(fmt::format("Reading time {}", t), "Clock");
    LUPNT_CHECK(t >= time_, "Time must be greater than or equal to the current time", "Clock");
    if (use_relativity_) {
      ClockRelativityContext relativity = BuildRelativityContext(time_, t);
      state_ = dynamics_->PropagateWithRelativity(state_, time_, t, relativity);
    } else {
      state_ = dynamics_->Propagate(state_, time_, t);
    }
    time_ = t;
    return time_ + ClockDynamics::BiasUnitsToSeconds(state_.b(), bias_unit_);
  }

  // Step
  void Clock::Step(Real t) { Logger::Debug("Step", "Clock", t); }

  // Setup
  void Clock::Setup() { Logger::Debug(fmt::format("Setting up {}", name_), "Clock"); }

  // Log
  void Clock::Log(Real time) {
    DataLogger::Log(fmt::format("{}/time", name_), time);
    for (int i = 0; i < state_.size(); i++) {
      auto name = state_.GetNames()[i];
      auto unit = state_.GetUnits()[i];
      std::replace(unit.begin(), unit.end(), '/', '_');
      DataLogger::Log(fmt::format("{}/state/{}_{}", name_, name, unit), state_(i));
    }
  }

  // Factory
  REGISTER_FACTORY_CLASS(Device, Clock);
}  // namespace lupnt