Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #10830 - incorrect curve unit type warning #10853

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from

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
@@ -2297,7 +2299,7 @@ namespace Curve {
// TODO: Actually use this to define output variable units
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

@@ -2953,10 +2955,21 @@ namespace Curve {
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.

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
3 participants