Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion idd/Energy+.idd.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Field name and keys borrowed from Output:VariableDictionary.

\type choice
\key Name
\key Unsorted
\default Unsorted


OutputControl:ReportingTolerances,
Expand Down
66 changes: 65 additions & 1 deletion src/EnergyPlus/OutputReportTabular.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -1373,9 +1375,19 @@ void GetInputTabularStyle(EnergyPlusData &state)
state.dataIPShortCut->cAlphaFieldNames(2),
AlphArray(2)));
}
ort->sortOption = SetSortOptionFromString(AlphArray(4));
if (ort->sortOption == SortOption::NotFound) {
Copy link
Copy Markdown
Collaborator

@rraustad rraustad Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sortOption is a key choice, and has a default. It is not possible for sortOption to be NotFound. If the field is missing or blank then the InputProcessor will fill that field with Unsorted. This check can be deleted, same for the new function SetSortOptionalFromString, just read the input here as done in SetSortOptionalFromString.

A4; \field Sort Option  
   \type choice
   \key Name
   \key Unsorted
   \default Unsorted

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;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't even matter if (NumAlphas < 2), AlphaArray(4) will have one of 2 key values so no need to even set these. I've checked this so many times that it's muscle memory now.

}
} else if (NumTabularStyle > 1) {
ShowWarningError(state, EnergyPlus::format("{}: Only one instance of this object is allowed. Commas will be used.", CurrentModuleObject));
Expand All @@ -1385,6 +1397,8 @@ 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, "! <Tabular Report>,Style,Unit Conversion, Format Reals\n");
Expand All @@ -1401,6 +1415,50 @@ UnitsStyle SetUnitsStyleFromString(std::string const &unitStringIn)
return unitsStyleReturn;
}

SortOption SetSortOptionFromString(std::string const &sortStringIn)
{
SortOption sortOptionReturn = static_cast<SortOption>(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 &columnLabels,
int rowsBody,
int colsBody)
{
int index = 0;
auto it = std::find(std::begin(columnLabels), std::end(columnLabels), "Name");
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are probably other column names we'd want to sort on (and not just "Name"). Not sure how to handle this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many times, the first column that you would want to sort on doesn't have a column heading at all (almost all predefined tables).

Monthly tables probably should not be sorted.

Tables that have statistics (sum, average, min, or max) as the last rows should probably keep them as the last rows and not intermingle them (like monthly tables).

The Initialization Summary has all the tables with a row count in the first column, so that they are in the same order as the EIO file, but sometimes the second column is the zone name or the object name, so maybe they should be sorted by the second column.

Overall, this is a good idea, but complicated with a lot of cases to consider.

Maybe the approach is that for each predefined table, a column that would make sense to sort on is optionally defined. If it is not defined, then maybe just the first column is used.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @JasonGlazer, this is very useful information. And agreed that this gets complicated with a lot of cases to consider.

if (it != std::end(columnLabels)) {
index = std::distance(std::begin(columnLabels), it) + 1;
}

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:
Expand Down Expand Up @@ -14731,6 +14789,12 @@ void WriteEioTables(EnergyPlusData &state)
}

if (currentStyle.produceTabular) {
if (tableName == "ScheduleTypeLimits") {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Just testing on this table for right now.)

// optionally sort
if (ort->sortOption == SortOption::Name) {
tableBody = SortTableByName(state, tableBody, columnHead, numRows, numCols);
}
}
WriteSubtitle(state, tableName);
std::string footnote;
WriteTable(state, tableBody, rowHead, columnHead, columnWidth, false, footnote);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could probably move the sort to within WriteTable, but putting it here may give more control (the table name isn't passed into WriteTable).

Expand Down
17 changes: 17 additions & 0 deletions src/EnergyPlus/OutputReportTabular.hh
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,17 @@ namespace OutputReportTabular {
constexpr std::array<std::string_view, static_cast<int>(UnitsStyle::Num) - 1> UnitsStyleNamesUC{
"NONE", "JTOKWH", "JTOMJ", "JTOGJ", "INCHPOUND", "INCHPOUNDEXCEPTELECTRICITY"};

enum class SortOption
{
Invalid = -1,
Name,
Unsorted,
NotFound,
Num
};
constexpr std::array<std::string_view, static_cast<int>(SortOption::Num) - 1> SortOptionNamesUC{
"NAME", "UNSORTED"};

enum class EndUseSubTableType
{
Invalid = -1,
Expand Down Expand Up @@ -612,6 +623,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 &columnLabels, int rowsBody, int colsBody);

void GetInputOutputTableSummaryReports(EnergyPlusData &state);

bool isCompLoadRepReq(EnergyPlusData &state);
Expand Down Expand Up @@ -1089,6 +1104,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
{
Expand Down Expand Up @@ -1415,6 +1431,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;
Expand Down
5 changes: 4 additions & 1 deletion testfiles/Supermarket.idf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could introduce similar field for Output:JSON and Output:SQLite? I'm not totally sure how these three objects are all related.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Output:JSON it would be good to have something similar. I'm not so sure if SQLite.


!- =========== ALL OBJECTS IN CLASS: OUTPUT:VARIABLE ===========

Expand Down
Loading