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 <list>
51 : #include <ostream>
52 : #include <string>
53 : #include <vector>
54 :
55 : // ObjexxFCL Headers
56 : #include <ObjexxFCL/Array1D.hh>
57 : #include <ObjexxFCL/Array2D.hh>
58 : #include <ObjexxFCL/Array2S.hh>
59 :
60 : // EnergyPlus Headers
61 : #include <EnergyPlus/CostEstimateManager.hh>
62 : #include <EnergyPlus/Data/EnergyPlusData.hh>
63 : #include <EnergyPlus/DataEnvironment.hh>
64 : #include <EnergyPlus/DataHVACGlobals.hh>
65 : #include <EnergyPlus/General.hh>
66 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
67 : #include <EnergyPlus/OutputProcessor.hh>
68 : #include <EnergyPlus/OutputReportData.hh>
69 : #include <EnergyPlus/OutputReportTabular.hh>
70 : #include <EnergyPlus/OutputReportTabularAnnual.hh>
71 : #include <EnergyPlus/SQLiteProcedures.hh>
72 : #include <EnergyPlus/ScheduleManager.hh>
73 : #include <EnergyPlus/UtilityRoutines.hh>
74 :
75 : namespace EnergyPlus::OutputReportTabularAnnual {
76 :
77 81 : void GetInputTabularAnnual(EnergyPlusData &state)
78 : {
79 : // Jason Glazer, August 2015
80 : // The function assigns the input information for
81 : // REPORT:TABLE:ANNUAL also known as row per object
82 : // reports that are defined by the user. The input
83 : // information is assigned to a data structure that
84 : // is used for both user defined monthly reports and
85 : // predefined monthly reports.
86 :
87 227 : static std::string const currentModuleObject("Output:Table:Annual");
88 :
89 : int jAlpha;
90 : int numParams; // Number of elements combined
91 : int numAlphas; // Number of elements in the alpha array
92 : int numNums; // Number of elements in the numeric array
93 81 : Array1D_string alphArray; // character string data
94 81 : Array1D<Real64> numArray; // numeric data
95 : int IOStat; // IO Status when calling get input subroutine
96 : // static bool ErrorsFound( false );
97 81 : int objCount(0);
98 : int curNumDgts;
99 81 : AnnualFieldSet::AggregationKind curAgg(AnnualFieldSet::AggregationKind::sumOrAvg);
100 :
101 81 : auto &annualTables = state.dataOutputReportTabularAnnual->annualTables;
102 :
103 81 : objCount = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, currentModuleObject);
104 81 : if (objCount > 0) {
105 :
106 7 : state.dataOutRptTab->WriteTabularFiles = true;
107 :
108 : // if not a run period using weather do not create reports
109 7 : if (!state.dataGlobal->DoWeathSim) {
110 0 : ShowWarningError(
111 : state,
112 0 : format("{} requested with SimulationControl Run Simulation for Weather File Run Periods set to No so {} will not be generated",
113 : currentModuleObject,
114 : currentModuleObject));
115 0 : return;
116 : }
117 : }
118 81 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, currentModuleObject, numParams, numAlphas, numNums);
119 81 : alphArray.allocate(numAlphas);
120 81 : numArray.dimension(numNums, 0.0);
121 88 : for (int tabNum = 1; tabNum <= objCount; ++tabNum) {
122 7 : state.dataInputProcessing->inputProcessor->getObjectItem(state, currentModuleObject, tabNum, alphArray, numAlphas, numArray, numNums, IOStat);
123 7 : if (numAlphas >= 5) {
124 7 : annualTables.push_back(AnnualTable(state, alphArray(1), alphArray(2), alphArray(3)));
125 : // the remaining fields are repeating in groups of three and need to be added to the data structure
126 40 : for (jAlpha = 4; jAlpha <= numAlphas; jAlpha += 2) {
127 33 : std::string curVarMtr = alphArray(jAlpha);
128 33 : if (curVarMtr.empty()) {
129 2 : ShowWarningError(state,
130 2 : format("{}: Blank column specified in '{}', need to provide a variable or meter or EMS variable name ",
131 : currentModuleObject,
132 : alphArray(1)));
133 : }
134 33 : if (jAlpha <= numAlphas) {
135 33 : std::string aggregationString = alphArray(jAlpha + 1);
136 33 : curAgg = stringToAggKind(state, aggregationString);
137 33 : } else {
138 0 : curAgg = AnnualFieldSet::AggregationKind::sumOrAvg; // if missing aggregation type use SumOrAverage
139 : }
140 33 : int indexNums = 1 + (jAlpha - 3) / 2; // compute the corresponding field index in the numArray
141 33 : if (indexNums <= numNums) {
142 29 : curNumDgts = numArray(indexNums);
143 : } else {
144 4 : curNumDgts = 2;
145 : }
146 33 : if (!curVarMtr.empty()) {
147 32 : annualTables.back().addFieldSet(curVarMtr, curAgg, curNumDgts);
148 : }
149 33 : }
150 7 : annualTables.back().setupGathering(state);
151 : } else {
152 0 : ShowSevereError(state, format("{}: Must enter at least the first six fields.", currentModuleObject));
153 : }
154 : }
155 81 : }
156 :
157 34 : void AnnualTable::addFieldSet(std::string varName, AnnualFieldSet::AggregationKind aggKind, int dgts)
158 : // Jason Glazer, August 2015
159 : // This method is used along with the constructor to convert the GetInput for REPORT:TABLE:ANNUAL
160 : // into the class data.
161 : {
162 34 : m_annualFields.push_back(AnnualFieldSet(varName, aggKind, dgts));
163 34 : m_annualFields.back().m_colHead = varName; // use the variable name for the column heading
164 34 : }
165 :
166 0 : void AnnualTable::addFieldSet(std::string varName, std::string colName, AnnualFieldSet::AggregationKind aggKind, int dgts)
167 : // Jason Glazer, August 2015
168 : // This overloaded method allows for a specific column name to be different than the output variable or meter name
169 : {
170 0 : m_annualFields.push_back(AnnualFieldSet(varName, aggKind, dgts));
171 0 : m_annualFields.back().m_colHead = colName; // use the user supplied column heading instead of just the variable name
172 0 : }
173 :
174 8 : void AnnualTable::setupGathering(EnergyPlusData &state)
175 : // Jason Glazer, August 2015
176 : // This method is used after GetInput for REPORT:TABLE:ANNUAL to set up how output variables, meters,
177 : // input fields, and ems variables are gathered.
178 : {
179 8 : OutputProcessor::VariableType typeVar = OutputProcessor::VariableType::Invalid;
180 : OutputProcessor::StoreType avgSumVar;
181 : OutputProcessor::TimeStepType stepTypeVar;
182 8 : Constant::Units unitsVar = Constant::Units::None;
183 8 : Array1D_string namesOfKeys; // keyNames
184 8 : Array1D_int indexesForKeyVar; // keyVarIndexes
185 8 : std::list<std::string> allKeys;
186 :
187 8 : std::string filterFieldUpper = m_filter;
188 8 : std::transform(filterFieldUpper.begin(), filterFieldUpper.end(), filterFieldUpper.begin(), ::toupper);
189 8 : bool useFilter = (m_filter.size() != 0);
190 :
191 8 : std::vector<AnnualFieldSet>::iterator fldStIt;
192 42 : for (fldStIt = m_annualFields.begin(); fldStIt != m_annualFields.end(); ++fldStIt) {
193 34 : int keyCount = fldStIt->getVariableKeyCountandTypeFromFldSt(state, typeVar, avgSumVar, stepTypeVar, unitsVar);
194 34 : fldStIt->getVariableKeysFromFldSt(state, typeVar, keyCount, fldStIt->m_namesOfKeys, fldStIt->m_indexesForKeyVar);
195 69 : for (std::string nm : fldStIt->m_namesOfKeys) {
196 35 : std::string nmUpper = nm;
197 35 : std::transform(nmUpper.begin(), nmUpper.end(), nmUpper.begin(), ::toupper);
198 35 : if (!useFilter || nmUpper.find(filterFieldUpper) != std::string::npos) {
199 35 : allKeys.push_back(nm); // create list of all items
200 : }
201 35 : }
202 34 : fldStIt->m_typeOfVar = typeVar;
203 34 : fldStIt->m_varAvgSum = avgSumVar;
204 34 : fldStIt->m_varStepType = stepTypeVar;
205 34 : fldStIt->m_varUnits = unitsVar;
206 34 : fldStIt->m_keyCount = keyCount;
207 : }
208 8 : allKeys.sort();
209 8 : allKeys.unique(); // will now just have a list of the unique keys that is sorted
210 8 : std::copy(allKeys.begin(), allKeys.end(), back_inserter(m_objectNames)); // copy list to the object names
211 : // size all columns list of cells to be the size of the
212 42 : for (fldStIt = m_annualFields.begin(); fldStIt != m_annualFields.end(); ++fldStIt) {
213 34 : fldStIt->m_cell.resize(m_objectNames.size());
214 : }
215 : // for each column (field set) set the rows cell to the output variable index (for variables)
216 : int foundKeyIndex;
217 8 : int tableRowIndex = 0;
218 21 : for (std::vector<std::string>::iterator objNmIt = m_objectNames.begin(); objNmIt != m_objectNames.end(); ++objNmIt) {
219 62 : for (fldStIt = m_annualFields.begin(); fldStIt != m_annualFields.end(); ++fldStIt) {
220 49 : foundKeyIndex = -1;
221 69 : for (std::string::size_type i = 0; i < fldStIt->m_namesOfKeys.size(); i++) {
222 55 : if (fldStIt->m_namesOfKeys[i] == *objNmIt) {
223 35 : foundKeyIndex = i;
224 35 : break;
225 : }
226 : }
227 49 : if (foundKeyIndex > -1) {
228 35 : fldStIt->m_cell[tableRowIndex].indexesForKeyVar = fldStIt->m_indexesForKeyVar[foundKeyIndex];
229 : } else {
230 14 : fldStIt->m_cell[tableRowIndex].indexesForKeyVar = -1; // flag value that cell is not gathered
231 : }
232 94 : if (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::maximum ||
233 45 : fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::maximumDuringHoursShown) {
234 6 : fldStIt->m_cell[tableRowIndex].result = -9.9e99;
235 85 : } else if (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::minimum ||
236 42 : fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::minimumDuringHoursShown) {
237 2 : fldStIt->m_cell[tableRowIndex].result = 9.9e99;
238 : } else {
239 41 : fldStIt->m_cell[tableRowIndex].result = 0.0;
240 : }
241 49 : fldStIt->m_cell[tableRowIndex].duration = 0.0;
242 49 : fldStIt->m_cell[tableRowIndex].timeStamp = 0;
243 : }
244 13 : tableRowIndex++;
245 : }
246 8 : }
247 :
248 74 : void checkAggregationOrderForAnnual(EnergyPlusData &state)
249 : {
250 74 : std::vector<AnnualTable>::iterator annualTableIt;
251 74 : bool invalidAggregationOrderFound = false;
252 74 : auto &annualTables = state.dataOutputReportTabularAnnual->annualTables;
253 74 : if (!state.dataGlobal->DoWeathSim) { // if no weather simulation than no reading of MonthlyInput array
254 73 : return;
255 : }
256 1 : for (annualTableIt = annualTables.begin(); annualTableIt != annualTables.end(); ++annualTableIt) {
257 0 : if (annualTableIt->invalidAggregationOrder(state)) {
258 0 : invalidAggregationOrderFound = true;
259 : }
260 : }
261 1 : if (invalidAggregationOrderFound) {
262 0 : ShowFatalError(state, "OutputReportTabularAnnual: Invalid aggregations detected, no simulation performed.");
263 : }
264 : }
265 :
266 : // Generate an error message if an advanced aggregation kind columns don't follow the appropriate column - Glazer 2017
267 1 : bool AnnualTable::invalidAggregationOrder(EnergyPlusData &state)
268 : {
269 1 : std::vector<AnnualFieldSet>::iterator fldStIt;
270 1 : bool foundMinOrMax = false;
271 1 : bool foundHourAgg = false;
272 1 : bool missingMaxOrMinError = false;
273 1 : bool missingHourAggError = false;
274 3 : for (fldStIt = m_annualFields.begin(); fldStIt != m_annualFields.end(); ++fldStIt) {
275 4 : if ((fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::maximum) ||
276 2 : (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::minimum)) {
277 0 : foundMinOrMax = true;
278 2 : } else if ((fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::hoursNonZero) ||
279 2 : (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::hoursZero) ||
280 2 : (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::hoursPositive) ||
281 2 : (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::hoursNonPositive) ||
282 6 : (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::hoursNegative) ||
283 2 : (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::hoursNonNegative)) {
284 0 : foundHourAgg = true;
285 2 : } else if (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::valueWhenMaxMin) {
286 0 : if (!foundMinOrMax) {
287 0 : missingMaxOrMinError = true;
288 : }
289 2 : } else if ((fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::sumOrAverageHoursShown) ||
290 3 : (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::maximumDuringHoursShown) ||
291 1 : (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::minimumDuringHoursShown)) {
292 1 : if (!foundHourAgg) {
293 1 : missingHourAggError = true;
294 : }
295 : }
296 : }
297 1 : if (missingMaxOrMinError) {
298 0 : ShowSevereError(state,
299 0 : format("The Output:Table:Annual report named=\"{}\" has a valueWhenMaxMin aggregation type for a column without a previous "
300 : "column that uses either the minimum or maximum aggregation types. The report will not be generated.",
301 0 : m_name));
302 : }
303 1 : if (missingHourAggError) {
304 2 : ShowSevereError(state,
305 2 : format("The Output:Table:Annual report named=\"{}\" has a --DuringHoursShown aggregation type for a column without a "
306 : "previous field that uses one of the Hour-- aggregation types. The report will not be generated.",
307 1 : m_name));
308 : }
309 2 : return (missingHourAggError || missingMaxOrMinError);
310 : }
311 :
312 3 : void GatherAnnualResultsForTimeStep(EnergyPlusData &state, OutputProcessor::TimeStepType kindOfTimeStep)
313 : {
314 : // Jason Glazer, August 2015
315 : // This function is not part of the class but acts as an interface between procedural code and the class by
316 : // gathering data for each of the AnnualTable objects
317 3 : std::vector<AnnualTable>::iterator annualTableIt;
318 3 : auto &annualTables = state.dataOutputReportTabularAnnual->annualTables;
319 4 : for (annualTableIt = annualTables.begin(); annualTableIt != annualTables.end(); ++annualTableIt) {
320 1 : annualTableIt->gatherForTimestep(state, kindOfTimeStep);
321 : }
322 3 : }
323 :
324 3 : void AnnualTable::gatherForTimestep(EnergyPlusData &state, OutputProcessor::TimeStepType kindOfTimeStep)
325 : {
326 : // Jason Glazer, August 2015
327 : // For each cell of the table, gather the value as indicated by the type of aggregation
328 :
329 : int timestepTimeStamp;
330 3 : Real64 elapsedTime = AnnualTable::getElapsedTime(state, kindOfTimeStep);
331 3 : Real64 secondsInTimeStep = AnnualTable::getSecondsInTimeStep(state, kindOfTimeStep);
332 3 : bool activeMinMax = false;
333 3 : bool activeHoursShown = false;
334 : // if schedule is used and the current value is zero, don't gather values
335 3 : if (m_sched != nullptr && m_sched->getCurrentVal() == 0.0) {
336 0 : return;
337 : }
338 : // loop through the fields
339 3 : std::vector<AnnualFieldSet>::iterator fldStIt;
340 3 : std::vector<AnnualFieldSet>::iterator fldStRemainIt;
341 8 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
342 18 : for (fldStIt = m_annualFields.begin(); fldStIt != m_annualFields.end(); ++fldStIt) {
343 13 : OutputProcessor::VariableType curTypeOfVar = fldStIt->m_typeOfVar;
344 13 : OutputProcessor::TimeStepType curStepType = fldStIt->m_varStepType;
345 13 : if (curStepType == kindOfTimeStep) // this is a much simpler conditional than the code in monthly gathering
346 : {
347 13 : int curVarNum = fldStIt->m_cell[row].indexesForKeyVar;
348 13 : if (curVarNum > -1) {
349 10 : Real64 curValue = GetInternalVariableValue(state, curTypeOfVar, curVarNum);
350 : // Get the value from the result array
351 10 : Real64 oldResultValue = fldStIt->m_cell[row].result;
352 : // int oldTimeStamp = fldStIt->m_cell[row].timeStamp;
353 10 : Real64 oldDuration = fldStIt->m_cell[row].duration;
354 : // Zero the revised values (as default if not set later)
355 10 : Real64 newResultValue = 0.0;
356 10 : int newTimeStamp = 0;
357 10 : Real64 newDuration = 0.0;
358 10 : bool activeNewValue = false;
359 : // the current timestamp
360 10 : int minuteCalculated = OutputProcessor::DetermineMinuteForReporting(state);
361 10 : General::EncodeMonDayHrMin(
362 10 : timestepTimeStamp, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth, state.dataGlobal->HourOfDay, minuteCalculated);
363 : // perform the selected aggregation type
364 : // the following types of aggregations are not gathered at this point:
365 : // noAggregation, valueWhenMaxMin, sumOrAverageHoursShown, maximumDuringHoursShown, minimumDuringHoursShown:
366 10 : switch (fldStIt->m_aggregate) {
367 3 : case AnnualFieldSet::AggregationKind::sumOrAvg:
368 3 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Sum) { // if it is a summed variable
369 3 : newResultValue = oldResultValue + curValue;
370 : } else {
371 0 : newResultValue = oldResultValue + curValue * elapsedTime; // for averaging - weight by elapsed time
372 : }
373 3 : newDuration = oldDuration + elapsedTime;
374 3 : activeNewValue = true;
375 3 : break;
376 3 : case AnnualFieldSet::AggregationKind::maximum:
377 : // per MJW when a summed variable is used divide it by the length of the time step
378 3 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Sum) { // if it is a summed variable
379 0 : curValue /= secondsInTimeStep;
380 : }
381 3 : if (curValue > oldResultValue) {
382 3 : newResultValue = curValue;
383 3 : newTimeStamp = timestepTimeStamp;
384 3 : activeMinMax = true;
385 3 : activeNewValue = true;
386 : } else {
387 0 : activeMinMax = false; // reset this
388 : }
389 3 : break;
390 0 : case AnnualFieldSet::AggregationKind::minimum:
391 : // per MJW when a summed variable is used divide it by the length of the time step
392 0 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Sum) { // if it is a summed variable
393 0 : curValue /= secondsInTimeStep;
394 : }
395 0 : if (curValue < oldResultValue) {
396 0 : newResultValue = curValue;
397 0 : newTimeStamp = timestepTimeStamp;
398 0 : activeMinMax = true;
399 0 : activeNewValue = true;
400 : } else {
401 0 : activeMinMax = false; // reset this
402 : }
403 0 : break;
404 0 : case AnnualFieldSet::AggregationKind::hoursNonZero:
405 0 : if (curValue != 0) {
406 0 : newResultValue = oldResultValue + elapsedTime;
407 0 : activeHoursShown = true;
408 0 : activeNewValue = true;
409 : } else {
410 0 : activeHoursShown = false;
411 : }
412 0 : break;
413 0 : case AnnualFieldSet::AggregationKind::hoursZero:
414 0 : if (curValue == 0) {
415 0 : newResultValue = oldResultValue + elapsedTime;
416 0 : activeHoursShown = true;
417 0 : activeNewValue = true;
418 : } else {
419 0 : activeHoursShown = false;
420 : }
421 0 : break;
422 2 : case AnnualFieldSet::AggregationKind::hoursPositive:
423 2 : if (curValue > 0) {
424 1 : newResultValue = oldResultValue + elapsedTime;
425 1 : activeHoursShown = true;
426 1 : activeNewValue = true;
427 : } else {
428 1 : activeHoursShown = false;
429 : }
430 2 : break;
431 0 : case AnnualFieldSet::AggregationKind::hoursNonPositive:
432 0 : if (curValue <= 0) {
433 0 : newResultValue = oldResultValue + elapsedTime;
434 0 : activeHoursShown = true;
435 0 : activeNewValue = true;
436 : } else {
437 0 : activeHoursShown = false;
438 : }
439 0 : break;
440 0 : case AnnualFieldSet::AggregationKind::hoursNegative:
441 0 : if (curValue < 0) {
442 0 : newResultValue = oldResultValue + elapsedTime;
443 0 : activeHoursShown = true;
444 0 : activeNewValue = true;
445 : } else {
446 0 : activeHoursShown = false;
447 : }
448 0 : break;
449 0 : case AnnualFieldSet::AggregationKind::hoursNonNegative:
450 0 : if (curValue >= 0) {
451 0 : newResultValue = oldResultValue + elapsedTime;
452 0 : activeHoursShown = true;
453 0 : activeNewValue = true;
454 : } else {
455 0 : activeHoursShown = false;
456 : }
457 0 : break;
458 0 : case AnnualFieldSet::AggregationKind::hoursInTenPercentBins:
459 : case AnnualFieldSet::AggregationKind::hoursInTenBinsMinToMax:
460 : case AnnualFieldSet::AggregationKind::hoursInTenBinsZeroToMax:
461 : case AnnualFieldSet::AggregationKind::hoursInTenBinsMinToZero:
462 : case AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusTwoStdDev:
463 : case AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusThreeStdDev:
464 : // for all of the binning options add the value to the deferred
465 0 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Sum) { // if it is a summed variable
466 0 : fldStIt->m_cell[row].deferredResults.push_back(curValue /= secondsInTimeStep); // divide by time just like max and min
467 : } else {
468 0 : fldStIt->m_cell[row].deferredResults.push_back(curValue);
469 : }
470 0 : fldStIt->m_cell[row].deferredElapsed.push_back(elapsedTime); // save the amount of time for this particular value
471 0 : newDuration = oldDuration + elapsedTime;
472 0 : break;
473 2 : case AnnualFieldSet::AggregationKind::noAggregation:
474 : case AnnualFieldSet::AggregationKind::valueWhenMaxMin:
475 : case AnnualFieldSet::AggregationKind::sumOrAverageHoursShown:
476 : case AnnualFieldSet::AggregationKind::maximumDuringHoursShown:
477 : case AnnualFieldSet::AggregationKind::minimumDuringHoursShown:
478 : // do nothing
479 2 : break;
480 : } // end switch fldStIt->m_aggregate
481 :
482 : // if the new value has been set then set the monthly values to the
483 : // new columns. This skips the aggregation types that don't even get
484 : // triggered now such as valueWhenMinMax and all the agg*HoursShown
485 10 : if (activeNewValue) {
486 7 : fldStIt->m_cell[row].result = newResultValue;
487 7 : fldStIt->m_cell[row].timeStamp = newTimeStamp;
488 7 : fldStIt->m_cell[row].duration = newDuration;
489 : }
490 : // if a minimum or maximum value was set this timeStep then
491 : // scan the remaining columns of the table looking for values
492 : // that are aggregation type "ValueWhenMaxMin" and set their values
493 : // if another minimum or maximum column is found then end
494 : // the scan (it will be taken care of when that column is done)
495 10 : if (activeMinMax) {
496 8 : for (fldStRemainIt = fldStIt + 1; fldStRemainIt != m_annualFields.end(); ++fldStRemainIt) {
497 8 : if (fldStRemainIt->m_aggregate == AnnualFieldSet::AggregationKind::maximum ||
498 3 : fldStRemainIt->m_aggregate == AnnualFieldSet::AggregationKind::minimum) {
499 : // end scanning since these might reset
500 2 : break; // for fldStRemainIt
501 3 : } else if (fldStRemainIt->m_aggregate == AnnualFieldSet::AggregationKind::valueWhenMaxMin) {
502 : // this case is when the value should be set
503 0 : OutputProcessor::VariableType scanTypeOfVar = fldStRemainIt->m_typeOfVar;
504 : // int scanStepType = fldStRemainIt->m_varStepType;
505 0 : int scanVarNum = fldStRemainIt->m_cell[row].indexesForKeyVar;
506 0 : if (scanVarNum > -1) {
507 0 : Real64 scanValue = GetInternalVariableValue(state, scanTypeOfVar, scanVarNum);
508 : // When a summed variable is used divide it by the length of the time step
509 0 : if (fldStRemainIt->m_varAvgSum == OutputProcessor::StoreType::Sum) { // if it is a summed variable
510 0 : scanValue /= secondsInTimeStep;
511 : }
512 0 : fldStRemainIt->m_cell[row].result = scanValue;
513 : }
514 : } else {
515 : // do nothing
516 : }
517 : }
518 : }
519 : // If the hours variable is active then scan through the rest of the variables
520 : // and accumulate
521 10 : if (activeHoursShown) {
522 2 : for (fldStRemainIt = fldStIt + 1; fldStRemainIt != m_annualFields.end(); ++fldStRemainIt) {
523 1 : OutputProcessor::VariableType scanTypeOfVar = fldStRemainIt->m_typeOfVar;
524 : // int scanStepType = fldStRemainIt->m_varStepType;
525 1 : int scanVarNum = fldStRemainIt->m_cell[row].indexesForKeyVar;
526 1 : Real64 oldScanValue = fldStRemainIt->m_cell[row].result;
527 1 : if (scanVarNum > -1) {
528 1 : Real64 scanValue = GetInternalVariableValue(state, scanTypeOfVar, scanVarNum);
529 1 : if (fldStRemainIt->m_aggregate == AnnualFieldSet::AggregationKind::hoursZero ||
530 1 : fldStRemainIt->m_aggregate == AnnualFieldSet::AggregationKind::hoursNonZero ||
531 1 : fldStRemainIt->m_aggregate == AnnualFieldSet::AggregationKind::hoursPositive ||
532 1 : fldStRemainIt->m_aggregate == AnnualFieldSet::AggregationKind::hoursNonPositive ||
533 3 : fldStRemainIt->m_aggregate == AnnualFieldSet::AggregationKind::hoursNegative ||
534 1 : fldStRemainIt->m_aggregate == AnnualFieldSet::AggregationKind::hoursNonNegative) {
535 : // end scanning since these might reset
536 0 : break; // for fldStRemainIt
537 1 : } else if (fldStRemainIt->m_aggregate == AnnualFieldSet::AggregationKind::sumOrAverageHoursShown) {
538 0 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Sum) { // if it is a summed variable
539 0 : fldStRemainIt->m_cell[row].result = oldScanValue + scanValue;
540 : } else {
541 0 : fldStRemainIt->m_cell[row].result =
542 0 : oldScanValue + scanValue * elapsedTime; // for averaging - weight by elapsed time
543 : }
544 0 : fldStRemainIt->m_cell[row].duration += elapsedTime;
545 1 : } else if (fldStRemainIt->m_aggregate == AnnualFieldSet::AggregationKind::minimumDuringHoursShown) {
546 0 : if (fldStRemainIt->m_varAvgSum == OutputProcessor::StoreType::Sum) { // if it is a summed variable
547 0 : scanValue /= secondsInTimeStep;
548 : }
549 0 : if (scanValue < oldScanValue) {
550 0 : fldStRemainIt->m_cell[row].result = scanValue;
551 0 : fldStRemainIt->m_cell[row].timeStamp = timestepTimeStamp;
552 : }
553 1 : } else if (fldStRemainIt->m_aggregate == AnnualFieldSet::AggregationKind::maximumDuringHoursShown) {
554 1 : if (fldStRemainIt->m_varAvgSum == OutputProcessor::StoreType::Sum) { // if it is a summed variable
555 1 : scanValue /= secondsInTimeStep;
556 : }
557 1 : if (scanValue > oldScanValue) {
558 1 : fldStRemainIt->m_cell[row].result = scanValue;
559 1 : fldStRemainIt->m_cell[row].timeStamp = timestepTimeStamp;
560 : }
561 : } else {
562 : // do nothing
563 : }
564 : }
565 1 : activeHoursShown = false; // fixed CR8317
566 : }
567 : }
568 : }
569 : }
570 : }
571 : }
572 : }
573 :
574 0 : void ResetAnnualGathering(EnergyPlusData &state)
575 : {
576 : // Jason Glazer, October 2015
577 : // This function is not part of the class but acts as an interface between procedural code and the class by
578 : // resetting data for each of the AnnualTable objects
579 0 : std::vector<AnnualTable>::iterator annualTableIt;
580 0 : auto &annualTables = state.dataOutputReportTabularAnnual->annualTables;
581 0 : for (annualTableIt = annualTables.begin(); annualTableIt != annualTables.end(); ++annualTableIt) {
582 0 : annualTableIt->resetGathering();
583 : }
584 0 : }
585 :
586 0 : void AnnualTable::resetGathering()
587 : {
588 0 : std::vector<AnnualFieldSet>::iterator fldStIt;
589 0 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
590 0 : for (fldStIt = m_annualFields.begin(); fldStIt != m_annualFields.end(); ++fldStIt) {
591 0 : if (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::maximum ||
592 0 : fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::maximumDuringHoursShown) {
593 0 : fldStIt->m_cell[row].result = -9.9e99;
594 0 : } else if (fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::minimum ||
595 0 : fldStIt->m_aggregate == AnnualFieldSet::AggregationKind::minimumDuringHoursShown) {
596 0 : fldStIt->m_cell[row].result = 9.9e99;
597 : } else {
598 0 : fldStIt->m_cell[row].result = 0.0;
599 : }
600 0 : fldStIt->m_cell[row].duration = 0.0;
601 0 : fldStIt->m_cell[row].timeStamp = 0;
602 : // if any defered results
603 0 : fldStIt->m_cell[row].deferredResults.clear();
604 0 : fldStIt->m_cell[row].deferredElapsed.clear();
605 : }
606 : }
607 0 : }
608 :
609 3 : Real64 AnnualTable::getElapsedTime(EnergyPlusData &state, OutputProcessor::TimeStepType kindOfTimeStep)
610 : {
611 : Real64 elapsedTime;
612 3 : if (kindOfTimeStep == OutputProcessor::TimeStepType::Zone) {
613 3 : elapsedTime = state.dataHVACGlobal->TimeStepSys;
614 : } else {
615 0 : elapsedTime = state.dataGlobal->TimeStepZone;
616 : }
617 3 : return elapsedTime;
618 : }
619 :
620 3 : Real64 AnnualTable::getSecondsInTimeStep(EnergyPlusData &state, OutputProcessor::TimeStepType kindOfTimeStep)
621 : {
622 : Real64 secondsInTimeStep;
623 3 : if (kindOfTimeStep == OutputProcessor::TimeStepType::Zone) {
624 3 : secondsInTimeStep = state.dataHVACGlobal->TimeStepSysSec;
625 : } else {
626 0 : secondsInTimeStep = state.dataGlobal->TimeStepZoneSec;
627 : }
628 3 : return secondsInTimeStep;
629 : }
630 :
631 1 : void WriteAnnualTables(EnergyPlusData &state)
632 : {
633 1 : auto &annualTables = state.dataOutputReportTabularAnnual->annualTables;
634 3 : for (int iUnitSystem = 0; iUnitSystem <= 1; iUnitSystem++) {
635 2 : OutputReportTabular::UnitsStyle unitsStyle_cur = state.dataOutRptTab->unitsStyle;
636 2 : bool produceTabular = true;
637 2 : bool produceSQLite = false;
638 2 : if (produceDualUnitsFlags(
639 2 : iUnitSystem, state.dataOutRptTab->unitsStyle, state.dataOutRptTab->unitsStyle_SQLite, unitsStyle_cur, produceTabular, produceSQLite))
640 0 : break;
641 :
642 : // Jason Glazer, August 2015
643 : // This function is not part of the class but acts as an interface between procedural code and the class by
644 : // invoking the writeTable member function for each of the AnnualTable objects
645 2 : std::vector<AnnualTable>::iterator annualTableIt;
646 4 : for (annualTableIt = annualTables.begin(); annualTableIt != annualTables.end(); ++annualTableIt) {
647 2 : annualTableIt->writeTable(state, unitsStyle_cur, produceTabular, produceSQLite);
648 : }
649 : }
650 1 : }
651 :
652 2 : void AnnualTable::writeTable(EnergyPlusData &state, OutputReportTabular::UnitsStyle unitsStyle, bool produceTabular_para, bool produceSQLite_para)
653 : {
654 2 : Array1D_string columnHead;
655 2 : Array1D_int columnWidth;
656 2 : Array1D_string rowHead;
657 2 : Array2D_string tableBody;
658 2 : Real64 veryLarge = 1.0E280;
659 2 : Real64 verySmall = -1.0E280;
660 2 : std::vector<std::string> aggString;
661 2 : std::string energyUnitsString;
662 2 : std::string varNameWithUnits;
663 : int indexUnitConv;
664 : Real64 curVal;
665 2 : std::string curUnits;
666 : Real64 curConversionFactor;
667 : Real64 curConversionOffset;
668 : Real64 minVal;
669 : Real64 maxVal;
670 : Real64 sumVal;
671 : Real64 sumDuration;
672 2 : bool createBinRangeTable = false;
673 :
674 : static Real64 const storedMaxVal(std::numeric_limits<Real64>::max());
675 : static Real64 const storedMinVal(std::numeric_limits<Real64>::lowest());
676 :
677 2 : aggString = setupAggString();
678 2 : Real64 energyUnitsConversionFactor = AnnualTable::setEnergyUnitStringAndFactor(unitsStyle, energyUnitsString);
679 :
680 : // Compute the columns related to the binning schemes
681 2 : computeBinColumns(state, unitsStyle);
682 :
683 : // Use title case names of variables if available for column headers
684 2 : columnHeadersToTitleCase(state);
685 :
686 : // first loop through and count how many 'columns' are defined
687 : // since max and min actually define two columns (the value
688 : // and the timestamp).
689 2 : int columnCount = 0;
690 2 : std::vector<AnnualFieldSet>::iterator fldStIt;
691 34 : for (fldStIt = m_annualFields.begin(); fldStIt != m_annualFields.end(); ++fldStIt) {
692 32 : columnCount += columnCountForAggregation(fldStIt->m_aggregate);
693 : }
694 2 : columnHead.allocate(columnCount);
695 2 : columnWidth.dimension(columnCount);
696 2 : columnWidth = 14; // array assignment - same for all columns
697 2 : int rowCount = m_objectNames.size() + 4; // add blank, sum/avg, min, max rows.
698 2 : int rowSumAvg = m_objectNames.size() + 2;
699 2 : int rowMin = m_objectNames.size() + 3;
700 2 : int rowMax = m_objectNames.size() + 4;
701 :
702 2 : rowHead.allocate(rowCount);
703 4 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
704 2 : rowHead(row + 1) = m_objectNames[row];
705 : }
706 2 : rowHead(rowSumAvg) = "Annual Sum or Average";
707 2 : rowHead(rowMin) = "Minimum of Rows";
708 2 : rowHead(rowMax) = "Maximum of Rows";
709 :
710 2 : tableBody.allocate(columnCount, rowCount);
711 2 : tableBody = ""; // set entire table to blank as default
712 2 : int columnRecount = 0;
713 34 : for (fldStIt = m_annualFields.begin(); fldStIt != m_annualFields.end(); ++fldStIt) {
714 32 : std::string curAggString = aggString[(int)fldStIt->m_aggregate];
715 32 : if (curAggString.size() > 0) {
716 30 : curAggString = " {" + trim(curAggString) + '}';
717 : }
718 : // do the unit conversions
719 32 : if (unitsStyle == OutputReportTabular::UnitsStyle::InchPound || unitsStyle == OutputReportTabular::UnitsStyle::InchPoundExceptElectricity) {
720 0 : varNameWithUnits = format("{} [{}]", fldStIt->m_variMeter, Constant::unitNames[(int)fldStIt->m_varUnits]);
721 0 : OutputReportTabular::LookupSItoIP(state, varNameWithUnits, indexUnitConv, curUnits);
722 0 : OutputReportTabular::GetUnitConversion(state, indexUnitConv, curConversionFactor, curConversionOffset, curUnits);
723 : } else { // just do the Joule conversion
724 : // if units is in Joules, convert if specified
725 32 : if (fldStIt->m_varUnits == Constant::Units::J) {
726 0 : curUnits = energyUnitsString;
727 0 : curConversionFactor = energyUnitsConversionFactor;
728 0 : curConversionOffset = 0.0;
729 : } else { // if not joules don't perform conversion
730 32 : curUnits = Constant::unitNames[(int)fldStIt->m_varUnits];
731 32 : curConversionFactor = 1.0;
732 32 : curConversionOffset = 0.0;
733 : }
734 : }
735 32 : int curAgg = fldStIt->m_aggregate;
736 32 : columnRecount += columnCountForAggregation(fldStIt->m_aggregate);
737 32 : if ((curAgg == AnnualFieldSet::AggregationKind::sumOrAvg) || (curAgg == AnnualFieldSet::AggregationKind::sumOrAverageHoursShown)) {
738 : // put in the name of the variable for the column
739 4 : columnHead(columnRecount) = fldStIt->m_colHead + curAggString + " [" + curUnits + ']';
740 4 : sumVal = 0.0;
741 4 : sumDuration = 0.0;
742 4 : minVal = storedMaxVal;
743 4 : maxVal = storedMinVal;
744 :
745 8 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
746 4 : if (fldStIt->m_cell[row].indexesForKeyVar >= 0) {
747 4 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Average) { // if it is a average variable divide by duration
748 0 : if (fldStIt->m_cell[row].duration != 0.0) {
749 0 : curVal = ((fldStIt->m_cell[row].result / fldStIt->m_cell[row].duration) * curConversionFactor) + curConversionOffset;
750 : } else {
751 0 : curVal = 0.0;
752 : }
753 0 : sumVal += (fldStIt->m_cell[row].result * curConversionFactor) + curConversionOffset;
754 0 : sumDuration += fldStIt->m_cell[row].duration;
755 : } else {
756 4 : curVal = (fldStIt->m_cell[row].result * curConversionFactor) + curConversionOffset;
757 4 : sumVal += curVal;
758 : }
759 4 : tableBody(columnRecount, row + 1) = OutputReportTabular::RealToStr(curVal, fldStIt->m_showDigits);
760 4 : if (curVal > maxVal) maxVal = curVal;
761 4 : if (curVal < minVal) minVal = curVal;
762 : } else {
763 0 : tableBody(columnRecount, row + 1) = "-";
764 : }
765 :
766 : } // row
767 : // add the summary to bottom
768 4 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Average) { // if it is a average variable divide by duration
769 0 : if (sumDuration > 0) {
770 0 : tableBody(columnRecount, rowSumAvg) = OutputReportTabular::RealToStr(sumVal / sumDuration, fldStIt->m_showDigits);
771 : } else {
772 0 : tableBody(columnRecount, rowSumAvg) = "";
773 : }
774 : } else {
775 4 : tableBody(columnRecount, rowSumAvg) = OutputReportTabular::RealToStr(sumVal, fldStIt->m_showDigits);
776 : }
777 4 : if (minVal != storedMaxVal) {
778 4 : tableBody(columnRecount, rowMax) = OutputReportTabular::RealToStr(minVal, fldStIt->m_showDigits);
779 : }
780 4 : if (maxVal != storedMinVal) {
781 4 : tableBody(columnRecount, rowMin) = OutputReportTabular::RealToStr(maxVal, fldStIt->m_showDigits);
782 : }
783 32 : } else if ((curAgg == AnnualFieldSet::AggregationKind::hoursZero) || (curAgg == AnnualFieldSet::AggregationKind::hoursNonZero) ||
784 22 : (curAgg == AnnualFieldSet::AggregationKind::hoursPositive) || (curAgg == AnnualFieldSet::AggregationKind::hoursNonPositive) ||
785 18 : (curAgg == AnnualFieldSet::AggregationKind::hoursNegative) || (curAgg == AnnualFieldSet::AggregationKind::hoursNonNegative)) {
786 : // put in the name of the variable for the column
787 12 : columnHead(columnRecount) = fldStIt->m_colHead + curAggString + " [HOURS]";
788 12 : sumVal = 0.0;
789 12 : minVal = storedMaxVal;
790 12 : maxVal = storedMinVal;
791 24 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
792 12 : curVal = fldStIt->m_cell[row].result;
793 12 : curVal = curVal * curConversionFactor + curConversionOffset;
794 12 : tableBody(columnRecount, row + 1) = OutputReportTabular::RealToStr(curVal, fldStIt->m_showDigits);
795 12 : sumVal += curVal;
796 12 : if (curVal > maxVal) maxVal = curVal;
797 12 : if (curVal < minVal) minVal = curVal;
798 : } // row
799 : // add the summary to bottom
800 12 : tableBody(columnRecount, rowSumAvg) = OutputReportTabular::RealToStr(sumVal, fldStIt->m_showDigits);
801 12 : if (minVal != storedMaxVal) {
802 12 : tableBody(columnRecount, rowMax) = OutputReportTabular::RealToStr(minVal, fldStIt->m_showDigits);
803 : }
804 12 : if (maxVal != storedMinVal) {
805 12 : tableBody(columnRecount, rowMin) = OutputReportTabular::RealToStr(maxVal, fldStIt->m_showDigits);
806 : }
807 28 : } else if (curAgg == AnnualFieldSet::AggregationKind::valueWhenMaxMin) {
808 2 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Sum) {
809 2 : curUnits += "/s";
810 : }
811 2 : fixUnitsPerSecond(curUnits, curConversionFactor);
812 2 : columnHead(columnRecount) = fldStIt->m_colHead + curAggString + " [" + curUnits + ']';
813 2 : minVal = storedMaxVal;
814 2 : maxVal = storedMinVal;
815 4 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
816 2 : curVal = fldStIt->m_cell[row].result;
817 2 : curVal = curVal * curConversionFactor + curConversionOffset;
818 2 : tableBody(columnRecount, row + 1) = OutputReportTabular::RealToStr(curVal, fldStIt->m_showDigits);
819 2 : if (curVal > maxVal) maxVal = curVal;
820 2 : if (curVal < minVal) minVal = curVal;
821 : } // row
822 : // add the summary to bottom
823 2 : if (minVal != storedMaxVal) {
824 2 : tableBody(columnRecount, rowMin) = OutputReportTabular::RealToStr(minVal, fldStIt->m_showDigits);
825 : }
826 2 : if (maxVal != storedMinVal) {
827 2 : tableBody(columnRecount, rowMax) = OutputReportTabular::RealToStr(maxVal, fldStIt->m_showDigits);
828 : }
829 14 : } else if ((curAgg == AnnualFieldSet::AggregationKind::maximum) || (curAgg == AnnualFieldSet::AggregationKind::minimum) ||
830 8 : (curAgg == AnnualFieldSet::AggregationKind::maximumDuringHoursShown) ||
831 : (curAgg == AnnualFieldSet::AggregationKind::minimumDuringHoursShown)) {
832 : // put in the name of the variable for the column
833 8 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Sum) { // if it is a summed variable
834 8 : curUnits += "/s";
835 : }
836 8 : fixUnitsPerSecond(curUnits, curConversionFactor);
837 8 : columnHead(columnRecount - 1) = fldStIt->m_colHead + curAggString + " [" + curUnits + ']';
838 8 : columnHead(columnRecount) = fldStIt->m_colHead + " {TIMESTAMP}";
839 8 : minVal = storedMaxVal;
840 8 : maxVal = storedMinVal;
841 16 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
842 8 : curVal = fldStIt->m_cell[row].result;
843 : // CR7788 the conversion factors were causing an overflow for the InchPound case since the
844 : // value was very small
845 : // restructured the following lines to hide showing HUGE and -HUGE values in output table CR8154 Glazer
846 8 : if ((curVal < veryLarge) && (curVal > verySmall)) {
847 8 : curVal = curVal * curConversionFactor + curConversionOffset;
848 8 : if (curVal > maxVal) maxVal = curVal;
849 8 : if (curVal < minVal) minVal = curVal;
850 8 : if (curVal < veryLarge && curVal > verySmall) {
851 8 : tableBody(columnRecount - 1, row + 1) = OutputReportTabular::RealToStr(curVal, fldStIt->m_showDigits);
852 : } else {
853 0 : tableBody(columnRecount - 1, row + 1) = "-";
854 : }
855 8 : tableBody(columnRecount, row + 1) = OutputReportTabular::DateToString(fldStIt->m_cell[row].timeStamp);
856 : } else {
857 0 : tableBody(columnRecount - 1, row + 1) = "-";
858 0 : tableBody(columnRecount, row + 1) = "-";
859 : }
860 : } // row
861 : // add the summary to bottom
862 : // Don't include if the original min and max values are still present
863 8 : if (minVal < veryLarge) {
864 8 : tableBody(columnRecount - 1, rowMin) = OutputReportTabular::RealToStr(minVal, fldStIt->m_showDigits);
865 : } else {
866 0 : tableBody(columnRecount - 1, rowMin) = "-";
867 : }
868 8 : if (maxVal > verySmall) {
869 8 : tableBody(columnRecount - 1, rowMax) = OutputReportTabular::RealToStr(maxVal, fldStIt->m_showDigits);
870 : } else {
871 0 : tableBody(columnRecount - 1, rowMax) = "-";
872 : }
873 14 : } else if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsMinToMax) {
874 : // put in the name of the variable for the column
875 2 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Sum) { // if it is a summed variable
876 2 : curUnits += "/s";
877 : }
878 2 : fixUnitsPerSecond(curUnits, curConversionFactor);
879 22 : for (int iBin = 0; iBin != 10; iBin++) {
880 20 : char binIndicator = iBin + 65;
881 20 : columnHead(columnRecount - 9 + iBin) = fldStIt->m_colHead + curAggString + " BIN " + binIndicator;
882 40 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
883 20 : tableBody(columnRecount - 9 + iBin, row + 1) =
884 40 : OutputReportTabular::RealToStr(fldStIt->m_cell[row].m_timeInBin[iBin], fldStIt->m_showDigits);
885 : }
886 20 : tableBody(columnRecount - 9 + iBin, rowSumAvg) =
887 40 : OutputReportTabular::RealToStr(fldStIt->m_timeInBinTotal[iBin], fldStIt->m_showDigits);
888 : }
889 2 : createBinRangeTable = true;
890 4 : } else if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsZeroToMax) {
891 : // put in the name of the variable for the column
892 2 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Sum) { // if it is a summed variable
893 2 : curUnits += "/s";
894 : }
895 2 : fixUnitsPerSecond(curUnits, curConversionFactor);
896 22 : for (int iBin = 0; iBin != 10; iBin++) {
897 20 : char binIndicator = iBin + 65;
898 20 : columnHead(columnRecount - 9 + iBin) = fldStIt->m_colHead + curAggString + " BIN " + binIndicator;
899 40 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
900 20 : tableBody(columnRecount - 9 + iBin, row + 1) =
901 40 : OutputReportTabular::RealToStr(fldStIt->m_cell[row].m_timeInBin[iBin], fldStIt->m_showDigits);
902 : }
903 20 : tableBody(columnRecount - 9 + iBin, rowSumAvg) =
904 40 : OutputReportTabular::RealToStr(fldStIt->m_timeInBinTotal[iBin], fldStIt->m_showDigits);
905 : }
906 2 : columnHead(columnRecount - 10) = fldStIt->m_colHead + curAggString + " LESS THAN BIN A";
907 4 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
908 2 : tableBody(columnRecount - 10, row + 1) =
909 4 : OutputReportTabular::RealToStr(fldStIt->m_cell[row].m_timeBelowBottomBin, fldStIt->m_showDigits);
910 : }
911 2 : tableBody(columnRecount - 10, rowSumAvg) = OutputReportTabular::RealToStr(fldStIt->m_timeBelowBottomBinTotal, fldStIt->m_showDigits);
912 2 : createBinRangeTable = true;
913 2 : } else if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsMinToZero) {
914 : // put in the name of the variable for the column
915 2 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Sum) { // if it is a summed variable
916 2 : curUnits += "/s";
917 : }
918 2 : fixUnitsPerSecond(curUnits, curConversionFactor);
919 22 : for (int iBin = 0; iBin != 10; iBin++) {
920 20 : char binIndicator = iBin + 65;
921 20 : columnHead(columnRecount - 10 + iBin) = fldStIt->m_colHead + curAggString + " BIN " + binIndicator;
922 40 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
923 20 : tableBody(columnRecount - 10 + iBin, row + 1) =
924 40 : OutputReportTabular::RealToStr(fldStIt->m_cell[row].m_timeInBin[iBin], fldStIt->m_showDigits);
925 : }
926 20 : tableBody(columnRecount - 10 + iBin, rowSumAvg) =
927 40 : OutputReportTabular::RealToStr(fldStIt->m_timeInBinTotal[iBin], fldStIt->m_showDigits);
928 : }
929 2 : columnHead(columnRecount) = fldStIt->m_colHead + curAggString + " MORE THAN BIN J";
930 4 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
931 2 : tableBody(columnRecount, row + 1) = OutputReportTabular::RealToStr(fldStIt->m_cell[row].m_timeAboveTopBin, fldStIt->m_showDigits);
932 : }
933 2 : tableBody(columnRecount, rowSumAvg) = OutputReportTabular::RealToStr(fldStIt->m_timeAboveTopBinTotal, fldStIt->m_showDigits);
934 2 : createBinRangeTable = true;
935 : } else if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenPercentBins ||
936 : curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusTwoStdDev ||
937 : curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusThreeStdDev) {
938 : }
939 32 : } // fldStIt
940 2 : if (produceTabular_para) {
941 2 : OutputReportTabular::WriteReportHeaders(state, m_name, "Entire Facility", OutputProcessor::StoreType::Average);
942 1 : OutputReportTabular::WriteSubtitle(state, "Custom Annual Report");
943 1 : OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth, true); // transpose annual XML tables.
944 : }
945 2 : if (produceSQLite_para) {
946 1 : if (state.dataSQLiteProcedures->sqlite) {
947 1 : state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
948 : tableBody, rowHead, columnHead, m_name, "Entire Facility", "Custom Annual Report");
949 : }
950 : }
951 : // for the new binning aggregation types create a second table of the bin ranges
952 2 : if (createBinRangeTable) {
953 2 : Array1D_string colHeadRange;
954 2 : Array1D_int colWidthRange;
955 2 : Array1D_string rowHeadRange;
956 2 : Array2D_string tableBodyRange;
957 2 : colHeadRange.allocate(10);
958 2 : colWidthRange.allocate(10);
959 2 : colWidthRange = 14; // array assignment - same for all columns
960 2 : rowHeadRange.allocate(2);
961 2 : rowHeadRange(1) = ">=";
962 2 : rowHeadRange(2) = "<";
963 2 : tableBodyRange.allocate(10, 2);
964 34 : for (fldStIt = m_annualFields.begin(); fldStIt != m_annualFields.end(); ++fldStIt) {
965 32 : int curAgg = fldStIt->m_aggregate;
966 32 : if ((curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsMinToMax) ||
967 28 : (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsZeroToMax) ||
968 : (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsMinToZero)) {
969 6 : tableBodyRange = ""; // set entire table to blank as default
970 6 : Real64 binBottom = fldStIt->m_bottomBinValue;
971 6 : Real64 binTop = fldStIt->m_topBinValue;
972 6 : Real64 numBins = 10.;
973 6 : Real64 intervalSize = (binTop - binBottom) / numBins;
974 :
975 : // could not get the following to work using
976 6 : colHeadRange(1) = "BIN A";
977 6 : colHeadRange(2) = "BIN B";
978 6 : colHeadRange(3) = "BIN C";
979 6 : colHeadRange(4) = "BIN D";
980 6 : colHeadRange(5) = "BIN E";
981 6 : colHeadRange(6) = "BIN F";
982 6 : colHeadRange(7) = "BIN G";
983 6 : colHeadRange(8) = "BIN H";
984 6 : colHeadRange(9) = "BIN I";
985 6 : colHeadRange(10) = "BIN J";
986 66 : for (int iBin = 0; iBin != 10; iBin++) {
987 : // colHeadRange( iBin + 1 ) = "BIN " + ( char )( iBin + 65 ); // not sure why this does not work
988 60 : tableBodyRange(iBin + 1, 1) = OutputReportTabular::RealToStr(binBottom + float(iBin) * intervalSize, fldStIt->m_showDigits);
989 60 : tableBodyRange(iBin + 1, 2) = OutputReportTabular::RealToStr(binBottom + float(iBin + 1) * intervalSize, fldStIt->m_showDigits);
990 : }
991 6 : if (produceTabular_para) {
992 3 : OutputReportTabular::WriteSubtitle(state, "Bin Sizes for: " + fldStIt->m_colHead);
993 3 : OutputReportTabular::WriteTable(
994 : state, tableBodyRange, rowHeadRange, colHeadRange, colWidthRange, true); // transpose annual XML tables.
995 : }
996 6 : if (produceSQLite_para) {
997 3 : if (state.dataSQLiteProcedures->sqlite) {
998 3 : state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
999 : tableBodyRange, rowHeadRange, colHeadRange, m_name, "Entire Facility", "Bin Sizes");
1000 : }
1001 : }
1002 : }
1003 : }
1004 2 : }
1005 2 : }
1006 :
1007 2 : std::vector<std::string> AnnualTable::setupAggString()
1008 : {
1009 2 : std::vector<std::string> retStringVec;
1010 2 : retStringVec.resize(20);
1011 2 : retStringVec[AnnualFieldSet::AggregationKind::sumOrAvg] = "";
1012 2 : retStringVec[AnnualFieldSet::AggregationKind::maximum] = " MAXIMUM ";
1013 2 : retStringVec[AnnualFieldSet::AggregationKind::minimum] = " MINIMUM ";
1014 2 : retStringVec[AnnualFieldSet::AggregationKind::valueWhenMaxMin] = " AT MAX/MIN ";
1015 2 : retStringVec[AnnualFieldSet::AggregationKind::hoursZero] = " HOURS ZERO ";
1016 2 : retStringVec[AnnualFieldSet::AggregationKind::hoursNonZero] = " HOURS NON-ZERO ";
1017 2 : retStringVec[AnnualFieldSet::AggregationKind::hoursPositive] = " HOURS POSITIVE ";
1018 2 : retStringVec[AnnualFieldSet::AggregationKind::hoursNonPositive] = " HOURS NON-POSITIVE ";
1019 2 : retStringVec[AnnualFieldSet::AggregationKind::hoursNegative] = " HOURS NEGATIVE ";
1020 2 : retStringVec[AnnualFieldSet::AggregationKind::hoursNonNegative] = " HOURS NON-NEGATIVE ";
1021 2 : retStringVec[AnnualFieldSet::AggregationKind::hoursInTenPercentBins] = " HOURS IN"; // " HOURS IN TEN PERCENT BINS ";
1022 2 : retStringVec[AnnualFieldSet::AggregationKind::hoursInTenBinsMinToMax] = " HOURS IN"; // " HOURS IN TEN BINS MIN TO MAX ";
1023 2 : retStringVec[AnnualFieldSet::AggregationKind::hoursInTenBinsZeroToMax] = " HOURS IN"; // " HOURS IN TEN BINS ZERO TO MAX ";
1024 2 : retStringVec[AnnualFieldSet::AggregationKind::hoursInTenBinsMinToZero] = " HOURS IN"; // " HOURS IN TEN BINS MIN TO ZERO ";
1025 2 : retStringVec[AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusTwoStdDev] = " HOURS IN"; // " HOURS IN TEN BINS PLUS OR MINUS TWO STD DEV ";
1026 2 : retStringVec[AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusThreeStdDev] =
1027 2 : " HOURS IN"; // " HOURS IN TEN BINS PLUS OR MINUS THREE STD DEV ";
1028 2 : retStringVec[AnnualFieldSet::AggregationKind::noAggregation] = " NO AGGREGATION ";
1029 2 : retStringVec[AnnualFieldSet::AggregationKind::sumOrAverageHoursShown] = " FOR HOURS SHOWN ";
1030 2 : retStringVec[AnnualFieldSet::AggregationKind::maximumDuringHoursShown] = " MAX FOR HOURS SHOWN ";
1031 2 : retStringVec[AnnualFieldSet::AggregationKind::minimumDuringHoursShown] = " MIN FOR HOURS SHOWN ";
1032 2 : return retStringVec;
1033 0 : }
1034 :
1035 8 : Real64 AnnualTable::setEnergyUnitStringAndFactor(OutputReportTabular::UnitsStyle const unitsStyle, std::string &unitString)
1036 : {
1037 : Real64 convFactor;
1038 : // set the unit conversion
1039 8 : if (unitsStyle == OutputReportTabular::UnitsStyle::None) {
1040 4 : unitString = "J";
1041 4 : convFactor = 1.0;
1042 4 : } else if (unitsStyle == OutputReportTabular::UnitsStyle::JtoKWH) {
1043 0 : unitString = "kWh";
1044 0 : convFactor = 1.0 / 3600000.0;
1045 4 : } else if (unitsStyle == OutputReportTabular::UnitsStyle::JtoMJ) {
1046 0 : unitString = "MJ";
1047 0 : convFactor = 1.0 / 1000000.0;
1048 4 : } else if (unitsStyle == OutputReportTabular::UnitsStyle::JtoGJ) {
1049 0 : unitString = "GJ";
1050 0 : convFactor = 1.0 / 1000000000.0;
1051 : } else { // Should never happen but assures compilers of initialization
1052 4 : unitString = "J";
1053 4 : convFactor = 1.0;
1054 : }
1055 8 : return convFactor;
1056 : }
1057 :
1058 22 : void AnnualTable::fixUnitsPerSecond(std::string &unitString, Real64 &conversionFactor)
1059 : {
1060 22 : if (unitString == "J/s") {
1061 0 : unitString = "W";
1062 22 : } else if (unitString == "kWh/s") {
1063 0 : unitString = "W";
1064 0 : conversionFactor *= 3600000.0;
1065 22 : } else if (unitString == "GJ/s") {
1066 0 : unitString = "kW";
1067 0 : conversionFactor *= 1000000.0;
1068 22 : } else if (unitString == "MJ/s") {
1069 0 : unitString = "kW";
1070 0 : conversionFactor *= 1000.0;
1071 22 : } else if (unitString == "therm/s") {
1072 0 : unitString = "kBtu/h";
1073 0 : conversionFactor *= 360000.0;
1074 22 : } else if (unitString == "kBtu/s") {
1075 0 : unitString = "kBtu/h";
1076 0 : conversionFactor *= 3600.0;
1077 22 : } else if (unitString == "ton-hrs/s") {
1078 0 : unitString = "ton";
1079 0 : conversionFactor *= 3600.0;
1080 : }
1081 22 : }
1082 :
1083 33 : AnnualFieldSet::AggregationKind stringToAggKind(EnergyPlusData &state, std::string inString)
1084 : // Jason Glazer, August 2015
1085 : // The function converts a string into an enumeration that describes the type of aggregation
1086 : // used in REPORT:TABLE:ANNUAL.
1087 : {
1088 : AnnualFieldSet::AggregationKind outAggType;
1089 :
1090 33 : if (Util::SameString(inString, "SumOrAverage")) {
1091 7 : outAggType = AnnualFieldSet::AggregationKind::sumOrAvg;
1092 26 : } else if (Util::SameString(inString, "Maximum")) {
1093 2 : outAggType = AnnualFieldSet::AggregationKind::maximum;
1094 24 : } else if (Util::SameString(inString, "Minimum")) {
1095 1 : outAggType = AnnualFieldSet::AggregationKind::minimum;
1096 23 : } else if (Util::SameString(inString, "ValueWhenMaximumOrMinimum")) {
1097 1 : outAggType = AnnualFieldSet::AggregationKind::valueWhenMaxMin;
1098 22 : } else if (Util::SameString(inString, "HoursZero")) {
1099 1 : outAggType = AnnualFieldSet::AggregationKind::hoursZero;
1100 21 : } else if (Util::SameString(inString, "HoursNonzero")) {
1101 5 : outAggType = AnnualFieldSet::AggregationKind::hoursNonZero;
1102 16 : } else if (Util::SameString(inString, "HoursPositive")) {
1103 1 : outAggType = AnnualFieldSet::AggregationKind::hoursPositive;
1104 15 : } else if (Util::SameString(inString, "HoursNonpositive")) {
1105 1 : outAggType = AnnualFieldSet::AggregationKind::hoursNonPositive;
1106 14 : } else if (Util::SameString(inString, "HoursNegative")) {
1107 1 : outAggType = AnnualFieldSet::AggregationKind::hoursNegative;
1108 13 : } else if (Util::SameString(inString, "HoursNonNegative")) {
1109 1 : outAggType = AnnualFieldSet::AggregationKind::hoursNonNegative;
1110 12 : } else if (Util::SameString(inString, "HoursInTenPercentBins")) {
1111 0 : outAggType = AnnualFieldSet::AggregationKind::hoursInTenPercentBins;
1112 12 : } else if (Util::SameString(inString, "HourInTenBinsMinToMax")) {
1113 1 : outAggType = AnnualFieldSet::AggregationKind::hoursInTenBinsMinToMax;
1114 11 : } else if (Util::SameString(inString, "HourInTenBinsZeroToMax")) {
1115 1 : outAggType = AnnualFieldSet::AggregationKind::hoursInTenBinsZeroToMax;
1116 10 : } else if (Util::SameString(inString, "HourInTenBinsMinToZero")) {
1117 1 : outAggType = AnnualFieldSet::AggregationKind::hoursInTenBinsMinToZero;
1118 9 : } else if (Util::SameString(inString, "HoursInTenBinsPlusMinusTwoStdDev")) {
1119 0 : outAggType = AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusTwoStdDev;
1120 9 : } else if (Util::SameString(inString, "HoursInTenBinsPlusMinusThreeStdDev")) {
1121 0 : outAggType = AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusThreeStdDev;
1122 9 : } else if (Util::SameString(inString, "NoAggregation")) {
1123 0 : outAggType = AnnualFieldSet::AggregationKind::noAggregation;
1124 9 : } else if (Util::SameString(inString, "SumOrAverageDuringHoursShown")) {
1125 3 : outAggType = AnnualFieldSet::AggregationKind::sumOrAverageHoursShown;
1126 6 : } else if (Util::SameString(inString, "MaximumDuringHoursShown")) {
1127 1 : outAggType = AnnualFieldSet::AggregationKind::maximumDuringHoursShown;
1128 5 : } else if (Util::SameString(inString, "MinimumDuringHoursShown")) {
1129 1 : outAggType = AnnualFieldSet::AggregationKind::minimumDuringHoursShown;
1130 : } else {
1131 4 : outAggType = AnnualFieldSet::AggregationKind::sumOrAvg;
1132 4 : ShowWarningError(state, format("Invalid aggregation type=\"{}\" Defaulting to SumOrAverage.", inString));
1133 : }
1134 33 : return outAggType;
1135 : }
1136 :
1137 64 : int AnnualTable::columnCountForAggregation(AnnualFieldSet::AggregationKind curAgg)
1138 : {
1139 64 : int returnCount = 0;
1140 64 : if (curAgg == AnnualFieldSet::AggregationKind::sumOrAvg || curAgg == AnnualFieldSet::AggregationKind::valueWhenMaxMin ||
1141 52 : curAgg == AnnualFieldSet::AggregationKind::hoursZero || curAgg == AnnualFieldSet::AggregationKind::hoursNonZero ||
1142 44 : curAgg == AnnualFieldSet::AggregationKind::hoursPositive || curAgg == AnnualFieldSet::AggregationKind::hoursNonPositive ||
1143 36 : curAgg == AnnualFieldSet::AggregationKind::hoursNegative || curAgg == AnnualFieldSet::AggregationKind::hoursNonNegative ||
1144 28 : curAgg == AnnualFieldSet::AggregationKind::sumOrAverageHoursShown || curAgg == AnnualFieldSet::AggregationKind::noAggregation) {
1145 36 : returnCount = 1;
1146 28 : } else if (curAgg == AnnualFieldSet::AggregationKind::maximum || curAgg == AnnualFieldSet::AggregationKind::minimum ||
1147 16 : curAgg == AnnualFieldSet::AggregationKind::maximumDuringHoursShown ||
1148 : curAgg == AnnualFieldSet::AggregationKind::minimumDuringHoursShown) {
1149 16 : returnCount = 2;
1150 12 : } else if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsMinToMax) {
1151 4 : returnCount = 10;
1152 8 : } else if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsZeroToMax ||
1153 : curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsMinToZero) {
1154 8 : returnCount = 11;
1155 0 : } else if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenPercentBins ||
1156 0 : curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusTwoStdDev ||
1157 : curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusThreeStdDev) {
1158 0 : returnCount = 12;
1159 : }
1160 64 : return returnCount;
1161 : }
1162 :
1163 30 : std::string AnnualTable::trim(const std::string &str)
1164 : {
1165 30 : std::string whitespace = " \t";
1166 30 : const size_t strBegin = str.find_first_not_of(whitespace);
1167 30 : if (strBegin == std::string::npos) return ""; // no content
1168 :
1169 30 : const size_t strEnd = str.find_last_not_of(whitespace);
1170 30 : const size_t strRange = strEnd - strBegin + 1;
1171 :
1172 30 : return str.substr(strBegin, strRange);
1173 30 : }
1174 :
1175 0 : void AddAnnualTableOfContents(EnergyPlusData &state, std::ostream &nameOfStream)
1176 : {
1177 : // Jason Glazer, August 2015
1178 : // This function is not part of the class but acts as an interface between procedural code and the class by
1179 : // invoking the writeTable member function for each of the AnnualTable objects
1180 0 : std::vector<AnnualTable>::iterator annualTableIt;
1181 0 : auto &annualTables = state.dataOutputReportTabularAnnual->annualTables;
1182 0 : for (annualTableIt = annualTables.begin(); annualTableIt != annualTables.end(); ++annualTableIt) {
1183 0 : annualTableIt->addTableOfContents(nameOfStream);
1184 : }
1185 0 : }
1186 :
1187 0 : void AnnualTable::addTableOfContents(std::ostream &nameOfStream)
1188 : {
1189 0 : nameOfStream << "<p><b>" << m_name << "</b></p> |\n";
1190 0 : nameOfStream << "<a href=\"#" << OutputReportTabular::MakeAnchorName(m_name, "Entire Facility") << "\">"
1191 : << "Entire Facility"
1192 0 : << "</a> | \n";
1193 0 : }
1194 :
1195 2 : void AnnualTable::computeBinColumns(EnergyPlusData &state, OutputReportTabular::UnitsStyle const unitsStyle_para)
1196 : {
1197 2 : std::vector<AnnualFieldSet>::iterator fldStIt;
1198 2 : Real64 constexpr veryLarge = 1.0E280;
1199 2 : Real64 constexpr verySmall = -1.0E280;
1200 34 : for (fldStIt = m_annualFields.begin(); fldStIt != m_annualFields.end(); ++fldStIt) {
1201 32 : int curAgg = fldStIt->m_aggregate;
1202 : // for columns with binning aggregation types compute the statistics
1203 32 : if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsMinToMax || curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsZeroToMax ||
1204 26 : curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsMinToZero || curAgg == AnnualFieldSet::AggregationKind::hoursInTenPercentBins ||
1205 26 : curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusTwoStdDev ||
1206 : curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusThreeStdDev) {
1207 : // the size the deferred vectors should be same for all rows
1208 6 : if (allRowsSameSizeDefferedVectors(fldStIt)) {
1209 6 : convertUnitForDeferredResults(state, fldStIt, unitsStyle_para);
1210 6 : std::vector<Real64> deferredTotalForColumn;
1211 6 : Real64 minVal = veryLarge;
1212 6 : Real64 maxVal = verySmall;
1213 6 : Real64 sum = 0;
1214 6 : Real64 curVal = 0.0;
1215 6 : for (unsigned int jDefRes = 0; jDefRes != fldStIt->m_cell[0].deferredResults.size(); jDefRes++) {
1216 0 : sum = 0;
1217 0 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
1218 0 : curVal = fldStIt->m_cell[row].deferredResults[jDefRes];
1219 0 : sum += curVal;
1220 0 : if (curVal > maxVal) {
1221 0 : maxVal = curVal;
1222 : }
1223 0 : if (curVal < minVal) {
1224 0 : minVal = curVal;
1225 : }
1226 : }
1227 0 : deferredTotalForColumn.push_back(sum / float(m_objectNames.size())); // put average value into the total row
1228 : }
1229 6 : if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsMinToMax) {
1230 2 : fldStIt->m_topBinValue = maxVal;
1231 2 : fldStIt->m_bottomBinValue = minVal;
1232 4 : } else if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsZeroToMax) {
1233 2 : fldStIt->m_topBinValue = maxVal;
1234 2 : fldStIt->m_bottomBinValue = 0.0;
1235 2 : } else if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsMinToZero) {
1236 2 : fldStIt->m_topBinValue = 0.0;
1237 2 : fldStIt->m_bottomBinValue = minVal;
1238 0 : } else if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenPercentBins) {
1239 0 : fldStIt->m_topBinValue = 1.0;
1240 0 : fldStIt->m_bottomBinValue = 0.0;
1241 : } else if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusTwoStdDev) {
1242 : } else if (curAgg == AnnualFieldSet::AggregationKind::hoursInTenBinsPlusMinusThreeStdDev) {
1243 : }
1244 : // compute the actual amount of time spent in each bin and above and below
1245 12 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
1246 12 : fldStIt->m_cell[row].m_timeInBin = calculateBins(10,
1247 6 : fldStIt->m_cell[row].deferredResults,
1248 6 : fldStIt->m_cell[row].deferredElapsed,
1249 6 : fldStIt->m_topBinValue,
1250 6 : fldStIt->m_bottomBinValue,
1251 6 : fldStIt->m_cell[row].m_timeAboveTopBin,
1252 12 : fldStIt->m_cell[row].m_timeBelowBottomBin);
1253 : }
1254 : // do the total row binning
1255 12 : fldStIt->m_timeInBinTotal = calculateBins(10,
1256 : deferredTotalForColumn,
1257 6 : fldStIt->m_cell[0].deferredElapsed,
1258 6 : fldStIt->m_topBinValue,
1259 6 : fldStIt->m_bottomBinValue,
1260 6 : fldStIt->m_timeAboveTopBinTotal,
1261 12 : fldStIt->m_timeBelowBottomBinTotal);
1262 6 : }
1263 : }
1264 : }
1265 2 : }
1266 :
1267 6 : bool AnnualTable::allRowsSameSizeDefferedVectors(std::vector<AnnualFieldSet>::iterator fldStIt)
1268 : {
1269 6 : bool returnFlag = true;
1270 6 : unsigned int sizeOfDeferred = 0;
1271 12 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
1272 6 : if (sizeOfDeferred == 0) {
1273 6 : sizeOfDeferred = fldStIt->m_cell[row].deferredResults.size();
1274 : } else {
1275 0 : if (fldStIt->m_cell[row].deferredResults.size() != sizeOfDeferred) {
1276 0 : returnFlag = false;
1277 0 : return returnFlag;
1278 : }
1279 : }
1280 : }
1281 6 : return returnFlag;
1282 : }
1283 :
1284 6 : void AnnualTable::convertUnitForDeferredResults(EnergyPlusData &state,
1285 : std::vector<AnnualFieldSet>::iterator fldStIt,
1286 : OutputReportTabular::UnitsStyle const unitsStyle)
1287 : {
1288 : Real64 curConversionFactor;
1289 : Real64 curConversionOffset;
1290 6 : std::string curUnits;
1291 6 : std::string energyUnitsString;
1292 : Real64 curSI;
1293 : Real64 curIP;
1294 6 : Real64 energyUnitsConversionFactor = AnnualTable::setEnergyUnitStringAndFactor(unitsStyle, energyUnitsString);
1295 : // do the unit conversions
1296 6 : if (unitsStyle == OutputReportTabular::UnitsStyle::InchPound || unitsStyle == OutputReportTabular::UnitsStyle::InchPoundExceptElectricity) {
1297 : int indexUnitConv;
1298 0 : std::string varNameWithUnits = format("{} [{}]", fldStIt->m_variMeter, Constant::unitNames[(int)fldStIt->m_varUnits]);
1299 0 : OutputReportTabular::LookupSItoIP(state, varNameWithUnits, indexUnitConv, curUnits);
1300 0 : OutputReportTabular::GetUnitConversion(state, indexUnitConv, curConversionFactor, curConversionOffset, curUnits);
1301 0 : } else { // just do the Joule conversion
1302 : // if units is in Joules, convert if specified
1303 6 : if (fldStIt->m_varUnits == Constant::Units::J) {
1304 0 : curUnits = energyUnitsString;
1305 0 : curConversionFactor = energyUnitsConversionFactor;
1306 0 : curConversionOffset = 0.0;
1307 : } else { // if not joules don't perform conversion
1308 6 : curUnits = Constant::unitNames[(int)fldStIt->m_varUnits];
1309 6 : curConversionFactor = 1.0;
1310 6 : curConversionOffset = 0.0;
1311 : }
1312 : }
1313 6 : if (fldStIt->m_varAvgSum == OutputProcessor::StoreType::Sum) {
1314 6 : curUnits += "/s";
1315 : }
1316 6 : fixUnitsPerSecond(curUnits, curConversionFactor);
1317 6 : if (curConversionFactor != 1.0 || curConversionOffset != 0.0) {
1318 0 : for (unsigned int row = 0; row != m_objectNames.size(); row++) { // loop through by row.
1319 0 : for (unsigned int jDefRes = 0; jDefRes != fldStIt->m_cell[0].deferredResults.size(); jDefRes++) {
1320 0 : curSI = fldStIt->m_cell[row].deferredResults[jDefRes];
1321 0 : curIP = curSI * curConversionFactor + curConversionOffset;
1322 0 : fldStIt->m_cell[row].deferredResults[jDefRes] = curIP;
1323 : }
1324 : }
1325 : }
1326 6 : }
1327 :
1328 12 : std::vector<Real64> AnnualTable::calculateBins(int const numberOfBins,
1329 : std::vector<Real64> valuesToBin,
1330 : std::vector<Real64> corrElapsedTime,
1331 : Real64 const topOfBins,
1332 : Real64 const bottomOfBins,
1333 : Real64 &timeAboveTopBin,
1334 : Real64 &timeBelowBottomBin)
1335 : {
1336 12 : std::vector<Real64> returnBins(0.0);
1337 12 : returnBins.resize(numberOfBins);
1338 12 : Real64 intervalSize = (topOfBins - bottomOfBins) / float(numberOfBins);
1339 12 : timeAboveTopBin = 0.0;
1340 12 : timeBelowBottomBin = 0.0;
1341 12 : std::vector<Real64>::iterator elapsedTimeIt;
1342 12 : elapsedTimeIt = corrElapsedTime.begin();
1343 12 : std::vector<Real64>::iterator valueIt;
1344 12 : for (valueIt = valuesToBin.begin(); valueIt != valuesToBin.end(); ++valueIt) {
1345 0 : if (*valueIt < bottomOfBins) {
1346 0 : timeBelowBottomBin += *elapsedTimeIt;
1347 0 : } else if (*valueIt >= topOfBins) {
1348 0 : timeAboveTopBin += *elapsedTimeIt;
1349 : } else {
1350 : // determine which bin the results are in
1351 0 : int binNum = int((*valueIt - bottomOfBins) / intervalSize);
1352 0 : if (binNum < numberOfBins && binNum >= 0) {
1353 0 : returnBins[binNum] += *elapsedTimeIt;
1354 : }
1355 : }
1356 0 : ++elapsedTimeIt;
1357 : }
1358 24 : return returnBins;
1359 0 : }
1360 :
1361 3 : void AnnualTable::columnHeadersToTitleCase(EnergyPlusData &state)
1362 : {
1363 3 : std::vector<AnnualFieldSet>::iterator fldStIt;
1364 38 : for (fldStIt = m_annualFields.begin(); fldStIt != m_annualFields.end(); ++fldStIt) {
1365 35 : if (fldStIt->m_variMeter == fldStIt->m_colHead) {
1366 35 : if (fldStIt->m_indexesForKeyVar.size() > 0) {
1367 35 : int varNum = fldStIt->m_indexesForKeyVar[0];
1368 35 : if (fldStIt->m_typeOfVar == OutputProcessor::VariableType::Real) {
1369 1 : fldStIt->m_colHead = state.dataOutputProcessor->outVars[varNum]->name;
1370 34 : } else if (fldStIt->m_typeOfVar == OutputProcessor::VariableType::Meter) {
1371 33 : fldStIt->m_colHead = state.dataOutputProcessor->meters[varNum]->Name;
1372 : }
1373 : }
1374 : }
1375 : }
1376 3 : }
1377 :
1378 0 : void AnnualTable::clearTable()
1379 : {
1380 0 : m_name = "";
1381 0 : m_filter = "";
1382 0 : m_sched = nullptr;
1383 0 : m_objectNames.clear();
1384 0 : m_annualFields.clear();
1385 0 : }
1386 :
1387 2 : std::vector<std::string> AnnualTable::inspectTable()
1388 : {
1389 : // added function just to inspect the main private AnnualTable members because no other
1390 : // interface to the AnnualTable class is output oriented except writeTable and that is very complex.
1391 2 : std::vector<std::string> ret;
1392 2 : ret.push_back(m_name);
1393 2 : ret.push_back(m_filter);
1394 2 : ret.push_back(m_sched->Name);
1395 2 : return ret;
1396 0 : }
1397 :
1398 12 : std::vector<std::string> AnnualTable::inspectTableFieldSets(int fldIndex)
1399 : {
1400 : // added function just to inspect the private field set members of AnnualTable because no other
1401 : // interface to the AnnualTable class is output oriented except writeTable and that is very complex.
1402 12 : std::vector<std::string> ret;
1403 12 : AnnualFieldSet fldSt;
1404 12 : fldSt = m_annualFields[fldIndex];
1405 12 : ret.push_back(fldSt.m_colHead);
1406 12 : ret.push_back(fldSt.m_variMeter);
1407 12 : ret.push_back(std::string(Constant::unitNames[(int)fldSt.m_varUnits]));
1408 12 : std::string outStr = std::to_string(fldSt.m_showDigits);
1409 : // ints
1410 12 : ret.push_back(outStr);
1411 12 : outStr = std::to_string((int)fldSt.m_typeOfVar);
1412 12 : ret.push_back(outStr);
1413 12 : outStr = std::to_string(fldSt.m_keyCount);
1414 12 : ret.push_back(outStr);
1415 12 : outStr = std::to_string((int)fldSt.m_varAvgSum);
1416 12 : ret.push_back(outStr);
1417 12 : outStr = std::to_string((int)fldSt.m_varStepType);
1418 12 : ret.push_back(outStr);
1419 12 : outStr = std::to_string(fldSt.m_aggregate);
1420 12 : ret.push_back(outStr);
1421 : // floats
1422 12 : outStr = std::to_string(fldSt.m_bottomBinValue);
1423 12 : ret.push_back(outStr);
1424 12 : outStr = std::to_string(fldSt.m_topBinValue);
1425 12 : ret.push_back(outStr);
1426 12 : outStr = std::to_string(fldSt.m_timeAboveTopBinTotal);
1427 12 : ret.push_back(outStr);
1428 12 : outStr = std::to_string(fldSt.m_timeBelowBottomBinTotal);
1429 12 : ret.push_back(outStr);
1430 : // cell value
1431 12 : if (fldSt.m_cell.size() > 0) {
1432 9 : outStr = std::to_string(fldSt.m_cell[0].result);
1433 9 : ret.push_back(outStr);
1434 : }
1435 24 : return ret;
1436 12 : }
1437 :
1438 : } // namespace EnergyPlus::OutputReportTabularAnnual
|