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