-
Notifications
You must be signed in to change notification settings - Fork 464
SolveRoot with local Optimization #11429
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
base: develop
Are you sure you want to change the base?
Changes from all commits
85f05f7
9d88281
52dea61
bedec29
34819ea
ecb0d1e
833a468
f9c4ccb
429ed2e
391fbf5
7bbec98
b978dc8
a09442a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -193,7 +193,7 @@ void SolveRoot(const EnergyPlusData &state, | |
| Real64 Y1 = f(X1); // f at X1 | ||
| // check initial values | ||
| if (Y0 * Y1 > 0) { | ||
| Flag = -2; | ||
| Flag = SOLVEROOT_ERROR_INIT; | ||
| XRes = X0; | ||
| return; | ||
| } | ||
|
|
@@ -209,43 +209,44 @@ void SolveRoot(const EnergyPlusData &state, | |
| break; | ||
| } | ||
| // new estimation | ||
| switch (state.dataRootFinder->HVACSystemRootFinding.HVACSystemRootSolverMethod) { | ||
| case HVACSystemRootSolverAlgorithm::RegulaFalsi: { | ||
| switch (state.dataRootFinder->rootAlgo) { | ||
| case RootAlgo::RegulaFalsi: { | ||
| XTemp = (Y0 * X1 - Y1 * X0) / DY; | ||
| break; | ||
| } | ||
| case HVACSystemRootSolverAlgorithm::Bisection: { | ||
| case RootAlgo::Bisection: { | ||
| XTemp = (X1 + X0) / 2.0; | ||
| break; | ||
| } | ||
| case HVACSystemRootSolverAlgorithm::RegulaFalsiThenBisection: { | ||
| if (NIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) { | ||
| case RootAlgo::RegulaFalsiThenBisection: { | ||
| if (NIte > state.dataRootFinder->NumOfIter) { | ||
| XTemp = (X1 + X0) / 2.0; | ||
| } else { | ||
| XTemp = (Y0 * X1 - Y1 * X0) / DY; | ||
| } | ||
| break; | ||
| } | ||
| case HVACSystemRootSolverAlgorithm::BisectionThenRegulaFalsi: { | ||
| if (NIte <= state.dataRootFinder->HVACSystemRootFinding.NumOfIter) { | ||
| case RootAlgo::BisectionThenRegulaFalsi: { | ||
| if (NIte <= state.dataRootFinder->NumOfIter) { | ||
| XTemp = (X1 + X0) / 2.0; | ||
| } else { | ||
| XTemp = (Y0 * X1 - Y1 * X0) / DY; | ||
| } | ||
| break; | ||
| } | ||
| case HVACSystemRootSolverAlgorithm::Alternation: { | ||
| if (AltIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) { | ||
| case RootAlgo::Alternation: { | ||
| if (AltIte > state.dataRootFinder->NumOfIter) { | ||
| XTemp = (X1 + X0) / 2.0; | ||
| if (AltIte >= 2 * state.dataRootFinder->HVACSystemRootFinding.NumOfIter) { | ||
|
|
||
| if (AltIte >= 2 * state.dataRootFinder->NumOfIter) { | ||
| AltIte = 0; | ||
| } | ||
| } else { | ||
| XTemp = (Y0 * X1 - Y1 * X0) / DY; | ||
| } | ||
| break; | ||
| } | ||
| case HVACSystemRootSolverAlgorithm::ShortBisectionThenRegulaFalsi: { | ||
| case RootAlgo::ShortBisectionThenRegulaFalsi: { | ||
| if (NIte < 3) { | ||
| XTemp = (X1 + X0) / 2.0; | ||
| } else { | ||
|
|
@@ -270,6 +271,15 @@ void SolveRoot(const EnergyPlusData &state, | |
| return; | ||
| }; | ||
|
|
||
| #ifdef GET_OUT | ||
| if (NIte > 20) { | ||
| assert(false); | ||
| Flag = NIte; | ||
| XRes = XTemp; | ||
| return; | ||
| } | ||
| #endif // GET_OUT | ||
|
|
||
|
Comment on lines
+274
to
+282
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this something you intend to leave in? |
||
| // OK, so we didn't converge, lets check max iterations to see if we should break early | ||
| if (NIte > MaxIte) { | ||
| break; | ||
|
|
@@ -297,10 +307,70 @@ void SolveRoot(const EnergyPlusData &state, | |
| } // Cont | ||
|
|
||
| // if we make it here we haven't converged, so just set the flag and leave | ||
| Flag = -1; | ||
| Flag = SOLVEROOT_ERROR_ITER; | ||
| XRes = XTemp; | ||
| } | ||
|
|
||
| // A second version that does not require a payload -- use lambdas | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the new function. |
||
| Real64 SolveRoot2(const EnergyPlusData &state, | ||
| Real64 Eps, // required absolute accuracy | ||
| int maxIters, | ||
| int &SolFla, | ||
| const std::function<Real64(Real64)> &f, | ||
| Real64 X_0, // 1st bound of interval that contains the solution | ||
| Real64 X_1, // 2nd bound of interval that contains the solution | ||
| SolveRootStats &stats) | ||
| { | ||
| // SUBROUTINE INFORMATION: | ||
| // AUTHOR Amir Roth | ||
| // DATE WRITTEN Nov. 2025 | ||
|
|
||
| // PURPOSE OF THIS SUBROUTINE: | ||
| // This is a wrapper to SolveRoot that iterates over all root finding algorithms to find the best one. | ||
|
|
||
| Real64 XRes; | ||
|
|
||
| // Save and restore "global" root finding algorithm | ||
| RootAlgo algoTemp = state.dataRootFinder->rootAlgo; | ||
| state.dataRootFinder->rootAlgo = stats.algo; | ||
|
|
||
| SolveRoot(state, Eps, maxIters, SolFla, XRes, f, X_0, X_1); | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At some point, the algortihm should just be made a parameter to this call, but that would have resulted in 200+ diffs. |
||
|
|
||
| state.dataRootFinder->rootAlgo = algoTemp; | ||
|
|
||
| if (SolFla > 0) { | ||
| stats.counts++; | ||
| stats.algoCounts[(int)stats.algo]++; | ||
| stats.algoIters[(int)stats.algo] += SolFla; | ||
|
|
||
| constexpr int TRIALS_PER_COUNT = 5; | ||
|
|
||
| // Trial period, cycle thru algorithms | ||
| if (stats.counts < TRIALS_PER_COUNT * (int)RootAlgo::Num) { | ||
| stats.algo = static_cast<RootAlgo>((int)stats.algo + 1); | ||
| if (stats.algo == RootAlgo::Num) { | ||
| stats.algo = RootAlgo::RegulaFalsi; | ||
| } | ||
|
|
||
| // Choose base algorithm, i.e., fewest total iterations | ||
| } else if (stats.counts == TRIALS_PER_COUNT * (int)RootAlgo::Num) { | ||
| int minIters = maxIters * TRIALS_PER_COUNT; | ||
| stats.algo = RootAlgo::Invalid; | ||
| for (int i = 0; i < (int)RootAlgo::Num; ++i) { | ||
| if (stats.algoIters[i] < minIters) { | ||
| stats.algo = static_cast<RootAlgo>(i); | ||
| minIters = stats.algoIters[i]; | ||
| } | ||
| } | ||
|
|
||
| // Have chosen an algorithm, stats.algo should be it | ||
| } else { | ||
| } | ||
| } | ||
|
|
||
| return XRes; | ||
| } | ||
|
|
||
| void MovingAvg(Array1D<Real64> &DataIn, int const NumItemsInAvg) | ||
| { | ||
| if (NumItemsInAvg <= 1) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -51,7 +51,8 @@ | |
| #include <EnergyPlus/Data/BaseData.hh> | ||
|
|
||
| namespace EnergyPlus { | ||
| enum class HVACSystemRootSolverAlgorithm : int | ||
|
|
||
| enum class RootAlgo : int | ||
| { | ||
| Invalid = -1, | ||
| RegulaFalsi, | ||
|
|
@@ -63,18 +64,16 @@ enum class HVACSystemRootSolverAlgorithm : int | |
| Num | ||
| }; | ||
|
|
||
| static constexpr std::array<std::string_view, static_cast<int>(HVACSystemRootSolverAlgorithm::Num)> HVACSystemRootSolverAlgorithmUC = { | ||
| static constexpr std::array<std::string_view, (int)RootAlgo::Num> rootAlgoNamesUC = { | ||
| "REGULAFALSI", "BISECTION", "REGULAFALSITHENBISECTION", "BISECTIONTHENREGULAFALSI", "ALTERNATION", "SHORTBISECTIONTHENREGULAFALSI"}; | ||
|
|
||
| struct HVACSystemRootFindingAlgorithm | ||
| { | ||
| std::string Algorithm = {}; // Choice of algorithm | ||
| int NumOfIter = 5; // Number of Iteration Before Algorithm Switch | ||
| HVACSystemRootSolverAlgorithm HVACSystemRootSolverMethod = HVACSystemRootSolverAlgorithm::RegulaFalsi; | ||
| }; | ||
| struct RootFindingData : BaseGlobalStruct | ||
| { | ||
| HVACSystemRootFindingAlgorithm HVACSystemRootFinding; | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need for this additional object when |
||
| std::string Algorithm = {}; // Choice of algorithm | ||
|
|
||
| int NumOfIter = 5; // Number of Iteration Before Algorith Switch | ||
| RootAlgo rootAlgo = RootAlgo::RegulaFalsi; | ||
|
|
||
| void init_constant_state([[maybe_unused]] EnergyPlusData &state) override | ||
| { | ||
| } | ||
|
|
@@ -85,7 +84,6 @@ struct RootFindingData : BaseGlobalStruct | |
|
|
||
| void clear_state() override | ||
| { | ||
| this->HVACSystemRootFinding = {}; | ||
| } | ||
| }; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added these
constexprdefinitions as well since nobody can be expected to remember what-1and-2stand for.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think I'll ever forget