DPsim
Loading...
Searching...
No Matches
RealTimeDataLogger.cpp
1/* A data logger for real-time simulation data logging.
2 *
3 * Author: Niklas Eiling <niklas.eiling@eonerc.rwth-aachen.de>
4 * SPDX-FileCopyrightText: 2024 Niklas Eiling <niklas.eiling@eonerc.rwth-aachen.de>
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#include <iomanip>
9#include <memory>
10
11#include <dpsim/RealTimeDataLogger.h>
12
13#include <dpsim-models/Attribute.h>
14#include <dpsim-models/Logger.h>
15
16using namespace DPsim;
17
18RealTimeDataLogger::RealTimeDataLogger(std::filesystem::path &filename,
19 size_t rowNumber)
20 : DataLoggerInterface(), mFilename(filename), mRowNumber(rowNumber),
21 mCurrentRow(0), mCurrentAttribute(0), mAttributeData() {}
22
23RealTimeDataLogger::RealTimeDataLogger(std::filesystem::path &filename,
24 Real finalTime, Real timeStep)
25 : DataLoggerInterface(), mFilename(filename),
26 mRowNumber((finalTime / timeStep + 0.5)), mCurrentRow(0),
27 mCurrentAttribute(0), mAttributeData() {}
28
29void RealTimeDataLogger::start() {
30 double mb_size =
31 static_cast<double>(mRowNumber) * (mAttributes.size() + 1) * sizeof(Real);
32 auto log = CPS::Logger::get("RealTimeDataLogger", CPS::Logger::Level::off,
33 CPS::Logger::Level::info);
34 SPDLOG_LOGGER_INFO(
35 log,
36 "Preallocating memory for real-time data logger: {} rows for {} "
37 "attributes ({} MB)",
38 mRowNumber, mAttributes.size(), mb_size / (1024 * 1024));
39 // We are doing real time so preallocate everything
40 mAttributeData.resize(mRowNumber);
41 for (auto &it : mAttributeData) {
42 // We have to add one to the size because we also log the time
43 it.resize(mAttributes.size() + 1);
44 }
45}
46
47void RealTimeDataLogger::stop() {
48 auto log = CPS::Logger::get("RealTimeDataLogger", CPS::Logger::Level::off,
49 CPS::Logger::Level::info);
50 SPDLOG_LOGGER_INFO(
51 log, "Stopping real-time data logger. Writing memory to file {}",
52 mFilename.string());
53
54 const auto parent = mFilename.parent_path();
55 if (!parent.empty()) {
56 std::error_code ec;
57 std::filesystem::create_directories(parent, ec);
58 if (ec) {
59 throw std::runtime_error("Cannot create log directory '" +
60 parent.string() + "': " + ec.message());
61 }
62 }
63
64 auto mLogFile =
65 std::ofstream(mFilename, std::ios_base::out | std::ios_base::trunc);
66 if (!mLogFile.is_open()) {
67 throw std::runtime_error("Cannot open log file " + mFilename.string());
68 }
69
70 mLogFile << std::right << std::setw(14) << "time";
71 for (auto it : mAttributes)
72 mLogFile << ", " << std::right << std::setw(13) << it.first;
73 mLogFile << '\n';
74
75 for (auto row : mAttributeData) {
76 mLogFile << std::scientific << std::right << std::setw(14) << row[0];
77 for (size_t i = 1; i < row.size(); ++i)
78 mLogFile << ", " << std::right << std::setw(13) << row[i];
79 mLogFile << '\n';
80 }
81 mLogFile.close();
82 SPDLOG_LOGGER_INFO(log, "Finished writing real-time data log to file {}",
83 mFilename.string());
84}
85
86void RealTimeDataLogger::log(Real time, Int timeStepCount) {
87 mCurrentRow = timeStepCount;
88 if (timeStepCount < 0 || static_cast<size_t>(timeStepCount) >= mRowNumber) {
89 throw std::runtime_error(
90 "RealTimeDataLogger: timeStepCount out of bounds. Please verify the "
91 "logger was initialized correctly.");
92 }
93 if (mAttributeData.size() != mRowNumber ||
94 mAttributeData[mCurrentRow].size() != mAttributes.size() + 1) {
95 throw std::runtime_error(
96 "RealTimeDataLogger: Attribute data size mismatch");
97 }
98 mAttributeData[mCurrentRow][0] = time;
99 mCurrentAttribute = 1;
100
101 for (auto &it : mAttributes) {
102 auto base = it.second.getPtr(); // std::shared_ptr<CPS::AttributeBase>
103
104 if (it.second->getType() == typeid(Real)) {
105 auto attr = std::dynamic_pointer_cast<CPS::Attribute<Real>>(base);
106 if (!attr) { /* skip */
107 continue;
108 }
109 mAttributeData[mCurrentRow][mCurrentAttribute++] = attr->get();
110 } else if (it.second->getType() == typeid(Int)) {
111 auto attr = std::dynamic_pointer_cast<CPS::Attribute<Int>>(base);
112 if (!attr) { /* skip */
113 continue;
114 }
115 mAttributeData[mCurrentRow][mCurrentAttribute++] = attr->get();
116 }
117 }
118}
119
120void RealTimeDataLogger::Step::execute(Real time, Int timeStepCount) {
121 mLogger.log(time, timeStepCount);
122}
123
124CPS::Task::Ptr RealTimeDataLogger::getTask() {
125 return std::make_shared<RealTimeDataLogger::Step>(*this);
126}