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 : #ifndef ResultsSchema_hh_INCLUDED
49 : #define ResultsSchema_hh_INCLUDED
50 :
51 : #include <memory>
52 : #include <unordered_map>
53 :
54 : // ObjexxFCL Headers
55 : #include <ObjexxFCL/Array1D.hh>
56 : #include <ObjexxFCL/Array2D.hh>
57 :
58 : #include <nlohmann/json.hpp>
59 :
60 : // EnergyPlus Headers
61 : #include <EnergyPlus/Data/BaseData.hh>
62 : #include <EnergyPlus/DataGlobals.hh>
63 : #include <EnergyPlus/EnergyPlus.hh>
64 : #include <EnergyPlus/OutputProcessor.hh>
65 :
66 : namespace EnergyPlus {
67 :
68 : // Forward declarations
69 : class EnergyPlusFixture;
70 : class ResultsFrameworkFixture;
71 : struct EnergyPlusData;
72 : struct JsonOutputFilePaths;
73 :
74 : namespace ResultsFramework {
75 :
76 : using json = nlohmann::json;
77 :
78 : using OutputProcessor::ReportFreq;
79 : using OutputProcessor::TimeStepType;
80 :
81 : // trim string
82 : std::string trim(std::string_view const s);
83 :
84 : // base result object
85 : class BaseResultObject
86 : {
87 : public:
88 81510 : BaseResultObject(){};
89 : };
90 :
91 : class SimInfo : public BaseResultObject
92 : {
93 : public:
94 : void setProgramVersion(const std::string &programVersion);
95 : std::string getProgramVersion() const;
96 : void setSimulationEnvironment(const std::string &simulationEnvironment);
97 : void setInputModelURI(const std::string &inputModelURI);
98 : void setStartDateTimeStamp(const std::string &startDateTimeStamp);
99 : void setRunTime(const std::string &elapsedTime);
100 : void setNumErrorsWarmup(const std::string &numWarningsDuringWarmup, const std::string &numSevereDuringWarmup);
101 : void setNumErrorsSizing(const std::string &numWarningsDuringSizing, const std::string &numSevereDuringSizing);
102 : void setNumErrorsSummary(const std::string &numWarnings, const std::string &numSevere);
103 : json getJSON() const;
104 :
105 : protected:
106 : std::string ProgramVersion;
107 : std::string SimulationEnvironment;
108 : std::string InputModelURI;
109 : std::string StartDateTimeStamp;
110 : std::string RunTime;
111 : std::string NumWarningsDuringWarmup, NumSevereDuringWarmup, NumWarningsDuringSizing, NumSevereDuringSizing, NumWarnings, NumSevere;
112 : };
113 :
114 : class Variable : public BaseResultObject
115 : {
116 : public:
117 27946 : Variable() = default;
118 : Variable(const std::string &VarName,
119 : const ReportFreq reportFrequency,
120 : const OutputProcessor::TimeStepType timeStepType,
121 : const int ReportID,
122 : Constant::Units units);
123 : Variable(const std::string &VarName,
124 : const ReportFreq reportFrequency,
125 : const OutputProcessor::TimeStepType timeStepType,
126 : const int ReportID,
127 : Constant::Units units,
128 : const std::string &customUnits);
129 :
130 : std::string variableName() const;
131 : void setVariableName(const std::string &VarName);
132 :
133 : std::string sReportFrequency() const;
134 : ReportFreq iReportFrequency() const;
135 : void setReportFrequency(const ReportFreq reportFrequency);
136 :
137 : OutputProcessor::TimeStepType timeStepType() const;
138 : void setTimeStepType(const OutputProcessor::TimeStepType timeStepType);
139 :
140 : int reportID() const;
141 : void setReportID(const int Id);
142 :
143 : Constant::Units units() const;
144 : void setUnits(Constant::Units units);
145 :
146 : std::string customUnits() const;
147 : void setCustomUnits(const std::string &customUnits);
148 :
149 : void pushValue(const double val);
150 : double value(size_t index) const;
151 : size_t numValues() const;
152 :
153 : virtual json getJSON() const;
154 :
155 : protected:
156 : std::string m_varName;
157 : ReportFreq m_reportFreq = ReportFreq::EachCall;
158 : OutputProcessor::TimeStepType m_timeStepType = OutputProcessor::TimeStepType::Zone;
159 : int m_rptID = -1;
160 : Constant::Units m_units;
161 : std::string m_customUnits;
162 : std::vector<double> m_values;
163 : };
164 :
165 : class OutputVariable : public Variable
166 : {
167 : public:
168 : OutputVariable(const std::string &VarName,
169 : const ReportFreq reportFrequency,
170 : const OutputProcessor::TimeStepType timeStepType,
171 : const int ReportID,
172 : Constant::Units units);
173 :
174 : OutputVariable(const std::string &VarName,
175 : const ReportFreq reportFrequency,
176 : const OutputProcessor::TimeStepType timeStepType,
177 : const int ReportID,
178 : Constant::Units units,
179 : const std::string &customUnits);
180 : };
181 :
182 : class MeterVariable : public Variable
183 : {
184 : public:
185 0 : MeterVariable() = default;
186 : MeterVariable(const std::string &VarName,
187 : const ReportFreq reportFrequency,
188 : const int ReportID,
189 : Constant::Units units,
190 : const bool MeterOnly,
191 : const bool Acculumative = false);
192 :
193 : bool accumulative() const;
194 : void setAccumulative(bool state);
195 : bool meterOnly() const;
196 : void setMeterOnly(bool state);
197 :
198 : json getJSON() const override;
199 :
200 : protected:
201 : bool acc = false;
202 : bool meter_only = true;
203 : };
204 :
205 : class DataFrame : public BaseResultObject
206 : {
207 : public:
208 : typedef std::pair<int, Variable> VarPtrPair;
209 :
210 : explicit DataFrame(const std::string &ReportFreq);
211 12736 : virtual ~DataFrame() = default;
212 :
213 : void addVariable(Variable const &var);
214 :
215 : void setDataFrameEnabled(bool state);
216 :
217 : bool dataFrameEnabled() const;
218 :
219 : void setVariablesScanned(bool state);
220 :
221 : bool variablesScanned() const;
222 :
223 : void newRow(const int month, const int dayOfMonth, int hourOfDay, int curMin, int calendarYear);
224 : // void newRow(const std::string &ts);
225 : virtual void pushVariableValue(const int reportID, double value);
226 :
227 : Variable &lastVariable();
228 :
229 : json getVariablesJSON();
230 : json getJSON() const;
231 :
232 : void writeReport(JsonOutputFilePaths &jsonOutputFilePaths, bool outputJSON, bool outputCBOR, bool outputMsgPack);
233 :
234 : // Need to find a way to protect these, they can't be changed on the fly
235 : bool iso8601 = false;
236 : bool beginningOfInterval = false;
237 :
238 : protected:
239 : bool DataFrameEnabled = false;
240 : bool VariablesScanned = false;
241 : int lastHour = 0;
242 : int lastMinute = 0;
243 : std::string ReportFrequency;
244 : std::vector<std::string> TS;
245 : std::map<int, Variable> variableMap;
246 : int lastVarID = -1;
247 : };
248 :
249 : class MeterDataFrame : public DataFrame
250 : {
251 : public:
252 5572 : explicit MeterDataFrame(const std::string &ReportFreq) : DataFrame(ReportFreq){};
253 5572 : virtual ~MeterDataFrame() = default;
254 :
255 : void addVariable(MeterVariable const &var);
256 :
257 : void pushVariableValue(const int reportID, double value) override;
258 :
259 : json getJSON(bool meterOnlyCheck = false) const;
260 :
261 : protected:
262 : std::map<int, MeterVariable> meterMap;
263 : };
264 :
265 : class Table : public BaseResultObject
266 : {
267 : public:
268 : std::string TableName;
269 : std::string FootnoteText;
270 : std::vector<std::string> ColHeaders;
271 : std::vector<std::string> RowHeaders;
272 : std::vector<std::vector<std::string>> Data;
273 :
274 : Table(Array2D_string const &body,
275 : Array1D_string const &rowLabels,
276 : Array1D_string const &columnLabels,
277 : std::string const &tableName,
278 : std::string const &footnoteText);
279 :
280 : json getJSON() const;
281 : };
282 :
283 : class Report : public BaseResultObject
284 : {
285 : public:
286 : std::string ReportName;
287 : std::string ReportForString;
288 : std::vector<Table> Tables;
289 :
290 : json getJSON() const;
291 : };
292 :
293 : class ReportsCollection : public BaseResultObject
294 : {
295 : public:
296 : typedef std::pair<std::string, Report> RptPtrPair;
297 :
298 : ReportsCollection();
299 :
300 : void addReportTable(Array2D_string const &body,
301 : Array1D_string const &rowLabels,
302 : Array1D_string const &columnLabels,
303 : std::string const &reportName,
304 : std::string const &reportForString,
305 : std::string const &tableName);
306 :
307 : void addReportTable(Array2D_string const &body,
308 : Array1D_string const &rowLabels,
309 : Array1D_string const &columnLabels,
310 : std::string const &reportName,
311 : std::string const &reportForString,
312 : std::string const &tableName,
313 : std::string const &footnoteText);
314 :
315 : json getJSON() const;
316 :
317 : protected:
318 : std::unordered_map<std::string, Report> reportsMap;
319 : Report rpt;
320 : };
321 :
322 : class CSVWriter : public BaseResultObject
323 : {
324 : public:
325 : CSVWriter() = default;
326 12 : explicit CSVWriter(std::size_t num_output_variables) : outputVariableIndices(std::vector<bool>(num_output_variables, false))
327 : {
328 12 : }
329 :
330 : void writeOutput(EnergyPlusData &state,
331 : std::vector<std::string> const &outputVariables,
332 : InputOutputFile &outputFile,
333 : bool outputControl,
334 : bool rewriteTimestamp);
335 : void parseTSOutputs(EnergyPlusData &state, json const &data, std::vector<std::string> const &outputVariables, ReportFreq reportingFrequency);
336 :
337 : private:
338 : friend class EnergyPlus::EnergyPlusFixture;
339 : friend class EnergyPlus::ResultsFrameworkFixture;
340 :
341 : char s[129] = {0};
342 : ReportFreq smallestReportFreq = ReportFreq::Year;
343 : std::map<std::string, std::vector<std::string>> outputs;
344 : std::vector<bool> outputVariableIndices;
345 :
346 : static std::string &convertToMonth(std::string &datetime);
347 : void updateReportFreq(ReportFreq reportingFrequency);
348 : // void readRVI();
349 : // void readMVI();
350 : };
351 :
352 : class ResultsFramework : public BaseResultObject
353 : {
354 : public:
355 796 : ResultsFramework() = default;
356 :
357 1592 : virtual ~ResultsFramework() = default;
358 :
359 : void setupOutputOptions(EnergyPlusData &state);
360 :
361 : bool timeSeriesEnabled() const;
362 :
363 : bool timeSeriesAndTabularEnabled() const;
364 :
365 : bool JSONEnabled() const;
366 :
367 : bool CBOREnabled() const;
368 :
369 : bool MsgPackEnabled() const;
370 :
371 : void initializeTSDataFrame(const ReportFreq reportFrequency,
372 : const std::vector<OutputProcessor::OutVar *> &Variables,
373 : const OutputProcessor::TimeStepType timeStepType = OutputProcessor::TimeStepType::Zone);
374 :
375 : void initializeMeters(const std::vector<OutputProcessor::Meter *> &EnergyMeters, const ReportFreq reportFrequency);
376 :
377 : std::array<DataFrame, (int)TimeStepType::Num> detailedTSData = {// DataFrame("Dummy"),
378 : DataFrame("Detailed-Zone"),
379 : DataFrame("Detailed-HVAC")};
380 :
381 : std::array<DataFrame, (int)ReportFreq::Num> freqTSData = {DataFrame("Each Call"),
382 : DataFrame("TimeStep"),
383 : DataFrame("Hourly"),
384 : DataFrame("Daily"),
385 : DataFrame("Monthly"),
386 : DataFrame("RunPeriod"),
387 : DataFrame("Yearly")};
388 :
389 : std::array<MeterDataFrame, (int)ReportFreq::Num> Meters = {MeterDataFrame("Each Call"),
390 : MeterDataFrame("TimeStep"),
391 : MeterDataFrame("Hourly"),
392 : MeterDataFrame("Daily"),
393 : MeterDataFrame("Monthly"),
394 : MeterDataFrame("RunPeriod"),
395 : MeterDataFrame("Yearly")};
396 :
397 1 : void setISO8601(const bool value)
398 : {
399 1 : rewriteTimestamp = !value;
400 3 : for (int iTimeStep = (int)TimeStepType::Zone; iTimeStep < (int)TimeStepType::Num; ++iTimeStep) {
401 2 : detailedTSData[iTimeStep].iso8601 = value;
402 : }
403 :
404 7 : for (int iFreq = (int)ReportFreq::TimeStep; iFreq < (int)ReportFreq::Num; ++iFreq) {
405 6 : freqTSData[iFreq].iso8601 = Meters[iFreq].iso8601 = value;
406 : }
407 1 : }
408 :
409 1 : void setBeginningOfInterval(const bool value)
410 : {
411 3 : for (int iTimeStep = 0; iTimeStep < (int)TimeStepType::Num; ++iTimeStep) {
412 2 : detailedTSData[iTimeStep].beginningOfInterval = value;
413 : }
414 :
415 8 : for (int iFreq = 0; iFreq < (int)ReportFreq::Num; ++iFreq) {
416 7 : freqTSData[iFreq].beginningOfInterval = Meters[iFreq].beginningOfInterval = value;
417 : }
418 1 : }
419 :
420 : void writeOutputs(EnergyPlusData &state);
421 :
422 : void addReportVariable(std::string_view const keyedValue,
423 : std::string_view const variableName,
424 : std::string_view const units,
425 : ReportFreq const reportingInterval);
426 :
427 : void addReportMeter(std::string const &meter, std::string_view const units, ReportFreq const reportingInterval);
428 :
429 : SimInfo SimulationInformation;
430 :
431 : std::vector<std::string> MDD;
432 : std::vector<std::string> RDD;
433 : ReportsCollection TabularReportsCollection;
434 :
435 : protected:
436 : bool tsEnabled = false;
437 : bool tsAndTabularEnabled = false;
438 : bool outputJSON = false;
439 : bool outputCBOR = false;
440 : bool outputMsgPack = false;
441 : bool rewriteTimestamp = true; // Convert monthly data timestamp to month name
442 : std::vector<std::string> outputVariables;
443 :
444 : void writeTimeSeriesReports(JsonOutputFilePaths &jsonOutputFilePaths);
445 :
446 : void writeReport(JsonOutputFilePaths &jsonOutputFilePaths);
447 :
448 : void writeCSVOutput(EnergyPlusData &state);
449 :
450 : private:
451 : friend class EnergyPlus::EnergyPlusFixture;
452 : friend class EnergyPlus::ResultsFrameworkFixture;
453 :
454 : protected:
455 24 : inline bool hasDetailedTSData(TimeStepType timeStepType) const
456 : {
457 24 : return detailedTSData[(int)timeStepType].dataFrameEnabled();
458 : }
459 :
460 36 : inline bool hasFreqTSData(ReportFreq freq) const
461 : {
462 36 : return freqTSData[(int)freq].dataFrameEnabled();
463 : }
464 :
465 : #ifdef GET_OUT
466 : inline bool hasRIDetailedZoneTSData() const
467 : {
468 : return detailedTSData[(int)TimeStepType::Zone].iDataFrameEnabled() || detailedTSData[(int)TimeStepType::Zone].rDataFrameEnabled();
469 : };
470 :
471 : inline bool hasRIDetailedHVACTSData() const
472 : {
473 : return detailedTSData[(int)TimeStepType::System].iDataFrameEnabled() || detailedTSData[(int)TimeStepType::System].rDataFrameEnabled();
474 : };
475 :
476 : // This API can be condensed in an obvious way
477 : inline bool hasRITimestepTSData() const
478 : {
479 : return freqTSData[(int)ReportFreq::TimeStep].iDataFrameEnabled() || freqTSData[(int)ReportFreq::TimeStep].rDataFrameEnabled();
480 : };
481 :
482 : inline bool hasRIHourlyTSData() const
483 : {
484 : return freqTSData[(int)ReportFreq::Hour].iDataFrameEnabled() || freqTSData[(int)ReportFreq::Hour].rDataFrameEnabled();
485 : };
486 :
487 : inline bool hasRIDailyTSData() const
488 : {
489 : return freqTSData[(int)ReportFreq::Day].iDataFrameEnabled() || freqTSData[(int)ReportFreq::Day].rDataFrameEnabled();
490 : };
491 :
492 : inline bool hasRIMonthlyTSData() const
493 : {
494 : return freqTSData[(int)ReportFreq::Month].iDataFrameEnabled() || freqTSData[(int)ReportFreq::Month].rDataFrameEnabled();
495 : };
496 :
497 : inline bool hasRIRunPeriodTSData() const
498 : {
499 : return freqTSData[(int)ReportFreq::Simulation].iDataFrameEnabled() || freqTSData[(int)ReportFreq::Simulation].rDataFrameEnabled();
500 : };
501 :
502 : inline bool hasRIYearlyTSData() const
503 : {
504 : return freqTSData[(int)ReportFreq::Year].iDataFrameEnabled() || freqTSData[(int)ReportFreq::Year].rDataFrameEnabled();
505 : };
506 :
507 : inline bool hasTSMeters() const
508 : {
509 : return Meters[(int)ReportFreq::TimeStep].dataFrameEnabled();
510 : };
511 :
512 : inline bool hasHRMeters() const
513 : {
514 : return Meters[(int)ReportFreq::Hour].dataFrameEnabled();
515 : };
516 :
517 : inline bool hasDYMeters() const
518 : {
519 : return Meters[(int)ReportFreq::Day].dataFrameEnabled();
520 : };
521 :
522 : inline bool hasMNMeters() const
523 : {
524 : return Meters[(int)ReportFreq::Month].dataFrameEnabled();
525 : };
526 :
527 : inline bool hasSMMeters() const
528 : {
529 : return Meters[(int)ReportFreq::Simulation].dataFrameEnabled();
530 : };
531 :
532 : inline bool hasYRMeters() const
533 : {
534 : return Meters[(int)ReportFreq::Year].dataFrameEnabled();
535 : };
536 :
537 : #endif //
538 74 : inline bool hasMeters(ReportFreq freq) const
539 : {
540 74 : return Meters[(int)freq].dataFrameEnabled();
541 : }
542 :
543 6 : inline bool hasMeterData() const
544 : {
545 12 : return hasMeters(ReportFreq::TimeStep) || hasMeters(ReportFreq::Hour) || hasMeters(ReportFreq::Day) || hasMeters(ReportFreq::Month) ||
546 12 : hasMeters(ReportFreq::Simulation) || hasMeters(ReportFreq::Year);
547 : };
548 :
549 36 : inline bool hasTSData(ReportFreq freq, TimeStepType timeStepType = TimeStepType::Invalid) const
550 : {
551 36 : assert(freq != ReportFreq::Invalid && (freq != ReportFreq::EachCall || timeStepType != TimeStepType::Invalid));
552 36 : return (freq == ReportFreq::EachCall) ? detailedTSData[(int)timeStepType].dataFrameEnabled() : freqTSData[(int)freq].dataFrameEnabled();
553 : };
554 :
555 6 : inline bool hasAnyTSData() const
556 : {
557 12 : for (int iTimeStep = 0; iTimeStep < (int)TimeStepType::Num; ++iTimeStep)
558 10 : if (detailedTSData[iTimeStep].dataFrameEnabled()) return true;
559 3 : for (int iFreq = (int)ReportFreq::TimeStep; iFreq < (int)ReportFreq::Num; ++iFreq)
560 3 : if (freqTSData[iFreq].dataFrameEnabled()) return true;
561 0 : return false;
562 : };
563 :
564 6 : inline bool hasOutputData() const
565 : {
566 6 : return hasAnyTSData() || hasMeterData();
567 : };
568 : };
569 :
570 : } // namespace ResultsFramework
571 :
572 : struct ResultsFrameworkData : BaseGlobalStruct
573 : {
574 :
575 : std::unique_ptr<ResultsFramework::ResultsFramework> resultsFramework = std::make_unique<ResultsFramework::ResultsFramework>();
576 :
577 796 : void init_state([[maybe_unused]] EnergyPlusData &state) override
578 : {
579 796 : }
580 :
581 0 : void clear_state() override
582 : {
583 : using OutputProcessor::ReportFreq;
584 0 : for (int iFreq = (int)ReportFreq::TimeStep; iFreq < (int)ReportFreq::Num; ++iFreq) {
585 0 : auto &meters = this->resultsFramework->Meters[iFreq];
586 0 : meters.setDataFrameEnabled(false);
587 0 : meters.setVariablesScanned(false);
588 : }
589 0 : }
590 : };
591 :
592 : } // namespace EnergyPlus
593 :
594 : #endif
|