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 log->info("Preallocating memory for real-time data logger: {} rows for {} "
35 "attributes ({} MB)",
36 mRowNumber, mAttributes.size(), mb_size / (1024 * 1024));
37 // We are doing real time so preallocate everything
38 mAttributeData.resize(mRowNumber);
39 for (auto &it : mAttributeData) {
40 // We have to add one to the size because we also log the time
41 it.resize(mAttributes.size() + 1);
42 }
43}
44
45void RealTimeDataLogger::stop() {
46 auto log = CPS::Logger::get("RealTimeDataLogger", CPS::Logger::Level::off,
47 CPS::Logger::Level::info);
48 log->info("Stopping real-time data logger. Writing memory to file {}",
49 mFilename.string());
50
51 const auto parent = mFilename.parent_path();
52 if (!parent.empty()) {
53 std::error_code ec;
54 std::filesystem::create_directories(parent, ec);
55 if (ec) {
56 throw std::runtime_error("Cannot create log directory '" +
57 parent.string() + "': " + ec.message());
58 }
59 }
60
61 auto mLogFile =
62 std::ofstream(mFilename, std::ios_base::out | std::ios_base::trunc);
63 if (!mLogFile.is_open()) {
64 throw std::runtime_error("Cannot open log file " + mFilename.string());
65 }
66
67 mLogFile << std::right << std::setw(14) << "time";
68 for (auto it : mAttributes)
69 mLogFile << ", " << std::right << std::setw(13) << it.first;
70 mLogFile << '\n';
71
72 for (auto row : mAttributeData) {
73 mLogFile << std::scientific << std::right << std::setw(14) << row[0];
74 for (size_t i = 1; i < row.size(); ++i)
75 mLogFile << ", " << std::right << std::setw(13) << row[i];
76 mLogFile << '\n';
77 }
78 mLogFile.close();
79 log->info("Finished writing real-time data log to file {}",
80 mFilename.string());
81}
82
83void RealTimeDataLogger::log(Real time, Int timeStepCount) {
84 mCurrentRow = timeStepCount;
85 if (timeStepCount < 0 || static_cast<size_t>(timeStepCount) >= mRowNumber) {
86 throw std::runtime_error(
87 "RealTimeDataLogger: timeStepCount out of bounds. Please verify the "
88 "logger was initialized correctly.");
89 }
90 if (mAttributeData.size() != mRowNumber ||
91 mAttributeData[mCurrentRow].size() != mAttributes.size() + 1) {
92 throw std::runtime_error(
93 "RealTimeDataLogger: Attribute data size mismatch");
94 }
95 mAttributeData[mCurrentRow][0] = time;
96 mCurrentAttribute = 1;
97
98 for (auto &it : mAttributes) {
99 auto base = it.second.getPtr(); // std::shared_ptr<CPS::AttributeBase>
100
101 if (it.second->getType() == typeid(Real)) {
102 auto attr = std::dynamic_pointer_cast<CPS::Attribute<Real>>(base);
103 if (!attr) { /* skip */
104 continue;
105 }
106 mAttributeData[mCurrentRow][mCurrentAttribute++] = attr->get();
107 } else if (it.second->getType() == typeid(Int)) {
108 auto attr = std::dynamic_pointer_cast<CPS::Attribute<Int>>(base);
109 if (!attr) { /* skip */
110 continue;
111 }
112 mAttributeData[mCurrentRow][mCurrentAttribute++] = attr->get();
113 }
114 }
115}
116
117void RealTimeDataLogger::Step::execute(Real time, Int timeStepCount) {
118 mLogger.log(time, timeStepCount);
119}
120
121CPS::Task::Ptr RealTimeDataLogger::getTask() {
122 return std::make_shared<RealTimeDataLogger::Step>(*this);
123}