Skip to content

Commit

Permalink
Merge pull request #8661 from NREL/epJSONminFields
Browse files Browse the repository at this point in the history
Fix epJSON minfields and extensible input processing
  • Loading branch information
Myoldmopar authored Mar 30, 2021
2 parents 1221990 + bd963e5 commit a229933
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/EnergyPlus/HeatBalanceManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ namespace HeatBalanceManager {
state.dataHeatBal->TempConvergTol = BuildingNumbers(3);
if (state.dataHeatBal->TempConvergTol <= 0.0) {
ShowSevereError(state,
format("{}{}: {} value invalid, [{:.3R}]", RoutineName, state.dataHeatBalMgr->CurrentModuleObject, state.dataIPShortCut->cNumericFieldNames(2), state.dataHeatBal->TempConvergTol));
format("{}{}: {} value invalid, [{:.3R}]", RoutineName, state.dataHeatBalMgr->CurrentModuleObject, state.dataIPShortCut->cNumericFieldNames(3), state.dataHeatBal->TempConvergTol));
ErrorsFound = true;
}
// Solar Distribution
Expand Down
16 changes: 12 additions & 4 deletions src/EnergyPlus/InputProcessing/InputProcessor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,8 @@ const json &InputProcessor::getObjectInstances(std::string const &ObjType)
return epJSON.find(ObjType).value();
}

InputProcessor::MaxFields InputProcessor::findMaxFields(EnergyPlusData &state, json const &ep_object, std::string const &extension_key, json const &legacy_idd)
InputProcessor::MaxFields InputProcessor::findMaxFields(
EnergyPlusData &state, json const &ep_object, std::string const &extension_key, json const &legacy_idd, std::size_t const min_fields)
{
InputProcessor::MaxFields maxFields;
if (!state.dataGlobal->isEpJSON) {
Expand All @@ -577,6 +578,8 @@ InputProcessor::MaxFields InputProcessor::findMaxFields(EnergyPlusData &state, j
}
} else {
auto const &legacy_idd_fields = legacy_idd["fields"];
// start with at least min_fields as the number of fields
maxFields.max_fields = min_fields;
for (auto const &field : ep_object.items()) {
auto const &field_key = field.key();
if (field_key == extension_key) continue;
Expand Down Expand Up @@ -691,13 +694,13 @@ void InputProcessor::setObjectItemValue(EnergyPlusData &state,
}
}
if (field_type == "a") {
if (within_max_fields) NumAlphas++;
if (within_max_fields) NumAlphas = alpha_index;
if (is_AlphaFieldNames) {
AlphaFieldNames()(alpha_index) = (state.dataGlobal->isEpJSON) ? field : legacy_field_info.at("field_name").get<std::string>();
}
alpha_index++;
} else if (field_type == "n") {
if (within_max_fields) NumNumbers++;
if (within_max_fields) NumNumbers = numeric_index;
if (is_NumericFieldNames) {
NumericFieldNames()(numeric_index) = (state.dataGlobal->isEpJSON) ? field : legacy_field_info.at("field_name").get<std::string>();
}
Expand Down Expand Up @@ -764,6 +767,11 @@ void InputProcessor::getObjectItem(EnergyPlusData &state,
auto const &legacy_idd_fields = legacy_idd["fields"];
auto const &schema_name_field = epJSON_schema_it_val.find("name");
auto const has_idd_name_field = schema_name_field != epJSON_schema_it_val.end();
auto const &found_min_fields = epJSON_schema_it_val.find("min_fields");
size_t min_fields = 0;
if (found_min_fields != epJSON_schema_it_val.end()) {
min_fields = found_min_fields.value();
}

auto key = legacy_idd.find("extension");
std::string extension_key;
Expand All @@ -777,7 +785,7 @@ void InputProcessor::getObjectItem(EnergyPlusData &state,

int alpha_index = 1;
int numeric_index = 1;
auto maxFields = findMaxFields(state, obj_val, extension_key, legacy_idd);
auto maxFields = findMaxFields(state, obj_val, extension_key, legacy_idd, min_fields);

Alphas = "";
Numbers = 0;
Expand Down
3 changes: 2 additions & 1 deletion src/EnergyPlus/InputProcessing/InputProcessor.hh
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ private:
std::size_t max_extensible_fields = 0;
};

MaxFields findMaxFields(EnergyPlusData &state, json const &ep_object, std::string const &extension_key, json const &legacy_idd);
MaxFields findMaxFields(
EnergyPlusData &state, json const &ep_object, std::string const &extension_key, json const &legacy_idd, std::size_t const min_fields);

void setObjectItemValue(EnergyPlusData &state,
json const &ep_object,
Expand Down
8 changes: 4 additions & 4 deletions testfiles/RefBldgMediumOfficeNew2004_Chicago_epJSON.epJSON
Original file line number Diff line number Diff line change
Expand Up @@ -6897,11 +6897,11 @@
"variable_details": [
{
"aggregation_type_for_variable_or_meter": "SumOrAverage",
"variable_or_meter_name": "Cooling Coil Electric Power"
"variable_or_meter_name": "Cooling Coil Electricity Rate"
},
{
"aggregation_type_for_variable_or_meter": "Maximum",
"variable_or_meter_name": "Cooling Coil Electric Power"
"variable_or_meter_name": "Cooling Coil Electricity Rate"
}
]
},
Expand Down Expand Up @@ -6943,11 +6943,11 @@
"variable_details": [
{
"aggregation_type_for_variable_or_meter": "SumOrAverage",
"variable_or_meter_name": "Fan Electric Power"
"variable_or_meter_name": "Fan Electricity Rate"
},
{
"aggregation_type_for_variable_or_meter": "Maximum",
"variable_or_meter_name": "Fan Electric Power"
"variable_or_meter_name": "Fan Electricity Rate"
}
]
},
Expand Down
99 changes: 99 additions & 0 deletions tst/EnergyPlus/unit/InputProcessor.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@

// EnergyPlus Headers
#include "Fixtures/InputProcessorFixture.hh"
#include <EnergyPlus/Data/EnergyPlusData.hh>
#include <EnergyPlus/DataIPShortCuts.hh>
#include <EnergyPlus/DataOutputs.hh>
#include <EnergyPlus/GeneralRoutines.hh>
#include <EnergyPlus/InputProcessing/InputProcessor.hh>
Expand Down Expand Up @@ -4223,6 +4225,103 @@ TEST_F(InputProcessorFixture, reportIDFRecordsStats_extensible_fields)

}

TEST_F(InputProcessorFixture, epJSONgetObjectItem_minfields)
{

json root;
std::string obj_name1 = "Building";
std::string name1 = "Building 1";
json bldg1 = {{"loads_convergence_tolerance_value", 0.1}, {"terrain", "Ocean"}};
EXPECT_TRUE(bldg1.is_object());
root[obj_name1][name1] = bldg1;

std::string obj_name2 = "Material:NoMass";
std::string name2 = "Standard insulation_01";
json mat1 = {{"name", name1}, {"roughness", "MediumRough"}, {"thermal_resistance", 2.0}, {"solar_absorptance", 0.5}};
EXPECT_TRUE(mat1.is_object());
root[obj_name2][name2] = mat1;

inputProcessor->epJSON = root;
// getEpJSON();

int numAlphas = 0;
int numNumbers = 0;
int ioStat = 0;
state->dataGlobal->isEpJSON = true;
inputProcessor->initializeMaps();

int maxAlphas = 20;
int maxNumbers = 20;
state->dataIPShortCut->lNumericFieldBlanks.allocate(maxNumbers);
state->dataIPShortCut->lAlphaFieldBlanks.allocate(maxAlphas);
state->dataIPShortCut->cAlphaFieldNames.allocate(maxAlphas);
state->dataIPShortCut->cNumericFieldNames.allocate(maxNumbers);
state->dataIPShortCut->cAlphaArgs.allocate(maxAlphas);
state->dataIPShortCut->rNumericArgs.allocate(maxNumbers);
state->dataIPShortCut->lNumericFieldBlanks = false;
state->dataIPShortCut->lAlphaFieldBlanks = false;
state->dataIPShortCut->cAlphaFieldNames = " ";
state->dataIPShortCut->cNumericFieldNames = " ";
state->dataIPShortCut->cAlphaArgs = " ";
state->dataIPShortCut->rNumericArgs = 0.0;

inputProcessor->getObjectItem(*state,
obj_name1,
1,
state->dataIPShortCut->cAlphaArgs,
numAlphas,
state->dataIPShortCut->rNumericArgs,
numNumbers,
ioStat,
state->dataIPShortCut->lNumericFieldBlanks,
state->dataIPShortCut->lAlphaFieldBlanks,
state->dataIPShortCut->cAlphaFieldNames,
state->dataIPShortCut->cNumericFieldNames);

// For Building, min-fields is 8, which is the entire object, regardless of the number of input object fields
EXPECT_EQ(numAlphas, 3);
EXPECT_EQ(numNumbers, 5);

// User inputs from above
// Note even though choice keys are case-sensitive during epJSON processing, getObjectItem pushes Alphas to UPPERcase
EXPECT_EQ(state->dataIPShortCut->cAlphaArgs(1), name1); // Building Name field is tagged with /retaincase
EXPECT_EQ(state->dataIPShortCut->cAlphaArgs(2), "OCEAN");
EXPECT_NEAR(state->dataIPShortCut->rNumericArgs(2), 0.1, 0.0001);
// Defaults from schema
EXPECT_EQ(state->dataIPShortCut->cAlphaArgs(3), "FULLEXTERIOR");
EXPECT_NEAR(state->dataIPShortCut->rNumericArgs(1), 0.0, 0.0001);
EXPECT_NEAR(state->dataIPShortCut->rNumericArgs(3), 0.4, 0.0001);
EXPECT_NEAR(state->dataIPShortCut->rNumericArgs(4), 25.0, 0.0001);
EXPECT_NEAR(state->dataIPShortCut->rNumericArgs(5), 1.0, 0.0001);

inputProcessor->getObjectItem(*state,
obj_name2,
1,
state->dataIPShortCut->cAlphaArgs,
numAlphas,
state->dataIPShortCut->rNumericArgs,
numNumbers,
ioStat,
state->dataIPShortCut->lNumericFieldBlanks,
state->dataIPShortCut->lAlphaFieldBlanks,
state->dataIPShortCut->cAlphaFieldNames,
state->dataIPShortCut->cNumericFieldNames);

// For Material:NoMass, min-fields is 3, but the input object above takes it to A2 and N3
EXPECT_EQ(numAlphas, 2);
EXPECT_EQ(numNumbers, 3);

// User inputs from above
// Note even though choice keys are case-sensitive during epJSON processing, getObjectItem pushes Alphas to UPPERcase
EXPECT_EQ(state->dataIPShortCut->cAlphaArgs(1), UtilityRoutines::MakeUPPERCase(name2)); // Material Name field is NOT tagged with /retaincase
EXPECT_EQ(state->dataIPShortCut->cAlphaArgs(2), "MEDIUMROUGH");
EXPECT_NEAR(state->dataIPShortCut->rNumericArgs(1), 2.0, 0.0001);
EXPECT_NEAR(state->dataIPShortCut->rNumericArgs(3), 0.5, 0.0001);
// Defaults from schema
EXPECT_NEAR(state->dataIPShortCut->rNumericArgs(2), 0.9, 0.0001);
// Fields beyond min-fields come back as blank or zero, even if they have a default
EXPECT_NEAR(state->dataIPShortCut->rNumericArgs(4), 0.0, 0.0001);
}

/*
TEST_F( InputProcessorFixture, processIDF_json )
Expand Down

5 comments on commit a229933

@nrel-bot-2b
Copy link

Choose a reason for hiding this comment

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

develop (Myoldmopar) - x86_64-Linux-Ubuntu-18.04-gcc-7.5: OK (2378 of 2378 tests passed, 0 test warnings)

Build Badge Test Badge

@nrel-bot-3
Copy link

Choose a reason for hiding this comment

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

develop (Myoldmopar) - x86_64-MacOS-10.15-clang-11.0.0: OK (2358 of 2358 tests passed, 0 test warnings)

Build Badge Test Badge

@nrel-bot-2
Copy link

Choose a reason for hiding this comment

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

develop (Myoldmopar) - x86_64-Linux-Ubuntu-18.04-gcc-7.5-UnitTestsCoverage-Debug: OK (1634 of 1634 tests passed, 0 test warnings)

Build Badge Test Badge Coverage Badge

@nrel-bot
Copy link

Choose a reason for hiding this comment

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

develop (Myoldmopar) - Win64-Windows-10-VisualStudio-16: OK (2329 of 2329 tests passed, 0 test warnings)

Build Badge Test Badge

@nrel-bot-2b
Copy link

Choose a reason for hiding this comment

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

develop (Myoldmopar) - x86_64-Linux-Ubuntu-18.04-gcc-7.5-IntegrationCoverage-Debug: OK (726 of 727 tests passed, 0 test warnings)

Failures:\n

integration Test Summary

  • Passed: 726
  • Timeout: 1

Build Badge Test Badge Coverage Badge

Please sign in to comment.