Program Listing for File agent.cc¶
↰ Return to documentation for file (agents/agent.cc)
#include "lupnt/agents/agent.h"
#include "lupnt/applications/application.h"
#include "lupnt/core/asset_factory.h"
#include "lupnt/core/constants.h"
#include "lupnt/core/definitions.h"
#include "lupnt/core/logger.h"
#include "lupnt/core/simulation.h"
#include "lupnt/devices/device.h"
#include "lupnt/states/state.h"
namespace lupnt {
// Constructor
Agent::Agent(Config& config) {
// Config
name_ = config["name"] ? config["name"].as<std::string>() : GetId();
config_ = config;
Logger::Debug(fmt::format("Creating {}", name_), "Agent");
if (config["frequency"]) frequency_ = config["frequency"].as<Real>();
// Devices
if (config["devices"]) {
Logger::Debug(fmt::format("Creating {} devices", config["devices"].size()), "Agent");
for (const auto& dev_item : config["devices"]) {
// Name
Config dev_config(dev_item.second);
std::string dev_class = dev_config["class"].as<std::string>();
if (!dev_config["name"]) dev_config["name"] = dev_item.first.as<std::string>();
dev_config["name"] = name_ + "/" + dev_config["name"].as<std::string>();
std::string dev_name = dev_config["name"].as<std::string>();
// Create
Logger::Debug(fmt::format("Creating {} {}/{}", dev_class, name_, dev_name), "Agent");
AddDevice(AssetFactory<Device, Config&>::Create(dev_class, dev_config));
}
Logger::Debug(fmt::format("Created {} devices", devices_.size()), "Agent");
} else {
Logger::Debug(fmt::format("No devices found for agent {}", name_), "Agent");
}
// Application
if (config["application"]) {
// Name
Config app_config(config["application"]);
auto app_class = app_config["class"].as<std::string>();
if (!app_config["name"]) app_config["name"] = "application";
app_config["name"] = name_ + "/" + app_config["name"].as<std::string>();
// Create
SetApplication(AssetFactory<Application, Config&>::Create(app_class, app_config));
} else {
Logger::Debug(fmt::format("No application found for agent {}", name_), "Agent");
}
}
void Agent::AddDevice(Ptr<Device> device) {
LUPNT_CHECK(devices_.find(device->GetName()) == devices_.end(), "Device already exists",
"Agent");
device->SetAgent(this);
devices_[device->GetName()] = std::move(device);
}
Ptr<Device> Agent::GetDevice(const std::string& name) const {
if (devices_.find(name) != devices_.end()) {
return devices_.at(name);
} else if (devices_.find(name_ + "/" + name) != devices_.end()) {
return devices_.at(name_ + "/" + name);
} else {
LUPNT_CHECK(false, fmt::format("Device {} not found", name), "Agent");
}
}
void Agent::Step(Real time) { Logger::Debug(fmt::format("Stepping {}", name_), "Agent", time); }
// Log
void Agent::Log(Real time) { (void)time; }
void Agent::LogCesium() {}
// Agent with dynamics ********************************************************
AgentWithDynamics::AgentWithDynamics(Config& config) {
// Dynamics
if (config["dynamics"]) {
// Name
Config dyn_config(config["dynamics"]);
auto dyn_class = dyn_config["class"].as<std::string>();
if (!dyn_config["name"]) dyn_config["name"] = "dynamics";
dyn_config["name"] = name_ + "/" + dyn_config["name"].as<std::string>();
// Create
SetDynamics(AssetFactory<Dynamics, Config&>::Create(dyn_class, dyn_config));
} else {
LUPNT_CHECK(false, "No dynamics found", "Agent");
}
// Attitude dynamics
if (config["attitude_dynamics"]) {
// Name
Config dyn_config(config["attitude_dynamics"]);
auto dyn_class = dyn_config["class"].as<std::string>();
if (!dyn_config["name"]) dyn_config["name"] = "attitude_dynamics";
dyn_config["name"] = name_ + "/" + dyn_class;
// Create
SetAttitudeDynamics(AssetFactory<AttitudeDynamics, Config&>::Create(dyn_class, dyn_config));
} else {
// Name
Logger::Debug(fmt::format("No attitude dynamics found for agent {}", name_), "Agent");
Config dyn_config{YAML::Node()};
std::string dyn_class = "FixedAttitudeDynamics";
if (!dyn_config["name"]) dyn_config["name"] = "attitude_dynamics";
dyn_config["name"] = name_ + "/" + dyn_class;
// Create
SetAttitudeDynamics(AssetFactory<AttitudeDynamics, Config&>::Create(dyn_class, dyn_config));
}
// State
state_ = Cart6(Vec6::Zero(), Frame::MOON_CI);
attitude_ = Attitude(Vec4(1.0, 0.0, 0.0, 0.0), Vec3::Zero(), Frame::MOON_CI);
// Precompute
precompute_ = config["precompute"].as<Real>(0.0);
}
// Setup
void AgentWithDynamics::Setup() { Agent::Setup(); }
// Setup
void Agent::Setup() {
Logger::Debug(fmt::format("Setting up {}", name_), "Agent");
// Check simulation
if (!sim_) {
Logger::Debug(fmt::format("No simulation set for {}", name_), "Agent");
return;
}
// Step
if (frequency_ > 0.0) {
sim_->Schedule(0.0, [this](Real t) { Step(t); }, frequency_, Event::Priority::AGENT);
Logger::Info(fmt::format("Scheduled {}, t={} s, f={} Hz", name_, 0.0, frequency_), "Agent");
} else {
if (frequency_ <= 0.0) Logger::Warn(fmt::format("No frequency set for {}", name_), "Agent");
}
// Devices
for (auto& [device_name, device] : devices_) {
device->Setup();
}
// Precompute
// if (sim_ && precompute_ > 0.0 && dynamics_) {
// t_precompute_ = Arange(0.0, sim_->GetDuration(), precompute_);
// Logger::Debug(fmt::format("Precomputing {} states for agent {}", t_precompute_.size(),
// name_),
// "Agent");
// x_precompute_ = dynamics_->Propagate(state_, time_, t_precompute_);
// // clk_precompute_ = MatX::Zero(t_precompute.size(), clk_.size());
// // attitude_precompute_ = MatX::Zero(t_precompute.size(), attitude_.size());
// Logger::Debug(fmt::format("Precomputed {} states for agent {}", t_precompute_.size(),
// name_),
// "Agent");
// // Cesium
// if (sim_->GetCesiumViewer()) {
// // VecX times = t_precompute_;
// // MatX3 positions = x_precompute_.block(0, 0, t_precompute_.size(), 3);
// // BodyId body_id = GetFrameCenter(dynamics_->GetFrame());
// // Frame frame_in = dynamics_->GetFrame();
// // Frame frame_out = GetBodyFixedFrameName(body_id);
// // VecX epochs = global_epoch + t_precompute_.array();
// // positions = ConvertFrame(epochs, positions, frame_in, frame_out);
// // std::vector<int> color = {255, 0, 255};
// // std::string description = name_;
// // int size = 5;
// // sim_->GetCesiumViewer()->AddEntity(times, positions, name_, name_, color,
// description,
// // body_id, size);
// Logger::Debug(fmt::format("Added {} to Cesium viewer", name_), "Agent");
// } else {
// Logger::Debug(fmt::format("Cesium viewer not available for agent {}", name_), "Agent");
// }
// } else {
// if (!dynamics_) Logger::Debug(fmt::format("No dynamics set for agent {}", name_),
// "Agent"); if (!sim_) Logger::Debug(fmt::format("No simulation set for agent {}", name_),
// "Agent"); if (precompute_ <= 0.0)
// Logger::Debug(fmt::format("Precompute not set for agent {}", name_), "Agent");
// }
}
// Step
void AgentWithDynamics::Step(Real time) {
Propagate(time);
Log(time);
}
// Propagate
void AgentWithDynamics::Propagate(Real t) {
Logger::Debug(fmt::format("Propagating {} from t={} s to t={} s", name_, time_, t), "Agent", t);
if (dynamics_) {
state_ = dynamics_->Propagate(state_, time_, t, &control_);
} else {
Logger::Debug(fmt::format("No dynamics set for agent {}", name_), "Agent", t);
}
if (attitude_dynamics_) {
attitude_ = attitude_dynamics_->Propagate(attitude_, time_, t, state_);
} else {
Logger::Debug(fmt::format("No attitude dynamics set for agent {}", name_), "Agent", t);
}
time_ = t;
}
Cart6 AgentWithDynamics::GetStateAt(Real t) const {
if (abs(t - time_) < EPS) return state_;
LUPNT_CHECK(dynamics_, "Dynamics not set", "Agent");
return Cart6(dynamics_->Propagate(state_, time_, t));
}
Attitude AgentWithDynamics::GetAttitudeAt(Real t) const {
if (abs(t - time_) < EPS) return attitude_;
if (!attitude_dynamics_) return attitude_;
Attitude att = attitude_dynamics_->Propagate(attitude_, time_, t, state_);
return att;
}
void AgentWithDynamics::Log(Real time) {
// State
// for (int i = 0; i < state_.size(); i++) {
// auto name = state_.GetNames()[i];
// auto unit = state_.GetUnits()[i];
// std::replace(unit.begin(), unit.end(), '/', '_');
// auto value = state_(i);
// DataLogger::Log(fmt::format("{}/state/{}_{}", name_, name, unit), value);
// }
DataLogger::Log(fmt::format("{}/state", name_), state_);
// Attitude
// for (int i = 0; i < attitude_.size(); i++) {
// auto name = attitude_.GetNames()[i];
// auto unit = attitude_.GetUnits()[i];
// std::replace(unit.begin(), unit.end(), '/', '_');
// auto value = attitude_(i);
// DataLogger::Log(fmt::format("{}/attitude/{}_{}", name_, name, unit), value);
// }
DataLogger::Log(fmt::format("{}/attitude", name_), attitude_);
// Control
// for (int i = 0; i < control_.size(); i++) {
// auto name = control_.GetNames()[i];
// auto unit = control_.GetUnits()[i];
// std::replace(unit.begin(), unit.end(), '/', '_');
// auto value = control_(i);
// DataLogger::Log(fmt::format("{}/control/{}_{}", name_, name, unit), value);
// }
DataLogger::Log(fmt::format("{}/control", name_), control_);
// Application
if (application_) application_->Log(time);
}
void AgentWithDynamics::LogCesium() {}
// Define the GetRegistry function for this specialization (must come before explicit
// instantiation)
template <> std::unordered_map<std::string, AssetFactory<Agent, Config&>::Creator>&
AssetFactory<Agent, Config&>::GetRegistry() {
return Registry();
}
// Explicit template instantiation to ensure single registry across library boundaries
template class AssetFactory<Agent, Config&>;
}; // namespace lupnt