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