Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <algorithm>
50 : #include <cassert>
51 : #include <cmath>
52 : #include <map>
53 : #include <ostream>
54 : #include <string>
55 : #include <vector>
56 :
57 : #include <fmt/format.h>
58 : #include <milo/dtoa.h>
59 :
60 : // ObjexxFCL Headers
61 : #include <ObjexxFCL/Array.functions.hh>
62 : #include <ObjexxFCL/Array1D.hh>
63 : #include <ObjexxFCL/Reference.fwd.hh>
64 : #include <ObjexxFCL/string.functions.hh>
65 :
66 : // EnergyPlus Headers
67 : #include <EnergyPlus/Data/EnergyPlusData.hh>
68 : #include <EnergyPlus/DataStringGlobals.hh>
69 : #include <EnergyPlus/GlobalNames.hh>
70 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
71 : #include <EnergyPlus/ResultsFramework.hh>
72 : #include <EnergyPlus/UtilityRoutines.hh>
73 :
74 : namespace EnergyPlus {
75 :
76 : namespace ResultsFramework {
77 :
78 : using namespace OutputProcessor;
79 :
80 : // trim string
81 7 : std::string trim(std::string_view const s)
82 : {
83 7 : if (s.empty()) {
84 0 : return std::string{};
85 : }
86 7 : auto const first = s.find_first_not_of(' ');
87 7 : auto const last = s.find_last_not_of(' ');
88 7 : if ((first == std::string::npos) || (last == std::string::npos)) {
89 0 : return std::string{};
90 : } else {
91 21 : return std::string{s.substr(first, last - first + 1)};
92 : }
93 : }
94 :
95 : // Class SimInfo
96 28 : void SimInfo::setProgramVersion(const std::string &programVersion)
97 : {
98 28 : ProgramVersion = programVersion;
99 28 : }
100 :
101 0 : std::string SimInfo::getProgramVersion() const
102 : {
103 0 : return ProgramVersion;
104 : }
105 :
106 2 : void SimInfo::setSimulationEnvironment(const std::string &simulationEnvironment)
107 : {
108 2 : SimulationEnvironment = simulationEnvironment;
109 2 : }
110 :
111 2 : void SimInfo::setInputModelURI(const std::string &inputModelURI)
112 : {
113 2 : InputModelURI = inputModelURI;
114 2 : }
115 :
116 28 : void SimInfo::setStartDateTimeStamp(const std::string &startDateTimeStamp)
117 : {
118 28 : StartDateTimeStamp = startDateTimeStamp;
119 28 : }
120 :
121 28 : void SimInfo::setRunTime(const std::string &elapsedTime)
122 : {
123 28 : RunTime = elapsedTime;
124 28 : }
125 :
126 28 : void SimInfo::setNumErrorsWarmup(const std::string &numWarningsDuringWarmup, const std::string &numSevereDuringWarmup)
127 : {
128 28 : NumWarningsDuringWarmup = numWarningsDuringWarmup;
129 28 : NumSevereDuringWarmup = numSevereDuringWarmup;
130 28 : }
131 :
132 28 : void SimInfo::setNumErrorsSizing(const std::string &numWarningsDuringSizing, const std::string &numSevereDuringSizing)
133 : {
134 28 : NumWarningsDuringSizing = numWarningsDuringSizing;
135 28 : NumSevereDuringSizing = numSevereDuringSizing;
136 28 : }
137 :
138 28 : void SimInfo::setNumErrorsSummary(const std::string &numWarnings, const std::string &numSevere)
139 : {
140 28 : NumWarnings = numWarnings;
141 28 : NumSevere = numSevere;
142 28 : }
143 :
144 2 : json SimInfo::getJSON() const
145 : {
146 2 : json root = {{"ProgramVersion", ProgramVersion},
147 2 : {"SimulationEnvironment", SimulationEnvironment},
148 2 : {"InputModelURI", InputModelURI},
149 2 : {"StartDateTimeStamp", StartDateTimeStamp},
150 2 : {"RunTime", RunTime},
151 4 : {"ErrorSummary", {{"NumWarnings", NumWarnings}, {"NumSevere", NumSevere}}},
152 4 : {"ErrorSummaryWarmup", {{"NumWarnings", NumWarningsDuringWarmup}, {"NumSevere", NumSevereDuringWarmup}}},
153 98 : {"ErrorSummarySizing", {{"NumWarnings", NumWarningsDuringSizing}, {"NumSevere", NumSevereDuringSizing}}}};
154 2 : return root;
155 84 : }
156 :
157 : // Class Variable
158 108 : Variable::Variable(const std::string &VarName,
159 : const OutputProcessor::ReportFreq reportFrequency,
160 : const OutputProcessor::TimeStepType timeStepType,
161 : const int ReportID,
162 108 : const Constant::Units units)
163 108 : : m_varName(VarName), m_reportFreq(reportFrequency), m_timeStepType(timeStepType), m_rptID(ReportID), m_units(units)
164 : {
165 108 : }
166 :
167 0 : Variable::Variable(const std::string &VarName,
168 : const OutputProcessor::ReportFreq reportFrequency,
169 : const OutputProcessor::TimeStepType timeStepType,
170 : const int ReportID,
171 : const Constant::Units units,
172 0 : const std::string &customUnits)
173 0 : : m_varName(VarName), m_reportFreq(reportFrequency), m_timeStepType(timeStepType), m_rptID(ReportID), m_units(units),
174 0 : m_customUnits(customUnits)
175 : {
176 0 : }
177 :
178 9 : std::string Variable::variableName() const
179 : {
180 9 : return m_varName;
181 : }
182 :
183 0 : void Variable::setVariableName(const std::string &VarName)
184 : {
185 0 : m_varName = VarName;
186 0 : }
187 :
188 4 : std::string Variable::sReportFrequency() const
189 : {
190 : static constexpr std::array<std::string_view, (int)ReportFreq::Num> reportFreqStrings = {
191 : "Detailed", "TimeStep", "Hourly", "Daily", "Monthly", "RunPeriod", "Yearly"};
192 :
193 : static constexpr std::array<std::string_view, (int)TimeStepType::Num> timeStepTypeStrings = {"Detailed - Zone", "Detailed - HVAC"};
194 :
195 4 : return (m_reportFreq == ReportFreq::EachCall) ? std::string(timeStepTypeStrings[(int)m_timeStepType])
196 12 : : std::string(reportFreqStrings[(int)m_reportFreq]);
197 : }
198 :
199 0 : OutputProcessor::ReportFreq Variable::iReportFrequency() const
200 : {
201 0 : return m_reportFreq;
202 : }
203 :
204 0 : void Variable::setReportFrequency(const OutputProcessor::ReportFreq reportFrequency)
205 : {
206 0 : m_reportFreq = reportFrequency;
207 0 : }
208 :
209 0 : OutputProcessor::TimeStepType Variable::timeStepType() const
210 : {
211 0 : return m_timeStepType;
212 : }
213 :
214 0 : void Variable::setTimeStepType(const OutputProcessor::TimeStepType timeStepType)
215 : {
216 0 : m_timeStepType = timeStepType;
217 0 : }
218 :
219 107 : int Variable::reportID() const
220 : {
221 107 : return m_rptID;
222 : }
223 :
224 0 : void Variable::setReportID(int Id)
225 : {
226 0 : m_rptID = Id;
227 0 : }
228 :
229 9 : Constant::Units Variable::units() const
230 : {
231 9 : return m_units;
232 : }
233 :
234 0 : void Variable::setUnits(const Constant::Units units)
235 : {
236 0 : m_units = units;
237 0 : }
238 :
239 9 : std::string Variable::customUnits() const
240 : {
241 9 : return m_customUnits;
242 : }
243 :
244 0 : void Variable::setCustomUnits(const std::string &customUnits)
245 : {
246 0 : m_customUnits = customUnits;
247 0 : }
248 :
249 3053 : void Variable::pushValue(const double val)
250 : {
251 3053 : m_values.push_back(val);
252 3053 : }
253 :
254 36 : double Variable::value(size_t index) const
255 : {
256 36 : return m_values.at(index);
257 : }
258 :
259 36 : size_t Variable::numValues() const
260 : {
261 36 : return m_values.size();
262 : }
263 :
264 4 : json Variable::getJSON() const
265 : {
266 4 : json root;
267 4 : if (m_customUnits.empty()) {
268 44 : root = {{"Name", m_varName}, {"Units", Constant::unitNames[(int)m_units]}, {"Frequency", sReportFrequency()}};
269 : } else {
270 0 : root = {{"Name", m_varName}, {"Units", m_customUnits}, {"Frequency", sReportFrequency()}};
271 : }
272 4 : return root;
273 36 : }
274 :
275 : // Class OutputVariable
276 0 : OutputVariable::OutputVariable(const std::string &VarName,
277 : const OutputProcessor::ReportFreq reportFrequency,
278 : const OutputProcessor::TimeStepType timeStepType,
279 : const int ReportID,
280 0 : const Constant::Units units)
281 0 : : Variable(VarName, reportFrequency, timeStepType, ReportID, units)
282 : {
283 0 : }
284 :
285 0 : OutputVariable::OutputVariable(const std::string &VarName,
286 : const OutputProcessor::ReportFreq reportFrequency,
287 : const OutputProcessor::TimeStepType timeStepType,
288 : const int ReportID,
289 : const Constant::Units units,
290 0 : const std::string &customUnits)
291 0 : : Variable(VarName, reportFrequency, timeStepType, ReportID, units, customUnits)
292 : {
293 0 : }
294 :
295 : // Class MeterVariable
296 98 : MeterVariable::MeterVariable(const std::string &VarName,
297 : const OutputProcessor::ReportFreq reportFrequency,
298 : const int ReportID,
299 : const Constant::Units units,
300 : const bool MeterOnly,
301 98 : const bool Accumulative)
302 98 : : Variable(VarName, reportFrequency, OutputProcessor::TimeStepType::Zone, ReportID, units)
303 : {
304 98 : acc = Accumulative;
305 98 : meter_only = MeterOnly;
306 98 : }
307 :
308 0 : bool MeterVariable::accumulative() const
309 : {
310 0 : return acc;
311 : }
312 :
313 0 : void MeterVariable::setAccumulative(bool state)
314 : {
315 0 : acc = state;
316 0 : }
317 :
318 0 : bool MeterVariable::meterOnly() const
319 : {
320 0 : return meter_only;
321 : }
322 :
323 0 : void MeterVariable::setMeterOnly(bool state)
324 : {
325 0 : meter_only = state;
326 0 : }
327 :
328 0 : json MeterVariable::getJSON() const
329 : {
330 0 : json root = Variable::getJSON();
331 0 : if (acc) {
332 0 : root["Cumulative"] = true;
333 : }
334 : // if (meter_only) {
335 : // root["MeterOnly"] = true;
336 : // }
337 0 : return root;
338 0 : }
339 :
340 : // class DataFrame
341 34064 : DataFrame::DataFrame(const std::string &ReportFreq)
342 : {
343 34064 : ReportFrequency = ReportFreq;
344 34064 : }
345 :
346 9 : void DataFrame::addVariable(Variable const &var)
347 : {
348 9 : lastVarID = var.reportID();
349 9 : variableMap.emplace(lastVarID, var);
350 9 : }
351 :
352 0 : Variable &DataFrame::lastVariable()
353 : {
354 0 : return variableMap.at(lastVarID);
355 : }
356 :
357 1102 : void DataFrame::newRow(const int month, const int dayOfMonth, int hourOfDay, int curMin, int calendarYear)
358 : {
359 1102 : if (curMin > 0) {
360 125 : hourOfDay -= 1;
361 : }
362 1102 : if (curMin == 60) {
363 38 : curMin = 0;
364 38 : hourOfDay += 1;
365 : }
366 :
367 1102 : if (beginningOfInterval) {
368 8 : if (hourOfDay == 24) {
369 2 : hourOfDay = 0;
370 : }
371 8 : std::swap(hourOfDay, lastHour);
372 8 : std::swap(curMin, lastMinute);
373 : }
374 : // future start of ISO 8601 datetime output
375 : // fmt::format("YYYY-{:02d}/{:02d}T{:02d}:{:02d}:00", month, dayOfMonth, hourOfDay, curMin);
376 : // fmt::format("{:02d}/{:02d} {:02d}:{:02d}:00", month, dayOfMonth, hourOfDay, curMin);
377 1102 : if (iso8601) {
378 16 : TS.emplace_back(fmt::format("{:04d}-{:02d}-{:02d}T{:02d}:{:02d}:00", calendarYear, month, dayOfMonth, hourOfDay, curMin));
379 : } else {
380 2188 : TS.emplace_back(fmt::format("{:02d}/{:02d} {:02d}:{:02d}:00", month, dayOfMonth, hourOfDay, curMin));
381 : }
382 1102 : }
383 :
384 : // void DataFrame::newRow(const std::string &ts)
385 : // {
386 : // TS.emplace_back(ts);
387 : // }
388 :
389 23423 : bool DataFrame::dataFrameEnabled() const
390 : {
391 23423 : return DataFrameEnabled;
392 : }
393 :
394 12698 : void DataFrame::setDataFrameEnabled(bool state)
395 : {
396 12698 : DataFrameEnabled = state;
397 12698 : }
398 :
399 33902 : void DataFrame::setVariablesScanned(bool state)
400 : {
401 33902 : VariablesScanned = state;
402 33902 : }
403 :
404 0 : bool DataFrame::variablesScanned() const
405 : {
406 0 : return VariablesScanned;
407 : }
408 :
409 28 : void DataFrame::pushVariableValue(const int reportID, double value)
410 : {
411 28 : variableMap[reportID].pushValue(value);
412 28 : }
413 :
414 1 : json DataFrame::getVariablesJSON()
415 : {
416 1 : json arr = json::array();
417 3 : for (auto const &varMap : variableMap) {
418 2 : arr.push_back(varMap.second.getJSON());
419 : }
420 1 : return arr;
421 0 : }
422 :
423 6 : json DataFrame::getJSON() const
424 : {
425 6 : json root;
426 6 : json cols = json::array();
427 6 : json rows = json::array();
428 :
429 15 : for (auto const &varMap : variableMap) {
430 9 : if (varMap.second.customUnits().empty()) {
431 81 : cols.push_back({{"Variable", varMap.second.variableName()}, {"Units", Constant::unitNames[(int)varMap.second.units()]}});
432 : } else {
433 0 : cols.push_back({{"Variable", varMap.second.variableName()}, {"Units", varMap.second.customUnits()}});
434 : }
435 : }
436 :
437 6 : json vals = json::array();
438 :
439 30 : for (size_t row = 0; row < TS.size(); ++row) {
440 24 : vals.clear();
441 :
442 60 : for (auto const &varMap : variableMap) {
443 36 : if (row < varMap.second.numValues()) {
444 36 : vals.push_back(varMap.second.value(row));
445 : } else {
446 0 : vals.push_back(nullptr);
447 : }
448 : }
449 96 : rows.push_back({{TS.at(row), vals}});
450 : }
451 60 : root = {{"ReportFrequency", ReportFrequency}, {"Cols", cols}, {"Rows", rows}};
452 6 : return root;
453 216 : }
454 :
455 98 : void MeterDataFrame::addVariable(MeterVariable const &var)
456 : {
457 98 : lastVarID = var.reportID();
458 98 : meterMap.emplace(lastVarID, var);
459 98 : }
460 :
461 3025 : void MeterDataFrame::pushVariableValue(const int reportID, double value)
462 : {
463 3025 : meterMap[reportID].pushValue(value);
464 3025 : }
465 :
466 0 : json MeterDataFrame::getJSON(bool meterOnlyCheck) const
467 : {
468 0 : json root;
469 0 : json cols = json::array();
470 0 : json rows = json::array();
471 :
472 0 : for (auto const &varMap : meterMap) {
473 0 : if (!(meterOnlyCheck && varMap.second.meterOnly())) {
474 0 : cols.push_back({{"Variable", varMap.second.variableName()}, {"Units", Constant::unitNames[(int)varMap.second.units()]}});
475 : }
476 : }
477 :
478 0 : if (cols.empty()) return root;
479 :
480 0 : json vals = json::array();
481 :
482 0 : for (size_t row = 0; row < TS.size(); ++row) {
483 0 : vals.clear();
484 :
485 0 : for (auto const &varMap : meterMap) {
486 0 : if (!(meterOnlyCheck && varMap.second.meterOnly())) {
487 0 : if (row < varMap.second.numValues()) {
488 0 : vals.push_back(varMap.second.value(row));
489 : } else {
490 0 : vals.push_back(nullptr);
491 : }
492 : }
493 : }
494 0 : rows.push_back({{TS.at(row), vals}});
495 : }
496 0 : root = {{"ReportFrequency", ReportFrequency}, {"Cols", cols}, {"Rows", rows}};
497 0 : return root;
498 0 : }
499 :
500 0 : void DataFrame::writeReport(JsonOutputFilePaths &jsonOutputFilePaths, bool outputJSON, bool outputCBOR, bool outputMsgPack)
501 : {
502 :
503 0 : json root = getJSON();
504 0 : if (ReportFrequency == "Detailed-HVAC") {
505 0 : if (outputJSON) {
506 0 : FileSystem::writeFile<FileSystem::FileTypes::JSON>(jsonOutputFilePaths.outputTSHvacJsonFilePath, root);
507 : }
508 0 : if (outputCBOR) {
509 0 : FileSystem::writeFile<FileSystem::FileTypes::CBOR>(jsonOutputFilePaths.outputTSHvacCborFilePath, root);
510 : }
511 0 : if (outputMsgPack) {
512 0 : FileSystem::writeFile<FileSystem::FileTypes::MsgPack>(jsonOutputFilePaths.outputTSHvacMsgPackFilePath, root);
513 : }
514 0 : } else if (ReportFrequency == "Detailed-Zone") {
515 0 : if (outputJSON) {
516 0 : FileSystem::writeFile<FileSystem::FileTypes::JSON>(jsonOutputFilePaths.outputTSZoneJsonFilePath, root);
517 : }
518 0 : if (outputCBOR) {
519 0 : FileSystem::writeFile<FileSystem::FileTypes::CBOR>(jsonOutputFilePaths.outputTSZoneCborFilePath, root);
520 : }
521 0 : if (outputMsgPack) {
522 0 : FileSystem::writeFile<FileSystem::FileTypes::MsgPack>(jsonOutputFilePaths.outputTSZoneMsgPackFilePath, root);
523 : }
524 0 : } else if (ReportFrequency == "TimeStep") {
525 0 : if (outputJSON) {
526 0 : FileSystem::writeFile<FileSystem::FileTypes::JSON>(jsonOutputFilePaths.outputTSJsonFilePath, root);
527 : }
528 0 : if (outputCBOR) {
529 0 : FileSystem::writeFile<FileSystem::FileTypes::CBOR>(jsonOutputFilePaths.outputTSCborFilePath, root);
530 : }
531 0 : if (outputMsgPack) {
532 0 : FileSystem::writeFile<FileSystem::FileTypes::MsgPack>(jsonOutputFilePaths.outputTSMsgPackFilePath, root);
533 : }
534 0 : } else if (ReportFrequency == "Daily") {
535 0 : if (outputJSON) {
536 0 : FileSystem::writeFile<FileSystem::FileTypes::JSON>(jsonOutputFilePaths.outputDYJsonFilePath, root);
537 : }
538 0 : if (outputCBOR) {
539 0 : FileSystem::writeFile<FileSystem::FileTypes::CBOR>(jsonOutputFilePaths.outputDYCborFilePath, root);
540 : }
541 0 : if (outputMsgPack) {
542 0 : FileSystem::writeFile<FileSystem::FileTypes::MsgPack>(jsonOutputFilePaths.outputDYMsgPackFilePath, root);
543 : }
544 0 : } else if (ReportFrequency == "Hourly") {
545 0 : if (outputJSON) {
546 0 : FileSystem::writeFile<FileSystem::FileTypes::JSON>(jsonOutputFilePaths.outputHRJsonFilePath, root);
547 : }
548 0 : if (outputCBOR) {
549 0 : FileSystem::writeFile<FileSystem::FileTypes::CBOR>(jsonOutputFilePaths.outputHRCborFilePath, root);
550 : }
551 0 : if (outputMsgPack) {
552 0 : FileSystem::writeFile<FileSystem::FileTypes::MsgPack>(jsonOutputFilePaths.outputHRMsgPackFilePath, root);
553 : }
554 0 : } else if (ReportFrequency == "Monthly") {
555 0 : if (outputJSON) {
556 0 : FileSystem::writeFile<FileSystem::FileTypes::JSON>(jsonOutputFilePaths.outputMNJsonFilePath, root);
557 : }
558 0 : if (outputCBOR) {
559 0 : FileSystem::writeFile<FileSystem::FileTypes::CBOR>(jsonOutputFilePaths.outputMNCborFilePath, root);
560 : }
561 0 : if (outputMsgPack) {
562 0 : FileSystem::writeFile<FileSystem::FileTypes::MsgPack>(jsonOutputFilePaths.outputMNMsgPackFilePath, root);
563 : }
564 0 : } else if (ReportFrequency == "RunPeriod") {
565 0 : if (outputJSON) {
566 0 : FileSystem::writeFile<FileSystem::FileTypes::JSON>(jsonOutputFilePaths.outputSMJsonFilePath, root);
567 : }
568 0 : if (outputCBOR) {
569 0 : FileSystem::writeFile<FileSystem::FileTypes::CBOR>(jsonOutputFilePaths.outputSMCborFilePath, root);
570 : }
571 0 : if (outputMsgPack) {
572 0 : FileSystem::writeFile<FileSystem::FileTypes::MsgPack>(jsonOutputFilePaths.outputSMMsgPackFilePath, root);
573 : }
574 0 : } else if (ReportFrequency == "Yearly") {
575 0 : if (outputJSON) {
576 0 : FileSystem::writeFile<FileSystem::FileTypes::JSON>(jsonOutputFilePaths.outputYRJsonFilePath, root);
577 : }
578 0 : if (outputCBOR) {
579 0 : FileSystem::writeFile<FileSystem::FileTypes::CBOR>(jsonOutputFilePaths.outputYRCborFilePath, root);
580 : }
581 0 : if (outputMsgPack) {
582 0 : FileSystem::writeFile<FileSystem::FileTypes::MsgPack>(jsonOutputFilePaths.outputYRMsgPackFilePath, root);
583 : }
584 : }
585 0 : }
586 : // class Table
587 :
588 3 : Table::Table(Array2D_string const &body,
589 : Array1D_string const &rowLabels,
590 : Array1D_string const &columnLabels,
591 : std::string const &tableName,
592 3 : std::string const &footnoteText)
593 : {
594 :
595 3 : size_t sizeColumnLabels = columnLabels.size();
596 3 : size_t sizeRowLabels = rowLabels.size();
597 3 : TableName = tableName;
598 3 : FootnoteText = footnoteText;
599 :
600 8 : for (size_t iCol = 0, k = body.index(1, 1); iCol < sizeColumnLabels; ++iCol) {
601 5 : ColHeaders.push_back(columnLabels[iCol]);
602 5 : std::vector<std::string> col;
603 12 : for (size_t iRow = 0; iRow < sizeRowLabels; ++iRow) {
604 7 : if (iCol == 0) {
605 : // do this once only
606 5 : RowHeaders.push_back(rowLabels[iRow]);
607 : }
608 7 : col.push_back(trim(body[k]));
609 7 : ++k;
610 : }
611 5 : Data.push_back(col);
612 5 : }
613 3 : }
614 :
615 3 : json Table::getJSON() const
616 : {
617 3 : json root;
618 3 : json cols = json::array();
619 3 : json rows;
620 :
621 8 : for (size_t col = 0; col < ColHeaders.size(); ++col) {
622 5 : cols.push_back(ColHeaders[col]);
623 : }
624 :
625 8 : for (size_t row = 0; row < RowHeaders.size(); ++row) {
626 5 : json rowvec = json::array();
627 12 : for (size_t col = 0; col < ColHeaders.size(); ++col) {
628 7 : rowvec.push_back(Data[col][row]);
629 : }
630 5 : rows[RowHeaders[row]] = rowvec;
631 5 : }
632 :
633 30 : root = {{"TableName", TableName}, {"Cols", cols}, {"Rows", rows}};
634 :
635 3 : if (!FootnoteText.empty()) root["Footnote"] = FootnoteText;
636 6 : return root;
637 27 : }
638 :
639 : // class Report
640 :
641 1 : json Report::getJSON() const
642 : {
643 :
644 7 : json root = {{"ReportName", ReportName}, {"For", ReportForString}};
645 :
646 1 : json cols = json::array();
647 :
648 3 : for (auto const &table : Tables) {
649 2 : cols.push_back(table.getJSON());
650 : }
651 :
652 1 : root["Tables"] = cols;
653 2 : return root;
654 7 : }
655 :
656 : // class ReportsCollection
657 2129 : ReportsCollection::ReportsCollection()
658 : {
659 2129 : }
660 :
661 0 : void ReportsCollection::addReportTable(Array2D_string const &body,
662 : Array1D_string const &rowLabels,
663 : Array1D_string const &columnLabels,
664 : std::string const &reportName,
665 : std::string const &reportForString,
666 : std::string const &tableName)
667 : {
668 0 : addReportTable(body, rowLabels, columnLabels, reportName, reportForString, tableName, "");
669 0 : }
670 :
671 0 : void ReportsCollection::addReportTable(Array2D_string const &body,
672 : Array1D_string const &rowLabels,
673 : Array1D_string const &columnLabels,
674 : std::string const &reportName,
675 : std::string const &reportForString,
676 : std::string const &tableName,
677 : std::string const &footnoteText)
678 : {
679 0 : std::string const key = reportName + reportForString;
680 : // Report *r;
681 0 : Table tbl(body, rowLabels, columnLabels, tableName, footnoteText);
682 :
683 0 : auto search = reportsMap.find(key);
684 0 : if (search != reportsMap.end()) {
685 : // r = search->second;
686 0 : search->second.Tables.push_back(tbl);
687 : } else {
688 : // r = new Report();
689 0 : Report r;
690 0 : r.ReportName = reportName;
691 0 : r.ReportForString = reportForString;
692 0 : r.Tables.push_back(tbl);
693 0 : reportsMap.emplace(key, r);
694 0 : }
695 :
696 : // Table *tbl = new Table( body, rowLabels, columnLabels, tableName, footnoteText );
697 : // r->Tables.push_back( tbl );
698 0 : }
699 :
700 0 : json ReportsCollection::getJSON() const
701 : {
702 0 : json root = json::array();
703 :
704 0 : for (auto const &iter : reportsMap) {
705 0 : root.push_back(iter.second.getJSON());
706 : }
707 0 : return root;
708 0 : }
709 :
710 4 : void CSVWriter::parseTSOutputs(EnergyPlusData &state,
711 : json const &data,
712 : std::vector<std::string> const &outputVariables,
713 : OutputProcessor::ReportFreq reportingFrequency)
714 : {
715 4 : if (data.empty()) return;
716 4 : updateReportFreq(reportingFrequency);
717 4 : std::vector<int> indices;
718 :
719 4 : std::string reportFrequency = data.at("ReportFrequency").get<std::string>();
720 4 : if (reportFrequency == "Detailed-HVAC" || reportFrequency == "Detailed-Zone") {
721 0 : reportFrequency = "Each Call";
722 : }
723 4 : auto const &columns = data.at("Cols");
724 8 : for (auto const &column : columns) {
725 : std::string search_string =
726 16 : fmt::format("{0} [{1}]({2})", column.at("Variable").get<std::string>(), column.at("Units").get<std::string>(), reportFrequency);
727 4 : auto found = std::find(outputVariables.begin(), outputVariables.end(), search_string);
728 4 : if (found == outputVariables.end()) {
729 : search_string =
730 0 : fmt::format("{0} [{1}]({2})", column.at("Variable").get<std::string>(), column.at("Units").get<std::string>(), "Each Call");
731 0 : found = std::find(outputVariables.begin(), outputVariables.end(), search_string);
732 : }
733 4 : if (found == outputVariables.end()) {
734 0 : ShowFatalError(state, fmt::format("Output variable ({0}) not found output variable list", search_string));
735 : }
736 8 : outputVariableIndices[std::distance(outputVariables.begin(), found)] = true;
737 8 : indices.emplace_back(std::distance(outputVariables.begin(), found));
738 4 : }
739 :
740 4 : auto const &rows = data.at("Rows");
741 20 : for (auto const &row : rows) {
742 32 : for (auto &el : row.items()) {
743 16 : auto found_key = outputs.find(el.key());
744 16 : if (found_key == outputs.end()) {
745 16 : std::vector<std::string> output(outputVariables.size());
746 16 : int i = 0;
747 32 : for (auto const &col : el.value()) {
748 16 : if (col.is_null()) {
749 0 : output[indices[i]] = "";
750 : } else {
751 16 : dtoa(col.get<double>(), s);
752 16 : output[indices[i]] = s;
753 : }
754 16 : ++i;
755 : }
756 16 : outputs[el.key()] = output;
757 16 : } else {
758 0 : int i = 0;
759 0 : for (auto const &col : el.value()) {
760 0 : if (col.is_null()) {
761 0 : found_key->second[indices[i]] = "";
762 : } else {
763 0 : dtoa(col.get<double>(), s);
764 0 : found_key->second[indices[i]] = s;
765 : }
766 0 : ++i;
767 : }
768 : }
769 16 : }
770 : }
771 4 : }
772 :
773 4 : void CSVWriter::updateReportFreq(OutputProcessor::ReportFreq reportingFrequency)
774 : {
775 4 : if (reportingFrequency < smallestReportFreq) {
776 4 : smallestReportFreq = reportingFrequency;
777 : }
778 4 : }
779 :
780 12 : std::string &CSVWriter::convertToMonth(std::string &datetime)
781 : {
782 : // if running this function, there should only ever be 12 + design days values to change
783 : static const std::map<std::string, std::string> months({{"01", "January"},
784 : {"02", "February"},
785 : {"03", "March"},
786 : {"04", "April"},
787 : {"05", "May"},
788 : {"06", "June"},
789 : {"07", "July"},
790 : {"08", "August"},
791 : {"09", "September"},
792 : {"10", "October"},
793 : {"11", "November"},
794 25 : {"12", "December"}});
795 : // 01/01 24:00:00
796 12 : std::string const month = datetime.substr(0, 2);
797 12 : size_t const pos = datetime.find(' ');
798 12 : std::string time;
799 12 : if (pos != std::string::npos) {
800 12 : time = datetime.substr(pos);
801 : }
802 : // This assert replaces ShowFatalError(state, "Monthly output variables should occur at the end of the day.");
803 12 : assert(time == " 24:00:00" || time == " 00:00:00");
804 :
805 12 : datetime = months.find(month)->second;
806 12 : return datetime;
807 13 : }
808 :
809 0 : void CSVWriter::writeOutput(EnergyPlusData &state,
810 : std::vector<std::string> const &outputVariables,
811 : InputOutputFile &outputFile,
812 : bool outputControl,
813 : bool rewriteTimestamp)
814 : {
815 0 : outputFile.ensure_open(state, "OpenOutputFiles", outputControl);
816 :
817 0 : print<FormatSyntax::FMT>(outputFile, "{}", "Date/Time,");
818 0 : std::string sep;
819 0 : for (auto it = outputVariables.begin(); it != outputVariables.end(); ++it) {
820 0 : if (!outputVariableIndices[std::distance(outputVariables.begin(), it)]) continue;
821 0 : print<FormatSyntax::FMT>(outputFile, "{}{}", sep, *it);
822 0 : if (sep.empty()) sep = ",";
823 : }
824 0 : print<FormatSyntax::FMT>(outputFile, "{}", '\n');
825 :
826 0 : for (auto &item : outputs) {
827 0 : std::string datetime = item.first;
828 0 : if (rewriteTimestamp) {
829 0 : if (smallestReportFreq < OutputProcessor::ReportFreq::Month) {
830 0 : datetime = datetime.replace(datetime.find(' '), 1, " ");
831 : } else {
832 0 : convertToMonth(datetime);
833 : }
834 : }
835 0 : print<FormatSyntax::FMT>(outputFile, " {},", datetime);
836 0 : item.second.erase(std::remove_if(item.second.begin(),
837 : item.second.end(),
838 0 : [&](const std::string &d) {
839 0 : auto pos = (&d - &*item.second.begin());
840 0 : return !outputVariableIndices[pos];
841 : }),
842 0 : item.second.end());
843 0 : auto result = std::find_if(item.second.rbegin(), item.second.rend(), [](std::string const &v) { return !v.empty(); });
844 0 : auto last = item.second.end() - 1;
845 0 : if (result != item.second.rend()) {
846 0 : last = (result + 1).base();
847 : }
848 :
849 0 : print<FormatSyntax::FMT>(outputFile, "{},", fmt::join(item.second.begin(), last, ","));
850 0 : print<FormatSyntax::FMT>(outputFile, "{}\n", *last);
851 0 : }
852 :
853 0 : outputFile.close();
854 0 : }
855 :
856 77 : void ResultsFramework::setupOutputOptions(EnergyPlusData &state)
857 : {
858 77 : if (state.files.outputControl.csv) {
859 0 : tsEnabled = true;
860 0 : tsAndTabularEnabled = true;
861 : }
862 :
863 77 : if (!state.files.outputControl.json) {
864 75 : return;
865 : }
866 :
867 77 : int numberOfOutputSchemaObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Output:JSON");
868 77 : if (numberOfOutputSchemaObjects == 0) {
869 75 : return;
870 : }
871 :
872 2 : Array1D_string alphas(5);
873 : int numAlphas;
874 2 : Array1D<Real64> numbers(2);
875 : int numNumbers;
876 : int status;
877 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state, "Output:JSON", 1, alphas, numAlphas, numbers, numNumbers, status);
878 :
879 2 : if (numAlphas > 0) {
880 2 : std::string option = alphas(1);
881 2 : if (Util::SameString(option, "TimeSeries")) {
882 1 : tsEnabled = true;
883 1 : } else if (Util::SameString(option, "TimeSeriesAndTabular")) {
884 1 : tsEnabled = true;
885 1 : tsAndTabularEnabled = true;
886 : }
887 :
888 : // defaults
889 2 : outputJSON = true;
890 2 : outputCBOR = false;
891 2 : outputMsgPack = false;
892 :
893 2 : if (numAlphas >= 2) {
894 0 : outputJSON = Util::SameString(alphas(2), "Yes");
895 : }
896 :
897 2 : if (numAlphas >= 3) {
898 0 : outputCBOR = Util::SameString(alphas(3), "Yes");
899 : }
900 :
901 2 : if (numAlphas >= 4) {
902 0 : outputMsgPack = Util::SameString(alphas(4), "Yes");
903 : }
904 2 : }
905 2 : }
906 :
907 138248 : bool ResultsFramework::timeSeriesEnabled() const
908 : {
909 138248 : return tsEnabled;
910 : }
911 :
912 7500 : bool ResultsFramework::timeSeriesAndTabularEnabled() const
913 : {
914 7500 : return tsAndTabularEnabled;
915 : }
916 :
917 0 : bool ResultsFramework::JSONEnabled() const
918 : {
919 0 : return outputJSON;
920 : }
921 :
922 0 : bool ResultsFramework::CBOREnabled() const
923 : {
924 0 : return outputCBOR;
925 : }
926 :
927 0 : bool ResultsFramework::MsgPackEnabled() const
928 : {
929 0 : return outputMsgPack;
930 : }
931 :
932 0 : void ResultsFramework::initializeTSDataFrame(const OutputProcessor::ReportFreq reportFrequency,
933 : const std::vector<OutputProcessor::OutVar *> &Variables,
934 : const OutputProcessor::TimeStepType timeStepType)
935 : {
936 0 : for (auto *var : Variables) {
937 :
938 0 : if (var->Report && var->freq == reportFrequency) {
939 0 : Variable rfvar;
940 0 : if (var->units == Constant::Units::customEMS) {
941 0 : rfvar = Variable(var->keyColonName, reportFrequency, var->timeStepType, var->ReportID, var->units, var->unitNameCustomEMS);
942 : } else {
943 0 : rfvar = Variable(var->keyColonName, reportFrequency, var->timeStepType, var->ReportID, var->units);
944 : }
945 :
946 0 : switch (reportFrequency) {
947 0 : case OutputProcessor::ReportFreq::EachCall: { // each time UpdatedataandReport is called
948 0 : if (timeStepType == var->timeStepType) {
949 0 : detailedTSData[(int)timeStepType].setDataFrameEnabled(true);
950 0 : detailedTSData[(int)timeStepType].addVariable(rfvar);
951 : }
952 0 : } break;
953 0 : case OutputProcessor::ReportFreq::Hour: // at 'EndHourFlag'
954 : case OutputProcessor::ReportFreq::TimeStep: // at 'EndTimeStepFlag'
955 : case OutputProcessor::ReportFreq::Day: // at 'EndDayFlag'
956 : case OutputProcessor::ReportFreq::Month: // at 'EndMonthFlag'
957 : case OutputProcessor::ReportFreq::Simulation: // once per environment 'EndEnvrnFlag'
958 : case OutputProcessor::ReportFreq::Year: { // at end of year
959 0 : freqTSData[(int)reportFrequency].setDataFrameEnabled(true);
960 0 : freqTSData[(int)reportFrequency].addVariable(rfvar);
961 0 : } break;
962 0 : default: {
963 0 : assert(false);
964 : } break;
965 : }
966 0 : }
967 : }
968 : // set the scanned variables to true or false
969 0 : switch (reportFrequency) {
970 0 : case OutputProcessor::ReportFreq::EachCall: {
971 0 : detailedTSData[(int)timeStepType].setVariablesScanned(true);
972 0 : } break;
973 0 : case OutputProcessor::ReportFreq::TimeStep: // at 'EndTimeStepFlag'
974 : case OutputProcessor::ReportFreq::Hour: // at 'EndHourFlag'
975 : case OutputProcessor::ReportFreq::Day: // at 'EndDayFlag'
976 : case OutputProcessor::ReportFreq::Month: // at end of month
977 : case OutputProcessor::ReportFreq::Simulation: // once per environment 'EndEnvrnFlag'
978 : case OutputProcessor::ReportFreq::Year: { // at end of year
979 0 : detailedTSData[(int)timeStepType].setVariablesScanned(true);
980 0 : } break;
981 0 : default: {
982 0 : assert(false);
983 : } break;
984 : }
985 0 : }
986 :
987 21302 : void ResultsFramework::initializeMeters(const std::vector<OutputProcessor::Meter *> &meters, const OutputProcessor::ReportFreq freq)
988 : {
989 21302 : switch (freq) {
990 0 : case OutputProcessor::ReportFreq::EachCall: {
991 : // nothing to do; meters are not reported at this frequency
992 0 : } break;
993 21302 : case OutputProcessor::ReportFreq::TimeStep: // at 'TimeStep'
994 : case OutputProcessor::ReportFreq::Hour: // at 'Hourly'
995 : case OutputProcessor::ReportFreq::Day: // at 'Daily'
996 : case OutputProcessor::ReportFreq::Month: // at 'Monthly'
997 : case OutputProcessor::ReportFreq::Simulation: // at 'RunPeriod'/'SM'
998 : case OutputProcessor::ReportFreq::Year: { // at 'Yearly'
999 827205 : for (auto const *meter : meters) {
1000 805903 : auto const &period = meter->periods[(int)freq];
1001 805903 : if (period.Rpt || period.RptFO) {
1002 98 : Meters[(int)freq].addVariable(MeterVariable(meter->Name, freq, period.RptNum, meter->units, period.RptFO));
1003 98 : Meters[(int)freq].setDataFrameEnabled(true);
1004 : }
1005 805903 : if (period.accRpt || period.accRptFO) {
1006 0 : Meters[(int)freq].addVariable(MeterVariable(meter->Name, freq, period.accRptNum, meter->units, period.accRptFO));
1007 0 : Meters[(int)freq].setDataFrameEnabled(true);
1008 : }
1009 : }
1010 21302 : } break;
1011 :
1012 0 : default: {
1013 0 : assert(false);
1014 : } break;
1015 : } // switch (frequency)
1016 :
1017 : // set the scanned variables to true or false
1018 21302 : switch (freq) {
1019 0 : case OutputProcessor::ReportFreq::EachCall:
1020 : // case should not happen in Meters
1021 0 : break;
1022 21302 : case OutputProcessor::ReportFreq::TimeStep: // at TimeStepFlag
1023 : case OutputProcessor::ReportFreq::Hour: // at Hourly
1024 : case OutputProcessor::ReportFreq::Day: // at Daily
1025 : case OutputProcessor::ReportFreq::Month: // at Monthly
1026 : case OutputProcessor::ReportFreq::Simulation: // at RunPeriod/SM
1027 : case OutputProcessor::ReportFreq::Year: { // at Yearly
1028 21302 : Meters[(int)freq].setVariablesScanned(true);
1029 21302 : } break;
1030 0 : default:
1031 0 : assert(false);
1032 : }
1033 21302 : }
1034 :
1035 26 : void ResultsFramework::writeOutputs(EnergyPlusData &state)
1036 : {
1037 26 : if (state.files.outputControl.csv) {
1038 0 : writeCSVOutput(state);
1039 : }
1040 :
1041 26 : if (timeSeriesEnabled() && (outputJSON || outputCBOR || outputMsgPack)) {
1042 0 : writeTimeSeriesReports(state.files.json);
1043 : }
1044 :
1045 26 : if (timeSeriesAndTabularEnabled() && (outputJSON || outputCBOR || outputMsgPack)) {
1046 0 : writeReport(state.files.json);
1047 : }
1048 26 : }
1049 :
1050 0 : void ResultsFramework::writeCSVOutput(EnergyPlusData &state)
1051 : {
1052 : using OutputProcessor::ReportFreq;
1053 :
1054 0 : if (!hasOutputData()) {
1055 0 : return;
1056 : }
1057 0 : CSVWriter csv(outputVariables.size());
1058 0 : CSVWriter mtr_csv(outputVariables.size());
1059 :
1060 0 : for (ReportFreq freq :
1061 0 : {ReportFreq::Year, ReportFreq::Simulation, ReportFreq::Month, ReportFreq::Day, ReportFreq::Hour, ReportFreq::TimeStep}) {
1062 : // Output yearly time series data
1063 0 : if (hasTSData(freq)) {
1064 0 : csv.parseTSOutputs(state, freqTSData[(int)freq].getJSON(), outputVariables, freq);
1065 : }
1066 :
1067 0 : if (hasMeters(freq)) {
1068 0 : csv.parseTSOutputs(state, Meters[(int)freq].getJSON(true), outputVariables, freq);
1069 0 : mtr_csv.parseTSOutputs(state, Meters[(int)freq].getJSON(), outputVariables, freq);
1070 : }
1071 : }
1072 :
1073 0 : for (TimeStepType timeStepType : {TimeStepType::System, TimeStepType::Zone}) {
1074 : // Output detailed HVAC time series data
1075 0 : if (hasDetailedTSData(timeStepType)) {
1076 0 : csv.parseTSOutputs(state, detailedTSData[(int)timeStepType].getJSON(), outputVariables, ReportFreq::EachCall);
1077 : }
1078 : }
1079 :
1080 0 : csv.writeOutput(state, outputVariables, state.files.csv, state.files.outputControl.csv, rewriteTimestamp);
1081 0 : if (hasMeterData()) {
1082 0 : mtr_csv.writeOutput(state, outputVariables, state.files.mtr_csv, state.files.outputControl.csv, rewriteTimestamp);
1083 : }
1084 0 : }
1085 :
1086 0 : void ResultsFramework::writeTimeSeriesReports(JsonOutputFilePaths &jsonOutputFilePaths)
1087 : {
1088 : // Output detailed Zone & HVAC time series data
1089 0 : for (TimeStepType timeStepType : {TimeStepType::Zone, TimeStepType::System}) {
1090 0 : if (hasDetailedTSData(timeStepType)) {
1091 0 : detailedTSData[(int)timeStepType].writeReport(jsonOutputFilePaths, outputJSON, outputCBOR, outputMsgPack);
1092 : }
1093 : }
1094 :
1095 : // Output timestep time series data
1096 0 : for (ReportFreq freq :
1097 0 : {ReportFreq::TimeStep, ReportFreq::Hour, ReportFreq::Day, ReportFreq::Month, ReportFreq::Simulation, ReportFreq::Year}) {
1098 0 : if (hasFreqTSData(freq)) {
1099 0 : freqTSData[(int)freq].writeReport(jsonOutputFilePaths, outputJSON, outputCBOR, outputMsgPack);
1100 : }
1101 : }
1102 0 : }
1103 :
1104 0 : void ResultsFramework::writeReport(JsonOutputFilePaths &jsonOutputFilePaths)
1105 : {
1106 0 : json root, outputVars, meterVars, meterData;
1107 0 : root = {{"SimulationResults", {{"Simulation", SimulationInformation.getJSON()}}}};
1108 :
1109 : // output variables
1110 :
1111 : // This could be constexpr except that json maps do not take string_view keys
1112 0 : static std::array<std::string, (int)TimeStepType::Num> const timeStepStrings = {"Detailed-Zone", "Detailed-HVAC"};
1113 0 : for (TimeStepType timeStep : {TimeStepType::Zone, TimeStepType::System}) {
1114 0 : if (hasDetailedTSData(timeStep)) {
1115 0 : outputVars[timeStepStrings[(int)timeStep]] = detailedTSData[(int)timeStep].getVariablesJSON();
1116 : }
1117 : }
1118 :
1119 : // Same issue here
1120 : static std::array<std::string, (int)ReportFreq::Num> const freqStrings = {
1121 0 : "Detailed", "TimeStep", "Hourly", "Daily", "Monthly", "RunPeriod", "Yearly"};
1122 0 : for (ReportFreq freq :
1123 0 : {ReportFreq::Year, ReportFreq::Simulation, ReportFreq::Month, ReportFreq::Day, ReportFreq::Hour, ReportFreq::TimeStep}) {
1124 0 : if (hasFreqTSData(freq)) {
1125 0 : outputVars[freqStrings[(int)freq]] = freqTSData[(int)freq].getVariablesJSON();
1126 : }
1127 : }
1128 :
1129 : // output dictionary
1130 0 : outputVars["OutputDictionary"] = {{"Description", "Dictionary containing output variables that may be requested"}, {"Variables", RDD}};
1131 :
1132 : // meter variables
1133 :
1134 : // -- meter values
1135 0 : for (ReportFreq freq :
1136 0 : {ReportFreq::Year, ReportFreq::Simulation, ReportFreq::Month, ReportFreq::Day, ReportFreq::Hour, ReportFreq::TimeStep}) {
1137 0 : if (hasMeters(freq)) {
1138 0 : meterVars[freqStrings[(int)freq]] = Meters[(int)freq].getVariablesJSON();
1139 0 : meterData[freqStrings[(int)freq]] = Meters[(int)freq].getJSON();
1140 : }
1141 : }
1142 :
1143 : // -- meter dictionary
1144 0 : meterVars["MeterDictionary"] = {{"Description", "Dictionary containing meter variables that may be requested"}, {"Meters", MDD}};
1145 :
1146 0 : root["OutputVariables"] = outputVars;
1147 0 : root["MeterVariables"] = meterVars;
1148 0 : root["MeterData"] = meterData;
1149 0 : root["TabularReports"] = TabularReportsCollection.getJSON();
1150 :
1151 0 : if (outputJSON) {
1152 0 : FileSystem::writeFile<FileSystem::FileTypes::JSON>(jsonOutputFilePaths.outputJsonFilePath, root);
1153 : }
1154 0 : if (outputCBOR) {
1155 0 : FileSystem::writeFile<FileSystem::FileTypes::CBOR>(jsonOutputFilePaths.outputCborFilePath, root);
1156 : }
1157 0 : if (outputMsgPack) {
1158 0 : FileSystem::writeFile<FileSystem::FileTypes::MsgPack>(jsonOutputFilePaths.outputMsgPackFilePath, root);
1159 : }
1160 0 : }
1161 :
1162 5575 : void ResultsFramework::addReportVariable(std::string_view const keyedValue,
1163 : std::string_view const variableName,
1164 : std::string_view const units,
1165 : OutputProcessor::ReportFreq const freq)
1166 : {
1167 11150 : outputVariables.emplace_back(fmt::format("{0}:{1} [{2}]({3})", keyedValue, variableName, units, reportFreqNames[(int)freq]));
1168 5575 : }
1169 :
1170 127 : void ResultsFramework::addReportMeter(std::string const &meter, std::string_view units, OutputProcessor::ReportFreq const freq)
1171 : {
1172 254 : outputVariables.emplace_back(fmt::format("{0} [{1}]({2})", meter, units, reportFreqNames[(int)freq]));
1173 127 : }
1174 :
1175 : } // namespace ResultsFramework
1176 :
1177 : } // namespace EnergyPlus
|