Program Listing for File data_logger.cc¶
↰ Return to documentation for file (core/data_logger.cc)
#include "lupnt/core/data_logger.h"
#include <fmt/format.h>
#include <highfive/H5Easy.hpp>
#include "lupnt/core/error.h"
#include "lupnt/core/logger.h"
namespace lupnt {
// Use function-local static for thread-safe initialization
DataLogger::DoubleMap& GetDoubleLogs() {
static DataLogger::DoubleMap double_logs;
return double_logs;
}
DataLogger::StringMap& GetStringLogs() {
static DataLogger::StringMap string_logs;
return string_logs;
}
DataLogger::MatrixMap& GetMatrixLogs() {
static DataLogger::MatrixMap matrix_logs;
return matrix_logs;
}
std::mutex& GetMutex() {
static std::mutex mutex;
return mutex;
}
std::unique_ptr<H5Easy::File>& GetFile() {
static std::unique_ptr<H5Easy::File> file = nullptr;
return file;
}
// Set output file for logging
void DataLogger::SetOutputFile(const std::filesystem::path& filename) {
Logger::Info("Output file: {}", filename.string());
std::lock_guard<std::mutex> lock(GetMutex());
if (std::filesystem::exists(filename)) {
Logger::Debug(fmt::format("Removing existing output file: {}", filename.string()),
"DataLogger");
std::filesystem::remove(filename);
}
GetFile() = std::make_unique<H5Easy::File>(filename, H5Easy::File::Overwrite);
LUPNT_CHECK(GetFile(), fmt::format("Failed to open log file: {}", filename.string()),
"DataLogger");
}
// Log functions for different data types
void DataLogger::Log(const std::string& name, double value) {
std::lock_guard<std::mutex> lock(GetMutex());
GetDoubleLogs()[name].push_back(value);
}
void DataLogger::Log(const std::string& name, Real value) {
std::lock_guard<std::mutex> lock(GetMutex());
GetDoubleLogs()[name].push_back(value.val());
}
void DataLogger::Log(const std::string& name, const std::string& value) {
std::lock_guard<std::mutex> lock(GetMutex());
GetStringLogs()[name].push_back(value);
}
void DataLogger::LogMatrix(const std::string& name, const Eigen::MatrixXd& value) {
std::lock_guard<std::mutex> lock(GetMutex());
GetMatrixLogs()[name].push_back(value);
}
void DataLogger::LogState(const std::string& parent, const State& 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);
Log(fmt::format("{}/{}_{}", parent, name, unit), value);
}
}
std::string FindTimeKey(const std::string& name) {
auto time_keys = std::vector<std::string>{"/time", "/t"};
std::string target = "";
// Parents
std::string parent1 = name;
size_t last_slash = parent1.rfind('/');
if (last_slash != std::string::npos) parent1 = parent1.substr(0, last_slash);
std::string parent2 = parent1;
last_slash = parent2.rfind('/');
if (last_slash != std::string::npos) parent2 = parent2.substr(0, last_slash);
// Candidates
bool found_time = false;
std::vector<std::string> parents = {parent1, parent2};
// Search
for (const auto& [curr, data] : GetDoubleLogs()) {
if (found_time) break;
for (const auto& parent : parents) {
for (const auto& time_key : time_keys) {
std::string candidate = parent + time_key;
if (curr == candidate) {
target = candidate;
found_time = true;
break;
}
}
}
}
return target;
}
// Flush all logs to HDF5 file
void DataLogger::Flush() {
if (!GetFile()) return;
Logger::Info("Saving data", "DataLogger");
std::lock_guard<std::mutex> lock(GetMutex());
for (const auto& [name, data] : GetDoubleLogs()) {
H5Easy::dump(*GetFile(), name, data);
}
for (const auto& [name, data] : GetStringLogs()) {
H5Easy::dump(*GetFile(), name, data);
}
for (const auto& [name, data] : GetMatrixLogs()) {
H5Easy::dump(*GetFile(), name, data);
}
GetFile()->flush();
// Clear logs after writing
GetDoubleLogs().clear();
GetStringLogs().clear();
GetMatrixLogs().clear();
}
} // namespace lupnt