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

Extended HI followup: fix speed issue #10733

Merged
merged 39 commits into from
Feb 13, 2025
Merged

Extended HI followup: fix speed issue #10733

merged 39 commits into from
Feb 13, 2025

Conversation

yujiex
Copy link
Collaborator

@yujiex yujiex commented Sep 12, 2024

Pull request overview

A couple of different approaches were tried out to improve the performance

  • changing the root solver type from Bisection to BisectionThenRegulaFalsi: this had the biggest impact, bringing the damage from 70% to about 12%
  • result caching: saving Zs(Rs) result to a variable before entering the root solvers. This improved about 1-2 percentage point.
  • limit the domain of application to the region where the two methods differ more (red and blue region). That doesn't help much either (< 0.5% improvement).

The new extend HI method might just requires a lot of computation. So The following object is added to provide a switch from the simplified to the extended HI method.

OutputControl:ResilienceSummaries,
       \memo Specifies methods for resilience reporting variables
       \unique-object
  A1 ; \field Heat Index Algorithm
       \note Whether the simplified or the extended method should be used for heat index
       \note Simplified: based on regression analysis carried out by Lans P. Rothfusz
       \note Extended: Based on paper by Lu & Romps
       \type choice
       \key Simplified
       \key Extended
       \default Simplified

Regression diff

There's diff in one file: 1ZoneUncontrolled_Win_ASH55_Thermal_Comfort.idf. The diff is a result of the added OutputControl:ResilienceSummaries
image

NOTE: ENHANCEMENTS MUST FOLLOW A SUBMISSION PROCESS INCLUDING A FEATURE PROPOSAL AND DESIGN DOCUMENT PRIOR TO SUBMITTING CODE

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

@yujiex yujiex added the Defect Includes code to repair a defect in EnergyPlus label Sep 12, 2024
@yujiex yujiex requested a review from Myoldmopar September 12, 2024 17:03
@yujiex yujiex self-assigned this Sep 12, 2024
Copy link

⚠️ Regressions detected on macos-14 for commit a71113f

Regression Summary
  • ESO Big Diffs: 4
  • Table Big Diffs: 3

@yujiex yujiex added Performance Includes code changes that are directed at improving the runtime performance of EnergyPlus and removed Defect Includes code to repair a defect in EnergyPlus labels Sep 12, 2024
Copy link

⚠️ Regressions detected on macos-14 for commit 942bb89

Regression Summary
  • ESO Big Diffs: 4
  • Table Big Diffs: 3

Copy link

⚠️ Regressions detected on macos-14 for commit ffd2aa0

Regression Summary
  • ESO Big Diffs: 4
  • Table Big Diffs: 3

Copy link

⚠️ Regressions detected on macos-14 for commit 59b978e

Regression Summary
  • ESO Big Diffs: 4
  • Table Big Diffs: 3

@Myoldmopar
Copy link
Member

Even with the latest commit, 4f4809f, it's still causing a 10% increase in instruction count in just our performance test files. We can figure out a solution for this, but it doesn't look like it's going in this release. I'm marking this for next release and we'll deal with this later.

If this method is trimmed as far down as possible but still this much slower, I would suggest adding a switch to calculate heat index using the old way by default and then enabling the new method as an alternative. This would be a user-facing input option, so definitely not in this current release.

@Myoldmopar Myoldmopar added this to the EnergyPlus 25.1 IO Freeze milestone Sep 13, 2024
@yujiex
Copy link
Collaborator Author

yujiex commented Sep 13, 2024

Thanks, @Myoldmopar . It seems that changing the solver type had the biggest impact. Then I tried adding some result caching but those doesn't save as much (like improved 1-2 percentage point). I also tried to limit the domain of its application (in the old PR there was a plot of how results differ between the old and the new methods. I restricted it to only apply on the bottom right region where the two methods differ a lot). That doesn't help much either. Potentially the new method just requires a lot of computation.

(modify): I might have had the equation part wrong for restraining the domain where extended HI is applied (the white region in the following figures. I modified it and tried locally, roughly it improved it by about 6-7%. Might still not be good enough.
image

Copy link

⚠️ Regressions detected on macos-14 for commit 8808e86

Regression Summary
  • ESO Big Diffs: 4
  • Table Big Diffs: 3

constexpr Real64 epsilon = 0.97; // , emissivity of surface, steadman1979
constexpr Real64 M = 83.6; // kg , mass of average US adults, fryar2018
constexpr Real64 H = 1.69; // m , height of average US adults, fryar2018
Real64 A = 0.202 * pow(M, 0.425) * pow(H, 0.725); // m^2 , DuBois formula, parson2014
Copy link
Collaborator

Choose a reason for hiding this comment

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

Don't use global variables.

Yujie Xu added 3 commits February 9, 2025 23:28
Copy link

⚠️ Regressions detected on macos-14 for commit 03996a8

Regression Summary
  • Table Big Diffs: 1

Copy link

⚠️ Regressions detected on macos-14 for commit 576adfb

Regression Summary
  • Table Big Diffs: 1

Real64 Rf;

if (flux1 <= 0.0) {
varname = static_cast<int>(EqvarName::Phi);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why cast this to int all the time? Just use the enum, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah I should use the enum class instead of casting to int

}

// Convert the find_T function
Real64 find_T(EnergyPlusData &state, int const eqvar_name, Real64 const eqvar)
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can use enums as parameters, why make it an int here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah also need to use enum class directly here as well

enum class EqvarName
{
Invalid = -1,
Phi = 1,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are these not starting at 0? Why do you have to assign explicit values to them?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This extended heat index was based on python code on this page. They have some dictionary defined the indices like this: dic = {"phi":1,"Rf":2,"Rs":3,"Rs*":3,"dTcdt":4} So I just used the same indices.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The values are meaningless unless you are using them in an array, but even then you should use them in a std::array and they should start at 0.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

make sense. Let me change this to starting at 0.

static_cast<HVACSystemRootSolverAlgorithm>(getEnumValue(HVACSystemRootSolverAlgorithmUC, Util::makeUPPER(AlphaName(1))));
if (HVACSystemRootFinding.HVACSystemRootSolverMethod == HVACSystemRootSolverAlgorithm::Invalid) {
HVACSystemRootFinding.HVACSystemRootSolverMethod = HVACSystemRootSolverAlgorithm::RegulaFalsi;
ShowWarningError(state,
Copy link
Collaborator

Choose a reason for hiding this comment

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

There is a shortcut for this warning called ShowWarningInvalidKey.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh! Didn't realize there's this shortcut.

constexpr Real64 Za_bar = 60.6 / 11.6; // Pa m^2/W, mass transfer resistance through air, clothed part of skin
constexpr Real64 Za_un = 60.6 / 12.3; // Pa m^2/W, mass transfer resistance through air, when being naked

constexpr Real64 tol = 1e-8;
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is an absolute tolerance level. What are the reasonable ranges of values here and what level of precision does this tolerance correspond to relative to those values?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The tolerance was from the python code here this page.

Copy link
Collaborator

Choose a reason for hiding this comment

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

What someone else chose for the tolerance is not relevant. What is the magnitude of the values produced by this function? 1e-4? 1e-1? 1e+2?

Copy link
Collaborator

Choose a reason for hiding this comment

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

If this function produces SGP (whatever that is) and the values are on the order of 1e-2 then a tolerance of 1e-8 is about six decimal places of precision which is about twice what is needed. I cannot conceive of any quantity that EnergyPlus that would need to know to a precision of more than 0.1% (1% may be okay for many thing too).

In fact, SolveRoot should probably be revised to use relative tolerance after some small fixed number of iterations. I wonder how much performance over-specific root precision is costing us. It could be quite a lot.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If I change tol to 1e-4, there will be a 0.6 difference for a target value of about 360 (0.2% relative difference). Using tol=1e-5 keeps the difference to below 0.1 (for values ranging from 200 to 400). Maybe I'll change it to tol = 1e-5?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Absolutely. Those additional digits are costing you iterations for no real benefit in terms of accuracy. Who cares if the SGP is "off" by less than 0.1%? How accurate is that metric anyway?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Normally heat index is reported at either integer or 1 decimal point. The range is mostly two three hundred. Hopefully within 0.1C accuracy is good enough.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Most thermostats used in buildings do not have this resolution.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah the inputs of temperature and relative humidity percentage points are integers

Copy link

⚠️ Regressions detected on macos-14 for commit 7d0f7b4

Regression Summary
  • Table Big Diffs: 1

Copy link

⚠️ Regressions detected on macos-14 for commit 38a54c0

Regression Summary
  • Table Big Diffs: 1

Copy link

⚠️ Regressions detected on macos-14 for commit d9c2553

Regression Summary
  • Table Big Diffs: 1

Copy link
Contributor

@mjwitte mjwitte left a comment

Choose a reason for hiding this comment

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

@yujiex Thanks for the idd changes.


This input specifies methods or algorithms used in certain resilience reporting variables.

\subsubsection{Inputs}\label{inputs-8-020}
Copy link
Contributor

Choose a reason for hiding this comment

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

When viewing the changes on github, there is a warning about this line:
Label inputs-8-020' multiply defined.`

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

let me check on why this happens

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I see, my label for the inputs section in my latex documentation collides with a existing one. I just changed the label.

@mjwitte mjwitte added the IDDChange Code changes impact the IDD file (cannot be merged after IO freeze) label Feb 12, 2025
Copy link

⚠️ Regressions detected on macos-14 for commit af75116

Regression Summary
  • Table Big Diffs: 1

Copy link
Member

@Myoldmopar Myoldmopar left a comment

Choose a reason for hiding this comment

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

Outside of the vector/array thing in the unit test code, I don't have any comments. And that's not worth holding this up. I will do final testing and try to get this in.

}

} // namespace ExtendedHI
} // namespace EnergyPlus
Copy link
Member

Choose a reason for hiding this comment

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

The strong use of const and constexpr in this file make me very happy.

@@ -1013,6 +1013,27 @@ namespace SimulationManager {
}
}

state.dataHeatBalMgr->CurrentModuleObject = "OutputControl:ResilienceSummaries";
Copy link
Member

Choose a reason for hiding this comment

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

In the future, there's no need to use a state variable to hold this string. Just keep a constexpr string view variable of it and use that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll remember and use string view in the future.

TEST_F(EnergyPlusFixture, extendedHI_pvstar)
{
Real64 tol = 1e-8;
std::vector<Real64> T_values = {200, 210, 220, 230, 240, 250, 260, 270, 280, 290, 300, 310, 320, 330, 340, 350, 360, 370};
Copy link
Member

Choose a reason for hiding this comment

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

You could use constexpr std::array all over the place in here. Since this is just in the tests, we don't have to hold this up, but always look for that in the future.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

oh! I see I see. I'll take a note and remember to use constexpr next time.

@Myoldmopar
Copy link
Member

Runs great here, ready to go in. Thanks @yujiex.

@Myoldmopar Myoldmopar merged commit 6342ea8 into develop Feb 13, 2025
10 checks passed
@Myoldmopar Myoldmopar deleted the extendedHIspeedFix branch February 13, 2025 16:49
@yujiex
Copy link
Collaborator Author

yujiex commented Feb 13, 2025

Thanks @Myoldmopar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
IDDChange Code changes impact the IDD file (cannot be merged after IO freeze) Performance Includes code changes that are directed at improving the runtime performance of EnergyPlus
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants