LCOV - code coverage report
Current view: top level - EnergyPlus - RootFinder.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 387 627 61.7 %
Date: 2023-01-17 19:17:23 Functions: 27 33 81.8 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
       2             : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3             : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4             : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5             : // contributors. All rights reserved.
       6             : //
       7             : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8             : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9             : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10             : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11             : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12             : //
      13             : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14             : // provided that the following conditions are met:
      15             : //
      16             : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17             : //     conditions and the following disclaimer.
      18             : //
      19             : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20             : //     conditions and the following disclaimer in the documentation and/or other materials
      21             : //     provided with the distribution.
      22             : //
      23             : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24             : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25             : //     used to endorse or promote products derived from this software without specific prior
      26             : //     written permission.
      27             : //
      28             : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29             : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30             : //     reference solely to the software portion of its product, Licensee must refer to the
      31             : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32             : //     obtained under this License and may not use a different name for the software. Except as
      33             : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34             : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35             : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36             : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37             : //
      38             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39             : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40             : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41             : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42             : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43             : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45             : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46             : // POSSIBILITY OF SUCH DAMAGE.
      47             : 
      48             : // C++ Headers
      49             : #include <cmath>
      50             : 
      51             : // ObjexxFCL Headers
      52             : #include <ObjexxFCL/Fmath.hh>
      53             : 
      54             : // EnergyPlus Headers
      55             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      56             : #include <EnergyPlus/DataPrecisionGlobals.hh>
      57             : #include <EnergyPlus/General.hh>
      58             : #include <EnergyPlus/RootFinder.hh>
      59             : #include <EnergyPlus/UtilityRoutines.hh>
      60             : 
      61             : namespace EnergyPlus::RootFinder {
      62             : // Module containing the derivative-free, root finder routines for smooth,
      63             : // "mostly" monotonic functions in one variable.
      64             : // The algorithm is guaranteed to find the root if:
      65             : // - it is bracketed between min/max bounds
      66             : // - there is an odd number of roots between the min/max bounds
      67             : // Note that there is an even number of roots between the min/max bounds then it is possible
      68             : // that the algorithm will terminate with a min or max constrained solution instead of the
      69             : // actual root.
      70             : 
      71             : // MODULE INFORMATION:
      72             : //       AUTHOR         Dimitri Curtil (LBNL)
      73             : //       DATE WRITTEN   February 2006
      74             : //       MODIFIED       na
      75             : //       RE-ENGINEERED  na
      76             : 
      77             : // PURPOSE OF THIS MODULE:
      78             : // To encapsulate the data and algorithms required to
      79             : // find the root of a 1-dimensional function F(X) = Y .
      80             : // At any moment during the solution process, the following condition is satisfied:
      81             : // - For an overall increasing function F(X):
      82             : //  MinPoint%X <= LowerPoint%X <= CurrentPoint%X <= UpperPoint%X <= MaxPoint%X
      83             : //  MinPoint%Y <= LowerPoint%Y <= CurrentPoint%Y <= UpperPoint%Y <= MaxPoint%Y
      84             : // - For an overall decreasing function F(X):
      85             : //  MinPoint%X <= LowerPoint%X <= CurrentPoint%X <= UpperPoint%X <= MaxPoint%X
      86             : //  MinPoint%Y >= LowerPoint%Y >= CurrentPoint%Y >= UpperPoint%Y >= MaxPoint%Y
      87             : // Requirements for function F():
      88             : // - smooth, continuous, deterministic function
      89             : // - root XRoot bracketed within the min and max bounds, referred to as XMin, XMax
      90             : // - XMin and XMax must remain constant during iterations
      91             : // - If F(X) is increasing, set action to iSlopeIncreasing
      92             : //   This implies that if X1 < X2, then F(X1) < F(X2) must be satisfied.
      93             : // - If F(X) is decreasing, set action to iSlopeDecreasing
      94             : //   This implies that if X1 < X2, then F(X1) > F(X2) must be satisfied.
      95             : // Note that the residual function is allowed to be non-monotonic between the min and max
      96             : // points as long as the slope specification is satisfied at the min and max points.
      97             : // Unconstrained convergence conditions:
      98             : // - ABS(F(XRoot)) <= ATolY
      99             : // - ABS(X2-X1)    <= TolX * (ABS(X2)+ABS(X1))/2 + ATolX
     100             : // Constrained convergence conditions:
     101             : // For iSlopeIncreasing action:
     102             : //   - YMin >= 0
     103             : //   - YMax <= 0
     104             : // For iSlopeDecreasing action:
     105             : //   - YMin <= 0
     106             : //   - YMax >= 0
     107             : 
     108             : // METHODOLOGY EMPLOYED:
     109             : // Implements an hybrid solution method consisting of:
     110             : // - bisection method (aka interval halving)
     111             : // - false position method (aka regula falsi)
     112             : // - secant method
     113             : // - Brent's method (inverse quadratic interpolation)
     114             : // with safeguards against:
     115             : // - out-of-range error
     116             : // - singularity (i.e., locally singular Jacobian)
     117             : // - bad slope
     118             : // - round-off error
     119             : // Typical usage of the root finder, assuming that :
     120             : // - the function is called MyFunc()
     121             : // - the function is strictly increasing between the min and max bounds
     122             : // - the root is bracketed between XMin=0 and XMax=1
     123             : // - the function is defined with the prototype real FUNCTION MyFunc( X )
     124             : // - the solution method to use is the Brent's method
     125             : // - the absolute tolerance for Y=MyFunc(X) is ATolY=1.0E-4
     126             : // As a safeguard the iterative process stops after 50 iterations if the root has not been
     127             : // located within the specified tolerance yet.
     128             : // <BEGIN CODE SNIPPET>
     129             : // TYPE(RootFinderDataType)  :: RF
     130             : // INTEGER                   :: IterationCount
     131             : // REAL(r64)                 :: X, Y
     132             : // LOGICAL                   :: IsDoneFlag
     133             : // CALL SetupRootFinder(   &
     134             : //   RF,                   & ! RootFinderData
     135             : //   iSlopeIncreasing,     & ! SlopeType
     136             : //   iMethodBrent,         & ! MethodType
     137             : //   1.0d-6,               & ! TolX
     138             : //   1.0d-6,               & ! ATolX
     139             : //   1.0d-4                & ! ATolY
     140             : // )
     141             : // CALL InitializeRootFinder(   &
     142             : //   RF,                   & ! RootFinderData
     143             : //   0.0d0,                & ! XMin
     144             : //   1.0d0                 & ! XMax
     145             : // )
     146             : // IterationCount = 0
     147             : // IsDoneFlag = .FALSE.
     148             : // RF%XCandidate = 0.1d0 ! Sets X to initial value XInit
     149             : // DO WHILE ( .NOT.IsDoneFlag )
     150             : //   IterationCount = IterationCount+1
     151             : //   IF ( IterationCount>50 ) THEN
     152             : //     WRITE(*,*) 'Error: Too many iterations..."
     153             : //     EXIT
     154             : //   END IF
     155             : //   ! Evaluate function with new root candidate
     156             : //   X = RF%XCandidate
     157             : //   Y = MyFunc( X )
     158             : //   ! Update root finder data with new iterate
     159             : //   CALL IterateRootFinder( RF, X, Y, IsDoneFlag )
     160             : // END DO
     161             : // ! Write root finder status description to standard output
     162             : // CALL WriteRootFinderStatus( 6, RF )
     163             : // <END CODE SNIPPET>
     164             : 
     165             : // REFERENCES:
     166             : // "Numerical Recipes in FORTRAN", Chapter 9 "Root Finding and Nonlinear Sets of Equations", pp.340-352
     167             : // Used for formulas, but not for code.
     168             : 
     169             : // Using/Aliasing
     170             : using namespace DataRootFinder;
     171             : 
     172      120779 : void SetupRootFinder(EnergyPlusData &state,
     173             :                      RootFinderDataType &RootFinderData,                // Data used by root finding algorithm
     174             :                      DataRootFinder::Slope const SlopeType,             // Either Slope::Increasing or Slope::Decreasing
     175             :                      DataRootFinder::RootFinderMethod const MethodType, // Any of the iMethod<name> code but iMethodNone
     176             :                      Real64 const TolX,                                 // Relative tolerance for X variables
     177             :                      Real64 const ATolX,                                // Absolute tolerance for X variables
     178             :                      Real64 const ATolY                                 // Absolute tolerance for Y variables
     179             : )
     180             : {
     181             : 
     182             :     // SUBROUTINE INFORMATION:
     183             :     //       AUTHOR         Dimitri Curtil (LBNL)
     184             :     //       DATE WRITTEN   February 2006
     185             :     //       MODIFIED
     186             :     //       RE-ENGINEERED  na
     187             : 
     188             :     // PURPOSE OF THIS SUBROUTINE:
     189             :     // This subroutine loads the numerical controls for the root finder.
     190             : 
     191             :     // Load assumed action for underlying function F(X)
     192      120779 :     if (SlopeType != DataRootFinder::Slope::Increasing && SlopeType != DataRootFinder::Slope::Decreasing) {
     193           0 :         ShowSevereError(state, "SetupRootFinder: Invalid function slope specification. Valid choices are:");
     194           0 :         ShowContinueError(state, format("SetupRootFinder: Slope::Increasing={}", DataRootFinder::Slope::Increasing));
     195           0 :         ShowContinueError(state, format("SetupRootFinder: Slope::Decreasing={}", DataRootFinder::Slope::Decreasing));
     196           0 :         ShowFatalError(state, "SetupRootFinder: Preceding error causes program termination.");
     197             :     }
     198      120779 :     RootFinderData.Controls.SlopeType = SlopeType;
     199             : 
     200             :     // Load solution method
     201      120779 :     if (MethodType != RootFinderMethod::Bisection && MethodType != RootFinderMethod::FalsePosition && MethodType != RootFinderMethod::Secant &&
     202             :         MethodType != RootFinderMethod::Brent) {
     203             : 
     204           0 :         ShowSevereError(state, "SetupRootFinder: Invalid solution method specification. Valid choices are:");
     205           0 :         ShowContinueError(state, format("SetupRootFinder: iMethodBisection={}", RootFinderMethod::Bisection));
     206           0 :         ShowContinueError(state, format("SetupRootFinder: iMethodFalsePosition={}", RootFinderMethod::FalsePosition));
     207           0 :         ShowContinueError(state, format("SetupRootFinder: iMethodSecant={}", RootFinderMethod::Secant));
     208           0 :         ShowContinueError(state, format("SetupRootFinder: iMethodBrent={}", RootFinderMethod::Brent));
     209           0 :         ShowFatalError(state, "SetupRootFinder: Preceding error causes program termination.");
     210             :     }
     211      120779 :     RootFinderData.Controls.MethodType = MethodType;
     212             : 
     213             :     // Load relative tolerance parameter for X variables
     214      120779 :     if (TolX < 0.0) {
     215           0 :         ShowFatalError(state, "SetupRootFinder: Invalid tolerance specification for X variables. TolX >= 0");
     216             :     }
     217      120779 :     RootFinderData.Controls.TolX = TolX;
     218             : 
     219             :     // Load absolute tolerance parameter for X variables
     220      120779 :     if (ATolX < 0.0) {
     221           0 :         ShowFatalError(state, "SetupRootFinder: Invalid absolute tolerance specification for X variables. ATolX >= 0");
     222             :     }
     223      120779 :     RootFinderData.Controls.ATolX = ATolX;
     224             : 
     225             :     // Load absolute tolerance parameter for Y variables
     226      120779 :     if (ATolY < 0.0) {
     227           0 :         ShowFatalError(state, "SetupRootFinder: Invalid absolute tolerance specification for Y variables. ATolY >= 0");
     228             :     }
     229      120779 :     RootFinderData.Controls.ATolY = ATolY;
     230             : 
     231             :     // Reset internal data for root finder with fictive min and max values
     232      120779 :     ResetRootFinder(RootFinderData, DataPrecisionGlobals::constant_zero, DataPrecisionGlobals::constant_zero);
     233      120779 : }
     234             : 
     235     8766996 : void ResetRootFinder(RootFinderDataType &RootFinderData, // Data used by root finding algorithm
     236             :                      Real64 const XMin,                  // Minimum X value allowed
     237             :                      Real64 const XMax                   // Maximum X value allowed
     238             : )
     239             : {
     240             : 
     241             :     // SUBROUTINE INFORMATION:
     242             :     //       AUTHOR         Dimitri Curtil (LBNL)
     243             :     //       DATE WRITTEN   February 2006
     244             :     //       MODIFIED
     245             :     //       RE-ENGINEERED  na
     246             : 
     247             :     // PURPOSE OF THIS SUBROUTINE:
     248             :     // This subroutine initializes the data for the root finder.
     249             : 
     250             :     // Reset min point
     251     8766996 :     RootFinderData.MinPoint.X = XMin;
     252     8766996 :     RootFinderData.MinPoint.Y = 0.0;
     253     8766996 :     RootFinderData.MinPoint.DefinedFlag = false;
     254             : 
     255             :     // Reset max point
     256     8766996 :     RootFinderData.MaxPoint.X = XMax;
     257     8766996 :     RootFinderData.MaxPoint.Y = 0.0;
     258     8766996 :     RootFinderData.MaxPoint.DefinedFlag = false;
     259             : 
     260             :     // Reset lower point
     261     8766996 :     RootFinderData.LowerPoint.X = 0.0;
     262     8766996 :     RootFinderData.LowerPoint.Y = 0.0;
     263     8766996 :     RootFinderData.LowerPoint.DefinedFlag = false;
     264             : 
     265             :     // Reset upper point
     266     8766996 :     RootFinderData.UpperPoint.X = 0.0;
     267     8766996 :     RootFinderData.UpperPoint.Y = 0.0;
     268     8766996 :     RootFinderData.UpperPoint.DefinedFlag = false;
     269             : 
     270             :     // Reset previous point
     271     8766996 :     RootFinderData.CurrentPoint.X = 0.0;
     272     8766996 :     RootFinderData.CurrentPoint.Y = 0.0;
     273     8766996 :     RootFinderData.CurrentPoint.DefinedFlag = false;
     274             : 
     275             :     // Reset iterate history with last 3 best points
     276     8766996 :     RootFinderData.NumHistory = 0;
     277    35067984 :     for (auto &e : RootFinderData.History) {
     278    26300988 :         e.X = e.Y = 0.0;
     279    26300988 :         e.DefinedFlag = false;
     280             :     }
     281             : 
     282             :     // Reset increments over successive iterations
     283     8766996 :     RootFinderData.Increment.X = 0.0;
     284     8766996 :     RootFinderData.Increment.Y = 0.0;
     285     8766996 :     RootFinderData.Increment.DefinedFlag = false;
     286             : 
     287     8766996 :     RootFinderData.XCandidate = 0.0;
     288             : 
     289             :     // Reset default state
     290     8766996 :     RootFinderData.StatusFlag = RootFinderStatus::None;
     291     8766996 :     RootFinderData.CurrentMethodType = RootFinderMethod::None;
     292     8766996 :     RootFinderData.ConvergenceRate = -1.0;
     293     8766996 : }
     294             : 
     295     8646217 : void InitializeRootFinder(EnergyPlusData &state,
     296             :                           RootFinderDataType &RootFinderData, // Data used by root finding algorithm
     297             :                           Real64 const XMin,                  // Minimum X value allowed
     298             :                           Real64 const XMax                   // Maximum X value allowed
     299             : )
     300             : {
     301             : 
     302             :     // SUBROUTINE INFORMATION:
     303             :     //       AUTHOR         Dimitri Curtil (LBNL)
     304             :     //       DATE WRITTEN   February 2006
     305             :     //       MODIFIED
     306             :     //       RE-ENGINEERED  na
     307             : 
     308             :     // PURPOSE OF THIS SUBROUTINE:
     309             :     // This subroutine initializes the min and max for the root finder before
     310             :     // finding a new root.
     311             : 
     312             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     313             :     Real64 SavedXCandidate;
     314             :     Real64 XMinReset;
     315             : 
     316     8646217 :     XMinReset = XMin;
     317     8646217 :     if (XMin > XMax) {
     318           0 :         if (XMax == 0.0) {
     319           0 :             XMinReset = XMax;
     320             :         } else {
     321           0 :             ShowFatalError(state, format("InitializeRootFinder: Invalid min/max bounds XMin={:.6T} must be smaller than XMax={:.6T}", XMin, XMax));
     322             :         }
     323             :     }
     324             : 
     325             :     // First save current candidate value before it is overriden in ResetRootFinder()
     326     8646217 :     SavedXCandidate = RootFinderData.XCandidate;
     327             : 
     328             :     // Reset internal data for root finder with actual min and max values
     329             :     // NOTE: This resets the value of RootFinderData%XCandidate to zero
     330     8646217 :     ResetRootFinder(RootFinderData, XMinReset, XMax);
     331             : 
     332             :     // Enforce min/max constraints on previous candidate if available
     333             :     // NOTE: If XMin == XMax then this forces the value of XCandidateto the desired solution
     334     8646217 :     RootFinderData.XCandidate = min(RootFinderData.MaxPoint.X, max(SavedXCandidate, RootFinderData.MinPoint.X));
     335     8646217 : }
     336             : 
     337    19153079 : void IterateRootFinder(EnergyPlusData &state,
     338             :                        RootFinderDataType &RootFinderData, // Data used by root finding algorithm
     339             :                        Real64 const X,                     // X value of current iterate
     340             :                        Real64 const Y,                     // Y value of current iterate
     341             :                        bool &IsDoneFlag                    // If TRUE indicates that the iteration should be stopped
     342             : )
     343             : {
     344             : 
     345             :     // SUBROUTINE INFORMATION:
     346             :     //       AUTHOR         Dimitri Curtil (LBNL)
     347             :     //       DATE WRITTEN   March 2006
     348             :     //       MODIFIED
     349             :     //       RE-ENGINEERED  na
     350             : 
     351             :     // PURPOSE OF THIS SUBROUTINE:
     352             :     // This subroutine is the workhorse of the root finder framework.
     353             :     // It should be invoked with every new candidate (X,Y) until
     354             :     // convergence is achieved or abnormal termination is detected.
     355             :     // The subroutine performs the following tasks:
     356             :     // - it checks for convergence
     357             :     // - it updates the internal data with the current iterate (X,Y)
     358             :     // - it computes a new root candidate if not converged yet.
     359             :     // Sets IsDoneFlag to FALSE when iteration should continue with the new candidate value.
     360             :     // Sets IsDoneFlag to TRUE  when iteration should be stopped because convergence has been achieved
     361             :     // or because of a fatal error.
     362             :     // Note that only upon normal termination (iStatusOK<...> codes)
     363             :     // will the XCandidate value contain the root.
     364             :     // If the root has not been located yet the XCandidate value contains
     365             :     // the next candidate root to try.
     366             :     // Status                          IsDoneFlag          XCandidate
     367             :     // ========================================================================
     368             :     // iStatusErrorRange               TRUE                na
     369             :     // iStatusErrorSingular            TRUE                na
     370             :     // iStatusErrorSlope               TRUE                na
     371             :     // iStatusErrorBracket             TRUE                na
     372             :     // ------------------------------------------------------------------------
     373             :     // iStatusOKMin                    TRUE                MinPoint%X
     374             :     // iStatusOKMax                    TRUE                MaxPoint%X
     375             :     // iStatusOK                       TRUE                X
     376             :     // iStatusOKRoundOff               TRUE                X
     377             :     // ------------------------------------------------------------------------
     378             :     // iStatusNone                     FALSE               AdvanceRootFinder()
     379             :     // iStatusWarningNonMonotonic      FALSE               AdvanceRootFinder()
     380             :     // iStatusWarningSingular          FALSE               AdvanceRootFinder()
     381             : 
     382             :     // METHODOLOGY EMPLOYED:
     383             :     // The methodology reflects the same approach implemented in the subroutine CalcSimpleController()
     384             :     // whereby the iteration was exited by checking the following conditions in this specified
     385             :     // sequence:
     386             :     //   1. Check for singular function so that YMin /= YMax
     387             :     //   2. Check for slope condition for the residual function
     388             :     //      - increasing: YMin < YMax
     389             :     //      - decreasing: YMin > YMax
     390             :     //   3. Check for min constraint
     391             :     //      - increasing: YMin <= 0
     392             :     //      - decreasing: YMin >= 0
     393             :     //   4. Check for max constraint
     394             :     //      - increasing: YMax > 0
     395             :     //      - decreasing: YMax < 0
     396             :     //   5. Check unconstrained convergence
     397             :     // Note that the slope condition was not explicitly checked in the original implementation
     398             :     // in CalcSimpleController().
     399             :     // Finally, we also check the X increments between successive iterations to detect possible
     400             :     // cases whereby the allowed precision in the X space limits the precision attainable in
     401             :     // the Y space. This check is implemented in:
     402             :     // - CheckIncrementRoundOff()
     403             :     // - CheckBracketRoundOff()
     404             : 
     405             :     // Reset status flag
     406    19153079 :     RootFinderData.StatusFlag = RootFinderStatus::None;
     407             : 
     408             :     // Check that MinPoint%X <= X <= MaxPoint%X
     409    19153079 :     if (!CheckMinMaxRange(RootFinderData, X)) {
     410           0 :         RootFinderData.StatusFlag = RootFinderStatus::ErrorRange;
     411             : 
     412             :         // Fatal error: No need to continue iterating
     413           0 :         IsDoneFlag = true;
     414           0 :         return;
     415             :     }
     416             : 
     417             :     // Update min/max support points with current iterate
     418    19153079 :     UpdateMinMax(RootFinderData, X, Y);
     419             : 
     420             :     //----------------------------------------------------------------------------
     421             :     // Check "global" singularity and bad slope conditions between min and
     422             :     // max points
     423             :     //----------------------------------------------------------------------------
     424             : 
     425             :     // NOTE: Performed before checking min and max constraints to mimic original implementation
     426             :     //       in ManagerControllers()
     427    19153079 :     if (RootFinderData.MinPoint.DefinedFlag && RootFinderData.MaxPoint.DefinedFlag) {
     428             : 
     429             :         // Check that min and max points are distinct
     430     2122365 :         if (RootFinderData.MinPoint.X == RootFinderData.MaxPoint.X) {
     431      439687 :             RootFinderData.StatusFlag = RootFinderStatus::OKMin;
     432      439687 :             RootFinderData.XCandidate = RootFinderData.MinPoint.X;
     433             : 
     434             :             // Solution found: No need to continue iterating
     435      439687 :             IsDoneFlag = true;
     436      439687 :             return;
     437             :         }
     438             : 
     439     1682678 :         if (RootFinderData.MinPoint.DefinedFlag) {
     440     1682678 :             if (CheckMinConstraint(state, RootFinderData)) {
     441           0 :                 RootFinderData.StatusFlag = RootFinderStatus::OKMin;
     442           0 :                 RootFinderData.XCandidate = RootFinderData.MinPoint.X;
     443             : 
     444             :                 // Solution found: No need to continue iterating
     445           0 :                 IsDoneFlag = true;
     446           0 :                 return;
     447             :             }
     448             :         }
     449             : 
     450             :         // Check singularity condition between min and max points
     451     1682678 :         if (!CheckNonSingularity(RootFinderData)) {
     452      385780 :             RootFinderData.StatusFlag = RootFinderStatus::ErrorSingular;
     453             : 
     454             :             // Fatal error: No need to continue iterating
     455      385780 :             IsDoneFlag = true;
     456      385780 :             return;
     457             :         }
     458             : 
     459             :         // Check slope condition between min and max points
     460     1296898 :         if (!CheckSlope(state, RootFinderData)) {
     461         662 :             RootFinderData.StatusFlag = RootFinderStatus::ErrorSlope;
     462             : 
     463             :             // Fatal error: No need to continue iterating
     464         662 :             IsDoneFlag = true;
     465         662 :             return;
     466             :         }
     467             :     }
     468             : 
     469             :     //----------------------------------------------------------------------------
     470             :     // Check that F(X) is not min or max constrained
     471             :     //----------------------------------------------------------------------------
     472             : 
     473             :     // Check min constraint before max constraint to mimic original implementation
     474             :     // in ManagerControllers()
     475    18326950 :     if (RootFinderData.MinPoint.DefinedFlag) {
     476    18310259 :         if (CheckMinConstraint(state, RootFinderData)) {
     477     3499387 :             RootFinderData.StatusFlag = RootFinderStatus::OKMin;
     478     3499387 :             RootFinderData.XCandidate = RootFinderData.MinPoint.X;
     479             : 
     480             :             // Solution found: No need to continue iterating
     481     3499387 :             IsDoneFlag = true;
     482     3499387 :             return;
     483             :         }
     484             :     }
     485             : 
     486             :     // Min point should always be evaluated first to ensure that we return with the min
     487             :     // consrained solution even in cases where the residual function has inconsistent slope.
     488             :     // TODO: Force to evaluate min point before exiting with max constrained solution
     489             :     //       in order to be able to detect singularity and bad slope conditions.
     490    14827563 :     if (RootFinderData.MaxPoint.DefinedFlag) {
     491     1299351 :         if (CheckMaxConstraint(state, RootFinderData)) {
     492             : 
     493      453428 :             RootFinderData.StatusFlag = RootFinderStatus::OKMax;
     494      453428 :             RootFinderData.XCandidate = RootFinderData.MaxPoint.X;
     495             : 
     496             :             // Solution found: No need to continue iterating
     497      453428 :             IsDoneFlag = true;
     498      453428 :             return;
     499             :         }
     500             :     }
     501             : 
     502             :     //----------------------------------------------------------------------------
     503             :     // Check convergence of current iterate
     504             :     //----------------------------------------------------------------------------
     505             : 
     506             :     // Check unconstrained convergence after we are sure that the candidate X value lies
     507             :     // within the allowed min/max range
     508    14374135 :     if (CheckRootFinderConvergence(RootFinderData, Y)) {
     509     3863597 :         RootFinderData.StatusFlag = RootFinderStatus::OK;
     510     3863597 :         RootFinderData.XCandidate = X;
     511             : 
     512             :         // Update root finder internal data with current iterate (X,Y)
     513     3863597 :         UpdateRootFinder(state, RootFinderData, X, Y);
     514             : 
     515             :         // Solution found: No need to continue iterating
     516     3863597 :         IsDoneFlag = true;
     517     3863597 :         return;
     518             :     }
     519             : 
     520             :     // Check last as this was not done in the original implementation
     521             :     // Essentially we stop the iteration if:
     522             :     // - the distance between the lower and upper bounds is smaller than the user-specified
     523             :     //   tolerance for the X variables. (USING brackets from previous iteration)
     524    10510538 :     if (CheckBracketRoundOff(RootFinderData)) {
     525        3646 :         RootFinderData.StatusFlag = RootFinderStatus::OKRoundOff;
     526             : 
     527             :         // Solution found: No need to continue iterating
     528        3646 :         IsDoneFlag = true;
     529        3646 :         return;
     530             :     }
     531             : 
     532             :     //----------------------------------------------------------------------------
     533             :     // If the current iterate lies within the current lower and upper brackets,
     534             :     // proceed with normal processing to identify the next root candidate:
     535             :     // - update lower/upper bracket with current iterate
     536             :     // - update history
     537             :     // - update increments across successive iterations
     538             :     // - update current point
     539             :     // - compute next candidate (see AdvanceRootFinder() ).
     540             :     //----------------------------------------------------------------------------
     541             : 
     542             :     // Check that current iterate is within the current lower and upper points
     543    10506892 :     if (!CheckLowerUpperBracket(RootFinderData, X)) {
     544           0 :         RootFinderData.StatusFlag = RootFinderStatus::ErrorBracket;
     545             : 
     546             :         // Fatal error: No need to continue iterating
     547           0 :         IsDoneFlag = true;
     548           0 :         return;
     549             :     }
     550             : 
     551             :     // Update root finder internal data with current iterate (X,Y)
     552    10506892 :     UpdateRootFinder(state, RootFinderData, X, Y);
     553             : 
     554             :     // Compute new root candidate and store value in in RootFinderData%XCandidate
     555             :     // - First attempt to bracket root within lower and upper points
     556             :     // - Then use whatever requested solution method in SetupRootFinder() to
     557             :     //   compute the next candidate.
     558    10506892 :     AdvanceRootFinder(state, RootFinderData);
     559             : 
     560             :     // Indicates that we should continue iterating with new candidate
     561    10506892 :     IsDoneFlag = false;
     562             : }
     563             : 
     564           0 : RootFinderStatus CheckInternalConsistency(EnergyPlusData &state, RootFinderDataType const &RootFinderData) // Data used by root finding algorithm
     565             : {
     566             :     // FUNCTION INFORMATION:
     567             :     //       AUTHOR         Dimitri Curtil (LBNL)
     568             :     //       DATE WRITTEN   March 2006
     569             :     //       MODIFIED
     570             :     //       RE-ENGINEERED  na
     571             : 
     572             :     // PURPOSE OF THIS FUNCTION:
     573             :     // This function checks whether the lower and upper points (if defined)
     574             :     // determine a consistent interval bracketting the root.
     575             :     // Returns the status code accordingly.
     576             :     // This function does not modify the argument RooFinderData.
     577             :     // Only used internally for debugging.
     578             : 
     579             :     // Return value
     580             :     RootFinderStatus CheckInternalConsistency;
     581             : 
     582             :     // Default initialization
     583           0 :     CheckInternalConsistency = RootFinderStatus::None;
     584             : 
     585             :     // Internal consistency check involving both support points
     586           0 :     if (RootFinderData.LowerPoint.DefinedFlag && RootFinderData.UpperPoint.DefinedFlag) {
     587             : 
     588             :         // Check that the existing lower and upper points do bracket the root
     589           0 :         if (RootFinderData.LowerPoint.X > RootFinderData.UpperPoint.X) {
     590           0 :             CheckInternalConsistency = RootFinderStatus::ErrorRange;
     591           0 :             return CheckInternalConsistency;
     592             :         }
     593             : 
     594             :         // Check for non-monotonicity between the existing lower and upper points
     595           0 :         switch (RootFinderData.Controls.SlopeType) {
     596           0 :         case DataRootFinder::Slope::Increasing: {
     597             :             // Y-value of lower point must be strictly smaller than Y-value of upper point
     598           0 :             if (RootFinderData.LowerPoint.Y > RootFinderData.UpperPoint.Y) {
     599           0 :                 CheckInternalConsistency = RootFinderStatus::WarningNonMonotonic;
     600           0 :                 return CheckInternalConsistency;
     601             :             }
     602           0 :         } break;
     603           0 :         case DataRootFinder::Slope::Decreasing: {
     604             :             // Y-value of lower point must be strictly larger than Y-value of upper point
     605           0 :             if (RootFinderData.LowerPoint.Y < RootFinderData.UpperPoint.Y) {
     606           0 :                 CheckInternalConsistency = RootFinderStatus::WarningNonMonotonic;
     607           0 :                 return CheckInternalConsistency;
     608             :             }
     609           0 :         } break;
     610           0 :         default: {
     611             :             // Should never happen
     612           0 :             ShowSevereError(state, "CheckInternalConsistency: Invalid function slope specification. Valid choices are:");
     613           0 :             ShowContinueError(state, format("CheckInternalConsistency: Slope::Increasing={}", DataRootFinder::Slope::Increasing));
     614           0 :             ShowContinueError(state, format("CheckInternalConsistency: Slope::Decreasing={}", DataRootFinder::Slope::Decreasing));
     615           0 :             ShowFatalError(state, "CheckInternalConsistency: Preceding error causes program termination.");
     616           0 :         } break;
     617             :         }
     618             : 
     619             :         // Check for in singularity with respect to the existing lower and upper points
     620             :         // Only check if the lower and upper points are distinct!
     621           0 :         if (RootFinderData.UpperPoint.X > RootFinderData.LowerPoint.X) {
     622           0 :             if (RootFinderData.UpperPoint.Y == RootFinderData.LowerPoint.Y) {
     623           0 :                 CheckInternalConsistency = RootFinderStatus::ErrorSingular;
     624           0 :                 return CheckInternalConsistency;
     625             :             }
     626             :         }
     627             :     }
     628             : 
     629             :     // Check min constraint for min point if already defined
     630           0 :     if (RootFinderData.MinPoint.DefinedFlag) {
     631           0 :         switch (RootFinderData.Controls.SlopeType) {
     632           0 :         case DataRootFinder::Slope::Increasing: {
     633           0 :             if (RootFinderData.MinPoint.Y >= 0.0) {
     634           0 :                 CheckInternalConsistency = RootFinderStatus::OKMin;
     635           0 :                 return CheckInternalConsistency;
     636             :             }
     637           0 :         } break;
     638           0 :         case DataRootFinder::Slope::Decreasing: {
     639           0 :             if (RootFinderData.MinPoint.Y <= 0.0) {
     640           0 :                 CheckInternalConsistency = RootFinderStatus::OKMin;
     641           0 :                 return CheckInternalConsistency;
     642             :             }
     643           0 :         } break;
     644           0 :         default: {
     645             :             // Should never happen
     646           0 :             ShowSevereError(state, "CheckInternalConsistency: Invalid function slope specification. Valid choices are:");
     647           0 :             ShowContinueError(state, format("CheckInternalConsistency: Slope::Increasing={}", DataRootFinder::Slope::Increasing));
     648           0 :             ShowContinueError(state, format("CheckInternalConsistency: Slope::Decreasing={}", DataRootFinder::Slope::Decreasing));
     649           0 :             ShowFatalError(state, "CheckInternalConsistency: Preceding error causes program termination.");
     650           0 :         } break;
     651             :         }
     652             :     }
     653             : 
     654             :     // Check max constraint for max point if already defined
     655           0 :     if (RootFinderData.MaxPoint.DefinedFlag) {
     656           0 :         switch (RootFinderData.Controls.SlopeType) {
     657           0 :         case DataRootFinder::Slope::Increasing: {
     658           0 :             if (RootFinderData.MaxPoint.Y <= 0.0) {
     659           0 :                 CheckInternalConsistency = RootFinderStatus::OKMax;
     660           0 :                 return CheckInternalConsistency;
     661             :             }
     662           0 :         } break;
     663           0 :         case DataRootFinder::Slope::Decreasing: {
     664           0 :             if (RootFinderData.MaxPoint.Y >= 0.0) {
     665           0 :                 CheckInternalConsistency = RootFinderStatus::OKMax;
     666           0 :                 return CheckInternalConsistency;
     667             :             }
     668           0 :         } break;
     669           0 :         default: {
     670             :             // Should never happen
     671           0 :             ShowSevereError(state, "CheckInternalConsistency: Invalid function slope specification. Valid choices are:");
     672           0 :             ShowContinueError(state, format("CheckInternalConsistency: Slope::Increasing={}", DataRootFinder::Slope::Increasing));
     673           0 :             ShowContinueError(state, format("CheckInternalConsistency: Slope::Decreasing={}", DataRootFinder::Slope::Decreasing));
     674           0 :             ShowFatalError(state, "CheckInternalConsistency: Preceding error causes program termination.");
     675           0 :         } break;
     676             :         }
     677             :     }
     678             : 
     679           0 :     return CheckInternalConsistency;
     680             : }
     681             : 
     682    17068370 : bool CheckRootFinderCandidate(RootFinderDataType const &RootFinderData, // Data used by root finding algorithm
     683             :                               Real64 const X                            // X value for current iterate
     684             : )
     685             : {
     686             :     // FUNCTION INFORMATION:
     687             :     //       AUTHOR         Dimitri Curtil (LBNL)
     688             :     //       DATE WRITTEN   February 2006
     689             :     //       MODIFIED
     690             :     //       RE-ENGINEERED  na
     691             : 
     692             :     // PURPOSE OF THIS FUNCTION:
     693             :     // This function checks whether the root candidate X lies within the specified
     694             :     // min/max limits as well as within the current lower and upper brackets (if defined).
     695             :     // Returns TRUE if X value is a valid root candidate.
     696             :     // Returns FALSE otherwise.
     697             : 
     698             :     // Return value
     699             :     bool CheckRootFinderCandidate;
     700             : 
     701    17068370 :     if (CheckMinMaxRange(RootFinderData, X) && CheckLowerUpperBracket(RootFinderData, X)) {
     702    17064845 :         CheckRootFinderCandidate = true;
     703             :     } else {
     704        3525 :         CheckRootFinderCandidate = false;
     705             :     }
     706             : 
     707    17068370 :     return CheckRootFinderCandidate;
     708             : }
     709             : 
     710    36221449 : bool CheckMinMaxRange(RootFinderDataType const &RootFinderData, // Data used by root finding algorithm
     711             :                       Real64 const X                            // X value for current iterate
     712             : )
     713             : {
     714             :     // FUNCTION INFORMATION:
     715             :     //       AUTHOR         Dimitri Curtil (LBNL)
     716             :     //       DATE WRITTEN   February 2006
     717             :     //       MODIFIED       Brent Griffith (NREL) added DefinedFlag traps
     718             :     //       RE-ENGINEERED  na
     719             : 
     720             :     // PURPOSE OF THIS FUNCTION:
     721             :     // This function checks whether the current iterate X lies within the specified min/max limits
     722             :     // or not.
     723             :     // Returns TRUE if current iterate satisfies min/max constraints.
     724             :     // Returns FALSE if current iterate is out-of-range.
     725             : 
     726             :     // Return value
     727             :     bool CheckMinMaxRange;
     728             : 
     729    36221449 :     if (RootFinderData.MinPoint.DefinedFlag) {
     730    19034132 :         if (X < RootFinderData.MinPoint.X) {
     731        3313 :             CheckMinMaxRange = false;
     732        3313 :             return CheckMinMaxRange;
     733             :         }
     734             :     }
     735             : 
     736    36218136 :     if (RootFinderData.MaxPoint.DefinedFlag) {
     737     1258755 :         if (X > RootFinderData.MaxPoint.X) {
     738           1 :             CheckMinMaxRange = false;
     739           1 :             return CheckMinMaxRange;
     740             :         }
     741             :     }
     742             : 
     743    36218135 :     CheckMinMaxRange = true;
     744             : 
     745    36218135 :     return CheckMinMaxRange;
     746             : }
     747             : 
     748    27571948 : bool CheckLowerUpperBracket(RootFinderDataType const &RootFinderData, // Data used by root finding algorithm
     749             :                             Real64 const X                            // X value for current iterate
     750             : )
     751             : {
     752             :     // FUNCTION INFORMATION:
     753             :     //       AUTHOR         Dimitri Curtil (LBNL)
     754             :     //       DATE WRITTEN   February 2006
     755             :     //       MODIFIED       Brent Griffith, March 2010, changed to LowerPoint%X <= X <= UpperPoint%X
     756             :     //       RE-ENGINEERED  na
     757             : 
     758             :     // PURPOSE OF THIS FUNCTION:
     759             :     // This function checks whether the current iterate X lies within the current lower
     760             :     // and upper points or not (if defined):
     761             :     //   LowerPoint%X < X < UpperPoint%X
     762             :     // Returns TRUE if current iterate lies within the lower/upper bracket.
     763             :     // Returns FALSE otherwise.
     764             : 
     765             :     // Return value
     766             :     bool CheckLowerUpperBracket;
     767             : 
     768    27571948 :     if (RootFinderData.LowerPoint.DefinedFlag) {
     769    15119347 :         if (X < RootFinderData.LowerPoint.X) {
     770         108 :             CheckLowerUpperBracket = false;
     771         108 :             return CheckLowerUpperBracket;
     772             :         }
     773             :     }
     774             : 
     775    27571840 :     if (RootFinderData.UpperPoint.DefinedFlag) {
     776     7446725 :         if (X > RootFinderData.UpperPoint.X) {
     777         103 :             CheckLowerUpperBracket = false;
     778         103 :             return CheckLowerUpperBracket;
     779             :         }
     780             :     }
     781             : 
     782    27571737 :     CheckLowerUpperBracket = true;
     783             : 
     784    27571737 :     return CheckLowerUpperBracket;
     785             : }
     786             : 
     787     1296898 : bool CheckSlope(EnergyPlusData &state, RootFinderDataType const &RootFinderData) // Data used by root finding algorithm
     788             : {
     789             :     // FUNCTION INFORMATION:
     790             :     //       AUTHOR         Dimitri Curtil (LBNL)
     791             :     //       DATE WRITTEN   February 2006
     792             :     //       MODIFIED
     793             :     //       RE-ENGINEERED  na
     794             : 
     795             :     // PURPOSE OF THIS FUNCTION:
     796             :     // This function checks whether the current iterate (X,Y) satisfies the slope
     797             :     // requirement between the min and max points.
     798             :     // Returns FALSE if the slope requirement is NOT satisfied.
     799             :     // Returns TRUE if the slope requirement is satisfied.
     800             :     // PRECONDITION:
     801             :     // - Function assumes that both the min and max points are defined.
     802             :     // POSTCONDITION:
     803             :     // - RootFinderData is NOT changed by this function.
     804             : 
     805             :     // Return value
     806             :     bool CheckSlope;
     807             : 
     808             :     // Check that the slope requirement is respected at the min and max points
     809             :     // Note that the singularity check takes care of RootFinderData%MinPoint%Y == RootFinderData%MaxPoint%Y
     810             :     // therefore we use strict comparison operators < and >.
     811     1296898 :     switch (RootFinderData.Controls.SlopeType) {
     812      450360 :     case DataRootFinder::Slope::Increasing: {
     813      450360 :         if (RootFinderData.MinPoint.Y < RootFinderData.MaxPoint.Y) {
     814      450317 :             CheckSlope = true;
     815      450317 :             return CheckSlope;
     816             :         }
     817          43 :     } break;
     818      846538 :     case DataRootFinder::Slope::Decreasing: {
     819      846538 :         if (RootFinderData.MinPoint.Y > RootFinderData.MaxPoint.Y) {
     820      845919 :             CheckSlope = true;
     821      845919 :             return CheckSlope;
     822             :         }
     823         619 :     } break;
     824           0 :     default: {
     825             :         // Should never happen
     826           0 :         ShowSevereError(state, "CheckSlope: Invalid function slope specification. Valid choices are:");
     827           0 :         ShowContinueError(state, format("CheckSlope: Slope::Increasing={}", DataRootFinder::Slope::Increasing));
     828           0 :         ShowContinueError(state, format("CheckSlope: Slope::Decreasing={}", DataRootFinder::Slope::Decreasing));
     829           0 :         ShowFatalError(state, "CheckSlope: Preceding error causes program termination.");
     830           0 :     } break;
     831             :     }
     832             : 
     833         662 :     CheckSlope = false;
     834             : 
     835         662 :     return CheckSlope;
     836             : }
     837             : 
     838     1682678 : bool CheckNonSingularity(RootFinderDataType const &RootFinderData) // Data used by root finding algorithm
     839             : {
     840             :     // FUNCTION INFORMATION:
     841             :     //       AUTHOR         Dimitri Curtil (LBNL)
     842             :     //       DATE WRITTEN   February 2006
     843             :     //       MODIFIED
     844             :     //       RE-ENGINEERED  na
     845             : 
     846             :     // PURPOSE OF THIS FUNCTION:
     847             :     // This function checks whether the min and max points define a locally, singular
     848             :     // equation system. In a 1-dimensional system, "singularity" is detected if the
     849             :     // min and max points have the same y-values, thereby producing a zero slope
     850             :     // across the min/max range.
     851             :     // Returns TRUE if the function satisfies the non-singularity condition.
     852             :     // Returns FALSE otherwise (i.e., F(X) essentially displays a zero slope
     853             :     // between the min and max points) .
     854             :     // PRECONDITION:
     855             :     // - Function assumes that both the min and max points are defined.
     856             :     // POSTCONDITION:
     857             :     // - RootFinderData is NOT changed by this function.
     858             : 
     859             :     // Return value
     860             :     bool CheckNonSingularity;
     861             : 
     862             :     // FUNCTION PARAMETER DEFINITIONS:
     863             :     // Safety factor used to detect a singular residual function between the min and max
     864             :     // points.
     865             :     // NOTE: Requesting exactly the same value is obtained by setting SafetyFactor = 0.0
     866     1682678 :     Real64 constexpr SafetyFactor(0.1);
     867             : 
     868             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
     869             :     Real64 DeltaY; // Difference between min and max Y-values
     870             :     Real64 ATolY;  // Absolute tolerance used to detected equal min and max Y-values
     871             : 
     872             :     // Added this check based on an absolute tolerance test for y values to avoid incorrectly detecting
     873             :     // functions with bad slope due to numerical noise.
     874             :     // Typically, this takes care of situations where the controlled equipment in ManageControllers()
     875             :     // would be misdiagnosed as displaying the "wrong slope" instead of being treated as "singular"
     876             :     // (i.e. in inactive mode).
     877     1682678 :     DeltaY = std::abs(RootFinderData.MinPoint.Y - RootFinderData.MaxPoint.Y);
     878     1682678 :     ATolY = SafetyFactor * RootFinderData.Controls.ATolY;
     879             : 
     880     1682678 :     if (std::abs(DeltaY) <= ATolY) {
     881      385780 :         CheckNonSingularity = false;
     882             :     } else {
     883     1296898 :         CheckNonSingularity = true;
     884             :     }
     885             : 
     886     1682678 :     return CheckNonSingularity;
     887             : }
     888             : 
     889    19992937 : bool CheckMinConstraint(EnergyPlusData &state, RootFinderDataType const &RootFinderData) // Data used by root finding algorithm
     890             : {
     891             :     // FUNCTION INFORMATION:
     892             :     //       AUTHOR         Dimitri Curtil (LBNL)
     893             :     //       DATE WRITTEN   February 2006
     894             :     //       MODIFIED
     895             :     //       RE-ENGINEERED  na
     896             : 
     897             :     // PURPOSE OF THIS FUNCTION:
     898             :     // This function checks whether the min point satisfies the min constraint
     899             :     // condition or not.
     900             :     // PRECONDITION:
     901             :     // - Function assumes that the min point is defined.
     902             :     // POSTCONDITION:
     903             :     // - RootFinderData is NOT changed by this function.
     904             : 
     905             :     // Return value
     906             :     bool CheckMinConstraint;
     907             : 
     908    19992937 :     switch (RootFinderData.Controls.SlopeType) {
     909     6497208 :     case DataRootFinder::Slope::Increasing: {
     910     6497208 :         if (RootFinderData.MinPoint.Y >= 0.0) {
     911     2758973 :             CheckMinConstraint = true;
     912     2758973 :             return CheckMinConstraint;
     913             :         }
     914     3738235 :     } break;
     915    13495729 :     case DataRootFinder::Slope::Decreasing: {
     916    13495729 :         if (RootFinderData.MinPoint.Y <= 0.0) {
     917      740414 :             CheckMinConstraint = true;
     918      740414 :             return CheckMinConstraint;
     919             :         }
     920    12755315 :     } break;
     921           0 :     default: {
     922             :         // Should never happen
     923           0 :         ShowSevereError(state, "CheckMinConstraint: Invalid function slope specification. Valid choices are:");
     924           0 :         ShowContinueError(state, format("CheckMinConstraint: Slope::Increasing={}", DataRootFinder::Slope::Increasing));
     925           0 :         ShowContinueError(state, format("CheckMinConstraint: Slope::Decreasing={}", DataRootFinder::Slope::Decreasing));
     926           0 :         ShowFatalError(state, "CheckMinConstraint: Preceding error causes program termination.");
     927           0 :     } break;
     928             :     }
     929             : 
     930    16493550 :     CheckMinConstraint = false;
     931             : 
     932    16493550 :     return CheckMinConstraint;
     933             : }
     934             : 
     935     1299351 : bool CheckMaxConstraint(EnergyPlusData &state, RootFinderDataType const &RootFinderData) // Data used by root finding algorithm
     936             : {
     937             :     // FUNCTION INFORMATION:
     938             :     //       AUTHOR         Dimitri Curtil (LBNL)
     939             :     //       DATE WRITTEN   February 2006
     940             :     //       MODIFIED
     941             :     //       RE-ENGINEERED  na
     942             : 
     943             :     // PURPOSE OF THIS FUNCTION:
     944             :     // This function checks whether the max point satisfies the max constraint
     945             :     // condition or not.
     946             :     // PRECONDITION:
     947             :     // - Function assumes that the max point is defined.
     948             :     // POSTCONDITION:
     949             :     // - RootFinderData is NOT changed by this function.
     950             : 
     951             :     // Return value
     952             :     bool CheckMaxConstraint;
     953             : 
     954             :     // Check for max constrained convergence with respect to the new iterate (X,Y)
     955     1299351 :     switch (RootFinderData.Controls.SlopeType) {
     956      453432 :     case DataRootFinder::Slope::Increasing: {
     957      453432 :         if (RootFinderData.MaxPoint.Y <= 0.0) {
     958      139661 :             CheckMaxConstraint = true;
     959      139661 :             return CheckMaxConstraint;
     960             :         }
     961      313771 :     } break;
     962      845919 :     case DataRootFinder::Slope::Decreasing: {
     963      845919 :         if (RootFinderData.MaxPoint.Y >= 0.0) {
     964      313767 :             CheckMaxConstraint = true;
     965      313767 :             return CheckMaxConstraint;
     966             :         }
     967      532152 :     } break;
     968           0 :     default: {
     969             :         // Should never happen
     970           0 :         ShowSevereError(state, "CheckMaxConstraint: Invalid function slope specification. Valid choices are:");
     971           0 :         ShowContinueError(state, format("CheckMaxConstraint: Slope::Increasing={}", DataRootFinder::Slope::Increasing));
     972           0 :         ShowContinueError(state, format("CheckMaxConstraint: Slope::Decreasing={}", DataRootFinder::Slope::Decreasing));
     973           0 :         ShowFatalError(state, "CheckMaxConstraint: Preceding error causes program termination.");
     974           0 :     } break;
     975             :     }
     976             : 
     977      845923 :     CheckMaxConstraint = false;
     978             : 
     979      845923 :     return CheckMaxConstraint;
     980             : }
     981             : 
     982    21045825 : bool CheckRootFinderConvergence(RootFinderDataType const &RootFinderData, // Data used by root finding algorithm
     983             :                                 Real64 const Y                            // Y value for current iterate
     984             : )
     985             : {
     986             :     // FUNCTION INFORMATION:
     987             :     //       AUTHOR         Dimitri Curtil (LBNL)
     988             :     //       DATE WRITTEN   February 2006
     989             :     //       MODIFIED
     990             :     //       RE-ENGINEERED  na
     991             : 
     992             :     // PURPOSE OF THIS FUNCTION:
     993             :     // This function checks whether the current iterate (X,Y) satisfies the
     994             :     // unconstrained convergence criterion or not.
     995             : 
     996             :     // Return value
     997             :     bool CheckRootFinderConvergence;
     998             : 
     999             :     // Check for unconstrained convergence
    1000    21045825 :     if (std::abs(Y) <= RootFinderData.Controls.ATolY) {
    1001     8351263 :         CheckRootFinderConvergence = true;
    1002     8351263 :         return CheckRootFinderConvergence;
    1003             :     }
    1004             : 
    1005    12694562 :     CheckRootFinderConvergence = false;
    1006             : 
    1007    12694562 :     return CheckRootFinderConvergence;
    1008             : }
    1009             : 
    1010    10510538 : bool CheckBracketRoundOff(RootFinderDataType const &RootFinderData) // Data used by root finding algorithm
    1011             : {
    1012             :     // FUNCTION INFORMATION:
    1013             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1014             :     //       DATE WRITTEN   February 2006
    1015             :     //       MODIFIED
    1016             :     //       RE-ENGINEERED  na
    1017             : 
    1018             :     // PURPOSE OF THIS FUNCTION:
    1019             :     // This function checks whether the current lower and upper brackets satisfies
    1020             :     // the round-off criterion or not.
    1021             : 
    1022             :     // Return value
    1023             :     bool CheckBracketRoundOff;
    1024             : 
    1025             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1026             :     Real64 DeltaUL; // Distance between lower and upper points
    1027             :     Real64 TypUL;   // Typical value for values lying within lower/upper interval
    1028             :     Real64 TolUL;   // Tolerance to satisfy for lower-upper distance
    1029             : 
    1030             :     // Check for round-off error in Lower/Upper interval
    1031    10510538 :     if (RootFinderData.LowerPoint.DefinedFlag && RootFinderData.UpperPoint.DefinedFlag) {
    1032     3547008 :         DeltaUL = RootFinderData.UpperPoint.X - RootFinderData.LowerPoint.X;
    1033     3547008 :         TypUL = (std::abs(RootFinderData.UpperPoint.X) + std::abs(RootFinderData.LowerPoint.X)) / 2.0;
    1034     3547008 :         TolUL = RootFinderData.Controls.TolX * std::abs(TypUL) + RootFinderData.Controls.ATolX;
    1035             : 
    1036             :         // Halve tolerance to reflect the fact that solution can be anywhere between the lower and upper points.
    1037     3547008 :         if (std::abs(DeltaUL) <= 0.5 * std::abs(TolUL)) {
    1038        3646 :             CheckBracketRoundOff = true;
    1039        3646 :             return CheckBracketRoundOff;
    1040             :         }
    1041             :     }
    1042             : 
    1043    10506892 :     CheckBracketRoundOff = false;
    1044             : 
    1045    10506892 :     return CheckBracketRoundOff;
    1046             : }
    1047             : 
    1048    19153079 : void UpdateMinMax(RootFinderDataType &RootFinderData, // Data used by root finding algorithm
    1049             :                   Real64 const X,                     // X value for current iterate
    1050             :                   Real64 const Y                      // Y value for current iterate, F(X)=Y
    1051             : )
    1052             : {
    1053             :     // SUBROUTINE INFORMATION:
    1054             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1055             :     //       DATE WRITTEN   February 2006
    1056             :     //       MODIFIED
    1057             :     //       RE-ENGINEERED  na
    1058             : 
    1059             :     // PURPOSE OF THIS SUBROUTINE:
    1060             :     // This subroutine updates the min/max support points in the root finder data.
    1061             : 
    1062             :     // METHODOLOGY EMPLOYED:
    1063             :     // PRECONDITION:
    1064             :     // na
    1065             :     // POSTCONDITION:
    1066             :     // - RootFinderData%MinPoint possibly updated
    1067             :     // - RootFinderData%MaxPoint possibly updated
    1068             : 
    1069             :     // Update min support point
    1070    19153079 :     if (X == RootFinderData.MinPoint.X) {
    1071     8639103 :         RootFinderData.MinPoint.Y = Y;
    1072     8639103 :         RootFinderData.MinPoint.DefinedFlag = true;
    1073             :     }
    1074             : 
    1075             :     // Update max support point
    1076    19153079 :     if (X == RootFinderData.MaxPoint.X) {
    1077     1423812 :         RootFinderData.MaxPoint.Y = Y;
    1078     1423812 :         RootFinderData.MaxPoint.DefinedFlag = true;
    1079             :     }
    1080    19153079 : }
    1081             : 
    1082    14370489 : void UpdateBracket(EnergyPlusData &state,
    1083             :                    RootFinderDataType &RootFinderData, // Data used by root finding algorithm
    1084             :                    Real64 const X,                     // X value for current iterate
    1085             :                    Real64 const Y                      // Y value for current iterate, F(X)=Y
    1086             : )
    1087             : {
    1088             :     // SUBROUTINE INFORMATION:
    1089             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1090             :     //       DATE WRITTEN   March 2006
    1091             :     //       MODIFIED
    1092             :     //       RE-ENGINEERED  na
    1093             : 
    1094             :     // PURPOSE OF THIS SUBROUTINE:
    1095             :     // This subroutine updates the lower/upper support points in the root finder data
    1096             :     // with the current iterate (X,Y).
    1097             : 
    1098             :     // METHODOLOGY EMPLOYED:
    1099             :     // PRECONDITION:
    1100             :     // - The current iterate (X,Y) must satisfy:
    1101             :     //   MinPoint%X <= LowerPoint%X < X < UpperPoint%X <= MaxPoint%X
    1102             :     // - RootFinderData%StatusFlag == iStatusNone
    1103             :     // POSTCONDITION:
    1104             :     // - RootFinderData%LowerPoint possibly updated
    1105             :     // - RootFinderData%UpperPoint possibly updated
    1106             :     // - RootFinderData%StatusFlag possibly updated with:
    1107             :     //   - iStatusWarningNonMonotonic
    1108             :     //   - iStatusWarningSingular
    1109             : 
    1110    14370489 :     switch (RootFinderData.Controls.SlopeType) {
    1111     3096535 :     case DataRootFinder::Slope::Increasing: {
    1112             :         // Update lower point
    1113     3096535 :         if (Y <= 0.0) {
    1114     2168099 :             if (!RootFinderData.LowerPoint.DefinedFlag) {
    1115     1342057 :                 RootFinderData.LowerPoint.DefinedFlag = true;
    1116     1342057 :                 RootFinderData.LowerPoint.X = X;
    1117     1342057 :                 RootFinderData.LowerPoint.Y = Y;
    1118             :             } else {
    1119      826042 :                 if (X >= RootFinderData.LowerPoint.X) {
    1120      826042 :                     if (Y == RootFinderData.LowerPoint.Y) {
    1121        1192 :                         RootFinderData.StatusFlag = RootFinderStatus::WarningSingular;
    1122      824850 :                     } else if (Y < RootFinderData.LowerPoint.Y) {
    1123        1109 :                         RootFinderData.StatusFlag = RootFinderStatus::WarningNonMonotonic;
    1124             :                     }
    1125             :                     // Update lower point with current iterate
    1126      826042 :                     RootFinderData.LowerPoint.X = X;
    1127      826042 :                     RootFinderData.LowerPoint.Y = Y;
    1128             :                 } else {
    1129             :                     // Should never happen if CheckLowerUpperBracket() is called before
    1130           0 :                     ShowSevereError(state, "UpdateBracket: Current iterate is smaller than the lower bracket.");
    1131           0 :                     ShowContinueError(state, format("UpdateBracket: X={:.15T}, Y={:.15T}", X, Y));
    1132           0 :                     ShowContinueError(
    1133           0 :                         state, format("UpdateBracket: XLower={:.15T}, YLower={:.15T}", RootFinderData.LowerPoint.X, RootFinderData.LowerPoint.Y));
    1134           0 :                     ShowFatalError(state, "UpdateBracket: Preceding error causes program termination.");
    1135             :                 }
    1136             :             }
    1137             : 
    1138             :             // Update upper point
    1139             :         } else {
    1140      928436 :             if (!RootFinderData.UpperPoint.DefinedFlag) {
    1141      379502 :                 RootFinderData.UpperPoint.DefinedFlag = true;
    1142      379502 :                 RootFinderData.UpperPoint.X = X;
    1143      379502 :                 RootFinderData.UpperPoint.Y = Y;
    1144             :             } else {
    1145      548934 :                 if (X <= RootFinderData.UpperPoint.X) {
    1146      548934 :                     if (Y == RootFinderData.UpperPoint.Y) {
    1147           0 :                         RootFinderData.StatusFlag = RootFinderStatus::WarningSingular;
    1148      548934 :                     } else if (Y > RootFinderData.UpperPoint.Y) {
    1149         721 :                         RootFinderData.StatusFlag = RootFinderStatus::WarningNonMonotonic;
    1150             :                     }
    1151             :                     // Update upper point with current iterate
    1152      548934 :                     RootFinderData.UpperPoint.X = X;
    1153      548934 :                     RootFinderData.UpperPoint.Y = Y;
    1154             :                 } else {
    1155             :                     // Should never happen if CheckLowerUpperBracket() is called before
    1156           0 :                     ShowSevereError(state, "UpdateBracket: Current iterate is greater than the upper bracket.");
    1157           0 :                     ShowContinueError(state, format("UpdateBracket: X={:.15T}, Y={:.15T}", X, Y));
    1158           0 :                     ShowContinueError(
    1159           0 :                         state, format("UpdateBracket: XUpper={:.15T}, YUpper={:.15T}", RootFinderData.UpperPoint.X, RootFinderData.UpperPoint.Y));
    1160           0 :                     ShowFatalError(state, "UpdateBracket: Preceding error causes program termination.");
    1161             :                 }
    1162             :             }
    1163             :         }
    1164             :         // Monotone, decreasing function
    1165     3096535 :     } break;
    1166    11273954 :     case DataRootFinder::Slope::Decreasing: {
    1167             :         // Update lower point
    1168    11273954 :         if (Y >= 0.0) {
    1169     7655454 :             if (!RootFinderData.LowerPoint.DefinedFlag) {
    1170     3360562 :                 RootFinderData.LowerPoint.DefinedFlag = true;
    1171     3360562 :                 RootFinderData.LowerPoint.X = X;
    1172     3360562 :                 RootFinderData.LowerPoint.Y = Y;
    1173             :             } else {
    1174     4294892 :                 if (X >= RootFinderData.LowerPoint.X) {
    1175     4294892 :                     if (Y == RootFinderData.LowerPoint.Y) {
    1176       15730 :                         RootFinderData.StatusFlag = RootFinderStatus::WarningSingular;
    1177     4279162 :                     } else if (Y > RootFinderData.LowerPoint.Y) {
    1178        1270 :                         RootFinderData.StatusFlag = RootFinderStatus::WarningNonMonotonic;
    1179             :                     }
    1180             :                     // Update lower point with current iterate
    1181     4294892 :                     RootFinderData.LowerPoint.X = X;
    1182     4294892 :                     RootFinderData.LowerPoint.Y = Y;
    1183             :                 } else {
    1184             :                     // Should never happen if CheckLowerUpperBracket() is called before
    1185           0 :                     ShowSevereError(state, "UpdateBracket: Current iterate is smaller than the lower bracket.");
    1186           0 :                     ShowContinueError(state, format("UpdateBracket: X={:.15T}, Y={:.15T}", X, Y));
    1187           0 :                     ShowContinueError(
    1188           0 :                         state, format("UpdateBracket: XLower={:.15T}, YLower={:.15T}", RootFinderData.LowerPoint.X, RootFinderData.LowerPoint.Y));
    1189           0 :                     ShowFatalError(state, "UpdateBracket: Preceding error causes program termination.");
    1190             :                 }
    1191             :             }
    1192             : 
    1193             :             // Update upper point
    1194             :         } else {
    1195     3618500 :             if (!RootFinderData.UpperPoint.DefinedFlag) {
    1196     1265891 :                 RootFinderData.UpperPoint.DefinedFlag = true;
    1197     1265891 :                 RootFinderData.UpperPoint.X = X;
    1198     1265891 :                 RootFinderData.UpperPoint.Y = Y;
    1199             :             } else {
    1200     2352609 :                 if (X <= RootFinderData.UpperPoint.X) {
    1201     2352609 :                     if (Y == RootFinderData.UpperPoint.Y) {
    1202         122 :                         RootFinderData.StatusFlag = RootFinderStatus::WarningSingular;
    1203     2352487 :                     } else if (Y < RootFinderData.UpperPoint.Y) {
    1204        2335 :                         RootFinderData.StatusFlag = RootFinderStatus::WarningNonMonotonic;
    1205             :                     }
    1206             :                     // Update upper point with current iterate
    1207     2352609 :                     RootFinderData.UpperPoint.X = X;
    1208     2352609 :                     RootFinderData.UpperPoint.Y = Y;
    1209             :                 } else {
    1210             :                     // Should never happen if CheckLowerUpperBracket() is called before
    1211           0 :                     ShowSevereError(state, "UpdateBracket: Current iterate is greater than the upper bracket.");
    1212           0 :                     ShowContinueError(state, format("UpdateBracket: X={:.15T}, Y={:.15T}", X, Y));
    1213           0 :                     ShowContinueError(
    1214           0 :                         state, format("UpdateBracket: XUpper={:.15T}, YUpper={:.15T}", RootFinderData.UpperPoint.X, RootFinderData.UpperPoint.Y));
    1215           0 :                     ShowFatalError(state, "UpdateBracket: Preceding error causes program termination.");
    1216             :                 }
    1217             :             }
    1218             :         }
    1219    11273954 :     } break;
    1220           0 :     default: {
    1221             :         // Should never happen
    1222           0 :         ShowSevereError(state, "UpdateBracket: Invalid function slope specification. Valid choices are:");
    1223           0 :         ShowContinueError(state, format("UpdateBracket: Slope::Increasing={}", DataRootFinder::Slope::Increasing));
    1224           0 :         ShowContinueError(state, format("UpdateBracket: Slope::Decreasing={}", DataRootFinder::Slope::Decreasing));
    1225           0 :         ShowFatalError(state, "UpdateBracket: Preceding error causes program termination.");
    1226           0 :     } break;
    1227             :     }
    1228    14370489 : }
    1229             : 
    1230    14370489 : void UpdateHistory(RootFinderDataType &RootFinderData, // Data used by root finding algorithm
    1231             :                    Real64 const X,                     // X value for current iterate
    1232             :                    Real64 const Y                      // Y value for current iterate, F(X)=Y
    1233             : )
    1234             : {
    1235             :     // SUBROUTINE INFORMATION:
    1236             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1237             :     //       DATE WRITTEN   February 2006
    1238             :     //       MODIFIED
    1239             :     //       RE-ENGINEERED  na
    1240             : 
    1241             :     // PURPOSE OF THIS SUBROUTINE:
    1242             :     // This subroutine updates the min/max support points in the root finder data.
    1243             : 
    1244             :     // METHODOLOGY EMPLOYED:
    1245             :     // PRECONDITION:
    1246             :     // - The current iterate (X,Y) must be a valid iterate:
    1247             :     //   MinPoint%X <= LowerPoint%X < X < UpperPoint%X <= MaxPoint%X
    1248             :     // POSTCONDITION:
    1249             :     // - RootFinderData%History(:) updated with last 3 best iterates
    1250             : 
    1251             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1252             :     int NumHistory;
    1253             : 
    1254             :     // Update history with best iterates so that:
    1255             :     //   ABS(History(1)%Y) <= ABS(History(2)%Y) <= ABS(History(3)%Y)
    1256             :     // Note that the history points are sorted so that
    1257             :     //   SIGN(History(1)%Y) = -SIGN(History(3)%Y)
    1258             :     // to ensure that the history points bracket the candidate root.
    1259    57481956 :     for (auto &e : RootFinderData.History) {
    1260    43111467 :         e.X = e.Y = 0.0;
    1261    43111467 :         e.DefinedFlag = false;
    1262             :     }
    1263             : 
    1264    14370489 :     NumHistory = 0;
    1265    14370489 :     if (RootFinderData.LowerPoint.DefinedFlag) {
    1266     9662151 :         ++NumHistory;
    1267     9662151 :         RootFinderData.History(NumHistory).DefinedFlag = RootFinderData.LowerPoint.DefinedFlag;
    1268     9662151 :         RootFinderData.History(NumHistory).X = RootFinderData.LowerPoint.X;
    1269     9662151 :         RootFinderData.History(NumHistory).Y = RootFinderData.LowerPoint.Y;
    1270             :     }
    1271    14370489 :     if (RootFinderData.UpperPoint.DefinedFlag) {
    1272     4895513 :         ++NumHistory;
    1273     4895513 :         RootFinderData.History(NumHistory).DefinedFlag = RootFinderData.UpperPoint.DefinedFlag;
    1274     4895513 :         RootFinderData.History(NumHistory).X = RootFinderData.UpperPoint.X;
    1275     4895513 :         RootFinderData.History(NumHistory).Y = RootFinderData.UpperPoint.Y;
    1276             :     }
    1277    14370489 :     ++NumHistory;
    1278    14370489 :     RootFinderData.History(NumHistory).DefinedFlag = true;
    1279    14370489 :     RootFinderData.History(NumHistory).X = X;
    1280    14370489 :     RootFinderData.History(NumHistory).Y = Y;
    1281             : 
    1282    14370489 :     RootFinderData.NumHistory = NumHistory;
    1283    14370489 :     SortHistory(NumHistory, RootFinderData.History);
    1284    14370489 : }
    1285             : 
    1286    14370489 : void UpdateRootFinder(EnergyPlusData &state,
    1287             :                       RootFinderDataType &RootFinderData, // Data used by root finding algorithm
    1288             :                       Real64 const X,                     // X value for current iterate
    1289             :                       Real64 const Y                      // Y value for current iterate, F(X)=Y
    1290             : )
    1291             : {
    1292             :     // SUBROUTINE INFORMATION:
    1293             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1294             :     //       DATE WRITTEN   February 2006
    1295             :     //       MODIFIED
    1296             :     //       RE-ENGINEERED  na
    1297             : 
    1298             :     // PURPOSE OF THIS SUBROUTINE:
    1299             :     // This subroutine updates the root finder internal data to account for
    1300             :     // the current iterate (X,Y):
    1301             :     // - Lower / Upper support points
    1302             :     // - Increments for successive iterates
    1303             :     // - Convergence rate
    1304             : 
    1305             :     // METHODOLOGY EMPLOYED:
    1306             :     // PRECONDITION:
    1307             :     // - The current iterate (X,Y) must be a valid iterate:
    1308             :     //   MinPoint%X <= LowerPoint%X < X < UpperPoint%X <= MaxPoint%X
    1309             :     // - Invoke UpdateRootFinder() only if:
    1310             :     //   - CheckRootFinderCandidate() returned TRUE
    1311             :     //   - CheckNonSingularity() returned TRUE
    1312             :     //   - CheckSlope() returned TRUE
    1313             :     // POSTCONDITION:
    1314             :     // - RootFinderData%LowerPoint possibly updated
    1315             :     // - RootFinderData%UpperPoint possibly updated
    1316             :     // - RootFinderData%CurrentPoint updated with current iterate (X,Y)
    1317             :     // - RootFinderData%History(:) updated with last 3 best iterates
    1318             :     // - RootFinderData%Increment updated
    1319             :     // - RootFinderData%ConvergenceRate updated
    1320             : 
    1321             :     // Update history with best iterates so that:
    1322             :     //   ABS(History(1)%Y) <= ABS(History(2)%Y) <= ABS(History(3)%Y)
    1323             :     // Note that we must update the history before updating the lower/upper points
    1324    14370489 :     UpdateHistory(RootFinderData, X, Y);
    1325             : 
    1326             :     // Update lower and upper points
    1327    14370489 :     UpdateBracket(state, RootFinderData, X, Y);
    1328             : 
    1329             :     // Update increments and convergence rate
    1330    14370489 :     if (RootFinderData.CurrentPoint.DefinedFlag) {
    1331     9662151 :         RootFinderData.Increment.DefinedFlag = true;
    1332     9662151 :         RootFinderData.Increment.X = X - RootFinderData.CurrentPoint.X;
    1333     9662151 :         RootFinderData.Increment.Y = Y - RootFinderData.CurrentPoint.Y;
    1334             : 
    1335     9662151 :         if (std::abs(RootFinderData.CurrentPoint.Y) > 0.0) {
    1336             :             // NOTE: Should be smaller than one for convergent process
    1337     9662151 :             RootFinderData.ConvergenceRate = std::abs(Y) / std::abs(RootFinderData.CurrentPoint.Y);
    1338             :         } else {
    1339             :             // NOTE: Should never happen
    1340           0 :             RootFinderData.ConvergenceRate = -1.0;
    1341             :         }
    1342             :     }
    1343             : 
    1344             :     // Finally update CurrentPoint (must be done last)
    1345    14370489 :     RootFinderData.CurrentPoint.DefinedFlag = true;
    1346    14370489 :     RootFinderData.CurrentPoint.X = X;
    1347    14370489 :     RootFinderData.CurrentPoint.Y = Y;
    1348    14370489 : }
    1349             : 
    1350    14370489 : void SortHistory(int const N,                // Number of points to sort in history array
    1351             :                  Array1D<PointType> &History // Array of PointType variables. At least N of them
    1352             : )
    1353             : {
    1354             :     // SUBROUTINE INFORMATION:
    1355             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1356             :     //       DATE WRITTEN   March 2006
    1357             :     //       MODIFIED
    1358             :     //       RE-ENGINEERED  na
    1359             : 
    1360             :     // PURPOSE OF THIS SUBROUTINE:
    1361             :     // This subroutine orders the N points in the history array in increasing
    1362             :     // order of ABS(Y) values.
    1363             : 
    1364             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1365             :     int I;
    1366             :     int J;
    1367             :     Real64 XTemp;
    1368             :     Real64 YTemp;
    1369             : 
    1370             :     // Nothing to do if only one point stored in history
    1371    14370489 :     if (N <= 1) {
    1372     4708338 :         return;
    1373             :     }
    1374             : 
    1375    24219815 :     for (I = 1; I <= N - 1; ++I) {
    1376    34010841 :         for (J = I + 1; J <= N; ++J) {
    1377    19453177 :             if (History(J).DefinedFlag) {
    1378             :                 // Swap I and J elements
    1379    19453177 :                 if (std::abs(History(J).Y) < std::abs(History(I).Y)) {
    1380    17950186 :                     XTemp = History(I).X;
    1381    17950186 :                     YTemp = History(I).Y;
    1382    17950186 :                     History(I).X = History(J).X;
    1383    17950186 :                     History(I).Y = History(J).Y;
    1384    17950186 :                     History(J).X = XTemp;
    1385    17950186 :                     History(J).Y = YTemp;
    1386             :                 }
    1387             :             }
    1388             :         }
    1389             :     }
    1390             : }
    1391             : 
    1392    10506892 : void AdvanceRootFinder(EnergyPlusData &state, RootFinderDataType &RootFinderData) // Data used by root finding algorithm
    1393             : {
    1394             :     // SUBROUTINE INFORMATION:
    1395             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1396             :     //       DATE WRITTEN   February 2006
    1397             :     //       MODIFIED
    1398             :     //       RE-ENGINEERED  na
    1399             : 
    1400             :     // PURPOSE OF THIS SUBROUTINE:
    1401             :     // This subroutine computes the next candidate value based on the information available so far.
    1402             :     // Stores new value into RootFinderData%XCandidate
    1403             :     // PRECONDITION:
    1404             :     // na
    1405             :     // POSTCONDITION:
    1406             :     // - LowerPoint%X < XCandidate < UpperPoint%X
    1407             :     // - RootFinderData%CurrentMethodType update with current solution method.
    1408             : 
    1409             :     // METHODOLOGY EMPLOYED:
    1410             :     // The subroutine first attempts to bracket the root within a lower and upper point.
    1411             :     // Once it is bracketed, then we use the specified solution methods (Bisection,
    1412             :     // False position, Secant and Brent) to compute the next candidate.
    1413             : 
    1414             :     // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    1415    10506892 :     auto &XNext = state.dataGeneral->XNext;
    1416             : 
    1417             :     //----------------------------------------------------------------------------
    1418             :     // First attempt to bracket root between a lower point and an upper point.
    1419             :     //----------------------------------------------------------------------------
    1420             : 
    1421             :     // Detect the lower bracket
    1422    10506892 :     if (!RootFinderData.LowerPoint.DefinedFlag) {
    1423        1161 :         RootFinderData.CurrentMethodType = RootFinderMethod::Bracket;
    1424             :         // If we have 2 points already, try to detect lower point using the Secant formula
    1425        1161 :         if (BracketRoot(RootFinderData, XNext)) {
    1426           0 :             RootFinderData.XCandidate = XNext;
    1427             :         } else {
    1428        1161 :             if (!RootFinderData.MinPoint.DefinedFlag) {
    1429        1161 :                 RootFinderData.XCandidate = RootFinderData.MinPoint.X;
    1430             :             } else {
    1431             :                 // Should never happen
    1432           0 :                 ShowFatalError(state, "AdvanceRootFinder: Cannot find lower bracket.");
    1433             :             }
    1434             :         }
    1435             : 
    1436             :         // Detect the upper bracket
    1437    10505731 :     } else if (!RootFinderData.UpperPoint.DefinedFlag) {
    1438     5606542 :         RootFinderData.CurrentMethodType = RootFinderMethod::Bracket;
    1439             :         // If we have 2 points already, try to detect upper point using the Secant formula
    1440     5606542 :         if (BracketRoot(RootFinderData, XNext)) {
    1441     1680000 :             RootFinderData.XCandidate = XNext;
    1442             :         } else {
    1443     3926542 :             if (!RootFinderData.MaxPoint.DefinedFlag) {
    1444     3926542 :                 RootFinderData.XCandidate = RootFinderData.MaxPoint.X;
    1445             :             } else {
    1446             :                 // Should never happen
    1447           0 :                 ShowFatalError(state, "AdvanceRootFinder: Cannot find upper bracket.");
    1448             :             }
    1449             :         }
    1450             : 
    1451             :         //----------------------------------------------------------------------------
    1452             :         // Root finding can start ...
    1453             :         // Assumptions:
    1454             :         // - the lower and upper support points are defined.
    1455             :         // - the increments are defined (at least 2 history points are available)
    1456             :         //----------------------------------------------------------------------------
    1457             :     } else {
    1458     4899189 :         switch (RootFinderData.StatusFlag) {
    1459           0 :         case RootFinderStatus::OKRoundOff: {
    1460             :             // Should never happen if we exit the root finder upon detecting round-off condition
    1461           0 :             RootFinderData.XCandidate = BisectionMethod(RootFinderData);
    1462           0 :         } break;
    1463       15973 :         case RootFinderStatus::WarningSingular:
    1464             :         case RootFinderStatus::WarningNonMonotonic: {
    1465             :             // Following local singularity or non-monotonicity warnings we attempt
    1466             :             // to recover with the false position method to avoid running into trouble
    1467             :             // because the latest iterate did nt produce any improvement compared to
    1468             :             // the previous lower and upper brackets.
    1469       15973 :             RootFinderData.XCandidate = FalsePositionMethod(RootFinderData);
    1470       15973 :         } break;
    1471     4883216 :         default: {
    1472             :             // Assuming that the root is bracketed between the lower and upper points,
    1473             :             // we execute the requested solution method to produce the next candidate value
    1474             :             // for the root.
    1475     4883216 :             switch (RootFinderData.Controls.MethodType) {
    1476           0 :             case RootFinderMethod::Bisection: {
    1477             :                 // Bisection method (aka interval halving)
    1478           0 :                 RootFinderData.XCandidate = BisectionMethod(RootFinderData);
    1479           0 :             } break;
    1480       42658 :             case RootFinderMethod::FalsePosition: {
    1481             :                 // False position method (aka regula falsi)
    1482       42658 :                 RootFinderData.XCandidate = FalsePositionMethod(RootFinderData);
    1483       42658 :             } break;
    1484           0 :             case RootFinderMethod::Secant: {
    1485             :                 // Secant method
    1486           0 :                 RootFinderData.XCandidate = SecantMethod(RootFinderData);
    1487           0 :             } break;
    1488     4840558 :             case RootFinderMethod::Brent: {
    1489             :                 // Brent method
    1490     4840558 :                 RootFinderData.XCandidate = BrentMethod(RootFinderData);
    1491     4840558 :             } break;
    1492           0 :             default: {
    1493           0 :                 ShowSevereError(state, "AdvanceRootFinder: Invalid solution method specification. Valid choices are:");
    1494           0 :                 ShowContinueError(state, format("AdvanceRootFinder: iMethodBisection={}", RootFinderMethod::Bisection));
    1495           0 :                 ShowContinueError(state, format("AdvanceRootFinder: iMethodFalsePosition={}", RootFinderMethod::FalsePosition));
    1496           0 :                 ShowContinueError(state, format("AdvanceRootFinder: iMethodSecant={}", RootFinderMethod::Secant));
    1497           0 :                 ShowContinueError(state, format("AdvanceRootFinder: iMethodBrent={}", RootFinderMethod::Brent));
    1498           0 :                 ShowFatalError(state, "AdvanceRootFinder: Preceding error causes program termination.");
    1499           0 :             } break;
    1500             :             }
    1501     4883216 :         } break;
    1502             :         }
    1503             :     }
    1504    10506892 : }
    1505             : 
    1506     5607703 : bool BracketRoot(RootFinderDataType const &RootFinderData, // Data used by root finding algorithm
    1507             :                  Real64 &XNext                             // Next value
    1508             : )
    1509             : {
    1510             :     // FUNCTION INFORMATION:
    1511             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1512             :     //       DATE WRITTEN   February 2006
    1513             :     //       MODIFIED
    1514             :     //       RE-ENGINEERED  na
    1515             : 
    1516             :     // PURPOSE OF THIS FUNCTION:
    1517             :     // This function attempts to compute a new point that will bracket the root
    1518             :     // using the secant formula to take advantage of the slope between the last 2
    1519             :     // iterates.
    1520             :     // Returns TRUE if successfully computed a new bracket in XNext.
    1521             :     // Else returns FASLE and does not update the XNext argument.
    1522             :     // Should only be used while in braketing mode (iMethodBracket).
    1523             :     // When the lower and upper brackets are detected then the FUNCTION SecantMethod
    1524             :     // should be used instead.
    1525             :     // PRECONDITION:
    1526             :     // na
    1527             :     // POSTCONDITION:
    1528             :     // - MinPoint%X <= XNext <= MaxPoint%X
    1529             :     // - LowerPoint%X < XNext < UpperPoint%X
    1530             : 
    1531             :     // Return value
    1532             :     bool BracketRoot;
    1533             : 
    1534             :     // Cannot use Secant method unless there are at least 2 points
    1535             :     // Also do not use Secant method more than once, i.e. NumHistory==3, in order to avoid
    1536             :     // the pathological case whereby the secant method always comes up short of bracketing
    1537             :     // the root because the function slope flattens as we come closer to either min/max point.
    1538     5607703 :     if (RootFinderData.NumHistory != 2) {
    1539     3921116 :         BracketRoot = false;
    1540     3921116 :         return BracketRoot;
    1541             :     }
    1542             : 
    1543             :     // Should not use Secant method if the last 2 points produced a warning
    1544     1686587 :     if (RootFinderData.StatusFlag == RootFinderStatus::WarningSingular || RootFinderData.StatusFlag == RootFinderStatus::WarningNonMonotonic) {
    1545        6506 :         BracketRoot = false;
    1546        6506 :         return BracketRoot;
    1547             :     }
    1548             : 
    1549             :     // Try to compute next root candidate using Secant formula
    1550     1680081 :     if (SecantFormula(RootFinderData, XNext)) {
    1551             : 
    1552             :         // Check that next candidate is consistent with min/max constraints and lower/upper brackets
    1553     1680000 :         if (CheckRootFinderCandidate(RootFinderData, XNext)) {
    1554     1680000 :             BracketRoot = true;
    1555     1680000 :             return BracketRoot;
    1556             :         }
    1557             :     }
    1558             : 
    1559          81 :     BracketRoot = false;
    1560             : 
    1561          81 :     return BracketRoot;
    1562             : }
    1563             : 
    1564      995929 : Real64 BisectionMethod(RootFinderDataType &RootFinderData) // Data used by root finding algorithm
    1565             : {
    1566             :     // FUNCTION INFORMATION:
    1567             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1568             :     //       DATE WRITTEN   February 2006
    1569             :     //       MODIFIED
    1570             :     //       RE-ENGINEERED  na
    1571             : 
    1572             :     // PURPOSE OF THIS FUNCTION:
    1573             :     // This function computes the next iterate using the bisection method (aka interval halving).
    1574             :     // Convergence rate is at best linear.
    1575             :     // PRECONDITION:
    1576             :     // Lower and upper points must be defined and distinct.
    1577             :     // POSTCONDITION:
    1578             :     // - LowerPoint%X < XCandidate < UpperPoint%X
    1579             :     // - RootFinderData%CurrentMethodType update with current solution method.
    1580             : 
    1581             :     // Return value
    1582             :     Real64 BisectionMethod;
    1583             : 
    1584      995929 :     RootFinderData.CurrentMethodType = RootFinderMethod::Bisection;
    1585      995929 :     BisectionMethod = (RootFinderData.LowerPoint.X + RootFinderData.UpperPoint.X) / 2.0;
    1586             : 
    1587      995929 :     return BisectionMethod;
    1588             : }
    1589             : 
    1590       62156 : Real64 FalsePositionMethod(RootFinderDataType &RootFinderData) // Data used by root finding algorithm
    1591             : {
    1592             :     // FUNCTION INFORMATION:
    1593             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1594             :     //       DATE WRITTEN   February 2006
    1595             :     //       MODIFIED
    1596             :     //       RE-ENGINEERED  na
    1597             : 
    1598             :     // PURPOSE OF THIS FUNCTION:
    1599             :     // This function computes the next iterate using the false position method (aka regula falsi).
    1600             :     // If new iterate does not lie within the lower and upper points then
    1601             :     // the Bisection method is used instead.
    1602             :     // Convergence rate is at best superlinear.
    1603             :     // PRECONDITION:
    1604             :     // Lower and upper points must be defined and distinct.
    1605             :     // POSTCONDITION:
    1606             :     // - LowerPoint%X < XCandidate < UpperPoint%X
    1607             :     // - RootFinderData%CurrentMethodType update with current solution method.
    1608             : 
    1609             :     // Return value
    1610             :     Real64 FalsePositionMethod;
    1611             : 
    1612             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1613             :     Real64 XCandidate;
    1614             :     Real64 Num;
    1615             :     Real64 Den;
    1616             : 
    1617       62156 :     Num = RootFinderData.UpperPoint.X - RootFinderData.LowerPoint.X;
    1618       62156 :     Den = RootFinderData.UpperPoint.Y - RootFinderData.LowerPoint.Y;
    1619             : 
    1620       62156 :     if (Den != 0.0) {
    1621             :         // False position method
    1622       62156 :         RootFinderData.CurrentMethodType = RootFinderMethod::FalsePosition;
    1623       62156 :         XCandidate = RootFinderData.LowerPoint.X - RootFinderData.LowerPoint.Y * Num / Den;
    1624             : 
    1625             :         // Check that new candidate is within range and brackets
    1626       62156 :         if (!CheckRootFinderCandidate(RootFinderData, XCandidate)) {
    1627             :             // Recovery method
    1628           0 :             XCandidate = BisectionMethod(RootFinderData);
    1629             :         }
    1630             :     } else {
    1631             :         // Recovery method
    1632           0 :         XCandidate = BisectionMethod(RootFinderData);
    1633             :     }
    1634             : 
    1635       62156 :     FalsePositionMethod = XCandidate;
    1636       62156 :     return FalsePositionMethod;
    1637             : }
    1638             : 
    1639     1338025 : Real64 SecantMethod(RootFinderDataType &RootFinderData) // Data used by root finding algorithm
    1640             : {
    1641             :     // FUNCTION INFORMATION:
    1642             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1643             :     //       DATE WRITTEN   February 2006
    1644             :     //       MODIFIED
    1645             :     //       RE-ENGINEERED  na
    1646             : 
    1647             :     // PURPOSE OF THIS FUNCTION:
    1648             :     // This function computes the next iterate using the secant method.
    1649             :     // If new iterate does not lie within the lower and upper points then
    1650             :     // the false position method is used instead.
    1651             :     // Convergence rate is at best superlinear.
    1652             :     // PRECONDITION:
    1653             :     // There must be at least 2 history points so that RootFinderData%Increment is defined.
    1654             :     // See FUNCTION SecantFormula.
    1655             :     // POSTCONDITION:
    1656             :     // - LowerPoint%X < XCandidate < UpperPoint%X
    1657             :     // - RootFinderData%CurrentMethodType update with current solution method.
    1658             : 
    1659             :     // Return value
    1660             :     Real64 SecantMethod;
    1661             : 
    1662             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1663             :     Real64 XCandidate;
    1664             : 
    1665             :     // Recover with false position
    1666     1338025 :     if (SecantFormula(RootFinderData, XCandidate)) {
    1667             :         // Secant method
    1668     1338025 :         RootFinderData.CurrentMethodType = RootFinderMethod::Secant;
    1669             : 
    1670             :         // Check that new candidate is within range and brackets
    1671     1338025 :         if (!CheckRootFinderCandidate(RootFinderData, XCandidate)) {
    1672             :             // Recovery method
    1673           0 :             XCandidate = FalsePositionMethod(RootFinderData);
    1674             :         }
    1675             :     } else {
    1676             :         // Recovery method
    1677           0 :         XCandidate = FalsePositionMethod(RootFinderData);
    1678             :     }
    1679             : 
    1680     1338025 :     SecantMethod = XCandidate;
    1681     1338025 :     return SecantMethod;
    1682             : }
    1683             : 
    1684     3018106 : bool SecantFormula(RootFinderDataType const &RootFinderData, // Data used by root finding algorithm
    1685             :                    Real64 &XNext                             // Result from Secant formula if possible to compute
    1686             : )
    1687             : {
    1688             :     // FUNCTION INFORMATION:
    1689             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1690             :     //       DATE WRITTEN   April 2006
    1691             :     //       MODIFIED
    1692             :     //       RE-ENGINEERED  na
    1693             : 
    1694             :     // PURPOSE OF THIS FUNCTION:
    1695             :     // This function computes the next iterate using the secant formula.
    1696             :     // If the new iterate cannot be computed the function returns FALSE, else TRUE.
    1697             :     // Convergence rate is at best superlinear.
    1698             :     // PRECONDITION:
    1699             :     // There must be at least 2 history points so that RootFinderData%Increment is defined.
    1700             :     // POSTCONDITION:
    1701             :     // XNext contains the result from applying the Secant formula.
    1702             :     // If XNext could not be computed then leave XNext unchanged.
    1703             : 
    1704             :     // Return value
    1705             :     bool SecantFormula;
    1706             : 
    1707             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1708             :     Real64 Num;
    1709             :     Real64 Den;
    1710             : 
    1711     3018106 :     Num = RootFinderData.Increment.X;
    1712     3018106 :     Den = RootFinderData.Increment.Y;
    1713             : 
    1714             :     // Cannot use secant with infinite slope (Den==0).
    1715             :     // Cannot use secant with null slope (Num==0).
    1716     3018106 :     if (Den != 0.0 && Num != 0.0) {
    1717     3018025 :         XNext = RootFinderData.CurrentPoint.X - RootFinderData.CurrentPoint.Y * Num / Den;
    1718     3018025 :         SecantFormula = true;
    1719             :     } else {
    1720          81 :         SecantFormula = false;
    1721             :     }
    1722             : 
    1723     3018106 :     return SecantFormula;
    1724             : }
    1725             : 
    1726     4840558 : Real64 BrentMethod(RootFinderDataType &RootFinderData) // Data used by root finding algorithm
    1727             : {
    1728             :     // FUNCTION INFORMATION:
    1729             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1730             :     //       DATE WRITTEN   March 2006
    1731             :     //       MODIFIED
    1732             :     //       RE-ENGINEERED  na
    1733             : 
    1734             :     // PURPOSE OF THIS FUNCTION:
    1735             :     // This function computes the next iterate using the Brent's method.
    1736             :     // If new iterate does not lie within the lower and upper points then
    1737             :     // the secant method is used instead.
    1738             :     // Convergence rate is at best quadratic.
    1739             :     // PRECONDITION:
    1740             :     // Lower and upper points must be defined and distinct.
    1741             :     // POSTCONDITION:
    1742             :     // - LowerPoint%X < XCandidate < UpperPoint%X
    1743             :     // - RootFinderData%CurrentMethodType update with current solution method.
    1744             : 
    1745             :     // METHODOLOGY EMPLOYED:
    1746             :     // Inverse quadratic interpolation using the last 3 best iterates.
    1747             :     // The next root estimate is x = B + P/Q whereby B is the current best estimate
    1748             :     // of the root.
    1749             : 
    1750             :     // Return value
    1751             :     Real64 BrentMethod;
    1752             : 
    1753             :     // FUNCTION LOCAL VARIABLE DECLARATIONS:
    1754             :     Real64 XCandidate;
    1755             :     Real64 A;
    1756             :     Real64 FA;
    1757             :     Real64 B;
    1758             :     Real64 FB;
    1759             :     Real64 C;
    1760             :     Real64 FC;
    1761             :     Real64 R;
    1762             :     Real64 S;
    1763             :     Real64 T;
    1764             :     Real64 P;
    1765             :     Real64 Q;
    1766             : 
    1767             :     // Only attempt Brent's method if enough history points are available
    1768             :     // and if the root finder is converging (not diverging) since the previous
    1769             :     // iterate.
    1770             :     // We assume that;
    1771             :     // - the root is bracketed between the lower and upper points (see AdvanceRootFinder() ).
    1772             :     // - there are at least 3 history points
    1773     4840558 :     if (RootFinderData.NumHistory == 3) {
    1774             : 
    1775     3502533 :         A = RootFinderData.History(2).X;
    1776     3502533 :         FA = RootFinderData.History(2).Y;
    1777     3502533 :         B = RootFinderData.History(1).X;
    1778     3502533 :         FB = RootFinderData.History(1).Y;
    1779     3502533 :         C = RootFinderData.History(3).X;
    1780     3502533 :         FC = RootFinderData.History(3).Y;
    1781             : 
    1782             :         // Should never happen if CheckRootFinderConvergence() is invoked prior to this subroutine
    1783     3502533 :         if (FC == 0.0) {
    1784           0 :             BrentMethod = C;
    1785           0 :             return BrentMethod;
    1786             :             // Should never happen if CheckRootFinderConvergence() is invoked prior to this subroutine
    1787     3502533 :         } else if (FA == 0.0) {
    1788           0 :             BrentMethod = A;
    1789           0 :             return BrentMethod;
    1790             :         } else {
    1791     3502533 :             R = FB / FC;
    1792     3502533 :             S = FB / FA;
    1793     3502533 :             T = FA / FC;
    1794             : 
    1795     3502533 :             P = S * (T * (R - T) * (C - B) - (1.0 - R) * (B - A));
    1796     3502533 :             Q = (T - 1.0) * (R - 1.0) * (S - 1.0);
    1797             : 
    1798             :             // Only accept correction if it is small enough (75% of previous increment)
    1799     3502533 :             if (std::abs(P) <= 0.75 * std::abs(Q * RootFinderData.Increment.X)) {
    1800     2506604 :                 RootFinderData.CurrentMethodType = RootFinderMethod::Brent;
    1801     2506604 :                 XCandidate = B + P / Q;
    1802             : 
    1803             :                 // Check that new candidate is within range and brackets
    1804     2506604 :                 if (!CheckRootFinderCandidate(RootFinderData, XCandidate)) {
    1805             :                     // Recovery method
    1806        3525 :                     XCandidate = FalsePositionMethod(RootFinderData);
    1807             :                 }
    1808             :             } else {
    1809             :                 // Recover from bad correction with bisection
    1810             :                 // Bisection produced the best numerical performance in testing compared to
    1811             :                 // - Secant
    1812             :                 // - False position (very slow recovery)
    1813      995929 :                 XCandidate = BisectionMethod(RootFinderData);
    1814             :             }
    1815             :         }
    1816             :     } else {
    1817             :         // Not enough history to try Brent's method yet: use Secant's method
    1818     1338025 :         XCandidate = SecantMethod(RootFinderData);
    1819             :     }
    1820             : 
    1821     4840558 :     BrentMethod = XCandidate;
    1822     4840558 :     return BrentMethod;
    1823             : }
    1824             : 
    1825           0 : void WriteRootFinderTraceHeader(InputOutputFile &TraceFile) // Unit for trace file
    1826             : {
    1827             :     // SUBROUTINE INFORMATION:
    1828             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1829             :     //       DATE WRITTEN   March 2006
    1830             :     //       MODIFIED
    1831             :     //       RE-ENGINEERED  na
    1832             : 
    1833             :     // PURPOSE OF THIS SUBROUTINE:
    1834             :     // This subroutine writes the header for the trace file to the specified
    1835             :     // file unit using CSV formatting.
    1836             : 
    1837           0 :     print(TraceFile,
    1838             :           "{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},",
    1839             :           "Status",
    1840             :           "Method",
    1841             :           "CurrentPoint%X",
    1842             :           "CurrentPoint%Y",
    1843             :           "XCandidate",
    1844             :           "ConvergenceRate",
    1845             :           "MinPoint%X",
    1846             :           "MinPoint%Y",
    1847             :           "LowerPoint%X",
    1848             :           "LowerPoint%Y",
    1849             :           "UpperPoint%X",
    1850             :           "UpperPoint%Y",
    1851             :           "MaxPoint%X",
    1852             :           "MaxPoint%Y",
    1853             :           "History(1)%X",
    1854             :           "History(1)%Y",
    1855             :           "History(2)%X",
    1856             :           "History(2)%Y",
    1857             :           "History(3)%X",
    1858           0 :           "History(3)%Y");
    1859           0 : }
    1860             : 
    1861           0 : void WriteRootFinderTrace(InputOutputFile &TraceFile,              // Unit for trace file
    1862             :                           RootFinderDataType const &RootFinderData // Data used by root finding algorithm
    1863             : )
    1864             : {
    1865             :     // SUBROUTINE INFORMATION:
    1866             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1867             :     //       DATE WRITTEN   March 2006
    1868             :     //       MODIFIED
    1869             :     //       RE-ENGINEERED  na
    1870             : 
    1871             :     // PURPOSE OF THIS SUBROUTINE:
    1872             :     // This subroutine writes the current state of the root finder data to the trace file
    1873             :     // unit using CSV formatting.
    1874             : 
    1875           0 :     print(TraceFile, "{},{},", RootFinderData.StatusFlag, RootFinderData.CurrentMethodType);
    1876             : 
    1877             :     // Only show current point if defined.
    1878           0 :     WritePoint(TraceFile, RootFinderData.CurrentPoint, false);
    1879             : 
    1880           0 :     print(TraceFile, "{:20.10F},{:20.10F},", RootFinderData.XCandidate, RootFinderData.ConvergenceRate);
    1881             : 
    1882             :     // Always show min and max points.
    1883             :     // Only show lower and upper points if defined.
    1884           0 :     WritePoint(TraceFile, RootFinderData.MinPoint, true);
    1885           0 :     WritePoint(TraceFile, RootFinderData.LowerPoint, false);
    1886           0 :     WritePoint(TraceFile, RootFinderData.UpperPoint, false);
    1887           0 :     WritePoint(TraceFile, RootFinderData.MaxPoint, true);
    1888             :     // Only show history points if defined.
    1889           0 :     WritePoint(TraceFile, RootFinderData.History(1), false);
    1890           0 :     WritePoint(TraceFile, RootFinderData.History(2), false);
    1891           0 :     WritePoint(TraceFile, RootFinderData.History(3), false);
    1892           0 : }
    1893             : 
    1894           0 : void WritePoint(InputOutputFile &TraceFile, // Unit for trace file
    1895             :                 PointType const &PointData, // Point data structure
    1896             :                 bool const ShowXValue)
    1897             : {
    1898             :     // SUBROUTINE INFORMATION:
    1899             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1900             :     //       DATE WRITTEN   March 2006
    1901             :     //       MODIFIED
    1902             :     //       RE-ENGINEERED  na
    1903             : 
    1904             :     // PURPOSE OF THIS SUBROUTINE:
    1905             :     // This subroutine writes the current point data to the trace file
    1906             :     // unit using CSV formatting.
    1907             :     // If not defined writes an empty string instead.
    1908             : 
    1909           0 :     if (PointData.DefinedFlag) {
    1910           0 :         print(TraceFile, "{:20.10F},{:20.10F},", PointData.X, PointData.Y);
    1911             :     } else {
    1912           0 :         if (ShowXValue) {
    1913           0 :             print(TraceFile, "{:20.10F},,", PointData.X);
    1914             :         } else {
    1915           0 :             print(TraceFile, ",,");
    1916             :         }
    1917             :     }
    1918           0 : }
    1919             : 
    1920           0 : void DebugRootFinder(InputOutputFile &DebugFile,              // File unit where to write debugging info
    1921             :                      RootFinderDataType const &RootFinderData // Data used by root finding algorithm
    1922             : )
    1923             : {
    1924             :     // SUBROUTINE INFORMATION:
    1925             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1926             :     //       DATE WRITTEN   April 2006
    1927             :     //       MODIFIED
    1928             :     //       RE-ENGINEERED  na
    1929             : 
    1930             :     // PURPOSE OF THIS SUBROUTINE:
    1931             :     // This subroutine writes the current min/max range and lower/upper bracket to
    1932             :     // the standard output file.
    1933             :     // Used only for debugging.
    1934             : 
    1935           0 :     print(DebugFile, "Current = ");
    1936           0 :     WritePoint(DebugFile, RootFinderData.CurrentPoint, true);
    1937           0 :     print(DebugFile, "\n");
    1938             : 
    1939           0 :     print(DebugFile, "Min     = ");
    1940           0 :     WritePoint(DebugFile, RootFinderData.MinPoint, true);
    1941           0 :     print(DebugFile, "\n");
    1942             : 
    1943           0 :     print(DebugFile, "Lower   = ");
    1944           0 :     WritePoint(DebugFile, RootFinderData.LowerPoint, false);
    1945           0 :     print(DebugFile, "\n");
    1946             : 
    1947           0 :     print(DebugFile, "Upper   = ");
    1948           0 :     WritePoint(DebugFile, RootFinderData.UpperPoint, false);
    1949           0 :     print(DebugFile, "\n");
    1950             : 
    1951           0 :     print(DebugFile, "Max     = ");
    1952           0 :     WritePoint(DebugFile, RootFinderData.MaxPoint, true);
    1953           0 :     print(DebugFile, "\n");
    1954           0 : }
    1955             : 
    1956           0 : void WriteRootFinderStatus(InputOutputFile &File,                   // File unit where to write the status description
    1957             :                            RootFinderDataType const &RootFinderData // Data used by root finding algorithm
    1958             : )
    1959             : {
    1960             :     // SUBROUTINE INFORMATION:
    1961             :     //       AUTHOR         Dimitri Curtil (LBNL)
    1962             :     //       DATE WRITTEN   May 2006
    1963             :     //       MODIFIED
    1964             :     //       RE-ENGINEERED  na
    1965             : 
    1966           0 :     switch (RootFinderData.StatusFlag) {
    1967           0 :     case RootFinderStatus::OK: {
    1968           0 :         print(File, "Found unconstrained root");
    1969           0 :     } break;
    1970           0 :     case RootFinderStatus::OKMin: {
    1971           0 :         print(File, "Found min constrained root");
    1972           0 :     } break;
    1973           0 :     case RootFinderStatus::OKMax: {
    1974           0 :         print(File, "Found max constrained root");
    1975           0 :     } break;
    1976           0 :     case RootFinderStatus::OKRoundOff: {
    1977           0 :         print(File, "Detected round-off convergence in bracket");
    1978           0 :     } break;
    1979           0 :     case RootFinderStatus::WarningSingular: {
    1980           0 :         print(File, "Detected singularity warning");
    1981           0 :     } break;
    1982           0 :     case RootFinderStatus::WarningNonMonotonic: {
    1983           0 :         print(File, "Detected non-monotonicity warning");
    1984           0 :     } break;
    1985           0 :     case RootFinderStatus::ErrorRange: {
    1986           0 :         print(File, "Detected out-of-range error");
    1987           0 :     } break;
    1988           0 :     case RootFinderStatus::ErrorBracket: {
    1989           0 :         print(File, "Detected bracket error");
    1990           0 :     } break;
    1991           0 :     case RootFinderStatus::ErrorSlope: {
    1992           0 :         print(File, "Detected slope error");
    1993           0 :     } break;
    1994           0 :     case RootFinderStatus::ErrorSingular: {
    1995           0 :         print(File, "Detected singularity error");
    1996           0 :     } break;
    1997           0 :     default: {
    1998           0 :         print(File, "Detected bad root finder status");
    1999           0 :     } break;
    2000             :     }
    2001           0 : }
    2002             : 
    2003        2313 : } // namespace EnergyPlus::RootFinder

Generated by: LCOV version 1.13