Skip to content

Conversation

@jmarrec
Copy link
Contributor

@jmarrec jmarrec commented Dec 12, 2024

Pull request overview

Pull Request Author

Add to this list or remove from it as applicable. This is a simple templated set of guidelines.

  • Title of PR should be user-synopsis style (clearly understandable in a standalone changelog context)
  • Label the PR with at least one of: Defect, Refactoring, NewFeature, Performance, and/or DoNoPublish
  • Pull requests that impact EnergyPlus code must also include unit tests to cover enhancement or defect repair
  • Author should provide a "walkthrough" of relevant code changes using a GitHub code review comment process
  • If any diffs are expected, author must demonstrate they are justified using plots and descriptions
  • If changes fix a defect, the fix should be demonstrated in plots and descriptions
  • If any defect files are updated to a more recent version, upload new versions here or on DevSupport
  • If IDD requires transition, transition source, rules, ExpandObjects, and IDFs must be updated, and add IDDChange label
  • If structural output changes, add to output rules file and add OutputChange label
  • If adding/removing any LaTeX docs or figures, update that document's CMakeLists file dependencies

Reviewer

This will not be exhaustively relevant to every PR.

  • Perform a Code Review on GitHub
  • If branch is behind develop, merge develop and build locally to check for side effects of the merge
  • If defect, verify by running develop branch and reproducing defect, then running PR and reproducing fix
  • If feature, test running new feature, try creative ways to break it
  • CI status: all green or justified
  • Check that performance is not impacted (CI Linux results include performance check)
  • Run Unit Test(s) locally
  • Check any new function arguments for performance impacts
  • Verify IDF naming conventions and styles, memos and notes and defaults
  • If new idf included, locally check the err file and other outputs

…it Types are accepted: they aren't

```
[ RUN      ] EnergyPlusFixture.AllPossibleUnitTypeValid
/home/julien/Software/Others/EnergyPlus2/tst/EnergyPlus/unit/CurveManager.unit.cc:967: Failure
Value of: Curve::IsCurveInputTypeValid(input_unit_type)
  Actual: false
Expected: true
VolumetricFlowPerPower is rejected by IsCurveOutputTypeValid
```
@jmarrec jmarrec added Defect Includes code to repair a defect in EnergyPlus NotIDDChange Code does not impact IDD (can be merged after IO freeze) labels Dec 12, 2024
@jmarrec jmarrec self-assigned this Dec 12, 2024
if (indVarInstance.count("unit_type")) {
std::string unitType = indVarInstance.at("unit_type").get<std::string>();
if (!IsCurveOutputTypeValid(unitType)) {
if (!IsCurveInputTypeValid(unitType)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Specific fix for #10830 is here

Comment on lines 802 to +804
if (NumAlphas >= 4) {
if (!IsCurveOutputTypeValid(Alphas(4))) {
ShowWarningError(state, format("In {} named {} the OInput Unit Type for Z is invalid.", CurrentModuleObject, Alphas(1)));
if (!IsCurveInputTypeValid(Alphas(4))) {
ShowWarningError(state, format("In {} named {} the Input Unit Type for Z is invalid.", CurrentModuleObject, Alphas(1)));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Noticed another mistake here in Curve:ChillerPartLoadWithLift

Distance,
Wavelength,
Angle,
VolumetricFlowPerPower,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add Missing Input Type VolumetricFlowPerPower: used by Curve:QuadLinear & Curve:QuintLinear

Comment on lines +748 to +782
nlohmann::json const &getPatternProperties(nlohmann::json const &schema_obj)
{
auto const &pattern_properties = schema_obj["patternProperties"];
int dot_star_present = pattern_properties.count(".*");
std::string pattern_property;
if (dot_star_present > 0) {
pattern_property = ".*";
} else {
int no_whitespace_present = pattern_properties.count(R"(^.*\S.*$)");
if (no_whitespace_present > 0) {
pattern_property = R"(^.*\S.*$)";
} else {
throw std::runtime_error(R"(The patternProperties value is not a valid choice (".*", "^.*\S.*$"))");
}
}
auto const &schema_obj_props = pattern_properties[pattern_property]["properties"];
return schema_obj_props;
}

std::vector<std::string> getPossibleChoicesFromSchema(const std::string &objectType, const std::string &fieldName)
{
// Should consider making this public, at least to the EnergyPlusFixture, but maybe in the InputProcessor directly
// At which point, should handle the "anyOf" case, here I don't need it, so not bothering
static const auto json_schema = nlohmann::json::from_cbor(EmbeddedEpJSONSchema::embeddedEpJSONSchema());
auto const &schema_properties = json_schema.at("properties");
const auto &object_schema = schema_properties.at(objectType);
auto const &schema_obj_props = getPatternProperties(object_schema);
auto const &schema_field_obj = schema_obj_props.at(fieldName);
std::vector<std::string> choices;
for (const auto &e : schema_field_obj.at("enum")) {
choices.push_back(e);
}

return choices;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mine the json schema for the choices

Comment on lines +769 to +770
// Should consider making this public, at least to the EnergyPlusFixture, but maybe in the InputProcessor directly
// At which point, should handle the "anyOf" case, here I don't need it, so not bothering
Copy link
Contributor Author

Choose a reason for hiding this comment

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

note

Comment on lines +805 to +826
class InputUnitTypeIsValid : public EnergyPlusFixture, public ::testing::WithParamInterface<std::string_view>
{
};
TEST_P(InputUnitTypeIsValid, IndepentVariable)
{
const auto &unit_type = GetParam();

std::string const idf_objects = delimited_string({
"Table:IndependentVariable,",
" SAFlow, !- Name",
" Cubic, !- Interpolation Method",
" Constant, !- Extrapolation Method",
" 0.714, !- Minimum Value",
" 1.2857, !- Maximum Value",
" , !- Normalization Reference Value",
fmt::format(" {}, !- Unit Type", unit_type),
" , !- External File Name",
" , !- External File Column Number",
" , !- External File Starting Row Number",
" 0.714286, !- Value 1",
" 1.0,",
" 1.2857;",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Parametrized test

Comment on lines +851 to +853
Curve::GetCurveInput(*state);
state->dataCurveManager->GetCurvesInputFlag = false;
EXPECT_TRUE(compare_err_stream("", true));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

That calls GetCurveInput specifically. That exhibits the issue where IsValidCurveInput is true, but it's IsValidCurveOUTPUT that's called by mistake

Comment on lines +856 to +864
INSTANTIATE_TEST_SUITE_P(CurveManager,
InputUnitTypeIsValid,
testing::Values("", "Angle", "Dimensionless", "Distance", "MassFlow", "Power", "Temperature", "VolumetricFlow"),
[](const testing::TestParamInfo<InputUnitTypeIsValid::ParamType> &info) -> std::string {
if (info.param.empty()) {
return "Blank";
}
return std::string{info.param};
});
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Instantiate the param tests... I could have used testing::ValuesIn(container) instead to make it fully dynamic but didn't

Comment on lines +866 to +869
class OutputUnitTypeIsValid : public EnergyPlusFixture, public ::testing::WithParamInterface<std::string_view>
{
};
TEST_P(OutputUnitTypeIsValid, TableLookup)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same stuff with TableLookup output unit type

Comment on lines +927 to +976
std::pair<std::set<std::string>, std::set<std::string>> getAllPossibleInputOutputTypesForCurves()
{
const auto json_schema = nlohmann::json::from_cbor(EmbeddedEpJSONSchema::embeddedEpJSONSchema());
auto const &schema_properties = json_schema.at("properties");
std::set<std::string> all_input_choices;
std::set<std::string> all_output_choices;

for (const auto &[objectType, object_schema] : schema_properties.items()) {
const bool is_curve = (objectType.rfind("Curve:", 0) == 0) || (objectType == "Table:Lookup") || (objectType == "Table:IndependentVariable");
if (!is_curve) {
continue;
}
auto const &schema_obj_props = getPatternProperties(object_schema);
for (const auto &[fieldName, schema_field_obj] : schema_obj_props.items()) {
if (std::string(fieldName) == "output_unit_type") {
for (const auto &e : schema_field_obj.at("enum")) {
all_output_choices.insert(std::string{e});
}
} else if (fieldName.find("unit_type") != std::string::npos) {
for (const auto &e : schema_field_obj.at("enum")) {
all_input_choices.insert(std::string{e});
}
}
}
}

return {all_input_choices, all_output_choices};
}

TEST_F(EnergyPlusFixture, AllPossibleUnitTypeValid)
{
auto const [all_input_choices, all_output_choices] = getAllPossibleInputOutputTypesForCurves();

// As of 2024-12-18
// in = ["", "Angle", "Dimensionless", "Distance", "MassFlow", "Power", "Pressure", "Temperature", "VolumetricFlow","VolumetricFlowPerPower"]
// out = ["", "Capacity", "Dimensionless", "Power", "Pressure", "Temperature"]
EXPECT_FALSE(all_input_choices.empty()) << fmt::format("{}", all_input_choices);
EXPECT_FALSE(all_output_choices.empty()) << fmt::format("{}", all_output_choices);

for (const auto &input_unit_type : all_input_choices) {
EXPECT_TRUE(Curve::IsCurveInputTypeValid(input_unit_type)) << input_unit_type << " is rejected by IsCurveOutputTypeValid";
}

for (const auto &output_unit_type : all_output_choices) {
if (output_unit_type.empty()) {
continue;
}
EXPECT_TRUE(Curve::IsCurveOutputTypeValid(output_unit_type)) << output_unit_type << " is rejected by IsCurveOutputTypeValid";
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Dynamic test that collates ALL possible input/output unit types by mining the schema for all curve objects and tests that IsCurve<In/Out>putTypeValid is ok. It wasn't for VolumetricFlowPerPower

@jmarrec jmarrec requested a review from Myoldmopar December 12, 2024 16:19
@nrel-bot-2
Copy link

@jmarrec it has been 8 days since this pull request was last updated.

@nrel-bot-2
Copy link

@jmarrec it has been 7 days since this pull request was last updated.

5 similar comments
@nrel-bot-2
Copy link

@jmarrec it has been 7 days since this pull request was last updated.

@nrel-bot-2
Copy link

@jmarrec it has been 7 days since this pull request was last updated.

@nrel-bot-2
Copy link

@jmarrec it has been 7 days since this pull request was last updated.

@nrel-bot-2
Copy link

@jmarrec it has been 7 days since this pull request was last updated.

@nrel-bot-2c
Copy link

@jmarrec it has been 7 days since this pull request was last updated.

@Myoldmopar
Copy link
Member

OK, something just struck me as I was looking through your new parameterized tests. I recalled our macro that actually parses through looking for unit tests to add as ctest entries with add_test(). Unfortunately it looks like the ctest run isn't getting them. Look here, and please correct me if I'm just making a silly mistake:

$ ctest -R InputUnitTypeIsValid
Test project /eplus/repos/2eplus/builds/r
No tests were found!!!

$ ./Products/energyplus_tests --gtest_filter="*InputUnitTypeIsValid*"
Note: Google Test filter = *InputUnitTypeIsValid*
[==========] Running 8 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 8 tests from CurveManager/InputUnitTypeIsValid
[ RUN      ] CurveManager/InputUnitTypeIsValid.IndepentVariable/Blank
[       OK ] CurveManager/InputUnitTypeIsValid.IndepentVariable/Blank (121 ms)
[ RUN      ] CurveManager/InputUnitTypeIsValid.IndepentVariable/Angle
[       OK ] CurveManager/InputUnitTypeIsValid.IndepentVariable/Angle (42 ms)
[ RUN      ] CurveManager/InputUnitTypeIsValid.IndepentVariable/Dimensionless
[       OK ] CurveManager/InputUnitTypeIsValid.IndepentVariable/Dimensionless (39 ms)
[ RUN      ] CurveManager/InputUnitTypeIsValid.IndepentVariable/Distance
[       OK ] CurveManager/InputUnitTypeIsValid.IndepentVariable/Distance (39 ms)
[ RUN      ] CurveManager/InputUnitTypeIsValid.IndepentVariable/MassFlow
[       OK ] CurveManager/InputUnitTypeIsValid.IndepentVariable/MassFlow (38 ms)
[ RUN      ] CurveManager/InputUnitTypeIsValid.IndepentVariable/Power
[       OK ] CurveManager/InputUnitTypeIsValid.IndepentVariable/Power (39 ms)
[ RUN      ] CurveManager/InputUnitTypeIsValid.IndepentVariable/Temperature
[       OK ] CurveManager/InputUnitTypeIsValid.IndepentVariable/Temperature (39 ms)
[ RUN      ] CurveManager/InputUnitTypeIsValid.IndepentVariable/VolumetricFlow
[       OK ] CurveManager/InputUnitTypeIsValid.IndepentVariable/VolumetricFlow (39 ms)
[----------] 8 tests from CurveManager/InputUnitTypeIsValid (399 ms total)

[----------] Global test environment tear-down
[==========] 8 tests from 1 test suite ran. (399 ms total)
[  PASSED  ] 8 tests.

The code that sets up the ctest entries is here, with specifically this section in question:

  string(REGEX MATCHALL "TEST_?F?\\(([A-Za-z_0-9 ,]+)\\)" found_tests ${contents})
  foreach(hit ${found_tests})
    string(REGEX REPLACE ".*\\(( )*([A-Za-z_0-9]+)( )*,( )*([A-Za-z_0-9]+)( )*\\).*" "\\2.\\5" test_name ${hit})
    add_test(NAME ${test_name} COMMAND "${executable}" "--gtest_filter=${test_name}")
  endforeach(hit)

It is looking for TEST or TEST_F. I added a P? in the regex, and it found 3 more tests but not 8. It looks like it needs some love to more intelligently find tests. Or maybe there is a more modern way to do this? I do like that the tests show up as individual tests in ctest rather than one enormous call to energyplus_tests so that it is easy to ctest -j 31 the whole thing.

I'm not inclined to hold this up to solve that, but I would like to solve it soon. Let me know if you have any thoughts.

@Myoldmopar
Copy link
Member

Oh, and anyway, your tests do pass. So this is good. I'll push the resolved commit and get this merged. Thanks @jmarrec

@Myoldmopar Myoldmopar merged commit 6b2812b into develop Feb 4, 2025
@Myoldmopar Myoldmopar deleted the 10830_Incorrect_CurveUnitTypeWarning branch February 4, 2025 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Defect Includes code to repair a defect in EnergyPlus NotIDDChange Code does not impact IDD (can be merged after IO freeze)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Piping Correction Factor for Length Independent Variable Unit Type is Incorrect

5 participants