diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index 8f9912ae00a..8874a49b60a 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -108304,13 +108304,18 @@ OutputControl:Table:Style, \key InchPound \key InchPoundExceptElectricity \default None - A3; \field Format Numeric Values + A3, \field Format Numeric Values \note If No, all digits are shown after the decimal point without any rounding (23.238769213). \note If Yes, values are rounded for readability (23.24). \type choice \key Yes \key No \default Yes + A4; \field Sort Option + \type choice + \key Name + \key Unsorted + \default Unsorted OutputControl:ReportingTolerances, diff --git a/src/EnergyPlus/OutputReportTabular.cc b/src/EnergyPlus/OutputReportTabular.cc index 6043358ca46..c1dc1709b65 100644 --- a/src/EnergyPlus/OutputReportTabular.cc +++ b/src/EnergyPlus/OutputReportTabular.cc @@ -1280,6 +1280,8 @@ void GetInputTabularStyle(EnergyPlusData &state) AlphArray(2) = "None"; ort->unitsStyle_Tabular = UnitsStyle::None; ort->formatReals_Tabular = true; + AlphArray(4) = "UNSORTED"; + ort->sortOption = SortOption::Unsorted; } else if (NumTabularStyle == 1) { state.dataInputProcessing->inputProcessor->getObjectItem(state, CurrentModuleObject, @@ -1363,8 +1365,8 @@ void GetInputTabularStyle(EnergyPlusData &state) ort->del(1) = DataStringGlobals::CharComma; // comma AlphArray(1) = "COMMA"; } - // MonthlyUnitConversion if (NumAlphas >= 2) { + // UnitConversion ort->unitsStyle_Tabular = SetUnitsStyleFromString(AlphArray(2)); if (ort->unitsStyle_Tabular == UnitsStyle::NotFound) { ShowWarningError(state, @@ -1373,9 +1375,19 @@ void GetInputTabularStyle(EnergyPlusData &state) state.dataIPShortCut->cAlphaFieldNames(2), AlphArray(2))); } + ort->sortOption = SetSortOptionFromString(AlphArray(4)); + if (ort->sortOption == SortOption::NotFound) { + ShowWarningError(state, + EnergyPlus::format("{}: Invalid {}=\"{}\". No sorting will be performed.", + CurrentModuleObject, + state.dataIPShortCut->cAlphaFieldNames(4), + AlphArray(4))); + } } else { ort->unitsStyle_Tabular = UnitsStyle::None; AlphArray(2) = "None"; + AlphArray(4) = "UNSORTED"; + ort->sortOption = SortOption::Unsorted; } } else if (NumTabularStyle > 1) { ShowWarningError(state, EnergyPlus::format("{}: Only one instance of this object is allowed. Commas will be used.", CurrentModuleObject)); @@ -1385,10 +1397,12 @@ void GetInputTabularStyle(EnergyPlusData &state) ort->unitsStyle_Tabular = UnitsStyle::None; AlphArray(2) = "None"; ort->formatReals_Tabular = getYesNoValue(AlphArray(3)) == BooleanSwitch::Yes; + AlphArray(4) = "UNSORTED"; + ort->sortOption = SortOption::Unsorted; } - print(state.files.eio, "! ,Style,Unit Conversion, Format Reals\n"); - print(state.files.eio, "Tabular Report,{},{},{}\n", AlphArray(1), AlphArray(2), ort->formatReals_Tabular ? "Yes" : "No"); + print(state.files.eio, "! ,Style,Unit Conversion,Format Reals,Sort Option\n"); + print(state.files.eio, "Tabular Report,{},{},{},{}\n", AlphArray(1), AlphArray(2), ort->formatReals_Tabular ? "Yes" : "No", AlphArray(4)); } UnitsStyle SetUnitsStyleFromString(std::string const &unitStringIn) @@ -1401,6 +1415,52 @@ UnitsStyle SetUnitsStyleFromString(std::string const &unitStringIn) return unitsStyleReturn; } +SortOption SetSortOptionFromString(std::string const &sortStringIn) +{ + SortOption sortOptionReturn = static_cast(getEnumValue(SortOptionNamesUC, Util::makeUPPER(sortStringIn))); + if (sortOptionReturn == SortOption::Invalid) { + sortOptionReturn = SortOption::NotFound; + } + + return sortOptionReturn; +} + +Array2D_string SortTableByName(EnergyPlusData &state, Array2D_string body, const Array1D_string &cLabels, int rowsBody, int colsBody) +{ + // starting from the left most column, find the first one that contains the Name substring + std::string sCol = "Name"; + auto it = std::find_if(cLabels.begin(), cLabels.end(), [&sCol](const std::string& s) { return s.find(sCol) != std::string::npos; }); + if (it != cLabels.end()) { + sCol = *it; + } + + int index = 0; + it = std::find(cLabels.begin(), cLabels.end(), sCol); + if (it != cLabels.end()) { + index = std::distance(cLabels.begin(), it) + 1; + } + + // if no column with Name found, just return the original unsorted table + if (index > 0) { + Array1D_int rowHeadSorted; + rowHeadSorted.allocate(rowsBody); + for (int jRow = 1; jRow <= rowsBody; ++jRow) { + rowHeadSorted(jRow) = jRow; + } + std::sort(rowHeadSorted.begin(), rowHeadSorted.end(), [&](int a, int b) { return body(index, a) < body(index, b); }); + + Array2D_string bodySorted; + bodySorted.allocate(colsBody, rowsBody); + for (int jRow = 1; jRow <= rowsBody; ++jRow) { + for (int iCol = 1; iCol <= colsBody; ++iCol) { + bodySorted(iCol, jRow) = body(iCol, rowHeadSorted(jRow)); + } + } + body = bodySorted; + } + return body; +} + void GetInputOutputTableSummaryReports(EnergyPlusData &state) { // SUBROUTINE INFORMATION: @@ -14731,6 +14791,9 @@ void WriteEioTables(EnergyPlusData &state) } if (currentStyle.produceTabular) { + if (ort->sortOption == SortOption::Name) { // optionally sort + tableBody = SortTableByName(state, tableBody, columnHead, numRows, numCols); + } WriteSubtitle(state, tableName); std::string footnote; WriteTable(state, tableBody, rowHead, columnHead, columnWidth, false, footnote); diff --git a/src/EnergyPlus/OutputReportTabular.hh b/src/EnergyPlus/OutputReportTabular.hh index 89520cd8a9c..4516df35b45 100644 --- a/src/EnergyPlus/OutputReportTabular.hh +++ b/src/EnergyPlus/OutputReportTabular.hh @@ -128,6 +128,16 @@ namespace OutputReportTabular { constexpr std::array(UnitsStyle::Num) - 1> UnitsStyleNamesUC{ "NONE", "JTOKWH", "JTOMJ", "JTOGJ", "INCHPOUND", "INCHPOUNDEXCEPTELECTRICITY"}; + enum class SortOption + { + Invalid = -1, + Name, + Unsorted, + NotFound, + Num + }; + constexpr std::array(SortOption::Num) - 1> SortOptionNamesUC{"NAME", "UNSORTED"}; + enum class EndUseSubTableType { Invalid = -1, @@ -612,6 +622,10 @@ namespace OutputReportTabular { UnitsStyle SetUnitsStyleFromString(std::string const &unitStringIn); + SortOption SetSortOptionFromString(std::string const &sortStringIn); + + Array2D_string SortTableByName(EnergyPlusData &state, Array2D_string body, const Array1D_string &cLabels, int rowsBody, int colsBody); + void GetInputOutputTableSummaryReports(EnergyPlusData &state); bool isCompLoadRepReq(EnergyPlusData &state); @@ -1089,6 +1103,7 @@ struct OutputReportTabularData : BaseGlobalStruct OutputReportTabular::UnitsStyle unitsStyle_Tabular = OutputReportTabular::UnitsStyle::None; OutputReportTabular::UnitsStyle unitsStyle_SQLite = OutputReportTabular::UnitsStyle::NotFound; OutputReportTabular::UnitsStyle unitsStyle_JSON = OutputReportTabular::UnitsStyle::NotFound; + OutputReportTabular::SortOption sortOption = OutputReportTabular::SortOption::Unsorted; bool ip() const { @@ -1415,6 +1430,7 @@ struct OutputReportTabularData : BaseGlobalStruct { this->unitsStyle_Tabular = OutputReportTabular::UnitsStyle::None; this->unitsStyle_SQLite = OutputReportTabular::UnitsStyle::NotFound; + this->sortOption = OutputReportTabular::SortOption::Unsorted; this->OutputTableBinnedCount = 0; this->BinResultsTableCount = 0; this->BinResultsIntervalCount = 0; diff --git a/testfiles/Supermarket.idf b/testfiles/Supermarket.idf index 3484aa61a20..7fce40c80f6 100644 --- a/testfiles/Supermarket.idf +++ b/testfiles/Supermarket.idf @@ -2357,7 +2357,10 @@ !- =========== ALL OBJECTS IN CLASS: OUTPUTCONTROL:TABLE:STYLE =========== OutputControl:Table:Style, - HTML; !- Column Separator + HTML, !- Column Separator + , !- Unit Conversion + , !- Format Numeric Values + Name; !- Sort Option !- =========== ALL OBJECTS IN CLASS: OUTPUT:VARIABLE ===========