Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, 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 66547 : std::string trim(std::string_view const s)
82 : {
83 66547 : if (s.empty()) {
84 6109 : return std::string{};
85 : }
86 60438 : auto const first = s.find_first_not_of(' ');
87 60438 : auto const last = s.find_last_not_of(' ');
88 60438 : if ((first == std::string::npos) || (last == std::string::npos)) {
89 0 : return std::string{};
90 : } else {
91 60438 : return std::string{s.substr(first, last - first + 1)};
92 : }
93 : }
94 :
95 : // Class SimInfo
96 796 : void SimInfo::setProgramVersion(const std::string &programVersion)
97 : {
98 796 : ProgramVersion = programVersion;
99 796 : }
100 :
101 0 : std::string SimInfo::getProgramVersion() const
102 : {
103 0 : return ProgramVersion;
104 : }
105 :
106 0 : void SimInfo::setSimulationEnvironment(const std::string &simulationEnvironment)
107 : {
108 0 : SimulationEnvironment = simulationEnvironment;
109 0 : }
110 :
111 0 : void SimInfo::setInputModelURI(const std::string &inputModelURI)
112 : {
113 0 : InputModelURI = inputModelURI;
114 0 : }
115 :
116 796 : void SimInfo::setStartDateTimeStamp(const std::string &startDateTimeStamp)
117 : {
118 796 : StartDateTimeStamp = startDateTimeStamp;
119 796 : }
120 :
121 796 : void SimInfo::setRunTime(const std::string &elapsedTime)
122 : {
123 796 : RunTime = elapsedTime;
124 796 : }
125 :
126 796 : void SimInfo::setNumErrorsWarmup(const std::string &numWarningsDuringWarmup, const std::string &numSevereDuringWarmup)
127 : {
128 796 : NumWarningsDuringWarmup = numWarningsDuringWarmup;
129 796 : NumSevereDuringWarmup = numSevereDuringWarmup;
130 796 : }
131 :
132 796 : void SimInfo::setNumErrorsSizing(const std::string &numWarningsDuringSizing, const std::string &numSevereDuringSizing)
133 : {
134 796 : NumWarningsDuringSizing = numWarningsDuringSizing;
135 796 : NumSevereDuringSizing = numSevereDuringSizing;
136 796 : }
137 :
138 796 : void SimInfo::setNumErrorsSummary(const std::string &numWarnings, const std::string &numSevere)
139 : {
140 796 : NumWarnings = numWarnings;
141 796 : NumSevere = numSevere;
142 796 : }
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 120 : {"ErrorSummarySizing", {{"NumWarnings", NumWarningsDuringSizing}, {"NumSevere", NumSevereDuringSizing}}}};
154 2 : return root;
155 : }
156 :
157 : // Class Variable
158 36254 : Variable::Variable(const std::string &VarName,
159 : const OutputProcessor::ReportFreq reportFrequency,
160 : const OutputProcessor::TimeStepType timeStepType,
161 : const int ReportID,
162 36254 : const Constant::Units units)
163 36254 : : m_varName(VarName), m_reportFreq(reportFrequency), m_timeStepType(timeStepType), m_rptID(ReportID), m_units(units)
164 : {
165 36254 : }
166 :
167 52 : 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 52 : const std::string &customUnits)
173 104 : : m_varName(VarName), m_reportFreq(reportFrequency), m_timeStepType(timeStepType), m_rptID(ReportID), m_units(units),
174 52 : m_customUnits(customUnits)
175 : {
176 52 : }
177 :
178 649 : std::string Variable::variableName() const
179 : {
180 649 : return m_varName;
181 : }
182 :
183 0 : void Variable::setVariableName(const std::string &VarName)
184 : {
185 0 : m_varName = VarName;
186 0 : }
187 :
188 96 : 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 98 : return (m_reportFreq == ReportFreq::EachCall) ? std::string(timeStepTypeStrings[(int)m_timeStepType])
196 96 : : 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 36277 : int Variable::reportID() const
220 : {
221 36277 : return m_rptID;
222 : }
223 :
224 0 : void Variable::setReportID(int Id)
225 : {
226 0 : m_rptID = Id;
227 0 : }
228 :
229 646 : Constant::Units Variable::units() const
230 : {
231 646 : return m_units;
232 : }
233 :
234 0 : void Variable::setUnits(const Constant::Units units)
235 : {
236 0 : m_units = units;
237 0 : }
238 :
239 496 : std::string Variable::customUnits() const
240 : {
241 496 : return m_customUnits;
242 : }
243 :
244 0 : void Variable::setCustomUnits(const std::string &customUnits)
245 : {
246 0 : m_customUnits = customUnits;
247 0 : }
248 :
249 123089 : void Variable::pushValue(const double val)
250 : {
251 123089 : m_values.push_back(val);
252 123089 : }
253 :
254 40762 : double Variable::value(size_t index) const
255 : {
256 40762 : return m_values.at(index);
257 : }
258 :
259 41854 : size_t Variable::numValues() const
260 : {
261 41854 : return m_values.size();
262 : }
263 :
264 96 : json Variable::getJSON() const
265 : {
266 96 : json root;
267 96 : if (m_customUnits.empty()) {
268 960 : 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 96 : return root;
273 0 : }
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 8360 : 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 8360 : const bool Accumulative)
302 8360 : : Variable(VarName, reportFrequency, OutputProcessor::TimeStepType::Zone, ReportID, units)
303 : {
304 8360 : acc = Accumulative;
305 8360 : meter_only = MeterOnly;
306 8360 : }
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 556 : bool MeterVariable::meterOnly() const
319 : {
320 556 : 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 12736 : DataFrame::DataFrame(const std::string &ReportFreq)
342 : {
343 12736 : ReportFrequency = ReportFreq;
344 12736 : }
345 :
346 27917 : void DataFrame::addVariable(Variable const &var)
347 : {
348 27917 : lastVarID = var.reportID();
349 27917 : variableMap.emplace(lastVarID, var);
350 27917 : }
351 :
352 0 : Variable &DataFrame::lastVariable()
353 : {
354 0 : return variableMap.at(lastVarID);
355 : }
356 :
357 25089 : void DataFrame::newRow(const int month, const int dayOfMonth, int hourOfDay, int curMin, int calendarYear)
358 : {
359 25089 : if (curMin > 0) {
360 13909 : hourOfDay -= 1;
361 : }
362 25089 : if (curMin == 60) {
363 2010 : curMin = 0;
364 2010 : hourOfDay += 1;
365 : }
366 :
367 25089 : if (beginningOfInterval) {
368 648 : if (hourOfDay == 24) {
369 18 : hourOfDay = 0;
370 : }
371 648 : std::swap(hourOfDay, lastHour);
372 648 : 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 25089 : if (iso8601) {
378 1296 : TS.emplace_back(fmt::format("{:04d}-{:02d}-{:02d}T{:02d}:{:02d}:00", calendarYear, month, dayOfMonth, hourOfDay, curMin));
379 : } else {
380 48882 : TS.emplace_back(fmt::format("{:02d}/{:02d} {:02d}:{:02d}:00", month, dayOfMonth, hourOfDay, curMin));
381 : }
382 25089 : }
383 :
384 : // void DataFrame::newRow(const std::string &ts)
385 : // {
386 : // TS.emplace_back(ts);
387 : // }
388 :
389 604096 : bool DataFrame::dataFrameEnabled() const
390 : {
391 604096 : return DataFrameEnabled;
392 : }
393 :
394 36277 : void DataFrame::setDataFrameEnabled(bool state)
395 : {
396 36277 : DataFrameEnabled = state;
397 36277 : }
398 :
399 575622 : void DataFrame::setVariablesScanned(bool state)
400 : {
401 575622 : VariablesScanned = state;
402 575622 : }
403 :
404 8881 : bool DataFrame::variablesScanned() const
405 : {
406 8881 : return VariablesScanned;
407 : }
408 :
409 39208 : void DataFrame::pushVariableValue(const int reportID, double value)
410 : {
411 39208 : variableMap[reportID].pushValue(value);
412 39208 : }
413 :
414 7 : json DataFrame::getVariablesJSON()
415 : {
416 7 : json arr = json::array();
417 103 : for (auto const &varMap : variableMap) {
418 96 : arr.push_back(varMap.second.getJSON());
419 7 : }
420 7 : return arr;
421 0 : }
422 :
423 15 : json DataFrame::getJSON() const
424 : {
425 15 : json root;
426 15 : json cols = json::array();
427 15 : json rows = json::array();
428 :
429 508 : for (auto const &varMap : variableMap) {
430 493 : if (varMap.second.customUnits().empty()) {
431 3430 : cols.push_back({{"Variable", varMap.second.variableName()}, {"Units", Constant::unitNames[(int)varMap.second.units()]}});
432 : } else {
433 21 : cols.push_back({{"Variable", varMap.second.variableName()}, {"Units", varMap.second.customUnits()}});
434 : }
435 15 : }
436 :
437 15 : json vals = json::array();
438 :
439 3431 : for (size_t row = 0; row < TS.size(); ++row) {
440 3416 : vals.clear();
441 :
442 43716 : for (auto const &varMap : variableMap) {
443 40300 : if (row < varMap.second.numValues()) {
444 39208 : vals.push_back(varMap.second.value(row));
445 : } else {
446 1092 : vals.push_back(nullptr);
447 : }
448 3416 : }
449 13664 : rows.push_back({{TS.at(row), vals}});
450 : }
451 150 : root = {{"ReportFrequency", ReportFrequency}, {"Cols", cols}, {"Rows", rows}};
452 30 : return root;
453 15 : }
454 :
455 8360 : void MeterDataFrame::addVariable(MeterVariable const &var)
456 : {
457 8360 : lastVarID = var.reportID();
458 8360 : meterMap.emplace(lastVarID, var);
459 8360 : }
460 :
461 83881 : void MeterDataFrame::pushVariableValue(const int reportID, double value)
462 : {
463 83881 : meterMap[reportID].pushValue(value);
464 83881 : }
465 :
466 20 : json MeterDataFrame::getJSON(bool meterOnlyCheck) const
467 : {
468 20 : json root;
469 20 : json cols = json::array();
470 20 : json rows = json::array();
471 :
472 210 : for (auto const &varMap : meterMap) {
473 190 : if (!(meterOnlyCheck && varMap.second.meterOnly())) {
474 1092 : cols.push_back({{"Variable", varMap.second.variableName()}, {"Units", Constant::unitNames[(int)varMap.second.units()]}});
475 : }
476 20 : }
477 :
478 20 : if (cols.empty()) return root;
479 :
480 14 : json vals = json::array();
481 :
482 180 : for (size_t row = 0; row < TS.size(); ++row) {
483 166 : vals.clear();
484 :
485 1720 : for (auto const &varMap : meterMap) {
486 1554 : if (!(meterOnlyCheck && varMap.second.meterOnly())) {
487 1554 : if (row < varMap.second.numValues()) {
488 1554 : vals.push_back(varMap.second.value(row));
489 : } else {
490 0 : vals.push_back(nullptr);
491 : }
492 : }
493 166 : }
494 664 : rows.push_back({{TS.at(row), vals}});
495 : }
496 140 : root = {{"ReportFrequency", ReportFrequency}, {"Cols", cols}, {"Rows", rows}};
497 14 : return root;
498 20 : }
499 :
500 5 : void DataFrame::writeReport(JsonOutputFilePaths &jsonOutputFilePaths, bool outputJSON, bool outputCBOR, bool outputMsgPack)
501 : {
502 :
503 5 : json root = getJSON();
504 5 : if (ReportFrequency == "Detailed-HVAC") {
505 1 : if (outputJSON) {
506 1 : FileSystem::writeFile<FileSystem::FileTypes::JSON>(jsonOutputFilePaths.outputTSHvacJsonFilePath, root);
507 : }
508 1 : if (outputCBOR) {
509 1 : FileSystem::writeFile<FileSystem::FileTypes::CBOR>(jsonOutputFilePaths.outputTSHvacCborFilePath, root);
510 : }
511 1 : if (outputMsgPack) {
512 1 : FileSystem::writeFile<FileSystem::FileTypes::MsgPack>(jsonOutputFilePaths.outputTSHvacMsgPackFilePath, root);
513 : }
514 4 : } 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 4 : } 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 4 : } 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 4 : } else if (ReportFrequency == "Hourly") {
545 4 : if (outputJSON) {
546 4 : FileSystem::writeFile<FileSystem::FileTypes::JSON>(jsonOutputFilePaths.outputHRJsonFilePath, root);
547 : }
548 4 : if (outputCBOR) {
549 1 : FileSystem::writeFile<FileSystem::FileTypes::CBOR>(jsonOutputFilePaths.outputHRCborFilePath, root);
550 : }
551 4 : if (outputMsgPack) {
552 1 : 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 5 : }
586 : // class Table
587 :
588 1155 : Table::Table(Array2D_string const &body,
589 : Array1D_string const &rowLabels,
590 : Array1D_string const &columnLabels,
591 : std::string const &tableName,
592 1155 : std::string const &footnoteText)
593 : {
594 :
595 1155 : size_t sizeColumnLabels = columnLabels.size();
596 1155 : size_t sizeRowLabels = rowLabels.size();
597 1155 : TableName = tableName;
598 1155 : FootnoteText = footnoteText;
599 :
600 10192 : for (size_t iCol = 0, k = body.index(1, 1); iCol < sizeColumnLabels; ++iCol) {
601 9037 : ColHeaders.push_back(columnLabels[iCol]);
602 9037 : std::vector<std::string> col;
603 75584 : for (size_t iRow = 0; iRow < sizeRowLabels; ++iRow) {
604 66547 : if (iCol == 0) {
605 : // do this once only
606 7407 : RowHeaders.push_back(rowLabels[iRow]);
607 : }
608 66547 : col.push_back(trim(body[k]));
609 66547 : ++k;
610 : }
611 9037 : Data.push_back(col);
612 9037 : }
613 1155 : }
614 :
615 285 : json Table::getJSON() const
616 : {
617 285 : json root;
618 285 : json cols = json::array();
619 285 : json rows;
620 :
621 2496 : for (size_t col = 0; col < ColHeaders.size(); ++col) {
622 2211 : cols.push_back(ColHeaders[col]);
623 : }
624 :
625 2106 : for (size_t row = 0; row < RowHeaders.size(); ++row) {
626 1821 : json rowvec = json::array();
627 17292 : for (size_t col = 0; col < ColHeaders.size(); ++col) {
628 15471 : rowvec.push_back(Data[col][row]);
629 : }
630 1821 : rows[RowHeaders[row]] = rowvec;
631 1821 : }
632 :
633 2850 : root = {{"TableName", TableName}, {"Cols", cols}, {"Rows", rows}};
634 :
635 285 : if (!FootnoteText.empty()) root["Footnote"] = FootnoteText;
636 570 : return root;
637 285 : }
638 :
639 : // class Report
640 :
641 36 : json Report::getJSON() const
642 : {
643 :
644 324 : json root = {{"ReportName", ReportName}, {"For", ReportForString}};
645 :
646 36 : json cols = json::array();
647 :
648 321 : for (auto const &table : Tables) {
649 285 : cols.push_back(table.getJSON());
650 36 : }
651 :
652 36 : root["Tables"] = cols;
653 72 : return root;
654 36 : }
655 :
656 : // class ReportsCollection
657 796 : ReportsCollection::ReportsCollection()
658 : {
659 796 : }
660 :
661 1083 : 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 1083 : addReportTable(body, rowLabels, columnLabels, reportName, reportForString, tableName, "");
669 1083 : }
670 :
671 1155 : 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 1155 : std::string const key = reportName + reportForString;
680 : // Report *r;
681 1155 : Table tbl(body, rowLabels, columnLabels, tableName, footnoteText);
682 :
683 1155 : auto search = reportsMap.find(key);
684 1155 : if (search != reportsMap.end()) {
685 : // r = search->second;
686 984 : search->second.Tables.push_back(tbl);
687 : } else {
688 : // r = new Report();
689 171 : Report r;
690 171 : r.ReportName = reportName;
691 171 : r.ReportForString = reportForString;
692 171 : r.Tables.push_back(tbl);
693 171 : reportsMap.emplace(key, r);
694 171 : }
695 :
696 : // Table *tbl = new Table( body, rowLabels, columnLabels, tableName, footnoteText );
697 : // r->Tables.push_back( tbl );
698 1155 : }
699 :
700 2 : json ReportsCollection::getJSON() const
701 : {
702 2 : json root = json::array();
703 :
704 38 : for (auto const &iter : reportsMap) {
705 36 : root.push_back(iter.second.getJSON());
706 2 : }
707 2 : return root;
708 0 : }
709 :
710 26 : void CSVWriter::parseTSOutputs(EnergyPlusData &state,
711 : json const &data,
712 : std::vector<std::string> const &outputVariables,
713 : OutputProcessor::ReportFreq reportingFrequency)
714 : {
715 26 : if (data.empty()) return;
716 20 : updateReportFreq(reportingFrequency);
717 20 : std::vector<int> indices;
718 20 : std::unordered_set<std::string> seen;
719 20 : std::string search_string;
720 :
721 40 : std::string reportFrequency = data.at("ReportFrequency").get<std::string>();
722 20 : if (reportFrequency == "Detailed-HVAC" || reportFrequency == "Detailed-Zone") {
723 6 : reportFrequency = "Each Call";
724 : }
725 20 : auto const &columns = data.at("Cols");
726 310 : for (auto const &column : columns) {
727 : search_string =
728 580 : fmt::format("{0} [{1}]({2})", column.at("Variable").get<std::string>(), column.at("Units").get<std::string>(), reportFrequency);
729 580 : auto found = std::find(outputVariables.begin(), outputVariables.end(), search_string);
730 290 : if (found == outputVariables.end()) {
731 : search_string =
732 0 : fmt::format("{0} [{1}]({2})", column.at("Variable").get<std::string>(), column.at("Units").get<std::string>(), "Each Call");
733 0 : found = std::find(outputVariables.begin(), outputVariables.end(), search_string);
734 : }
735 290 : if (found == outputVariables.end()) {
736 0 : ShowFatalError(state, fmt::format("Output variable ({0}) not found output variable list", search_string));
737 : }
738 290 : outputVariableIndices[std::distance(outputVariables.begin(), found)] = true;
739 290 : indices.emplace_back(std::distance(outputVariables.begin(), found));
740 310 : }
741 :
742 20 : auto const &rows = data.at("Rows");
743 2729 : for (auto const &row : rows) {
744 5418 : for (auto &el : row.items()) {
745 2709 : auto found_key = outputs.find(el.key());
746 2709 : if (found_key == outputs.end()) {
747 2193 : std::vector<std::string> output(outputVariables.size());
748 2193 : int i = 0;
749 26187 : for (auto const &col : el.value()) {
750 23994 : if (col.is_null()) {
751 0 : output[indices[i]] = "";
752 : } else {
753 23994 : dtoa(col.get<double>(), s);
754 23994 : output[indices[i]] = s;
755 : }
756 23994 : ++i;
757 2193 : }
758 2193 : outputs[el.key()] = output;
759 2193 : } else {
760 516 : int i = 0;
761 1872 : for (auto const &col : el.value()) {
762 1356 : if (col.is_null()) {
763 0 : found_key->second[indices[i]] = "";
764 : } else {
765 1356 : dtoa(col.get<double>(), s);
766 1356 : found_key->second[indices[i]] = s;
767 : }
768 1356 : ++i;
769 516 : }
770 : }
771 5418 : }
772 20 : }
773 20 : }
774 :
775 20 : void CSVWriter::updateReportFreq(OutputProcessor::ReportFreq reportingFrequency)
776 : {
777 20 : if (reportingFrequency < smallestReportFreq) {
778 17 : smallestReportFreq = reportingFrequency;
779 : }
780 20 : }
781 :
782 4 : std::string &CSVWriter::convertToMonth(std::string &datetime)
783 : {
784 : // if running this function, there should only ever be 12 + design days values to change
785 : static const std::map<std::string, std::string> months({{"01", "January"},
786 : {"02", "February"},
787 : {"03", "March"},
788 : {"04", "April"},
789 : {"05", "May"},
790 : {"06", "June"},
791 : {"07", "July"},
792 : {"08", "August"},
793 : {"09", "September"},
794 : {"10", "October"},
795 : {"11", "November"},
796 28 : {"12", "December"}});
797 : // 01/01 24:00:00
798 4 : std::string const month = datetime.substr(0, 2);
799 4 : size_t const pos = datetime.find(' ');
800 4 : std::string time;
801 4 : if (pos != std::string::npos) {
802 4 : time = datetime.substr(pos);
803 : }
804 : // This assert replaces ShowFatalError(state, "Monthly output variables should occur at the end of the day.");
805 4 : assert(time == " 24:00:00" || time == " 00:00:00");
806 :
807 4 : datetime = months.find(month)->second;
808 4 : return datetime;
809 4 : }
810 :
811 10 : void CSVWriter::writeOutput(EnergyPlusData &state,
812 : std::vector<std::string> const &outputVariables,
813 : InputOutputFile &outputFile,
814 : bool outputControl,
815 : bool rewriteTimestamp)
816 : {
817 10 : outputFile.ensure_open(state, "OpenOutputFiles", outputControl);
818 :
819 10 : print<FormatSyntax::FMT>(outputFile, "{}", "Date/Time,");
820 10 : std::string sep;
821 470 : for (auto it = outputVariables.begin(); it != outputVariables.end(); ++it) {
822 460 : if (!outputVariableIndices[std::distance(outputVariables.begin(), it)]) continue;
823 290 : print<FormatSyntax::FMT>(outputFile, "{}{}", sep, *it);
824 290 : if (sep.empty()) sep = ",";
825 10 : }
826 10 : print<FormatSyntax::FMT>(outputFile, "{}", '\n');
827 :
828 2203 : for (auto &item : outputs) {
829 2193 : std::string datetime = item.first;
830 2193 : if (rewriteTimestamp) {
831 2143 : if (smallestReportFreq < OutputProcessor::ReportFreq::Month) {
832 2139 : datetime = datetime.replace(datetime.find(' '), 1, " ");
833 : } else {
834 4 : convertToMonth(datetime);
835 : }
836 : }
837 2193 : print<FormatSyntax::FMT>(outputFile, " {},", datetime);
838 4386 : item.second.erase(std::remove_if(item.second.begin(),
839 4386 : item.second.end(),
840 90897 : [&](const std::string &d) {
841 90897 : auto pos = (&d - &*item.second.begin());
842 90897 : return !outputVariableIndices[pos];
843 : }),
844 4386 : item.second.end());
845 37442 : auto result = std::find_if(item.second.rbegin(), item.second.rend(), [](std::string const &v) { return !v.empty(); });
846 2193 : auto last = item.second.end() - 1;
847 2193 : if (result != item.second.rend()) {
848 2193 : last = (result + 1).base();
849 : }
850 :
851 2193 : print<FormatSyntax::FMT>(outputFile, "{},", fmt::join(item.second.begin(), last, ","));
852 2193 : print<FormatSyntax::FMT>(outputFile, "{}\n", *last);
853 2203 : }
854 :
855 10 : outputFile.close();
856 10 : }
857 :
858 796 : void ResultsFramework::setupOutputOptions(EnergyPlusData &state)
859 : {
860 796 : if (state.files.outputControl.csv) {
861 6 : tsEnabled = true;
862 6 : tsAndTabularEnabled = true;
863 : }
864 :
865 796 : if (!state.files.outputControl.json) {
866 792 : return;
867 : }
868 :
869 795 : int numberOfOutputSchemaObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Output:JSON");
870 795 : if (numberOfOutputSchemaObjects == 0) {
871 791 : return;
872 : }
873 :
874 4 : Array1D_string alphas(5);
875 : int numAlphas;
876 4 : Array1D<Real64> numbers(2);
877 : int numNumbers;
878 : int status;
879 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state, "Output:JSON", 1, alphas, numAlphas, numbers, numNumbers, status);
880 :
881 4 : if (numAlphas > 0) {
882 4 : std::string option = alphas(1);
883 4 : if (Util::SameString(option, "TimeSeries")) {
884 2 : tsEnabled = true;
885 2 : } else if (Util::SameString(option, "TimeSeriesAndTabular")) {
886 2 : tsEnabled = true;
887 2 : tsAndTabularEnabled = true;
888 : }
889 :
890 : // defaults
891 4 : outputJSON = true;
892 4 : outputCBOR = false;
893 4 : outputMsgPack = false;
894 :
895 4 : if (numAlphas >= 2) {
896 2 : outputJSON = Util::SameString(alphas(2), "Yes");
897 : }
898 :
899 4 : if (numAlphas >= 3) {
900 2 : outputCBOR = Util::SameString(alphas(3), "Yes");
901 : }
902 :
903 4 : if (numAlphas >= 4) {
904 2 : outputMsgPack = Util::SameString(alphas(4), "Yes");
905 : }
906 4 : }
907 4 : }
908 :
909 19416514 : bool ResultsFramework::timeSeriesEnabled() const
910 : {
911 19416514 : return tsEnabled;
912 : }
913 :
914 145281 : bool ResultsFramework::timeSeriesAndTabularEnabled() const
915 : {
916 145281 : return tsAndTabularEnabled;
917 : }
918 :
919 0 : bool ResultsFramework::JSONEnabled() const
920 : {
921 0 : return outputJSON;
922 : }
923 :
924 0 : bool ResultsFramework::CBOREnabled() const
925 : {
926 0 : return outputCBOR;
927 : }
928 :
929 0 : bool ResultsFramework::MsgPackEnabled() const
930 : {
931 0 : return outputMsgPack;
932 : }
933 :
934 2864 : void ResultsFramework::initializeTSDataFrame(const OutputProcessor::ReportFreq reportFrequency,
935 : const std::vector<OutputProcessor::OutVar *> &Variables,
936 : const OutputProcessor::TimeStepType timeStepType)
937 : {
938 462408 : for (auto *var : Variables) {
939 :
940 459544 : if (var->Report && var->freq == reportFrequency) {
941 27946 : Variable rfvar;
942 27946 : if (var->units == Constant::Units::customEMS) {
943 52 : rfvar = Variable(var->keyColonName, reportFrequency, var->timeStepType, var->ReportID, var->units, var->unitNameCustomEMS);
944 : } else {
945 27894 : rfvar = Variable(var->keyColonName, reportFrequency, var->timeStepType, var->ReportID, var->units);
946 : }
947 :
948 27946 : switch (reportFrequency) {
949 58 : case OutputProcessor::ReportFreq::EachCall: { // each time UpdatedataandReport is called
950 58 : if (timeStepType == var->timeStepType) {
951 29 : detailedTSData[(int)timeStepType].setDataFrameEnabled(true);
952 29 : detailedTSData[(int)timeStepType].addVariable(rfvar);
953 : }
954 58 : } break;
955 27888 : case OutputProcessor::ReportFreq::Hour: // at 'EndHourFlag'
956 : case OutputProcessor::ReportFreq::TimeStep: // at 'EndTimeStepFlag'
957 : case OutputProcessor::ReportFreq::Day: // at 'EndDayFlag'
958 : case OutputProcessor::ReportFreq::Month: // at 'EndMonthFlag'
959 : case OutputProcessor::ReportFreq::Simulation: // once per environment 'EndEnvrnFlag'
960 : case OutputProcessor::ReportFreq::Year: { // at end of year
961 27888 : freqTSData[(int)reportFrequency].setDataFrameEnabled(true);
962 27888 : freqTSData[(int)reportFrequency].addVariable(rfvar);
963 27888 : } break;
964 0 : default: {
965 0 : assert(false);
966 : } break;
967 : }
968 27946 : }
969 2864 : }
970 : // set the scanned variables to true or false
971 2864 : switch (reportFrequency) {
972 20 : case OutputProcessor::ReportFreq::EachCall: {
973 20 : detailedTSData[(int)timeStepType].setVariablesScanned(true);
974 20 : } break;
975 2844 : case OutputProcessor::ReportFreq::TimeStep: // at 'EndTimeStepFlag'
976 : case OutputProcessor::ReportFreq::Hour: // at 'EndHourFlag'
977 : case OutputProcessor::ReportFreq::Day: // at 'EndDayFlag'
978 : case OutputProcessor::ReportFreq::Month: // at end of month
979 : case OutputProcessor::ReportFreq::Simulation: // once per environment 'EndEnvrnFlag'
980 : case OutputProcessor::ReportFreq::Year: { // at end of year
981 2844 : detailedTSData[(int)timeStepType].setVariablesScanned(true);
982 2844 : } break;
983 0 : default: {
984 0 : assert(false);
985 : } break;
986 : }
987 2864 : }
988 :
989 572758 : void ResultsFramework::initializeMeters(const std::vector<OutputProcessor::Meter *> &meters, const OutputProcessor::ReportFreq freq)
990 : {
991 572758 : switch (freq) {
992 0 : case OutputProcessor::ReportFreq::EachCall: {
993 : // nothing to do; meters are not reported at this frequency
994 0 : } break;
995 572758 : case OutputProcessor::ReportFreq::TimeStep: // at 'TimeStep'
996 : case OutputProcessor::ReportFreq::Hour: // at 'Hourly'
997 : case OutputProcessor::ReportFreq::Day: // at 'Daily'
998 : case OutputProcessor::ReportFreq::Month: // at 'Monthly'
999 : case OutputProcessor::ReportFreq::Simulation: // at 'RunPeriod'/'SM'
1000 : case OutputProcessor::ReportFreq::Year: { // at 'Yearly'
1001 57828987 : for (auto const *meter : meters) {
1002 57256229 : auto const &period = meter->periods[(int)freq];
1003 57256229 : if (period.Rpt || period.RptFO) {
1004 8355 : Meters[(int)freq].addVariable(MeterVariable(meter->Name, freq, period.RptNum, meter->units, period.RptFO));
1005 8355 : Meters[(int)freq].setDataFrameEnabled(true);
1006 : }
1007 57256229 : if (period.accRpt || period.accRptFO) {
1008 5 : Meters[(int)freq].addVariable(MeterVariable(meter->Name, freq, period.accRptNum, meter->units, period.accRptFO));
1009 5 : Meters[(int)freq].setDataFrameEnabled(true);
1010 : }
1011 572758 : }
1012 572758 : } break;
1013 :
1014 0 : default: {
1015 0 : assert(false);
1016 : } break;
1017 : } // switch (frequency)
1018 :
1019 : // set the scanned variables to true or false
1020 572758 : switch (freq) {
1021 0 : case OutputProcessor::ReportFreq::EachCall:
1022 : // case should not happen in Meters
1023 0 : break;
1024 572758 : case OutputProcessor::ReportFreq::TimeStep: // at TimeStepFlag
1025 : case OutputProcessor::ReportFreq::Hour: // at Hourly
1026 : case OutputProcessor::ReportFreq::Day: // at Daily
1027 : case OutputProcessor::ReportFreq::Month: // at Monthly
1028 : case OutputProcessor::ReportFreq::Simulation: // at RunPeriod/SM
1029 : case OutputProcessor::ReportFreq::Year: { // at Yearly
1030 572758 : Meters[(int)freq].setVariablesScanned(true);
1031 572758 : } break;
1032 0 : default:
1033 0 : assert(false);
1034 : }
1035 572758 : }
1036 :
1037 796 : void ResultsFramework::writeOutputs(EnergyPlusData &state)
1038 : {
1039 796 : if (state.files.outputControl.csv) {
1040 6 : writeCSVOutput(state);
1041 : }
1042 :
1043 796 : if (timeSeriesEnabled() && (outputJSON || outputCBOR || outputMsgPack)) {
1044 4 : writeTimeSeriesReports(state.files.json);
1045 : }
1046 :
1047 796 : if (timeSeriesAndTabularEnabled() && (outputJSON || outputCBOR || outputMsgPack)) {
1048 2 : writeReport(state.files.json);
1049 : }
1050 796 : }
1051 :
1052 6 : void ResultsFramework::writeCSVOutput(EnergyPlusData &state)
1053 : {
1054 : using OutputProcessor::ReportFreq;
1055 :
1056 6 : if (!hasOutputData()) {
1057 0 : return;
1058 : }
1059 6 : CSVWriter csv(outputVariables.size());
1060 6 : CSVWriter mtr_csv(outputVariables.size());
1061 :
1062 42 : for (ReportFreq freq :
1063 48 : {ReportFreq::Year, ReportFreq::Simulation, ReportFreq::Month, ReportFreq::Day, ReportFreq::Hour, ReportFreq::TimeStep}) {
1064 : // Output yearly time series data
1065 36 : if (hasTSData(freq)) {
1066 4 : csv.parseTSOutputs(state, freqTSData[(int)freq].getJSON(), outputVariables, freq);
1067 : }
1068 :
1069 36 : if (hasMeters(freq)) {
1070 8 : csv.parseTSOutputs(state, Meters[(int)freq].getJSON(true), outputVariables, freq);
1071 8 : mtr_csv.parseTSOutputs(state, Meters[(int)freq].getJSON(), outputVariables, freq);
1072 : }
1073 : }
1074 :
1075 18 : for (TimeStepType timeStepType : {TimeStepType::System, TimeStepType::Zone}) {
1076 : // Output detailed HVAC time series data
1077 12 : if (hasDetailedTSData(timeStepType)) {
1078 6 : csv.parseTSOutputs(state, detailedTSData[(int)timeStepType].getJSON(), outputVariables, ReportFreq::EachCall);
1079 : }
1080 : }
1081 :
1082 6 : csv.writeOutput(state, outputVariables, state.files.csv, state.files.outputControl.csv, rewriteTimestamp);
1083 6 : if (hasMeterData()) {
1084 4 : mtr_csv.writeOutput(state, outputVariables, state.files.mtr_csv, state.files.outputControl.csv, rewriteTimestamp);
1085 : }
1086 6 : }
1087 :
1088 4 : void ResultsFramework::writeTimeSeriesReports(JsonOutputFilePaths &jsonOutputFilePaths)
1089 : {
1090 : // Output detailed Zone & HVAC time series data
1091 12 : for (TimeStepType timeStepType : {TimeStepType::Zone, TimeStepType::System}) {
1092 8 : if (hasDetailedTSData(timeStepType)) {
1093 1 : detailedTSData[(int)timeStepType].writeReport(jsonOutputFilePaths, outputJSON, outputCBOR, outputMsgPack);
1094 : }
1095 : }
1096 :
1097 : // Output timestep time series data
1098 28 : for (ReportFreq freq :
1099 32 : {ReportFreq::TimeStep, ReportFreq::Hour, ReportFreq::Day, ReportFreq::Month, ReportFreq::Simulation, ReportFreq::Year}) {
1100 24 : if (hasFreqTSData(freq)) {
1101 4 : freqTSData[(int)freq].writeReport(jsonOutputFilePaths, outputJSON, outputCBOR, outputMsgPack);
1102 : }
1103 : }
1104 4 : }
1105 :
1106 2 : void ResultsFramework::writeReport(JsonOutputFilePaths &jsonOutputFilePaths)
1107 : {
1108 2 : json root, outputVars, meterVars, meterData;
1109 14 : root = {{"SimulationResults", {{"Simulation", SimulationInformation.getJSON()}}}};
1110 :
1111 : // output variables
1112 :
1113 : // This could be constexpr except that json maps do not take string_view keys
1114 2 : static std::array<std::string, (int)TimeStepType::Num> const timeStepStrings = {"Detailed-Zone", "Detailed-HVAC"};
1115 6 : for (TimeStepType timeStep : {TimeStepType::Zone, TimeStepType::System}) {
1116 4 : if (hasDetailedTSData(timeStep)) {
1117 1 : outputVars[timeStepStrings[(int)timeStep]] = detailedTSData[(int)timeStep].getVariablesJSON();
1118 : }
1119 : }
1120 :
1121 : // Same issue here
1122 : static std::array<std::string, (int)ReportFreq::Num> const freqStrings = {
1123 2 : "Detailed", "TimeStep", "Hourly", "Daily", "Monthly", "RunPeriod", "Yearly"};
1124 14 : for (ReportFreq freq :
1125 16 : {ReportFreq::Year, ReportFreq::Simulation, ReportFreq::Month, ReportFreq::Day, ReportFreq::Hour, ReportFreq::TimeStep}) {
1126 12 : if (hasFreqTSData(freq)) {
1127 2 : outputVars[freqStrings[(int)freq]] = freqTSData[(int)freq].getVariablesJSON();
1128 : }
1129 : }
1130 :
1131 : // output dictionary
1132 14 : outputVars["OutputDictionary"] = {{"Description", "Dictionary containing output variables that may be requested"}, {"Variables", RDD}};
1133 :
1134 : // meter variables
1135 :
1136 : // -- meter values
1137 14 : for (ReportFreq freq :
1138 16 : {ReportFreq::Year, ReportFreq::Simulation, ReportFreq::Month, ReportFreq::Day, ReportFreq::Hour, ReportFreq::TimeStep}) {
1139 12 : if (hasMeters(freq)) {
1140 4 : meterVars[freqStrings[(int)freq]] = Meters[(int)freq].getVariablesJSON();
1141 4 : meterData[freqStrings[(int)freq]] = Meters[(int)freq].getJSON();
1142 : }
1143 : }
1144 :
1145 : // -- meter dictionary
1146 14 : meterVars["MeterDictionary"] = {{"Description", "Dictionary containing meter variables that may be requested"}, {"Meters", MDD}};
1147 :
1148 2 : root["OutputVariables"] = outputVars;
1149 2 : root["MeterVariables"] = meterVars;
1150 2 : root["MeterData"] = meterData;
1151 2 : root["TabularReports"] = TabularReportsCollection.getJSON();
1152 :
1153 2 : if (outputJSON) {
1154 2 : FileSystem::writeFile<FileSystem::FileTypes::JSON>(jsonOutputFilePaths.outputJsonFilePath, root);
1155 : }
1156 2 : if (outputCBOR) {
1157 1 : FileSystem::writeFile<FileSystem::FileTypes::CBOR>(jsonOutputFilePaths.outputCborFilePath, root);
1158 : }
1159 2 : if (outputMsgPack) {
1160 1 : FileSystem::writeFile<FileSystem::FileTypes::MsgPack>(jsonOutputFilePaths.outputMsgPackFilePath, root);
1161 : }
1162 2 : }
1163 :
1164 61042 : void ResultsFramework::addReportVariable(std::string_view const keyedValue,
1165 : std::string_view const variableName,
1166 : std::string_view const units,
1167 : OutputProcessor::ReportFreq const freq)
1168 : {
1169 122084 : outputVariables.emplace_back(fmt::format("{0}:{1} [{2}]({3})", keyedValue, variableName, units, reportFreqNames[(int)freq]));
1170 61042 : }
1171 :
1172 8478 : void ResultsFramework::addReportMeter(std::string const &meter, std::string_view units, OutputProcessor::ReportFreq const freq)
1173 : {
1174 16956 : outputVariables.emplace_back(fmt::format("{0} [{1}]({2})", meter, units, reportFreqNames[(int)freq]));
1175 8478 : }
1176 :
1177 : } // namespace ResultsFramework
1178 :
1179 : } // namespace EnergyPlus
|