Skip to content

Commit

Permalink
Merge pull request #7584 from NREL/PR_opened/7481_EndUseBySubcategory…
Browse files Browse the repository at this point in the history
…_SQL

Modify End Use by Subcategory tables in SQL so they can be queried
  • Loading branch information
Myoldmopar authored Jan 8, 2020
2 parents e217f0e + 5d09fa2 commit 6bb670b
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 6 deletions.
60 changes: 54 additions & 6 deletions src/EnergyPlus/OutputReportTabular.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8464,8 +8464,7 @@ namespace OutputReportTabular {
columnHead.allocate(7);
columnWidth.allocate(7);
columnWidth = 14; // array assignment - same for all columns
tableBody.allocate(7, numRows);

tableBody.allocate(7, numRows); // TODO: this appears to be (column, row)...
rowHead = "";
tableBody = "";

Expand Down Expand Up @@ -8541,14 +8540,31 @@ namespace OutputReportTabular {
if (displayTabularBEPS) {
WriteSubtitle("End Uses By Subcategory");
WriteTable(tableBody, rowHead, columnHead, columnWidth);

Array1D_string rowHeadTemp(rowHead);
// Before outputing to SQL, we forward fill the End use column (rowHead) (cf #7481)
// for better sql queries
FillRowHead(rowHeadTemp);

for (int i = 1; i <= numRows; ++i) {
rowHeadTemp(i) = rowHeadTemp(i) + ":" + tableBody(1, i);
}

// Erase the SubCategory (first column), using slicing
Array2D_string tableBodyTemp(tableBody({2, _, _ }, {_, _, _}));
Array1D_string columnHeadTemp(columnHead({2, _, _ }));

if (sqlite) {
sqlite->createSQLiteTabularDataRecords(
tableBody, rowHead, columnHead, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "End Uses By Subcategory");
tableBodyTemp, rowHeadTemp, columnHeadTemp, "AnnualBuildingUtilityPerformanceSummary", "Entire Facility", "End Uses By Subcategory");
}
if (ResultsFramework::OutputSchema->timeSeriesAndTabularEnabled()) {
ResultsFramework::OutputSchema->TabularReportsCollection.addReportTable(
tableBody, rowHead, columnHead, "Annual Building Utility Performance Summary", "Entire Facility", "End Uses By Subcategory");
tableBodyTemp, rowHeadTemp, columnHeadTemp, "Annual Building Utility Performance Summary", "Entire Facility", "End Uses By Subcategory");
}
rowHeadTemp.deallocate();
tableBodyTemp.deallocate();
columnHeadTemp.deallocate();
}

// EAp2-4/5. Performance Rating Method Compliance
Expand Down Expand Up @@ -9869,14 +9885,31 @@ namespace OutputReportTabular {
// heading for the entire sub-table
WriteSubtitle("End Uses By Subcategory");
WriteTable(tableBody, rowHead, columnHead, columnWidth, false, footnote);

Array1D_string rowHeadTemp(rowHead);
// Before outputing to SQL, we forward fill the End use column (rowHead) (cf #7481)
// for better sql queries
FillRowHead(rowHeadTemp);

for (int i = 1; i <= numRows; ++i) {
rowHeadTemp(i) = rowHeadTemp(i) + ":" + tableBody(1, i);
}

// Erase the SubCategory (first column), using slicing
Array2D_string tableBodyTemp(tableBody({2, _, _ }, {_, _, _}));
Array1D_string columnHeadTemp(columnHead({2, _, _ }));

if (sqlite) {
sqlite->createSQLiteTabularDataRecords(
tableBody, rowHead, columnHead, "DemandEndUseComponentsSummary", "Entire Facility", "End Uses By Subcategory");
tableBodyTemp, rowHeadTemp, columnHeadTemp, "DemandEndUseComponentsSummary", "Entire Facility", "End Uses By Subcategory");
}
if (ResultsFramework::OutputSchema->timeSeriesAndTabularEnabled()) {
ResultsFramework::OutputSchema->TabularReportsCollection.addReportTable(
tableBody, rowHead, columnHead, "Demand End Use Components Summary", "Entire Facility", "End Uses By Subcategory");
tableBodyTemp, rowHeadTemp, columnHeadTemp, "Demand End Use Components Summary", "Entire Facility", "End Uses By Subcategory");
}
rowHeadTemp.deallocate();
tableBodyTemp.deallocate();
columnHeadTemp.deallocate();

// EAp2-4/5. Performance Rating Method Compliance
for (iResource = 1; iResource <= 6; ++iResource) {
Expand Down Expand Up @@ -15127,6 +15160,21 @@ namespace OutputReportTabular {
}
}

void FillRowHead(Array1D_string & rowHead)
{
// Forward fill the blanks in rowHead (eg End use column)
std::string currentEndUseName;
for (size_t i = 1; i <= rowHead.size(); ++i) {
std::string thisEndUseName = rowHead(i);
if (thisEndUseName.empty()) {
rowHead(i) = currentEndUseName;
} else {
currentEndUseName = thisEndUseName;
}
}
}


//======================================================================================================================
//======================================================================================================================

Expand Down
4 changes: 4 additions & 0 deletions src/EnergyPlus/OutputReportTabular.hh
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,10 @@ namespace OutputReportTabular {

void DetermineBuildingFloorArea();

/* Tables with Subcategories in particular have a blank for rowHead for display in the HTML output.
* This routine will fill up the blanks for output to Sql in particular */
void FillRowHead(Array1D_string & rowHead);

//======================================================================================================================
//======================================================================================================================

Expand Down
53 changes: 53 additions & 0 deletions src/Transition/OutputRulesFiles/OutputChanges9-2-0-to-9-3-0.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,56 @@ Environment:Design Day Data,33.00,6.60,DefaultMultipliers,Enthalpy,90500.00,{J/k
```

See [#PR7577](https://github.com/NREL/EnergyPlus/pull/7577)

### End Use By Subcategory in SQL

In the SQL Output file, for `ReportName = "AnnualBuildingUtilityPerformanceSummary"` and `ReportName = "DemandEndUseComponentsSummary"`,
the tables `TableName = "End Uses by Subcategory"` have been refactored. `RowName` is now in the format `<End Use Category>:<End Use Subcategory>`.
This will allow querying a specific End Use Subcategory in the SQL file more easily.

Example SQL Queries:

* Get the Value corresponding to a specific Fuel Type "Electricity", End Use "Interior Lighting", Subcategory "GeneralLights":

```sql
SELECT Value FROM TabularDataWithStrings
WHERE TableName = 'End Uses By Subcategory'
AND ReportName = 'AnnualBuildingUtilityPerformanceSummary'
AND ColumnName = 'Electricity'
AND RowName = 'Interior Lighting:GeneralLights'
```

* Return all rows (one row per fuel type) for End Use "Interior Lighting", Subcategory "GeneralLights":

```sql
SELECT ColumnName as FuelType, Value FROM TabularDataWithStrings
WHERE TableName = 'End Uses By Subcategory'
AND ReportName = 'AnnualBuildingUtilityPerformanceSummary'
AND RowName = 'Interior Lighting:GeneralLights'
```

| FuelType | Value |
|------------------|-------|
| Electricity | 83.33 |
| Natural Gas | 0.00 |
| Additional Fuel | 0.00 |
| District Cooling | 0.00 |
| District Heating | 0.00 |
| Water | 0.00 |

* Get all rows related to Electricity usage by Interior Lighting:

```sql
SELECT RowName as "End Use&Subcategory", Value FROM TabularDataWithStrings
WHERE TableName = 'End Uses By Subcategory'
AND ReportName = 'AnnualBuildingUtilityPerformanceSummary'
AND ColumnName = 'Electricity'
AND RowName LIKE 'Interior Lighting:%'
```

| End Use&Subcategory | Value |
|---------------------------------------|--------|
| Interior Lighting:GeneralLights | 166.67 |
| Interior Lighting:AnotherEndUseSubCat | 83.33 |

See [PR#7584](https://github.com/NREL/EnergyPlus/pull/7584).
166 changes: 166 additions & 0 deletions tst/EnergyPlus/unit/OutputReportTabular.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
#include <EnergyPlus/DataSurfaces.hh>
#include <EnergyPlus/DataZoneEnergyDemands.hh>
#include <EnergyPlus/DataZoneEquipment.hh>
#include <EnergyPlus/ElectricPowerServiceManager.hh>
#include <EnergyPlus/General.hh>
#include <EnergyPlus/HeatBalanceManager.hh>
#include <EnergyPlus/HeatBalanceSurfaceManager.hh>
Expand Down Expand Up @@ -7653,3 +7654,168 @@ TEST_F(SQLiteFixture, WriteSourceEnergyEndUseSummary_TestPerArea) {

EnergyPlus::sqlite->sqliteCommit();
}

TEST_F(SQLiteFixture, OutputReportTabular_EndUseBySubcategorySQL)
{
EnergyPlus::sqlite->sqliteBegin();
EnergyPlus::sqlite->createSQLiteSimulationsRecord(1, "EnergyPlus Version", "Current Time");

OutputReportTabular::displayTabularBEPS = true;
OutputReportTabular::displayDemandEndUse = true;
OutputReportTabular::displayLEEDSummary = true;

OutputReportTabular::WriteTabularFiles = true;

SetupUnitConversions();
OutputReportTabular::unitsStyle = OutputReportTabular::unitsStyleJtoKWH;

// Needed to avoid crash (from ElectricPowerServiceManager.hh)
createFacilityElectricPowerServiceObject();

SetPredefinedTables();

Real64 extLitUse = 1e8;

SetupOutputVariable("Exterior Lights Electric Energy",
OutputProcessor::Unit::J,
extLitUse,
"Zone",
"Sum",
"Lite1",
_,
"Electricity",
"Exterior Lights",
"General");
SetupOutputVariable("Exterior Lights Electric Energy",
OutputProcessor::Unit::J,
extLitUse,
"Zone",
"Sum",
"Lite2",
_,
"Electricity",
"Exterior Lights",
"AnotherEndUseSubCat");
SetupOutputVariable("Exterior Lights Electric Energy",
OutputProcessor::Unit::J,
extLitUse,
"Zone",
"Sum",
"Lite3",
_,
"Electricity",
"Exterior Lights",
"General");

DataGlobals::DoWeathSim = true;
DataGlobals::TimeStepZone = 1.0;
displayTabularBEPS = true;
// OutputProcessor::TimeValue.allocate(2);

auto timeStep = 1.0;

SetupTimePointers("Zone", timeStep);
SetupTimePointers("HVAC", timeStep);

TimeValue.at(OutputProcessor::TimeStepType::TimeStepZone).TimeStep = 60;
TimeValue.at(OutputProcessor::TimeStepType::TimeStepSystem).TimeStep = 60;

GetInputOutputTableSummaryReports();

DataEnvironment::Month = 12;

UpdateMeterReporting();
UpdateDataandReport(OutputProcessor::TimeStepType::TimeStepZone);
GatherBEPSResultsForTimestep(OutputProcessor::TimeStepType::TimeStepZone);
GatherPeakDemandForTimestep(OutputProcessor::TimeStepType::TimeStepZone);
EXPECT_NEAR(extLitUse * 3, gatherEndUseBEPS(1, DataGlobalConstants::endUseExteriorLights), 1.);
// General
EXPECT_NEAR(extLitUse * 2, gatherEndUseSubBEPS(1, DataGlobalConstants::endUseExteriorLights, 1), 1.);
// AnotherEndUseSubCat
EXPECT_NEAR(extLitUse * 1, gatherEndUseSubBEPS(2, DataGlobalConstants::endUseExteriorLights, 1), 1.);

UpdateMeterReporting();
UpdateDataandReport(OutputProcessor::TimeStepType::TimeStepZone);
GatherBEPSResultsForTimestep(OutputProcessor::TimeStepType::TimeStepZone);
GatherPeakDemandForTimestep(OutputProcessor::TimeStepType::TimeStepZone);
EXPECT_NEAR(extLitUse * 6, gatherEndUseBEPS(1, DataGlobalConstants::endUseExteriorLights), 1.);
// General
EXPECT_NEAR(extLitUse * 4, gatherEndUseSubBEPS(1, DataGlobalConstants::endUseExteriorLights, 1), 1.);
// AnotherEndUseSubCat
EXPECT_NEAR(extLitUse * 2, gatherEndUseSubBEPS(2, DataGlobalConstants::endUseExteriorLights, 1), 1.);

UpdateMeterReporting();
UpdateDataandReport(OutputProcessor::TimeStepType::TimeStepZone);
GatherBEPSResultsForTimestep(OutputProcessor::TimeStepType::TimeStepZone);
GatherPeakDemandForTimestep(OutputProcessor::TimeStepType::TimeStepZone);
EXPECT_NEAR(extLitUse * 9, gatherEndUseBEPS(1, DataGlobalConstants::endUseExteriorLights), 1.);
// General
EXPECT_NEAR(extLitUse * 6, gatherEndUseSubBEPS(1, DataGlobalConstants::endUseExteriorLights, 1), 1.);
// AnotherEndUseSubCat
EXPECT_NEAR(extLitUse * 3, gatherEndUseSubBEPS(2, DataGlobalConstants::endUseExteriorLights, 1), 1.);

OutputReportTabular::WriteBEPSTable();
OutputReportTabular::WriteDemandEndUseSummary();

EnergyPlus::sqlite->sqliteCommit();

// We test for Heating and Total, since they should be the same
std::vector<std::string> testReportNames = {"AnnualBuildingUtilityPerformanceSummary", "DemandEndUseComponentsSummary"};
std::vector<std::string> endUseSubCategoryNames = {"General", "AnotherEndUseSubCat"};

std::string endUseName = "Exterior Lighting";
std::string endUseSubCategoryName = "AnotherEndUseSubCat";
std::string rowName = endUseName + ":" + endUseSubCategoryName;
std::string columnName = "Electricity";

for (auto& endUseSubCategoryName: endUseSubCategoryNames) {
for (auto& reportName: testReportNames) {

std::string query("SELECT Value From TabularDataWithStrings"
" WHERE TableName = 'End Uses By Subcategory'"
" AND ColumnName = 'Electricity'"
" AND ReportName = '" + reportName + "'"
" AND RowName = '" + endUseName + ":" + endUseSubCategoryName + "'"); // Now Like 'Exterior Lighting:General'

auto result = queryResult(query, "TabularDataWithStrings");

ASSERT_EQ(1ul, result.size()) << "Query crashed for reportName=" << reportName;
}
}


// Specifically get the electricity usage for End Use = Exterior Lighting, and End Use Subcat = AnotherEndUseSubCat,
// and make sure it's the right number that's returned
std::string query("SELECT Value From TabularDataWithStrings"
" WHERE TableName = 'End Uses By Subcategory'"
" AND ReportName = 'AnnualBuildingUtilityPerformanceSummary'"
" AND ColumnName = 'Electricity'"
" AND RowName = 'Exterior Lighting:AnotherEndUseSubCat'");
Real64 return_val = execAndReturnFirstDouble(query);

EXPECT_NEAR(extLitUse * 3 / 3.6e6, return_val, 0.01) << "Failed for query: " << query;


// Get all Interior Lighting End Uses (all subcats) for Electricity
{
std::string query("SELECT Value From TabularDataWithStrings"
" WHERE TableName = 'End Uses By Subcategory'"
" AND ReportName = 'AnnualBuildingUtilityPerformanceSummary'"
" AND ColumnName = 'Electricity'"
" AND RowName LIKE 'Exterior Lighting:%'");
auto result = queryResult(query, "TabularDataWithStrings");

ASSERT_EQ(2u, result.size()) << "Failed for query: " << query;
}

// Get all subcat usage for all fuels (6)
{
std::string query("SELECT Value From TabularDataWithStrings"
" WHERE TableName = 'End Uses By Subcategory'"
" AND ReportName = 'AnnualBuildingUtilityPerformanceSummary'"
" AND RowName = 'Exterior Lighting:AnotherEndUseSubCat'");
auto result = queryResult(query, "TabularDataWithStrings");

ASSERT_EQ(6u, result.size()) << "Failed for query: " << query;
}
}

0 comments on commit 6bb670b

Please sign in to comment.