LCOV - code coverage report
Current view: top level - EnergyPlus - OutputReportTabularAnnual.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 75.7 % 907 687
Test Date: 2025-05-22 16:09:37 Functions: 80.0 % 30 24

            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
        

Generated by: LCOV version 2.0-1