DPsim
DataLogger.cpp
1 /* Copyright 2017-2021 Institute for Automation of Complex Power Systems,
2  * EONERC, RWTH Aachen University
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7  *********************************************************************************/
8 
9 #include <iomanip>
10 
11 #include <dpsim-models/Logger.h>
12 #include <dpsim/DataLogger.h>
13 
14 using namespace DPsim;
15 
16 DataLogger::DataLogger(Bool enabled)
17  : mLogFile(), mEnabled(enabled), mDownsampling(1) {
18  mLogFile.setstate(std::ios_base::badbit);
19 }
20 
21 DataLogger::DataLogger(String name, Bool enabled, UInt downsampling)
22  : mName(name), mEnabled(enabled), mDownsampling(downsampling) {
23  if (!mEnabled)
24  return;
25 
26  mFilename = CPS::Logger::logDir() + "/" + name + ".csv";
27 
28  if (mFilename.has_parent_path() && !fs::exists(mFilename.parent_path()))
29  fs::create_directory(mFilename.parent_path());
30 
31  open();
32 }
33 
34 void DataLogger::open() {
35  mLogFile =
36  std::ofstream(mFilename, std::ios_base::out | std::ios_base::trunc);
37  if (!mLogFile.is_open()) {
38  // TODO: replace by exception
39  std::cerr << "Cannot open log file " << mFilename << std::endl;
40  mEnabled = false;
41  }
42 }
43 
44 void DataLogger::close() { mLogFile.close(); }
45 
46 void DataLogger::setColumnNames(std::vector<String> names) {
47  if (mLogFile.tellp() == std::ofstream::pos_type(0)) {
48  mLogFile << std::right << std::setw(14) << "time";
49  for (auto name : names) {
50  mLogFile << ", " << std::right << std::setw(13) << name;
51  }
52  mLogFile << '\n';
53  }
54 }
55 
56 void DataLogger::logDataLine(Real time, Real data) {
57  if (!mEnabled)
58  return;
59 
60  mLogFile << std::scientific << std::right << std::setw(14) << time;
61  mLogFile << ", " << std::right << std::setw(13) << data;
62  mLogFile << '\n';
63 }
64 
65 void DataLogger::logDataLine(Real time, const Matrix &data) {
66  if (!mEnabled)
67  return;
68 
69  mLogFile << std::scientific << std::right << std::setw(14) << time;
70  for (Int i = 0; i < data.rows(); ++i) {
71  mLogFile << ", " << std::right << std::setw(13) << data(i, 0);
72  }
73  mLogFile << '\n';
74 }
75 
76 void DataLogger::logDataLine(Real time, const MatrixComp &data) {
77  if (!mEnabled)
78  return;
79  mLogFile << std::scientific << std::right << std::setw(14) << time;
80  for (Int i = 0; i < data.rows(); ++i) {
81  mLogFile << ", " << std::right << std::setw(13) << data(i, 0);
82  }
83  mLogFile << '\n';
84 }
85 
86 void DataLogger::logPhasorNodeValues(Real time, const Matrix &data,
87  Int freqNum) {
88  if (mLogFile.tellp() == std::ofstream::pos_type(0)) {
89  std::vector<String> names;
90 
91  Int harmonicOffset = data.rows() / freqNum;
92  Int complexOffset = harmonicOffset / 2;
93 
94  for (Int freq = 0; freq < freqNum; ++freq) {
95  for (Int node = 0; node < complexOffset; ++node) {
96  std::stringstream name;
97  name << "n" << std::setfill('0') << std::setw(5) << node << "f"
98  << std::setfill('0') << std::setw(2) << freq << ".re";
99  names.push_back(name.str());
100  }
101  for (Int node = 0; node < complexOffset; ++node) {
102  std::stringstream name;
103  name << "n" << std::setfill('0') << std::setw(5) << node << "f"
104  << std::setfill('0') << std::setw(2) << freq << ".im";
105  names.push_back(name.str());
106  }
107  }
108  setColumnNames(names);
109  }
110  logDataLine(time, data);
111 }
112 
113 void DataLogger::logEMTNodeValues(Real time, const Matrix &data) {
114  if (mLogFile.tellp() == std::ofstream::pos_type(0)) {
115  std::vector<String> names;
116  for (Int i = 0; i < data.rows(); ++i) {
117  std::stringstream name;
118  name << "node" << std::setfill('0') << std::setw(5) << i;
119  names.push_back(name.str());
120  }
121  setColumnNames(names);
122  }
123  logDataLine(time, data);
124 }
125 
126 void DataLogger::log(Real time, Int timeStepCount) {
127  if (!mEnabled || !(timeStepCount % mDownsampling == 0))
128  return;
129 
130  if (mLogFile.tellp() == std::ofstream::pos_type(0)) {
131  mLogFile << std::right << std::setw(14) << "time";
132  for (auto it : mAttributes)
133  mLogFile << ", " << std::right << std::setw(13) << it.first;
134  mLogFile << '\n';
135  }
136 
137  mLogFile << std::scientific << std::right << std::setw(14) << time;
138  for (auto it : mAttributes)
139  mLogFile << ", " << std::right << std::setw(13) << it.second->toString();
140  mLogFile << '\n';
141 }
142 
143 void DataLogger::Step::execute(Real time, Int timeStepCount) {
144  mLogger.log(time, timeStepCount);
145 }
146 
147 CPS::Task::Ptr DataLogger::getTask() {
148  return std::make_shared<DataLogger::Step>(*this);
149 }
150 
151 void DataLogger::logAttribute(const std::vector<String> &name,
153  if (auto attrMatrix =
154  std::dynamic_pointer_cast<CPS::Attribute<Matrix>>(attr.getPtr())) {
155  if ((**attrMatrix).rows() == 1 && (**attrMatrix).cols() == 1) {
156  logAttribute(name[0], attrMatrix->deriveCoeff<CPS::Real>(0, 0));
157  } else if ((**attrMatrix).cols() == 1) {
158  for (UInt k = 0; k < (**attrMatrix).rows(); ++k) {
159  logAttribute(name[k], attrMatrix->deriveCoeff<CPS::Real>(k, 0));
160  }
161  } else {
162  for (UInt k = 0; k < (**attrMatrix).rows(); ++k) {
163  for (UInt l = 0; l < (**attrMatrix).cols(); ++l) {
164  logAttribute(name[k * (**attrMatrix).cols() + l],
165  attrMatrix->deriveCoeff<CPS::Real>(k, l));
166  }
167  }
168  }
169  } else if (auto attrMatrix =
170  std::dynamic_pointer_cast<CPS::Attribute<MatrixComp>>(
171  attr.getPtr())) {
172  if ((**attrMatrix).rows() == 1 && (**attrMatrix).cols() == 1) {
173  logAttribute(name[0], attrMatrix->deriveCoeff<CPS::Complex>(0, 0));
174  } else if ((**attrMatrix).cols() == 1) {
175  for (UInt k = 0; k < (**attrMatrix).rows(); ++k) {
176  logAttribute(name[k], attrMatrix->deriveCoeff<CPS::Complex>(k, 0));
177  }
178  } else {
179  for (UInt k = 0; k < (**attrMatrix).rows(); ++k) {
180  for (UInt l = 0; l < (**attrMatrix).cols(); ++l) {
181  logAttribute(name[k * (**attrMatrix).cols() + l],
182  attrMatrix->deriveCoeff<CPS::Complex>(k, l));
183  }
184  }
185  }
186  }
187 }
188 
189 void DataLogger::logAttribute(const String &name, CPS::AttributeBase::Ptr attr,
190  UInt rowsMax, UInt colsMax) {
191  if (auto attrReal =
192  std::dynamic_pointer_cast<CPS::Attribute<Real>>(attr.getPtr())) {
193  mAttributes[name] = attrReal;
194  } else if (auto attrComp = std::dynamic_pointer_cast<CPS::Attribute<Complex>>(
195  attr.getPtr())) {
196  mAttributes[name + ".re"] = attrComp->deriveReal();
197  mAttributes[name + ".im"] = attrComp->deriveImag();
198  } else if (auto attrMatrix =
199  std::dynamic_pointer_cast<CPS::Attribute<Matrix>>(
200  attr.getPtr())) {
201  UInt rows = static_cast<UInt>((**attrMatrix).rows());
202  UInt cols = static_cast<UInt>((**attrMatrix).cols());
203  if (rowsMax == 0 || rowsMax > rows)
204  rowsMax = rows;
205  if (colsMax == 0 || colsMax > cols)
206  colsMax = cols;
207  if (rows == 1 && cols == 1) {
208  mAttributes[name] = attrMatrix->deriveCoeff<Real>(0, 0);
209  } else if (cols == 1) {
210  for (UInt k = 0; k < rowsMax; ++k) {
211  mAttributes[name + "_" + std::to_string(k)] =
212  attrMatrix->deriveCoeff<Real>(k, 0);
213  }
214  } else {
215  for (UInt k = 0; k < rowsMax; ++k) {
216  for (UInt l = 0; l < colsMax; ++l) {
217  mAttributes[name + "_" + std::to_string(k) + "_" +
218  std::to_string(l)] = attrMatrix->deriveCoeff<Real>(k, l);
219  }
220  }
221  }
222  } else if (auto attrMatrix =
223  std::dynamic_pointer_cast<CPS::Attribute<MatrixComp>>(
224  attr.getPtr())) {
225  UInt rows = static_cast<UInt>((**attrMatrix).rows());
226  UInt cols = static_cast<UInt>((**attrMatrix).cols());
227  if (rowsMax == 0 || rowsMax > rows)
228  rowsMax = rows;
229  if (colsMax == 0 || colsMax > cols)
230  colsMax = cols;
231  if (rows == 1 && cols == 1) {
232  mAttributes[name + ".re"] =
233  attrMatrix->deriveCoeff<Complex>(0, 0)->deriveReal();
234  mAttributes[name + ".im"] =
235  attrMatrix->deriveCoeff<Complex>(0, 0)->deriveImag();
236  } else if (cols == 1) {
237  for (UInt k = 0; k < rowsMax; ++k) {
238  mAttributes[name + "_" + std::to_string(k) + ".re"] =
239  attrMatrix->deriveCoeff<Complex>(k, 0)->deriveReal();
240  mAttributes[name + "_" + std::to_string(k) + ".im"] =
241  attrMatrix->deriveCoeff<Complex>(k, 0)->deriveImag();
242  }
243  } else {
244  for (UInt k = 0; k < rowsMax; ++k) {
245  for (UInt l = 0; l < colsMax; ++l) {
246  mAttributes[name + "_" + std::to_string(k) + "_" + std::to_string(l) +
247  ".re"] =
248  attrMatrix->deriveCoeff<Complex>(k, l)->deriveReal();
249  mAttributes[name + "_" + std::to_string(k) + "_" + std::to_string(l) +
250  ".im"] =
251  attrMatrix->deriveCoeff<Complex>(k, l)->deriveImag();
252  }
253  }
254  }
255  } else {
256  mAttributes[name] = attr;
257  }
258 }