LCOV - code coverage report
Current view: top level - EnergyPlus - CurveManager.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 1319 1715 76.9 %
Date: 2023-01-17 19:17:23 Functions: 32 34 94.1 %

          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 <algorithm>
      50             : #include <cmath>
      51             : #include <limits>
      52             : #include <string>
      53             : 
      54             : // ObjexxFCL Headers
      55             : #include <ObjexxFCL/Array.functions.hh>
      56             : #include <ObjexxFCL/Array3D.hh>
      57             : #include <ObjexxFCL/Fmath.hh>
      58             : #include <ObjexxFCL/string.functions.hh>
      59             : 
      60             : // Third-party Headers
      61             : #include <fast_float/fast_float.h>
      62             : 
      63             : // EnergyPlus Headers
      64             : #include <EnergyPlus/CurveManager.hh>
      65             : #include <EnergyPlus/Data/EnergyPlusData.hh>
      66             : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
      67             : #include <EnergyPlus/DataIPShortCuts.hh>
      68             : #include <EnergyPlus/DataLoopNode.hh>
      69             : #include <EnergyPlus/DataSystemVariables.hh>
      70             : #include <EnergyPlus/EMSManager.hh>
      71             : #include <EnergyPlus/FileSystem.hh>
      72             : #include <EnergyPlus/GlobalNames.hh>
      73             : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      74             : #include <EnergyPlus/OutputProcessor.hh>
      75             : #include <EnergyPlus/UtilityRoutines.hh>
      76             : 
      77             : namespace EnergyPlus {
      78             : 
      79             : namespace Curve {
      80             :     // Module containing the Curve Manager routines
      81             : 
      82             :     // MODULE INFORMATION:
      83             :     //       AUTHOR         Fred Buhl
      84             :     //       DATE WRITTEN   May 2000
      85             :     //       MODIFIED       January 2006, Rick Strand, added a curve type (quadratic-linear)
      86             :     //                      July 2006, L. Gu, added a new curve type (bicubic)
      87             : 
      88             :     //                      July 2006, Brent Griffith, added triquadratic curve
      89             :     //                       RR added exponential curve
      90             :     //                      May 2009 Brent griffith add EMS actuator registry and override (for custom equations)
      91             :     //                      August 2010, Richard Raustad, FSEC, added Table:* objects
      92             :     //                      August 2014, Rick Strand, added a curve type (cubic-linear)
      93             :     //                      Future Improvements:
      94             :     //                          Subroutine PerformanceTableObject is not really needed (and is probably slower)
      95             :     //                          since Subroutine TableLookupObject can do the same thing. The difference
      96             :     //                          is that Sub PerformanceTableObject does a linear interpolation without extrapolation.
      97             :     //                          More math is also involved. Sub TableLookupObject can also do this if a) the limits
      98             :     //                          of the input data use the boundaries of the tabular data, b) the arrays are corrected
      99             :     //                          to use this other subroutine, and c) the Number of Interpolation Points is set to 2.
     100             :     //                      22Aug2010 Craig Wray, added new curves for fan component model:
     101             :     //                          FanPressureRise, ExponentialSkewNormal, Sigmoid, RectangularHyperbola1,
     102             :     //                          RectangularHyperbola2, ExponentialDecay
     103             :     //                      March 2012, Atefe Makhmalbaf and Heejin Cho, added a new curve type (QuadLinear)
     104             :     //                      Jan 2021 Yueyue, added a new curve type (QuintLinear)
     105             :     //                      Aug.  2014, Rongpeng Zhang, added a new curve type (ChillerPartLoadWithLift)
     106             :     //       RE-ENGINEERED  na
     107             : 
     108             :     // PURPOSE OF THIS MODULE:
     109             :     // To provide the capabilities of getting the curve data from the input,
     110             :     // validating it, and storing it in such a manner that the curve manager
     111             :     // can provide the simulation with performance curve output.
     112             : 
     113        2313 :     std::map<std::string, Btwxt::Method> BtwxtManager::interpMethods = // NOLINT(cert-err58-cpp)
     114        1542 :         {{"Linear", Btwxt::Method::LINEAR}, {"Cubic", Btwxt::Method::CUBIC}};
     115             : 
     116        2313 :     std::map<std::string, Btwxt::Method> BtwxtManager::extrapMethods = // NOLINT(cert-err58-cpp)
     117        1542 :         {{"Linear", Btwxt::Method::LINEAR}, {"Constant", Btwxt::Method::CONSTANT}};
     118             : 
     119             :     // Functions
     120           1 :     void BtwxtMessageCallback(const Btwxt::MsgLevel messageType, const std::string message, void *contextPtr)
     121             :     {
     122           2 :         std::pair<EnergyPlusData *, std::string> contextPair = *(std::pair<EnergyPlusData *, std::string> *)contextPtr;
     123           2 :         std::string fullMessage = format("{}: {}", contextPair.second, message);
     124           1 :         if (messageType == Btwxt::MsgLevel::MSG_ERR) {
     125           1 :             ShowSevereError(*contextPair.first, fullMessage);
     126           2 :             ShowFatalError(*contextPair.first, "Btwxt: Errors discovered, program terminates.");
     127             :         } else {
     128           0 :             if (static_cast<int>(messageType) >= Btwxt::LOG_LEVEL) {
     129           0 :                 if (messageType == Btwxt::MsgLevel::MSG_WARN) {
     130           0 :                     ShowWarningError(*contextPair.first, fullMessage);
     131             :                 } else {
     132           0 :                     ShowMessage(*contextPair.first, fullMessage);
     133             :                 }
     134             :             }
     135             :         }
     136           0 :     }
     137             : 
     138         980 :     void ResetPerformanceCurveOutput(EnergyPlusData &state)
     139             :     {
     140             :         // SUBROUTINE INFORMATION:
     141             :         //       AUTHOR         Richard Raustad, FSEC
     142             :         //       DATE WRITTEN   August 2010
     143             :         //       MODIFIED       na
     144             :         //       RE-ENGINEERED  na
     145             :         // PURPOSE OF THIS SUBROUTINE:
     146             :         // Reset curve outputs prior to simulating air loops, plant loops, etc.
     147             :         // This allows the report variable for curve/table objects to show an inactive state.
     148             : 
     149       18103 :         for (auto &c : state.dataCurveManager->PerfCurve) {
     150       17123 :             c.output = DataLoopNode::SensedNodeFlagValue;
     151      119861 :             for (auto &i : c.inputs) {
     152      102738 :                 i = DataLoopNode::SensedNodeFlagValue;
     153             :             }
     154             :         }
     155         980 :     }
     156             : 
     157   605508771 :     Real64 CurveValue(EnergyPlusData &state,
     158             :                       int const CurveIndex,        // index of curve in curve array
     159             :                       Real64 const Var1,           // 1st independent variable
     160             :                       Optional<Real64 const> Var2, // 2nd independent variable
     161             :                       Optional<Real64 const> Var3, // 3rd independent variable
     162             :                       Optional<Real64 const> Var4, // 4th independent variable
     163             :                       Optional<Real64 const> Var5, // 5th independent variable
     164             :                       Optional<Real64 const> Var6  // 6th independent variable
     165             :     )
     166             :     {
     167             : 
     168             :         // FUNCTION INFORMATION:
     169             :         //       AUTHOR         Richard Raustad, FSEC
     170             :         //       DATE WRITTEN   May 2010
     171             :         //       MODIFIED       na
     172             :         //       RE-ENGINEERED  na
     173             : 
     174             :         // PURPOSE OF THIS FUNCTION:
     175             :         // Given the curve index and the values of 1 or 2 independent variables,
     176             :         // calls the curve or table routine to return the value of an equipment performance curve or table.
     177             : 
     178             :         // Return value
     179   605508771 :         Real64 CurveValue(0.0);
     180             : 
     181             :         // need to be careful on where and how resetting curve outputs to some "inactive value" is done
     182             :         // EMS can intercept curves and modify output
     183   605508771 :         if (state.dataGlobal->BeginEnvrnFlag && state.dataCurveManager->CurveValueMyBeginTimeStepFlag) {
     184         980 :             ResetPerformanceCurveOutput(state);
     185         980 :             state.dataCurveManager->CurveValueMyBeginTimeStepFlag = false;
     186             :         }
     187             : 
     188   605508771 :         if (!state.dataGlobal->BeginEnvrnFlag) {
     189   603798086 :             state.dataCurveManager->CurveValueMyBeginTimeStepFlag = true;
     190             :         }
     191             : 
     192   605508771 :         if ((CurveIndex <= 0) || (CurveIndex > state.dataCurveManager->NumCurves)) {
     193           0 :             ShowFatalError(state, "CurveValue: Invalid curve passed.");
     194             :         }
     195             : 
     196   605508771 :         auto &thisCurve = state.dataCurveManager->PerfCurve(CurveIndex);
     197   605508771 :         switch (thisCurve.interpolationType) {
     198   596628038 :         case InterpType::EvaluateCurveToLimits:
     199   596628038 :             CurveValue = PerformanceCurveObject(state, CurveIndex, Var1, Var2, Var3, Var4, Var5);
     200   596628038 :             break;
     201     8880733 :         case InterpType::BtwxtMethod:
     202     8880734 :             CurveValue = BtwxtTableInterpolation(state, CurveIndex, Var1, Var2, Var3, Var4, Var5, Var6);
     203     8880732 :             break;
     204           0 :         default:
     205           0 :             assert(false);
     206             :         }
     207             : 
     208   605508770 :         if (thisCurve.EMSOverrideOn) CurveValue = thisCurve.EMSOverrideCurveValue;
     209             : 
     210   605508770 :         thisCurve.output = CurveValue;
     211   605508770 :         thisCurve.inputs[0] = Var1;
     212   605508770 :         if (present(Var2)) thisCurve.inputs[1] = Var2;
     213   605508770 :         if (present(Var3)) thisCurve.inputs[2] = Var3;
     214   605508770 :         if (present(Var4)) thisCurve.inputs[3] = Var4;
     215   605508770 :         if (present(Var5)) thisCurve.inputs[4] = Var5;
     216   605508770 :         if (present(Var6)) thisCurve.inputs[5] = Var6;
     217             : 
     218   605508770 :         return CurveValue;
     219             :     }
     220             : 
     221         638 :     void GetCurveInput(EnergyPlusData &state)
     222             :     {
     223             :         // wrapper for GetInput to allow unit testing when fatal inputs are detected - follow pattern from GetSetPointManagerInputs()
     224         638 :         bool GetInputErrorsFound = false;
     225             : 
     226         638 :         GetCurveInputData(state, GetInputErrorsFound);
     227         638 :         state.dataCurveManager->GetCurvesInputFlag = false;
     228             : 
     229         638 :         if (GetInputErrorsFound) {
     230           0 :             ShowFatalError(state, "GetCurveInput: Errors found in getting Curve Objects.  Preceding condition(s) cause termination.");
     231             :         }
     232         638 :     }
     233             : 
     234         638 :     void GetCurveInputData(EnergyPlusData &state, bool &ErrorsFound)
     235             :     {
     236             : 
     237             :         // SUBROUTINE INFORMATION:
     238             :         //       AUTHOR         Fred Buhl
     239             :         //       DATE WRITTEN   May 2000
     240             :         //       MODIFIED       January 2006, Rick Strand, added a curve type (quadratic-linear)
     241             :         //                      July 2006, L. Gu, added a curve type (bicubic)
     242             :         //                      July 2006, BG added triquadratic.
     243             :         //                      April 2008, LL Added Linear Curve; July 2008, restructure for easier renaming
     244             :         //                      Feb 2009, R. Raustad - FSEC, added exponent curve
     245             :         //                      22Aug2010 Craig Wray, added new curves for fan component model:
     246             :         //                          FanPressureRise, ExponentialSkewNormal, Sigmoid, RectangularHyperbola1,
     247             :         //                          RectangularHyperbola2, ExponentialDecay
     248             :         //                      Aug.  2014, Rongpeng Zhang, added a new curve type (ChillerPartLoadWithLift)
     249             :         //                      Jan. 2017, Jason DeGraw, added WPC input into tables
     250             :         //       RE-ENGINEERED  na
     251             : 
     252             :         // PURPOSE OF THIS SUBROUTINE:
     253             :         // Obtains input data for EnergyPlus equipment performance curves
     254             : 
     255             :         // METHODOLOGY EMPLOYED:
     256             :         // Uses "Get" routines to read in data.
     257             : 
     258             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
     259        1276 :         Array1D_string Alphas(14);       // Alpha items for object
     260        1276 :         Array1D<Real64> Numbers(10000);  // Numeric items for object
     261             :         int NumAlphas;                   // Number of Alphas for each GetObjectItem call
     262             :         int NumNumbers;                  // Number of Numbers for each GetObjectItem call
     263             :         int IOStatus;                    // Used in GetObjectItem
     264        1276 :         std::string CurrentModuleObject; // for ease in renaming.
     265         638 :         int MaxTableNums(0);             // Maximum number of numeric input fields in Tables
     266             :         //   certain object in the input file
     267             : 
     268             :         // Find the number of each type of curve (note: Current Module object not used here, must rename manually)
     269             : 
     270         638 :         int const NumBiQuad = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Biquadratic");
     271         638 :         int const NumCubic = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Cubic");
     272         638 :         int const NumQuartic = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Quartic");
     273         638 :         int const NumQuad = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Quadratic");
     274         638 :         int const NumQLinear = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:QuadLinear");
     275         638 :         int const NumQuintLinear = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:QuintLinear");
     276         638 :         int const NumQuadLinear = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:QuadraticLinear");
     277         638 :         int const NumCubicLinear = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:CubicLinear");
     278         638 :         int const NumLinear = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Linear");
     279         638 :         int const NumBicubic = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Bicubic");
     280         638 :         int const NumTriQuad = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Triquadratic");
     281         638 :         int const NumExponent = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Exponent");
     282         638 :         int const NumTableLookup = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Table:Lookup");
     283         638 :         int const NumFanPressRise = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:FanPressureRise");
     284         638 :         int const NumExpSkewNorm = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:ExponentialSkewNormal");
     285         638 :         int const NumSigmoid = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:Sigmoid");
     286         638 :         int const NumRectHyper1 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:RectangularHyperbola1");
     287         638 :         int const NumRectHyper2 = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:RectangularHyperbola2");
     288         638 :         int const NumExpDecay = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:ExponentialDecay");
     289         638 :         int const NumDoubleExpDecay = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:DoubleExponentialDecay");
     290             :         int const NumChillerPartLoadWithLift =
     291         638 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Curve:ChillerPartLoadWithLift"); // zrp_Aug2014
     292             : 
     293             :         int const NumWPCValTab =
     294         638 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "AirflowNetwork:MultiZone:WindPressureCoefficientValues");
     295             : 
     296        1276 :         state.dataCurveManager->NumCurves = NumBiQuad + NumCubic + NumQuad + NumQuadLinear + NumCubicLinear + NumLinear + NumBicubic + NumTriQuad +
     297         638 :                                             NumExponent + NumQuartic + NumTableLookup + NumFanPressRise + NumExpSkewNorm + NumSigmoid +
     298         638 :                                             NumRectHyper1 + NumRectHyper2 + NumExpDecay + NumDoubleExpDecay + NumQLinear + NumQuintLinear +
     299         638 :                                             NumChillerPartLoadWithLift + NumWPCValTab;
     300             : 
     301             :         // allocate the data structure
     302         638 :         state.dataCurveManager->PerfCurve.allocate(state.dataCurveManager->NumCurves);
     303         638 :         state.dataCurveManager->UniqueCurveNames.reserve(state.dataCurveManager->NumCurves);
     304             :         // initialize the array
     305             : 
     306         638 :         int CurveNum = 0; // keep track of the current curve index in the main curve array
     307             : 
     308             :         // Loop over biquadratic curves and load data
     309         638 :         CurrentModuleObject = "Curve:Biquadratic";
     310        2631 :         for (int CurveIndex = 1; CurveIndex <= NumBiQuad; ++CurveIndex) {
     311        7972 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     312             :                                                                      CurrentModuleObject,
     313             :                                                                      CurveIndex,
     314             :                                                                      Alphas,
     315             :                                                                      NumAlphas,
     316             :                                                                      Numbers,
     317             :                                                                      NumNumbers,
     318             :                                                                      IOStatus,
     319        1993 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     320             :                                                                      _,
     321        1993 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     322        1993 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     323        3986 :             GlobalNames::VerifyUniqueInterObjectName(state,
     324        1993 :                                                      state.dataCurveManager->UniqueCurveNames,
     325        1993 :                                                      Alphas(1),
     326             :                                                      CurrentModuleObject,
     327        1993 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     328             :                                                      ErrorsFound);
     329        1993 :             ++CurveNum;
     330             : 
     331        1993 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
     332             : 
     333             :             // could add checks for blank numeric fields, and use field names for errors.
     334        1993 :             thisCurve.Name = Alphas(1);
     335        1993 :             thisCurve.curveType = CurveType::BiQuadratic;
     336        1993 :             thisCurve.numDims = 2;
     337        1993 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
     338       13951 :             for (int in = 0; in < 6; ++in) {
     339       11958 :                 thisCurve.coeff[in] = Numbers(in + 1);
     340             :             }
     341        1993 :             thisCurve.inputLimits[0].min = Numbers(7);
     342        1993 :             thisCurve.inputLimits[0].max = Numbers(8);
     343        1993 :             thisCurve.inputLimits[1].min = Numbers(9);
     344        1993 :             thisCurve.inputLimits[1].max = Numbers(10);
     345        1993 :             if (NumNumbers > 10 && !state.dataIPShortCut->lNumericFieldBlanks(11)) {
     346         257 :                 thisCurve.outputLimits.min = Numbers(11);
     347         257 :                 thisCurve.outputLimits.minPresent = true;
     348             :             }
     349        1993 :             if (NumNumbers > 11 && !state.dataIPShortCut->lNumericFieldBlanks(12)) {
     350         254 :                 thisCurve.outputLimits.max = Numbers(12);
     351         254 :                 thisCurve.outputLimits.maxPresent = true;
     352             :             }
     353             : 
     354        1993 :             if (Numbers(7) > Numbers(8)) { // error
     355           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
     356           0 :                 ShowContinueError(state,
     357           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
     358           0 :                                          state.dataIPShortCut->cNumericFieldNames(7),
     359             :                                          Numbers(7),
     360           0 :                                          state.dataIPShortCut->cNumericFieldNames(8),
     361           0 :                                          Numbers(8)));
     362           0 :                 ErrorsFound = true;
     363             :             }
     364        1993 :             if (Numbers(9) > Numbers(10)) { // error
     365           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
     366           0 :                 ShowContinueError(state,
     367           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
     368           0 :                                          state.dataIPShortCut->cNumericFieldNames(9),
     369             :                                          Numbers(9),
     370           0 :                                          state.dataIPShortCut->cNumericFieldNames(10),
     371           0 :                                          Numbers(10)));
     372           0 :                 ErrorsFound = true;
     373             :             }
     374        1993 :             if (NumAlphas >= 2) {
     375        1177 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
     376           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
     377             :                 }
     378             :             }
     379        1993 :             if (NumAlphas >= 3) {
     380        1177 :                 if (!IsCurveInputTypeValid(Alphas(3))) {
     381           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for Y is invalid.", CurrentModuleObject, Alphas(1)));
     382             :                 }
     383             :             }
     384        1993 :             if (NumAlphas >= 4) {
     385        1177 :                 if (!IsCurveOutputTypeValid(Alphas(4))) {
     386           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
     387             :                 }
     388             :             }
     389             :         }
     390             : 
     391             :         // Loop over ChillerPartLoadWithLift curves and load data //zrp_Aug2014
     392         638 :         CurrentModuleObject = "Curve:ChillerPartLoadWithLift";
     393         639 :         for (int CurveIndex = 1; CurveIndex <= NumChillerPartLoadWithLift; ++CurveIndex) {
     394           4 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     395             :                                                                      CurrentModuleObject,
     396             :                                                                      CurveIndex,
     397             :                                                                      Alphas,
     398             :                                                                      NumAlphas,
     399             :                                                                      Numbers,
     400             :                                                                      NumNumbers,
     401             :                                                                      IOStatus,
     402           1 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     403             :                                                                      _,
     404           1 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     405           1 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     406           2 :             GlobalNames::VerifyUniqueInterObjectName(state,
     407           1 :                                                      state.dataCurveManager->UniqueCurveNames,
     408           1 :                                                      Alphas(1),
     409             :                                                      CurrentModuleObject,
     410           1 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     411             :                                                      ErrorsFound);
     412           1 :             ++CurveNum;
     413           1 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
     414             : 
     415           1 :             thisCurve.Name = Alphas(1);
     416             : 
     417           1 :             thisCurve.curveType = CurveType::ChillerPartLoadWithLift;
     418           1 :             thisCurve.numDims = 3;
     419           1 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
     420             : 
     421          13 :             for (int in = 0; in < 12; ++in) {
     422          12 :                 thisCurve.coeff[in] = Numbers(in + 1);
     423             :             }
     424             : 
     425           1 :             thisCurve.inputLimits[0].min = Numbers(13);
     426           1 :             thisCurve.inputLimits[0].max = Numbers(14);
     427           1 :             thisCurve.inputLimits[1].min = Numbers(15);
     428           1 :             thisCurve.inputLimits[1].max = Numbers(16);
     429           1 :             thisCurve.inputLimits[2].min = Numbers(17);
     430           1 :             thisCurve.inputLimits[2].max = Numbers(18);
     431             : 
     432           1 :             if (NumNumbers > 18 && !state.dataIPShortCut->lNumericFieldBlanks(19)) {
     433           0 :                 thisCurve.outputLimits.min = Numbers(19);
     434           0 :                 thisCurve.outputLimits.minPresent = true;
     435             :             }
     436           1 :             if (NumNumbers > 19 && !state.dataIPShortCut->lNumericFieldBlanks(20)) {
     437           0 :                 thisCurve.outputLimits.max = Numbers(20);
     438           0 :                 thisCurve.outputLimits.maxPresent = true;
     439             :             }
     440             : 
     441           1 :             if (NumAlphas >= 2) {
     442           1 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
     443           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
     444             :                 }
     445             :             }
     446           1 :             if (NumAlphas >= 3) {
     447           1 :                 if (!IsCurveInputTypeValid(Alphas(3))) {
     448           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for Y is invalid.", CurrentModuleObject, Alphas(1)));
     449             :                 }
     450             :             }
     451           1 :             if (NumAlphas >= 4) {
     452           1 :                 if (!IsCurveOutputTypeValid(Alphas(4))) {
     453           0 :                     ShowWarningError(state, format("In {} named {} the OInput Unit Type for Z is invalid.", CurrentModuleObject, Alphas(1)));
     454             :                 }
     455             :             }
     456           1 :             if (NumAlphas >= 5) {
     457           1 :                 if (!IsCurveOutputTypeValid(Alphas(5))) {
     458           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
     459             :                 }
     460             :             }
     461             :         }
     462             : 
     463             :         // Loop over cubic curves and load data
     464         638 :         CurrentModuleObject = "Curve:Cubic";
     465        1569 :         for (int CurveIndex = 1; CurveIndex <= NumCubic; ++CurveIndex) {
     466        3724 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     467             :                                                                      CurrentModuleObject,
     468             :                                                                      CurveIndex,
     469             :                                                                      Alphas,
     470             :                                                                      NumAlphas,
     471             :                                                                      Numbers,
     472             :                                                                      NumNumbers,
     473             :                                                                      IOStatus,
     474         931 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     475             :                                                                      _,
     476         931 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     477         931 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     478         931 :             ++CurveNum;
     479        1862 :             GlobalNames::VerifyUniqueInterObjectName(state,
     480         931 :                                                      state.dataCurveManager->UniqueCurveNames,
     481         931 :                                                      Alphas(1),
     482             :                                                      CurrentModuleObject,
     483         931 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     484             :                                                      ErrorsFound);
     485         931 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
     486             : 
     487         931 :             thisCurve.Name = Alphas(1);
     488         931 :             thisCurve.curveType = CurveType::Cubic;
     489         931 :             thisCurve.numDims = 1;
     490         931 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
     491        4655 :             for (int in = 0; in < 4; ++in) {
     492        3724 :                 thisCurve.coeff[in] = Numbers(in + 1);
     493             :             }
     494         931 :             thisCurve.inputLimits[0].min = Numbers(5);
     495         931 :             thisCurve.inputLimits[0].max = Numbers(6);
     496         931 :             if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) {
     497          77 :                 thisCurve.outputLimits.min = Numbers(7);
     498          77 :                 thisCurve.outputLimits.minPresent = true;
     499             :             }
     500         931 :             if (NumNumbers > 7 && !state.dataIPShortCut->lNumericFieldBlanks(8)) {
     501          77 :                 thisCurve.outputLimits.max = Numbers(8);
     502          77 :                 thisCurve.outputLimits.maxPresent = true;
     503             :             }
     504             : 
     505         931 :             if (Numbers(5) > Numbers(6)) { // error
     506           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
     507           0 :                 ShowContinueError(state,
     508           0 :                                   format("{}[{:.R2}] > {} [{.R2}]",
     509           0 :                                          state.dataIPShortCut->cNumericFieldNames(5),
     510             :                                          Numbers(5),
     511           0 :                                          state.dataIPShortCut->cNumericFieldNames(6),
     512           0 :                                          Numbers(6)));
     513           0 :                 ErrorsFound = true;
     514             :             }
     515         931 :             if (NumAlphas >= 2) {
     516         292 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
     517           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
     518             :                 }
     519             :             }
     520         931 :             if (NumAlphas >= 3) {
     521         292 :                 if (!IsCurveOutputTypeValid(Alphas(3))) {
     522           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
     523             :                 }
     524             :             }
     525             :         }
     526             : 
     527             :         // Loop over quadrinomial curves and load data
     528         638 :         CurrentModuleObject = "Curve:Quartic";
     529         652 :         for (int CurveIndex = 1; CurveIndex <= NumQuartic; ++CurveIndex) {
     530          56 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     531             :                                                                      CurrentModuleObject,
     532             :                                                                      CurveIndex,
     533             :                                                                      Alphas,
     534             :                                                                      NumAlphas,
     535             :                                                                      Numbers,
     536             :                                                                      NumNumbers,
     537             :                                                                      IOStatus,
     538          14 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     539             :                                                                      _,
     540          14 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     541          14 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     542          28 :             GlobalNames::VerifyUniqueInterObjectName(state,
     543          14 :                                                      state.dataCurveManager->UniqueCurveNames,
     544          14 :                                                      Alphas(1),
     545             :                                                      CurrentModuleObject,
     546          14 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     547             :                                                      ErrorsFound);
     548          14 :             ++CurveNum;
     549          14 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
     550             : 
     551          14 :             thisCurve.Name = Alphas(1);
     552          14 :             thisCurve.curveType = CurveType::Quartic;
     553          14 :             thisCurve.numDims = 1;
     554          14 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
     555          84 :             for (int in = 0; in < 5; ++in) {
     556          70 :                 thisCurve.coeff[in] = Numbers(in + 1);
     557             :             }
     558          14 :             thisCurve.inputLimits[0].min = Numbers(6);
     559          14 :             thisCurve.inputLimits[0].max = Numbers(7);
     560          14 :             if (NumNumbers > 7 && !state.dataIPShortCut->lNumericFieldBlanks(8)) {
     561          12 :                 thisCurve.outputLimits.min = Numbers(8);
     562          12 :                 thisCurve.outputLimits.minPresent = true;
     563             :             }
     564          14 :             if (NumNumbers > 8 && !state.dataIPShortCut->lNumericFieldBlanks(9)) {
     565          12 :                 thisCurve.outputLimits.max = Numbers(9);
     566          12 :                 thisCurve.outputLimits.maxPresent = true;
     567             :             }
     568             : 
     569          14 :             if (Numbers(6) > Numbers(7)) { // error
     570           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
     571           0 :                 ShowContinueError(state,
     572           0 :                                   format("{}[{:.R2}] > {} [{.R2}]",
     573           0 :                                          state.dataIPShortCut->cNumericFieldNames(6),
     574             :                                          Numbers(6),
     575           0 :                                          state.dataIPShortCut->cNumericFieldNames(7),
     576           0 :                                          Numbers(7)));
     577           0 :                 ErrorsFound = true;
     578             :             }
     579          14 :             if (NumAlphas >= 2) {
     580           8 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
     581           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
     582             :                 }
     583             :             }
     584          14 :             if (NumAlphas >= 3) {
     585           8 :                 if (!IsCurveOutputTypeValid(Alphas(3))) {
     586           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
     587             :                 }
     588             :             }
     589             :         }
     590             : 
     591             :         // Loop over quadratic curves and load data
     592         638 :         CurrentModuleObject = "Curve:Quadratic";
     593        2950 :         for (int CurveIndex = 1; CurveIndex <= NumQuad; ++CurveIndex) {
     594        9248 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     595             :                                                                      CurrentModuleObject,
     596             :                                                                      CurveIndex,
     597             :                                                                      Alphas,
     598             :                                                                      NumAlphas,
     599             :                                                                      Numbers,
     600             :                                                                      NumNumbers,
     601             :                                                                      IOStatus,
     602        2312 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     603             :                                                                      _,
     604        2312 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     605        2312 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     606        4624 :             GlobalNames::VerifyUniqueInterObjectName(state,
     607        2312 :                                                      state.dataCurveManager->UniqueCurveNames,
     608        2312 :                                                      Alphas(1),
     609             :                                                      CurrentModuleObject,
     610        2312 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     611             :                                                      ErrorsFound);
     612        2312 :             ++CurveNum;
     613        2312 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
     614             : 
     615        2312 :             thisCurve.Name = Alphas(1);
     616        2312 :             thisCurve.curveType = CurveType::Quadratic;
     617        2312 :             thisCurve.numDims = 1;
     618        2312 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
     619        9248 :             for (int in = 0; in < 3; ++in) {
     620        6936 :                 thisCurve.coeff[in] = Numbers(in + 1);
     621             :             }
     622        2312 :             thisCurve.inputLimits[0].min = Numbers(4);
     623        2312 :             thisCurve.inputLimits[0].max = Numbers(5);
     624        2312 :             if (NumNumbers > 5 && !state.dataIPShortCut->lNumericFieldBlanks(6)) {
     625          86 :                 thisCurve.outputLimits.min = Numbers(6);
     626          86 :                 thisCurve.outputLimits.minPresent = true;
     627             :             }
     628        2312 :             if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) {
     629          86 :                 thisCurve.outputLimits.max = Numbers(7);
     630          86 :                 thisCurve.outputLimits.maxPresent = true;
     631             :             }
     632             : 
     633        2312 :             if (Numbers(4) > Numbers(5)) { // error
     634           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
     635           0 :                 ShowContinueError(state,
     636           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
     637           0 :                                          state.dataIPShortCut->cNumericFieldNames(4),
     638             :                                          Numbers(4),
     639           0 :                                          state.dataIPShortCut->cNumericFieldNames(5),
     640           0 :                                          Numbers(5)));
     641           0 :                 ErrorsFound = true;
     642             :             }
     643        2312 :             if (NumAlphas >= 2) {
     644         122 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
     645           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
     646             :                 }
     647             :             }
     648        2312 :             if (NumAlphas >= 3) {
     649         122 :                 if (!IsCurveOutputTypeValid(Alphas(3))) {
     650           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
     651             :                 }
     652             :             }
     653             :         }
     654             : 
     655             :         // Loop over quadratic-linear curves and load data
     656         638 :         CurrentModuleObject = "Curve:QuadraticLinear";
     657         650 :         for (int CurveIndex = 1; CurveIndex <= NumQuadLinear; ++CurveIndex) {
     658          48 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     659             :                                                                      CurrentModuleObject,
     660             :                                                                      CurveIndex,
     661             :                                                                      Alphas,
     662             :                                                                      NumAlphas,
     663             :                                                                      Numbers,
     664             :                                                                      NumNumbers,
     665             :                                                                      IOStatus,
     666          12 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     667             :                                                                      _,
     668          12 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     669          12 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     670          24 :             GlobalNames::VerifyUniqueInterObjectName(state,
     671          12 :                                                      state.dataCurveManager->UniqueCurveNames,
     672          12 :                                                      Alphas(1),
     673             :                                                      CurrentModuleObject,
     674          12 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     675             :                                                      ErrorsFound);
     676          12 :             ++CurveNum;
     677          12 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
     678             : 
     679          12 :             thisCurve.Name = Alphas(1);
     680          12 :             thisCurve.curveType = CurveType::QuadraticLinear;
     681          12 :             thisCurve.numDims = 2;
     682          12 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
     683          84 :             for (int in = 0; in < 6; ++in) {
     684          72 :                 thisCurve.coeff[in] = Numbers(in + 1);
     685             :             }
     686          12 :             thisCurve.inputLimits[0].min = Numbers(7);
     687          12 :             thisCurve.inputLimits[0].max = Numbers(8);
     688          12 :             thisCurve.inputLimits[1].min = Numbers(9);
     689          12 :             thisCurve.inputLimits[1].max = Numbers(10);
     690          12 :             if (NumNumbers > 10 && !state.dataIPShortCut->lNumericFieldBlanks(11)) {
     691           0 :                 thisCurve.outputLimits.min = Numbers(11);
     692           0 :                 thisCurve.outputLimits.minPresent = true;
     693             :             }
     694          12 :             if (NumNumbers > 11 && !state.dataIPShortCut->lNumericFieldBlanks(12)) {
     695           0 :                 thisCurve.outputLimits.max = Numbers(12);
     696           0 :                 thisCurve.outputLimits.maxPresent = true;
     697             :             }
     698             : 
     699          12 :             if (Numbers(7) > Numbers(8)) { // error
     700           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
     701           0 :                 ShowContinueError(state,
     702           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
     703           0 :                                          state.dataIPShortCut->cNumericFieldNames(7),
     704             :                                          Numbers(7),
     705           0 :                                          state.dataIPShortCut->cNumericFieldNames(8),
     706           0 :                                          Numbers(8)));
     707           0 :                 ErrorsFound = true;
     708             :             }
     709          12 :             if (Numbers(9) > Numbers(10)) { // error
     710           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
     711           0 :                 ShowContinueError(state,
     712           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
     713           0 :                                          state.dataIPShortCut->cNumericFieldNames(9),
     714             :                                          Numbers(9),
     715           0 :                                          state.dataIPShortCut->cNumericFieldNames(10),
     716           0 :                                          Numbers(10)));
     717           0 :                 ErrorsFound = true;
     718             :             }
     719          12 :             if (NumAlphas >= 2) {
     720           0 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
     721           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
     722             :                 }
     723             :             }
     724          12 :             if (NumAlphas >= 3) {
     725           0 :                 if (!IsCurveInputTypeValid(Alphas(3))) {
     726           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for Y is invalid.", CurrentModuleObject, Alphas(1)));
     727             :                 }
     728             :             }
     729          12 :             if (NumAlphas >= 4) {
     730           0 :                 if (!IsCurveOutputTypeValid(Alphas(4))) {
     731           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
     732             :                 }
     733             :             }
     734             :         }
     735             : 
     736             :         // Loop over cubic-linear curves and load data
     737         638 :         CurrentModuleObject = "Curve:CubicLinear";
     738         640 :         for (int CurveIndex = 1; CurveIndex <= NumCubicLinear; ++CurveIndex) {
     739           8 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     740             :                                                                      CurrentModuleObject,
     741             :                                                                      CurveIndex,
     742             :                                                                      Alphas,
     743             :                                                                      NumAlphas,
     744             :                                                                      Numbers,
     745             :                                                                      NumNumbers,
     746             :                                                                      IOStatus,
     747           2 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     748             :                                                                      _,
     749           2 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     750           2 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     751           4 :             GlobalNames::VerifyUniqueInterObjectName(state,
     752           2 :                                                      state.dataCurveManager->UniqueCurveNames,
     753           2 :                                                      Alphas(1),
     754             :                                                      CurrentModuleObject,
     755           2 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     756             :                                                      ErrorsFound);
     757           2 :             ++CurveNum;
     758           2 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
     759             : 
     760           2 :             thisCurve.Name = Alphas(1);
     761           2 :             thisCurve.curveType = CurveType::CubicLinear;
     762           2 :             thisCurve.numDims = 2;
     763           2 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
     764          14 :             for (int in = 0; in < 6; ++in) {
     765          12 :                 thisCurve.coeff[in] = Numbers(in + 1);
     766             :             }
     767           2 :             thisCurve.inputLimits[0].min = Numbers(7);
     768           2 :             thisCurve.inputLimits[0].max = Numbers(8);
     769           2 :             thisCurve.inputLimits[1].min = Numbers(9);
     770           2 :             thisCurve.inputLimits[1].max = Numbers(10);
     771           2 :             if (NumNumbers > 10 && !state.dataIPShortCut->lNumericFieldBlanks(11)) {
     772           0 :                 thisCurve.outputLimits.min = Numbers(11);
     773           0 :                 thisCurve.outputLimits.minPresent = true;
     774             :             }
     775           2 :             if (NumNumbers > 11 && !state.dataIPShortCut->lNumericFieldBlanks(12)) {
     776           0 :                 thisCurve.outputLimits.max = Numbers(12);
     777           0 :                 thisCurve.outputLimits.maxPresent = true;
     778             :             }
     779             : 
     780           2 :             if (Numbers(7) > Numbers(8)) { // error
     781           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
     782           0 :                 ShowContinueError(state,
     783           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
     784           0 :                                          state.dataIPShortCut->cNumericFieldNames(7),
     785             :                                          Numbers(7),
     786           0 :                                          state.dataIPShortCut->cNumericFieldNames(8),
     787           0 :                                          Numbers(8)));
     788           0 :                 ErrorsFound = true;
     789             :             }
     790           2 :             if (Numbers(9) > Numbers(10)) { // error
     791           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
     792           0 :                 ShowContinueError(state,
     793           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
     794           0 :                                          state.dataIPShortCut->cNumericFieldNames(9),
     795             :                                          Numbers(9),
     796           0 :                                          state.dataIPShortCut->cNumericFieldNames(10),
     797           0 :                                          Numbers(10)));
     798           0 :                 ErrorsFound = true;
     799             :             }
     800           2 :             if (NumAlphas >= 2) {
     801           0 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
     802           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
     803             :                 }
     804             :             }
     805           2 :             if (NumAlphas >= 3) {
     806           0 :                 if (!IsCurveInputTypeValid(Alphas(3))) {
     807           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for Y is invalid.", CurrentModuleObject, Alphas(1)));
     808             :                 }
     809             :             }
     810           2 :             if (NumAlphas >= 4) {
     811           0 :                 if (!IsCurveOutputTypeValid(Alphas(4))) {
     812           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
     813             :                 }
     814             :             }
     815             :         }
     816             : 
     817             :         // Loop over linear curves and load data
     818         638 :         CurrentModuleObject = "Curve:Linear";
     819         692 :         for (int CurveIndex = 1; CurveIndex <= NumLinear; ++CurveIndex) {
     820         216 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     821             :                                                                      CurrentModuleObject,
     822             :                                                                      CurveIndex,
     823             :                                                                      Alphas,
     824             :                                                                      NumAlphas,
     825             :                                                                      Numbers,
     826             :                                                                      NumNumbers,
     827             :                                                                      IOStatus,
     828          54 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     829             :                                                                      _,
     830          54 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     831          54 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     832         108 :             GlobalNames::VerifyUniqueInterObjectName(state,
     833          54 :                                                      state.dataCurveManager->UniqueCurveNames,
     834          54 :                                                      Alphas(1),
     835             :                                                      CurrentModuleObject,
     836          54 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     837             :                                                      ErrorsFound);
     838          54 :             ++CurveNum;
     839          54 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
     840             : 
     841          54 :             thisCurve.Name = Alphas(1);
     842          54 :             thisCurve.curveType = CurveType::Linear;
     843          54 :             thisCurve.numDims = 1;
     844          54 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
     845         162 :             for (int in = 0; in < 2; ++in) {
     846         108 :                 thisCurve.coeff[in] = Numbers(in + 1);
     847             :             }
     848          54 :             thisCurve.inputLimits[0].min = Numbers(3);
     849          54 :             thisCurve.inputLimits[0].max = Numbers(4);
     850          54 :             if (NumNumbers > 4 && !state.dataIPShortCut->lNumericFieldBlanks(5)) {
     851          19 :                 thisCurve.outputLimits.min = Numbers(5);
     852          19 :                 thisCurve.outputLimits.minPresent = true;
     853             :             }
     854          54 :             if (NumNumbers > 5 && !state.dataIPShortCut->lNumericFieldBlanks(6)) {
     855          19 :                 thisCurve.outputLimits.max = Numbers(6);
     856          19 :                 thisCurve.outputLimits.maxPresent = true;
     857             :             }
     858             : 
     859          54 :             if (Numbers(3) > Numbers(4)) { // error
     860           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
     861           0 :                 ShowContinueError(state,
     862           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
     863           0 :                                          state.dataIPShortCut->cNumericFieldNames(3),
     864             :                                          Numbers(3),
     865           0 :                                          state.dataIPShortCut->cNumericFieldNames(4),
     866           0 :                                          Numbers(4)));
     867           0 :                 ErrorsFound = true;
     868             :             }
     869          54 :             if (NumAlphas >= 2) {
     870          14 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
     871           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
     872             :                 }
     873             :             }
     874          54 :             if (NumAlphas >= 3) {
     875          14 :                 if (!IsCurveOutputTypeValid(Alphas(3))) {
     876           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
     877             :                 }
     878             :             }
     879             :         }
     880             : 
     881             :         // Loop over bicubic curves and load data
     882         638 :         CurrentModuleObject = "Curve:Bicubic";
     883         972 :         for (int CurveIndex = 1; CurveIndex <= NumBicubic; ++CurveIndex) {
     884        1336 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     885             :                                                                      CurrentModuleObject,
     886             :                                                                      CurveIndex,
     887             :                                                                      Alphas,
     888             :                                                                      NumAlphas,
     889             :                                                                      Numbers,
     890             :                                                                      NumNumbers,
     891             :                                                                      IOStatus,
     892         334 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     893             :                                                                      _,
     894         334 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     895         334 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     896         668 :             GlobalNames::VerifyUniqueInterObjectName(state,
     897         334 :                                                      state.dataCurveManager->UniqueCurveNames,
     898         334 :                                                      Alphas(1),
     899             :                                                      CurrentModuleObject,
     900         334 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     901             :                                                      ErrorsFound);
     902         334 :             ++CurveNum;
     903         334 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
     904             : 
     905         334 :             thisCurve.Name = Alphas(1);
     906         334 :             thisCurve.curveType = CurveType::BiCubic;
     907         334 :             thisCurve.numDims = 2;
     908         334 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
     909        3674 :             for (int in = 0; in < 10; ++in) {
     910        3340 :                 thisCurve.coeff[in] = Numbers(in + 1);
     911             :             }
     912         334 :             thisCurve.inputLimits[0].min = Numbers(11);
     913         334 :             thisCurve.inputLimits[0].max = Numbers(12);
     914         334 :             thisCurve.inputLimits[1].min = Numbers(13);
     915         334 :             thisCurve.inputLimits[1].max = Numbers(14);
     916         334 :             if (NumNumbers > 14 && !state.dataIPShortCut->lNumericFieldBlanks(15)) {
     917           0 :                 thisCurve.outputLimits.min = Numbers(15);
     918           0 :                 thisCurve.outputLimits.minPresent = true;
     919             :             }
     920         334 :             if (NumNumbers > 15 && !state.dataIPShortCut->lNumericFieldBlanks(16)) {
     921           0 :                 thisCurve.outputLimits.max = Numbers(16);
     922           0 :                 thisCurve.outputLimits.maxPresent = true;
     923             :             }
     924             : 
     925         334 :             if (Numbers(11) > Numbers(12)) { // error
     926           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
     927           0 :                 ShowContinueError(state,
     928           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
     929           0 :                                          state.dataIPShortCut->cNumericFieldNames(11),
     930             :                                          Numbers(11),
     931           0 :                                          state.dataIPShortCut->cNumericFieldNames(12),
     932           0 :                                          Numbers(12)));
     933           0 :                 ErrorsFound = true;
     934             :             }
     935         334 :             if (Numbers(13) > Numbers(14)) { // error
     936           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
     937           0 :                 ShowContinueError(state,
     938           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
     939           0 :                                          state.dataIPShortCut->cNumericFieldNames(13),
     940             :                                          Numbers(13),
     941           0 :                                          state.dataIPShortCut->cNumericFieldNames(14),
     942           0 :                                          Numbers(14)));
     943           0 :                 ErrorsFound = true;
     944             :             }
     945         334 :             if (NumAlphas >= 2) {
     946          17 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
     947           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
     948             :                 }
     949             :             }
     950         334 :             if (NumAlphas >= 3) {
     951          17 :                 if (!IsCurveInputTypeValid(Alphas(3))) {
     952           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for Y is invalid.", CurrentModuleObject, Alphas(1)));
     953             :                 }
     954             :             }
     955         334 :             if (NumAlphas >= 4) {
     956          17 :                 if (!IsCurveOutputTypeValid(Alphas(4))) {
     957           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
     958             :                 }
     959             :             }
     960             :         }
     961             : 
     962             :         // Loop over Triquadratic curves and load data
     963         638 :         CurrentModuleObject = "Curve:Triquadratic";
     964         645 :         for (int CurveIndex = 1; CurveIndex <= NumTriQuad; ++CurveIndex) {
     965          28 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     966             :                                                                      CurrentModuleObject,
     967             :                                                                      CurveIndex,
     968             :                                                                      Alphas,
     969             :                                                                      NumAlphas,
     970             :                                                                      Numbers,
     971             :                                                                      NumNumbers,
     972             :                                                                      IOStatus,
     973           7 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
     974             :                                                                      _,
     975           7 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     976           7 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     977          14 :             GlobalNames::VerifyUniqueInterObjectName(state,
     978           7 :                                                      state.dataCurveManager->UniqueCurveNames,
     979           7 :                                                      Alphas(1),
     980             :                                                      CurrentModuleObject,
     981           7 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
     982             :                                                      ErrorsFound);
     983           7 :             ++CurveNum;
     984           7 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
     985             : 
     986           7 :             thisCurve.Name = Alphas(1);
     987           7 :             thisCurve.curveType = CurveType::TriQuadratic;
     988           7 :             thisCurve.numDims = 3;
     989           7 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
     990           7 :             thisCurve.tri2ndOrder[0] = Numbers(1);
     991           7 :             thisCurve.tri2ndOrder[1] = Numbers(2);
     992           7 :             thisCurve.tri2ndOrder[2] = Numbers(3);
     993           7 :             thisCurve.tri2ndOrder[3] = Numbers(4);
     994           7 :             thisCurve.tri2ndOrder[4] = Numbers(5);
     995           7 :             thisCurve.tri2ndOrder[5] = Numbers(6);
     996           7 :             thisCurve.tri2ndOrder[6] = Numbers(7);
     997           7 :             thisCurve.tri2ndOrder[7] = Numbers(8);
     998           7 :             thisCurve.tri2ndOrder[8] = Numbers(9);
     999           7 :             thisCurve.tri2ndOrder[9] = Numbers(10);
    1000           7 :             thisCurve.tri2ndOrder[10] = Numbers(11);
    1001           7 :             thisCurve.tri2ndOrder[11] = Numbers(12);
    1002           7 :             thisCurve.tri2ndOrder[12] = Numbers(13);
    1003           7 :             thisCurve.tri2ndOrder[13] = Numbers(14);
    1004           7 :             thisCurve.tri2ndOrder[14] = Numbers(15);
    1005           7 :             thisCurve.tri2ndOrder[15] = Numbers(16);
    1006           7 :             thisCurve.tri2ndOrder[16] = Numbers(17);
    1007           7 :             thisCurve.tri2ndOrder[17] = Numbers(18);
    1008           7 :             thisCurve.tri2ndOrder[18] = Numbers(19);
    1009           7 :             thisCurve.tri2ndOrder[19] = Numbers(20);
    1010           7 :             thisCurve.tri2ndOrder[20] = Numbers(21);
    1011           7 :             thisCurve.tri2ndOrder[21] = Numbers(22);
    1012           7 :             thisCurve.tri2ndOrder[22] = Numbers(23);
    1013           7 :             thisCurve.tri2ndOrder[23] = Numbers(24);
    1014           7 :             thisCurve.tri2ndOrder[24] = Numbers(25);
    1015           7 :             thisCurve.tri2ndOrder[25] = Numbers(26);
    1016           7 :             thisCurve.tri2ndOrder[26] = Numbers(27);
    1017           7 :             thisCurve.inputLimits[0].min = Numbers(28);
    1018           7 :             thisCurve.inputLimits[0].max = Numbers(29);
    1019           7 :             thisCurve.inputLimits[1].min = Numbers(30);
    1020           7 :             thisCurve.inputLimits[1].max = Numbers(31);
    1021           7 :             thisCurve.inputLimits[2].min = Numbers(32);
    1022           7 :             thisCurve.inputLimits[2].max = Numbers(33);
    1023           7 :             if (NumNumbers > 33 && !state.dataIPShortCut->lNumericFieldBlanks(34)) {
    1024           1 :                 thisCurve.outputLimits.min = Numbers(34);
    1025           1 :                 thisCurve.outputLimits.minPresent = true;
    1026             :             }
    1027           7 :             if (NumNumbers > 34 && !state.dataIPShortCut->lNumericFieldBlanks(35)) {
    1028           1 :                 thisCurve.outputLimits.max = Numbers(35);
    1029           1 :                 thisCurve.outputLimits.maxPresent = true;
    1030             :             }
    1031             : 
    1032           7 :             if (Numbers(28) > Numbers(29)) { // error
    1033           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1034           0 :                 ShowContinueError(state,
    1035           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
    1036           0 :                                          state.dataIPShortCut->cNumericFieldNames(28),
    1037             :                                          Numbers(28),
    1038           0 :                                          state.dataIPShortCut->cNumericFieldNames(29),
    1039           0 :                                          Numbers(29)));
    1040           0 :                 ErrorsFound = true;
    1041             :             }
    1042           7 :             if (Numbers(30) > Numbers(31)) { // error
    1043           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1044           0 :                 ShowContinueError(state,
    1045           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
    1046           0 :                                          state.dataIPShortCut->cNumericFieldNames(30),
    1047             :                                          Numbers(30),
    1048           0 :                                          state.dataIPShortCut->cNumericFieldNames(31),
    1049           0 :                                          Numbers(31)));
    1050           0 :                 ErrorsFound = true;
    1051             :             }
    1052           7 :             if (Numbers(32) > Numbers(33)) { // error
    1053           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1054           0 :                 ShowContinueError(state,
    1055           0 :                                   format("{} [{:.R2}] > {} [{.R2}]",
    1056           0 :                                          state.dataIPShortCut->cNumericFieldNames(32),
    1057             :                                          Numbers(32),
    1058           0 :                                          state.dataIPShortCut->cNumericFieldNames(33),
    1059           0 :                                          Numbers(33)));
    1060           0 :                 ErrorsFound = true;
    1061             :             }
    1062           7 :             if (NumAlphas >= 2) {
    1063           0 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
    1064           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
    1065             :                 }
    1066             :             }
    1067           7 :             if (NumAlphas >= 3) {
    1068           0 :                 if (!IsCurveInputTypeValid(Alphas(3))) {
    1069           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for Y is invalid.", CurrentModuleObject, Alphas(1)));
    1070             :                 }
    1071             :             }
    1072           7 :             if (NumAlphas >= 4) {
    1073           0 :                 if (!IsCurveInputTypeValid(Alphas(4))) {
    1074           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for Z is invalid.", CurrentModuleObject, Alphas(1)));
    1075             :                 }
    1076             :             }
    1077           7 :             if (NumAlphas >= 5) {
    1078           0 :                 if (!IsCurveOutputTypeValid(Alphas(5))) {
    1079           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
    1080             :                 }
    1081             :             }
    1082             :         }
    1083             : 
    1084             :         // Loop over quad linear curves and load data
    1085         638 :         CurrentModuleObject = "Curve:QuadLinear";
    1086        1106 :         for (int CurveIndex = 1; CurveIndex <= NumQLinear; ++CurveIndex) {
    1087        1872 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1088             :                                                                      CurrentModuleObject,
    1089             :                                                                      CurveIndex,
    1090             :                                                                      Alphas,
    1091             :                                                                      NumAlphas,
    1092             :                                                                      Numbers,
    1093             :                                                                      NumNumbers,
    1094             :                                                                      IOStatus,
    1095         468 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1096             :                                                                      _,
    1097         468 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1098         468 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1099         936 :             GlobalNames::VerifyUniqueInterObjectName(state,
    1100         468 :                                                      state.dataCurveManager->UniqueCurveNames,
    1101         468 :                                                      Alphas(1),
    1102             :                                                      CurrentModuleObject,
    1103         468 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
    1104             :                                                      ErrorsFound);
    1105         468 :             ++CurveNum;
    1106         468 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
    1107             : 
    1108         468 :             thisCurve.Name = Alphas(1);
    1109         468 :             thisCurve.curveType = CurveType::QuadLinear;
    1110         468 :             thisCurve.numDims = 4;
    1111         468 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
    1112        2808 :             for (int in = 0; in < 5; ++in) {
    1113        2340 :                 thisCurve.coeff[in] = Numbers(in + 1);
    1114             :             }
    1115         468 :             thisCurve.inputLimits[0].min = Numbers(6);
    1116         468 :             thisCurve.inputLimits[0].max = Numbers(7);
    1117         468 :             thisCurve.inputLimits[1].min = Numbers(8);
    1118         468 :             thisCurve.inputLimits[1].max = Numbers(9);
    1119         468 :             thisCurve.inputLimits[2].min = Numbers(10);
    1120         468 :             thisCurve.inputLimits[2].max = Numbers(11);
    1121         468 :             thisCurve.inputLimits[3].min = Numbers(12);
    1122         468 :             thisCurve.inputLimits[3].max = Numbers(13);
    1123             : 
    1124         468 :             if (NumNumbers > 13 && !state.dataIPShortCut->lNumericFieldBlanks(14)) {
    1125          60 :                 thisCurve.outputLimits.min = Numbers(14);
    1126          60 :                 thisCurve.outputLimits.minPresent = true;
    1127             :             }
    1128         468 :             if (NumNumbers > 14 && !state.dataIPShortCut->lNumericFieldBlanks(15)) {
    1129          60 :                 thisCurve.outputLimits.max = Numbers(15);
    1130          60 :                 thisCurve.outputLimits.maxPresent = true;
    1131             :             }
    1132             : 
    1133         468 :             constexpr int NumVar = 4;
    1134         936 :             std::string VarNames[NumVar] = {"w", "x", "y", "z"};
    1135        2340 :             for (int i = 1; i <= NumVar; ++i) {
    1136        1872 :                 int MinIndex = 2 * i + 4;
    1137        1872 :                 int MaxIndex = MinIndex + 1;
    1138        1872 :                 if (Numbers(MinIndex) > Numbers(MaxIndex)) { // error
    1139           0 :                     ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1140           0 :                     ShowContinueError(state,
    1141           0 :                                       format("{} [{:.R2}] > {} [{.R2}]",
    1142           0 :                                              state.dataIPShortCut->cNumericFieldNames(MinIndex),
    1143             :                                              Numbers(MinIndex),
    1144           0 :                                              state.dataIPShortCut->cNumericFieldNames(MaxIndex),
    1145           0 :                                              Numbers(MaxIndex)));
    1146           0 :                     ErrorsFound = true;
    1147             :                 }
    1148        1872 :                 int InputTypeIndex = i + 1;
    1149        1872 :                 if (NumAlphas >= InputTypeIndex) {
    1150          48 :                     if (!IsCurveInputTypeValid(Alphas(InputTypeIndex))) {
    1151           0 :                         ShowWarningError(
    1152           0 :                             state, format("In {} named {} the Input Unit Type for {} is invalid.", CurrentModuleObject, Alphas(1), VarNames[i]));
    1153             :                     }
    1154             :                 }
    1155             :             }
    1156         468 :             if (NumAlphas >= 6) {
    1157           0 :                 if (!IsCurveOutputTypeValid(Alphas(6))) {
    1158           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
    1159             :                 }
    1160             :             }
    1161             :         }
    1162             : 
    1163             :         // Loop over quint linear curves and load data
    1164         638 :         CurrentModuleObject = "Curve:QuintLinear";
    1165         750 :         for (int CurveIndex = 1; CurveIndex <= NumQuintLinear; ++CurveIndex) {
    1166         448 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1167             :                                                                      CurrentModuleObject,
    1168             :                                                                      CurveIndex,
    1169             :                                                                      Alphas,
    1170             :                                                                      NumAlphas,
    1171             :                                                                      Numbers,
    1172             :                                                                      NumNumbers,
    1173             :                                                                      IOStatus,
    1174         112 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1175             :                                                                      _,
    1176         112 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1177         112 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1178         224 :             GlobalNames::VerifyUniqueInterObjectName(state,
    1179         112 :                                                      state.dataCurveManager->UniqueCurveNames,
    1180         112 :                                                      Alphas(1),
    1181             :                                                      CurrentModuleObject,
    1182         112 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
    1183             :                                                      ErrorsFound);
    1184         112 :             ++CurveNum;
    1185         112 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
    1186             : 
    1187         112 :             thisCurve.Name = Alphas(1);
    1188         112 :             thisCurve.curveType = CurveType::QuintLinear;
    1189         112 :             thisCurve.numDims = 5;
    1190         112 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
    1191         784 :             for (int in = 0; in < 6; ++in) {
    1192         672 :                 thisCurve.coeff[in] = Numbers(in + 1);
    1193             :             }
    1194         112 :             thisCurve.inputLimits[0].min = Numbers(7);
    1195         112 :             thisCurve.inputLimits[0].max = Numbers(8);
    1196         112 :             thisCurve.inputLimits[1].min = Numbers(9);
    1197         112 :             thisCurve.inputLimits[1].max = Numbers(10);
    1198         112 :             thisCurve.inputLimits[2].min = Numbers(11);
    1199         112 :             thisCurve.inputLimits[2].max = Numbers(12);
    1200         112 :             thisCurve.inputLimits[3].min = Numbers(13);
    1201         112 :             thisCurve.inputLimits[3].max = Numbers(14);
    1202         112 :             thisCurve.inputLimits[4].min = Numbers(15);
    1203         112 :             thisCurve.inputLimits[4].max = Numbers(16);
    1204         112 :             if (NumNumbers > 16 && !state.dataIPShortCut->lNumericFieldBlanks(17)) {
    1205          10 :                 thisCurve.outputLimits.min = Numbers(17);
    1206          10 :                 thisCurve.outputLimits.minPresent = true;
    1207             :             }
    1208         112 :             if (NumNumbers > 17 && !state.dataIPShortCut->lNumericFieldBlanks(18)) {
    1209          10 :                 thisCurve.outputLimits.max = Numbers(18);
    1210          10 :                 thisCurve.outputLimits.maxPresent = true;
    1211             :             }
    1212             : 
    1213         112 :             constexpr int NumVar = 5;
    1214         224 :             std::string VarNames[NumVar] = {"v", "w", "x", "y", "z"};
    1215         672 :             for (int i = 1; i <= NumVar; ++i) {
    1216         560 :                 int MinIndex = 2 * i + 5;
    1217         560 :                 int MaxIndex = MinIndex + 1;
    1218         560 :                 if (Numbers(MinIndex) > Numbers(MaxIndex)) { // error
    1219           0 :                     ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1220           0 :                     ShowContinueError(state,
    1221           0 :                                       format("{} [{:.R2}] > {} [{.R2}]",
    1222           0 :                                              state.dataIPShortCut->cNumericFieldNames(MinIndex),
    1223             :                                              Numbers(MinIndex),
    1224           0 :                                              state.dataIPShortCut->cNumericFieldNames(MaxIndex),
    1225           0 :                                              Numbers(MaxIndex)));
    1226           0 :                     ErrorsFound = true;
    1227             :                 }
    1228         560 :                 int InputTypeIndex = i + 1;
    1229         560 :                 if (NumAlphas >= InputTypeIndex) {
    1230           0 :                     if (!IsCurveInputTypeValid(Alphas(InputTypeIndex))) {
    1231           0 :                         ShowWarningError(
    1232           0 :                             state, format("In {} named {} the Input Unit Type for {} is invalid.", CurrentModuleObject, Alphas(1), VarNames[i]));
    1233             :                     }
    1234             :                 }
    1235             :             }
    1236         112 :             if (NumAlphas >= 7) {
    1237           0 :                 if (!IsCurveOutputTypeValid(Alphas(7))) {
    1238           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
    1239             :                 }
    1240             :             }
    1241             :         }
    1242             : 
    1243             :         // Loop over Exponent curves and load data
    1244         638 :         CurrentModuleObject = "Curve:Exponent";
    1245         654 :         for (int CurveIndex = 1; CurveIndex <= NumExponent; ++CurveIndex) {
    1246          64 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1247             :                                                                      CurrentModuleObject,
    1248             :                                                                      CurveIndex,
    1249             :                                                                      Alphas,
    1250             :                                                                      NumAlphas,
    1251             :                                                                      Numbers,
    1252             :                                                                      NumNumbers,
    1253             :                                                                      IOStatus,
    1254          16 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1255             :                                                                      _,
    1256          16 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1257          16 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1258          32 :             GlobalNames::VerifyUniqueInterObjectName(state,
    1259          16 :                                                      state.dataCurveManager->UniqueCurveNames,
    1260          16 :                                                      Alphas(1),
    1261             :                                                      CurrentModuleObject,
    1262          16 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
    1263             :                                                      ErrorsFound);
    1264          16 :             ++CurveNum;
    1265          16 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
    1266             : 
    1267          16 :             thisCurve.Name = Alphas(1);
    1268          16 :             thisCurve.curveType = CurveType::Exponent;
    1269          16 :             thisCurve.numDims = 1;
    1270          16 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
    1271          64 :             for (int in = 0; in < 3; ++in) {
    1272          48 :                 thisCurve.coeff[in] = Numbers(in + 1);
    1273             :             }
    1274          16 :             thisCurve.inputLimits[0].min = Numbers(4);
    1275          16 :             thisCurve.inputLimits[0].max = Numbers(5);
    1276          16 :             if (NumNumbers > 5 && !state.dataIPShortCut->lNumericFieldBlanks(6)) {
    1277           8 :                 thisCurve.outputLimits.min = Numbers(6);
    1278           8 :                 thisCurve.outputLimits.minPresent = true;
    1279             :             }
    1280          16 :             if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) {
    1281           8 :                 thisCurve.outputLimits.max = Numbers(7);
    1282           8 :                 thisCurve.outputLimits.maxPresent = true;
    1283             :             }
    1284          16 :             if (NumAlphas >= 2) {
    1285           0 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
    1286           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
    1287             :                 }
    1288             :             }
    1289          16 :             if (NumAlphas >= 3) {
    1290           0 :                 if (!IsCurveOutputTypeValid(Alphas(3))) {
    1291           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
    1292             :                 }
    1293             :             }
    1294             :         }
    1295             : 
    1296             :         // Loop over Fan Pressure Rise curves and load data
    1297         638 :         CurrentModuleObject = "Curve:FanPressureRise";
    1298         642 :         for (int CurveIndex = 1; CurveIndex <= NumFanPressRise; ++CurveIndex) {
    1299          16 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1300             :                                                                      CurrentModuleObject,
    1301             :                                                                      CurveIndex,
    1302             :                                                                      Alphas,
    1303             :                                                                      NumAlphas,
    1304             :                                                                      Numbers,
    1305             :                                                                      NumNumbers,
    1306             :                                                                      IOStatus,
    1307           4 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1308             :                                                                      _,
    1309           4 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1310           4 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1311           8 :             GlobalNames::VerifyUniqueInterObjectName(state,
    1312           4 :                                                      state.dataCurveManager->UniqueCurveNames,
    1313           4 :                                                      Alphas(1),
    1314             :                                                      CurrentModuleObject,
    1315           4 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
    1316             :                                                      ErrorsFound);
    1317           4 :             ++CurveNum;
    1318           4 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
    1319             : 
    1320           4 :             thisCurve.Name = Alphas(1);
    1321           4 :             thisCurve.curveType = CurveType::FanPressureRise;
    1322           4 :             thisCurve.numDims = 2;
    1323           4 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
    1324          20 :             for (int in = 0; in < 4; ++in) {
    1325          16 :                 thisCurve.coeff[in] = Numbers(in + 1);
    1326             :             }
    1327           4 :             thisCurve.inputLimits[0].min = Numbers(5);
    1328           4 :             thisCurve.inputLimits[0].max = Numbers(6);
    1329           4 :             thisCurve.inputLimits[1].min = Numbers(7);
    1330           4 :             thisCurve.inputLimits[1].max = Numbers(8);
    1331             : 
    1332           4 :             if (NumNumbers > 8 && !state.dataIPShortCut->lNumericFieldBlanks(9)) {
    1333           4 :                 thisCurve.outputLimits.min = Numbers(9);
    1334           4 :                 thisCurve.outputLimits.minPresent = true;
    1335             :             }
    1336           4 :             if (NumNumbers > 9 && !state.dataIPShortCut->lNumericFieldBlanks(10)) {
    1337           4 :                 thisCurve.outputLimits.max = Numbers(10);
    1338           4 :                 thisCurve.outputLimits.maxPresent = true;
    1339             :             }
    1340             : 
    1341           4 :             if (Numbers(5) > Numbers(6)) { // error
    1342           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1343           0 :                 ShowContinueError(state,
    1344           0 :                                   format("{}[{:.R2}] > {} [{.R2}]",
    1345           0 :                                          state.dataIPShortCut->cNumericFieldNames(5),
    1346             :                                          Numbers(5),
    1347           0 :                                          state.dataIPShortCut->cNumericFieldNames(6),
    1348           0 :                                          Numbers(6)));
    1349           0 :                 ErrorsFound = true;
    1350             :             }
    1351           4 :             if (Numbers(7) > Numbers(8)) { // error
    1352           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1353           0 :                 ShowContinueError(state,
    1354           0 :                                   format("{}[{:.R2}] > {} [{.R2}]",
    1355           0 :                                          state.dataIPShortCut->cNumericFieldNames(7),
    1356             :                                          Numbers(7),
    1357           0 :                                          state.dataIPShortCut->cNumericFieldNames(8),
    1358           0 :                                          Numbers(8)));
    1359           0 :                 ErrorsFound = true;
    1360             :             }
    1361             : 
    1362             :         } // Fan Pressure Rise
    1363             : 
    1364             :         // Loop over Exponential Skew Normal curves and load data
    1365         638 :         CurrentModuleObject = "Curve:ExponentialSkewNormal";
    1366         646 :         for (int CurveIndex = 1; CurveIndex <= NumExpSkewNorm; ++CurveIndex) {
    1367          32 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1368             :                                                                      CurrentModuleObject,
    1369             :                                                                      CurveIndex,
    1370             :                                                                      Alphas,
    1371             :                                                                      NumAlphas,
    1372             :                                                                      Numbers,
    1373             :                                                                      NumNumbers,
    1374             :                                                                      IOStatus,
    1375           8 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1376             :                                                                      _,
    1377           8 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1378           8 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1379          16 :             GlobalNames::VerifyUniqueInterObjectName(state,
    1380           8 :                                                      state.dataCurveManager->UniqueCurveNames,
    1381           8 :                                                      Alphas(1),
    1382             :                                                      CurrentModuleObject,
    1383           8 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
    1384             :                                                      ErrorsFound);
    1385           8 :             ++CurveNum;
    1386           8 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
    1387             : 
    1388           8 :             thisCurve.Name = Alphas(1);
    1389           8 :             thisCurve.curveType = CurveType::ExponentialSkewNormal;
    1390           8 :             thisCurve.numDims = 1;
    1391           8 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
    1392          40 :             for (int in = 0; in < 4; ++in) {
    1393          32 :                 thisCurve.coeff[in] = Numbers(in + 1);
    1394             :             }
    1395           8 :             thisCurve.inputLimits[0].min = Numbers(5);
    1396           8 :             thisCurve.inputLimits[0].max = Numbers(6);
    1397             : 
    1398           8 :             if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) {
    1399           8 :                 thisCurve.outputLimits.min = Numbers(7);
    1400           8 :                 thisCurve.outputLimits.minPresent = true;
    1401             :             }
    1402           8 :             if (NumNumbers > 7 && !state.dataIPShortCut->lNumericFieldBlanks(8)) {
    1403           8 :                 thisCurve.outputLimits.max = Numbers(8);
    1404           8 :                 thisCurve.outputLimits.maxPresent = true;
    1405             :             }
    1406             : 
    1407           8 :             if (Numbers(5) > Numbers(6)) { // error
    1408           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1409           0 :                 ShowContinueError(state,
    1410           0 :                                   format("{}[{:.R2}] > {} [{.R2}]",
    1411           0 :                                          state.dataIPShortCut->cNumericFieldNames(5),
    1412             :                                          Numbers(5),
    1413           0 :                                          state.dataIPShortCut->cNumericFieldNames(6),
    1414           0 :                                          Numbers(6)));
    1415           0 :                 ErrorsFound = true;
    1416             :             }
    1417             : 
    1418           8 :             if (NumAlphas >= 2) {
    1419           0 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
    1420           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
    1421             :                 }
    1422             :             }
    1423           8 :             if (NumAlphas >= 3) {
    1424           0 :                 if (!IsCurveOutputTypeValid(Alphas(3))) {
    1425           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
    1426             :                 }
    1427             :             }
    1428             :         } // Exponential Skew Normal
    1429             : 
    1430             :         // Loop over Sigmoid curves and load data
    1431         638 :         CurrentModuleObject = "Curve:Sigmoid";
    1432         646 :         for (int CurveIndex = 1; CurveIndex <= NumSigmoid; ++CurveIndex) {
    1433          32 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1434             :                                                                      CurrentModuleObject,
    1435             :                                                                      CurveIndex,
    1436             :                                                                      Alphas,
    1437             :                                                                      NumAlphas,
    1438             :                                                                      Numbers,
    1439             :                                                                      NumNumbers,
    1440             :                                                                      IOStatus,
    1441           8 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1442             :                                                                      _,
    1443           8 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1444           8 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1445          16 :             GlobalNames::VerifyUniqueInterObjectName(state,
    1446           8 :                                                      state.dataCurveManager->UniqueCurveNames,
    1447           8 :                                                      Alphas(1),
    1448             :                                                      CurrentModuleObject,
    1449           8 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
    1450             :                                                      ErrorsFound);
    1451           8 :             ++CurveNum;
    1452           8 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
    1453             : 
    1454           8 :             thisCurve.Name = Alphas(1);
    1455           8 :             thisCurve.curveType = CurveType::Sigmoid;
    1456           8 :             thisCurve.numDims = 1;
    1457           8 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
    1458          48 :             for (int in = 0; in < 5; ++in) {
    1459          40 :                 thisCurve.coeff[in] = Numbers(in + 1);
    1460             :             }
    1461           8 :             thisCurve.inputLimits[0].min = Numbers(6);
    1462           8 :             thisCurve.inputLimits[0].max = Numbers(7);
    1463             : 
    1464           8 :             if (NumNumbers > 7 && !state.dataIPShortCut->lNumericFieldBlanks(8)) {
    1465           8 :                 thisCurve.outputLimits.min = Numbers(8);
    1466           8 :                 thisCurve.outputLimits.minPresent = true;
    1467             :             }
    1468           8 :             if (NumNumbers > 8 && !state.dataIPShortCut->lNumericFieldBlanks(9)) {
    1469           8 :                 thisCurve.outputLimits.max = Numbers(9);
    1470           8 :                 thisCurve.outputLimits.maxPresent = true;
    1471             :             }
    1472             : 
    1473           8 :             if (Numbers(6) > Numbers(7)) { // error
    1474           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1475           0 :                 ShowContinueError(state,
    1476           0 :                                   format("{}[{:.R2}] > {} [{.R2}]",
    1477           0 :                                          state.dataIPShortCut->cNumericFieldNames(6),
    1478             :                                          Numbers(6),
    1479           0 :                                          state.dataIPShortCut->cNumericFieldNames(7),
    1480           0 :                                          Numbers(7)));
    1481           0 :                 ErrorsFound = true;
    1482             :             }
    1483             : 
    1484           8 :             if (NumAlphas >= 2) {
    1485           0 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
    1486           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
    1487             :                 }
    1488             :             }
    1489           8 :             if (NumAlphas >= 3) {
    1490           0 :                 if (!IsCurveOutputTypeValid(Alphas(3))) {
    1491           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
    1492             :                 }
    1493             :             }
    1494             :         } // Sigmoid
    1495             : 
    1496             :         // Loop over Rectangular Hyperbola Type 1 curves and load data
    1497         638 :         CurrentModuleObject = "Curve:RectangularHyperbola1";
    1498         642 :         for (int CurveIndex = 1; CurveIndex <= NumRectHyper1; ++CurveIndex) {
    1499          16 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1500             :                                                                      CurrentModuleObject,
    1501             :                                                                      CurveIndex,
    1502             :                                                                      Alphas,
    1503             :                                                                      NumAlphas,
    1504             :                                                                      Numbers,
    1505             :                                                                      NumNumbers,
    1506             :                                                                      IOStatus,
    1507           4 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1508             :                                                                      _,
    1509           4 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1510           4 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1511           8 :             GlobalNames::VerifyUniqueInterObjectName(state,
    1512           4 :                                                      state.dataCurveManager->UniqueCurveNames,
    1513           4 :                                                      Alphas(1),
    1514             :                                                      CurrentModuleObject,
    1515           4 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
    1516             :                                                      ErrorsFound);
    1517           4 :             ++CurveNum;
    1518           4 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
    1519             : 
    1520           4 :             thisCurve.Name = Alphas(1);
    1521           4 :             thisCurve.curveType = CurveType::RectangularHyperbola1;
    1522           4 :             thisCurve.numDims = 1;
    1523           4 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
    1524          16 :             for (int in = 0; in < 3; ++in) {
    1525          12 :                 thisCurve.coeff[in] = Numbers(in + 1);
    1526             :             }
    1527           4 :             thisCurve.inputLimits[0].min = Numbers(4);
    1528           4 :             thisCurve.inputLimits[0].max = Numbers(5);
    1529             : 
    1530           4 :             if (NumNumbers > 5 && !state.dataIPShortCut->lNumericFieldBlanks(6)) {
    1531           4 :                 thisCurve.outputLimits.min = Numbers(6);
    1532           4 :                 thisCurve.outputLimits.minPresent = true;
    1533             :             }
    1534           4 :             if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) {
    1535           4 :                 thisCurve.outputLimits.max = Numbers(7);
    1536           4 :                 thisCurve.outputLimits.maxPresent = true;
    1537             :             }
    1538             : 
    1539           4 :             if (Numbers(4) > Numbers(5)) { // error
    1540           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1541           0 :                 ShowContinueError(state,
    1542           0 :                                   format("{}[{:.R2}] > {} [{.R2}]",
    1543           0 :                                          state.dataIPShortCut->cNumericFieldNames(4),
    1544             :                                          Numbers(4),
    1545           0 :                                          state.dataIPShortCut->cNumericFieldNames(5),
    1546           0 :                                          Numbers(5)));
    1547           0 :                 ErrorsFound = true;
    1548             :             }
    1549             : 
    1550           4 :             if (NumAlphas >= 2) {
    1551           0 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
    1552           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
    1553             :                 }
    1554             :             }
    1555           4 :             if (NumAlphas >= 3) {
    1556           0 :                 if (!IsCurveOutputTypeValid(Alphas(3))) {
    1557           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
    1558             :                 }
    1559             :             }
    1560             :         } // Rectangular Hyperbola Type 1
    1561             : 
    1562             :         // Loop over Rectangular Hyperbola Type 2 curves and load data
    1563         638 :         CurrentModuleObject = "Curve:RectangularHyperbola2";
    1564         656 :         for (int CurveIndex = 1; CurveIndex <= NumRectHyper2; ++CurveIndex) {
    1565          72 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1566             :                                                                      CurrentModuleObject,
    1567             :                                                                      CurveIndex,
    1568             :                                                                      Alphas,
    1569             :                                                                      NumAlphas,
    1570             :                                                                      Numbers,
    1571             :                                                                      NumNumbers,
    1572             :                                                                      IOStatus,
    1573          18 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1574             :                                                                      _,
    1575          18 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1576          18 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1577          36 :             GlobalNames::VerifyUniqueInterObjectName(state,
    1578          18 :                                                      state.dataCurveManager->UniqueCurveNames,
    1579          18 :                                                      Alphas(1),
    1580             :                                                      CurrentModuleObject,
    1581          18 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
    1582             :                                                      ErrorsFound);
    1583          18 :             ++CurveNum;
    1584          18 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
    1585             : 
    1586          18 :             thisCurve.Name = Alphas(1);
    1587          18 :             thisCurve.curveType = CurveType::RectangularHyperbola2;
    1588          18 :             thisCurve.numDims = 1;
    1589          18 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
    1590          72 :             for (int in = 0; in < 3; ++in) {
    1591          54 :                 thisCurve.coeff[in] = Numbers(in + 1);
    1592             :             }
    1593          18 :             thisCurve.inputLimits[0].min = Numbers(4);
    1594          18 :             thisCurve.inputLimits[0].max = Numbers(5);
    1595             : 
    1596          18 :             if (NumNumbers > 5 && !state.dataIPShortCut->lNumericFieldBlanks(6)) {
    1597          18 :                 thisCurve.outputLimits.min = Numbers(6);
    1598          18 :                 thisCurve.outputLimits.minPresent = true;
    1599             :             }
    1600          18 :             if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) {
    1601          18 :                 thisCurve.outputLimits.max = Numbers(7);
    1602          18 :                 thisCurve.outputLimits.maxPresent = true;
    1603             :             }
    1604             : 
    1605          18 :             if (Numbers(4) > Numbers(5)) { // error
    1606           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1607           0 :                 ShowContinueError(state,
    1608           0 :                                   format("{}[{:.R2}] > {} [{.R2}]",
    1609           0 :                                          state.dataIPShortCut->cNumericFieldNames(4),
    1610             :                                          Numbers(4),
    1611           0 :                                          state.dataIPShortCut->cNumericFieldNames(5),
    1612           0 :                                          Numbers(5)));
    1613           0 :                 ErrorsFound = true;
    1614             :             }
    1615             : 
    1616          18 :             if (NumAlphas >= 2) {
    1617           2 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
    1618           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
    1619             :                 }
    1620             :             }
    1621          18 :             if (NumAlphas >= 3) {
    1622           2 :                 if (!IsCurveOutputTypeValid(Alphas(3))) {
    1623           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
    1624             :                 }
    1625             :             }
    1626             :         } // Rectangular Hyperbola Type 2
    1627             : 
    1628             :         // Loop over Exponential Decay curves and load data
    1629         638 :         CurrentModuleObject = "Curve:ExponentialDecay";
    1630         642 :         for (int CurveIndex = 1; CurveIndex <= NumExpDecay; ++CurveIndex) {
    1631          16 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1632             :                                                                      CurrentModuleObject,
    1633             :                                                                      CurveIndex,
    1634             :                                                                      Alphas,
    1635             :                                                                      NumAlphas,
    1636             :                                                                      Numbers,
    1637             :                                                                      NumNumbers,
    1638             :                                                                      IOStatus,
    1639           4 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1640             :                                                                      _,
    1641           4 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1642           4 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1643           8 :             GlobalNames::VerifyUniqueInterObjectName(state,
    1644           4 :                                                      state.dataCurveManager->UniqueCurveNames,
    1645           4 :                                                      Alphas(1),
    1646             :                                                      CurrentModuleObject,
    1647           4 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
    1648             :                                                      ErrorsFound);
    1649           4 :             ++CurveNum;
    1650           4 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
    1651             : 
    1652           4 :             thisCurve.Name = Alphas(1);
    1653           4 :             thisCurve.curveType = CurveType::ExponentialDecay;
    1654           4 :             thisCurve.numDims = 1;
    1655           4 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
    1656          16 :             for (int in = 0; in < 3; ++in) {
    1657          12 :                 thisCurve.coeff[in] = Numbers(in + 1);
    1658             :             }
    1659           4 :             thisCurve.inputLimits[0].min = Numbers(4);
    1660           4 :             thisCurve.inputLimits[0].max = Numbers(5);
    1661             : 
    1662           4 :             if (NumNumbers > 5 && !state.dataIPShortCut->lNumericFieldBlanks(6)) {
    1663           4 :                 thisCurve.outputLimits.min = Numbers(6);
    1664           4 :                 thisCurve.outputLimits.minPresent = true;
    1665             :             }
    1666           4 :             if (NumNumbers > 6 && !state.dataIPShortCut->lNumericFieldBlanks(7)) {
    1667           4 :                 thisCurve.outputLimits.max = Numbers(7);
    1668           4 :                 thisCurve.outputLimits.maxPresent = true;
    1669             :             }
    1670             : 
    1671           4 :             if (Numbers(4) > Numbers(5)) { // error
    1672           0 :                 ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1673           0 :                 ShowContinueError(state,
    1674           0 :                                   format("{}[{:.R2}] > {} [{.R2}]",
    1675           0 :                                          state.dataIPShortCut->cNumericFieldNames(4),
    1676             :                                          Numbers(4),
    1677           0 :                                          state.dataIPShortCut->cNumericFieldNames(5),
    1678           0 :                                          Numbers(5)));
    1679           0 :                 ErrorsFound = true;
    1680             :             }
    1681             : 
    1682           4 :             if (NumAlphas >= 2) {
    1683           0 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
    1684           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
    1685             :                 }
    1686             :             }
    1687           4 :             if (NumAlphas >= 3) {
    1688           0 :                 if (!IsCurveOutputTypeValid(Alphas(3))) {
    1689           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
    1690             :                 }
    1691             :             }
    1692             :         } // Exponential Decay
    1693             : 
    1694             :         // ykt July,2011 Loop over DoubleExponential Decay curves and load data
    1695         638 :         CurrentModuleObject = "Curve:DoubleExponentialDecay";
    1696         640 :         for (int CurveIndex = 1; CurveIndex <= NumDoubleExpDecay; ++CurveIndex) {
    1697           8 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1698             :                                                                      CurrentModuleObject,
    1699             :                                                                      CurveIndex,
    1700             :                                                                      Alphas,
    1701             :                                                                      NumAlphas,
    1702             :                                                                      Numbers,
    1703             :                                                                      NumNumbers,
    1704             :                                                                      IOStatus,
    1705           2 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    1706             :                                                                      _,
    1707           2 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    1708           2 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    1709           4 :             GlobalNames::VerifyUniqueInterObjectName(state,
    1710           2 :                                                      state.dataCurveManager->UniqueCurveNames,
    1711           2 :                                                      Alphas(1),
    1712             :                                                      CurrentModuleObject,
    1713           2 :                                                      state.dataIPShortCut->cAlphaFieldNames(1),
    1714             :                                                      ErrorsFound);
    1715           2 :             ++CurveNum;
    1716           2 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
    1717             : 
    1718           2 :             thisCurve.Name = Alphas(1);
    1719           2 :             thisCurve.curveType = CurveType::DoubleExponentialDecay;
    1720           2 :             thisCurve.numDims = 1;
    1721           2 :             thisCurve.interpolationType = InterpType::EvaluateCurveToLimits;
    1722          12 :             for (int in = 0; in < 5; ++in) {
    1723          10 :                 thisCurve.coeff[in] = Numbers(in + 1);
    1724             :             }
    1725           2 :             thisCurve.inputLimits[0].min = Numbers(6);
    1726           2 :             thisCurve.inputLimits[0].max = Numbers(7);
    1727             : 
    1728           2 :             if (NumNumbers > 7 && !state.dataIPShortCut->lNumericFieldBlanks(8)) {
    1729           0 :                 thisCurve.outputLimits.min = Numbers(8);
    1730           0 :                 thisCurve.outputLimits.minPresent = true;
    1731             :             }
    1732           2 :             if (NumNumbers > 8 && !state.dataIPShortCut->lNumericFieldBlanks(9)) {
    1733           0 :                 thisCurve.outputLimits.max = Numbers(9);
    1734           0 :                 thisCurve.outputLimits.maxPresent = true;
    1735             :             }
    1736             : 
    1737           2 :             if (NumAlphas >= 2) {
    1738           2 :                 if (!IsCurveInputTypeValid(Alphas(2))) {
    1739           0 :                     ShowWarningError(state, format("In {} named {} the Input Unit Type for X is invalid.", CurrentModuleObject, Alphas(1)));
    1740             :                 }
    1741             :             }
    1742           2 :             if (NumAlphas >= 3) {
    1743           2 :                 if (!IsCurveOutputTypeValid(Alphas(3))) {
    1744           0 :                     ShowWarningError(state, format("In {} named {} the Output Unit Type is invalid.", CurrentModuleObject, Alphas(1)));
    1745             :                 }
    1746             :             }
    1747             :         } // Exponential Decay
    1748             : 
    1749             :         // Loop over wind pressure coefficient tables and load data
    1750         638 :         if (NumWPCValTab > 0) {
    1751             :             // Get the angle values
    1752          27 :             CurrentModuleObject = "AirflowNetwork:MultiZone:WindPressureCoefficientArray";
    1753          27 :             int numOfCPArray = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
    1754             : 
    1755          27 :             if (numOfCPArray != 1) {
    1756           0 :                 ShowSevereError(state,
    1757           0 :                                 "GetCurveInput: Currently exactly one (\"1\") " + CurrentModuleObject +
    1758             :                                     " object per simulation is required when using the AirflowNetwork model.");
    1759           0 :                 ErrorsFound = true;
    1760          27 :             } else if (numOfCPArray == 1) {
    1761         108 :                 state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1762             :                                                                          CurrentModuleObject,
    1763             :                                                                          1,
    1764             :                                                                          Alphas,
    1765             :                                                                          NumAlphas,
    1766             :                                                                          Numbers,
    1767             :                                                                          NumNumbers,
    1768             :                                                                          IOStatus,
    1769          27 :                                                                          state.dataIPShortCut->lNumericFieldBlanks,
    1770             :                                                                          _,
    1771          27 :                                                                          state.dataIPShortCut->cAlphaFieldNames,
    1772          27 :                                                                          state.dataIPShortCut->cNumericFieldNames);
    1773             : 
    1774          54 :                 std::string wpcName = Alphas(1); // Name of CP array
    1775          27 :                 int numWindDir = NumNumbers;
    1776          54 :                 std::vector<Real64> windDirs(numWindDir);
    1777             : 
    1778          27 :                 Real64 dirMin = 0;
    1779          27 :                 Real64 dirMax = 0;
    1780         323 :                 for (int j = 1; j <= NumNumbers; ++j) { // Wind direction
    1781         296 :                     windDirs[j - 1] = Numbers(j);
    1782         296 :                     dirMin = std::min(dirMin, Numbers(j));
    1783         296 :                     dirMax = std::max(dirMax, Numbers(j));
    1784         296 :                     if (j > 1) {
    1785         269 :                         if (windDirs[j - 2] >= windDirs[j - 1]) {
    1786           0 :                             ShowSevereError(state, format("GetCurveInput: An {} object ", CurrentModuleObject));
    1787           0 :                             ShowContinueError(state,
    1788             :                                               "has either the same values for two consecutive wind directions, or a lower wind direction value after "
    1789             :                                               "a higher wind direction value.");
    1790           0 :                             ShowContinueError(state, "Wind direction values must be entered in ascending order.");
    1791           0 :                             ShowContinueError(state,
    1792           0 :                                               format("{} = {:.2R} {} = {:.2R}",
    1793           0 :                                                      state.dataIPShortCut->cNumericFieldNames(j),
    1794           0 :                                                      windDirs[j - 2],
    1795           0 :                                                      state.dataIPShortCut->cNumericFieldNames[j + 1],
    1796           0 :                                                      windDirs[j - 1]));
    1797           0 :                             ErrorsFound = true;
    1798             :                         }
    1799             :                     }
    1800             :                 }
    1801             :                 // Check that the first table value is zero
    1802          27 :                 if (dirMin != 0.0) {
    1803           0 :                     ShowSevereError(state, format("GetCurveInput: An {} object ", CurrentModuleObject));
    1804           0 :                     ShowContinueError(state, format("has a nonzero minimum value of {:.2R}", dirMin));
    1805           0 :                     ShowContinueError(state, "Wind direction values must begin at zero.");
    1806           0 :                     ErrorsFound = true;
    1807             :                 }
    1808             : 
    1809             :                 // Now that we have the directions, we can read the tables themselves
    1810          27 :                 CurrentModuleObject = "AirflowNetwork:MultiZone:WindPressureCoefficientValues";
    1811         140 :                 for (int index = 1; index <= NumWPCValTab; ++index) {
    1812         452 :                     state.dataInputProcessing->inputProcessor->getObjectItem(state,
    1813             :                                                                              CurrentModuleObject,
    1814             :                                                                              index,
    1815             :                                                                              Alphas,
    1816             :                                                                              NumAlphas,
    1817             :                                                                              Numbers,
    1818             :                                                                              NumNumbers,
    1819             :                                                                              IOStatus,
    1820         113 :                                                                              state.dataIPShortCut->lNumericFieldBlanks,
    1821             :                                                                              _,
    1822         113 :                                                                              state.dataIPShortCut->cAlphaFieldNames,
    1823         113 :                                                                              state.dataIPShortCut->cNumericFieldNames);
    1824         113 :                     ++CurveNum;
    1825         226 :                     GlobalNames::VerifyUniqueInterObjectName(state,
    1826         113 :                                                              state.dataCurveManager->UniqueCurveNames,
    1827         113 :                                                              Alphas(1),
    1828             :                                                              CurrentModuleObject,
    1829         113 :                                                              state.dataIPShortCut->cAlphaFieldNames(1),
    1830             :                                                              ErrorsFound);
    1831             : 
    1832             :                     // Ensure the CP array name should be the same as the name of AirflowNetwork:MultiZone:WindPressureCoefficientArray
    1833         113 :                     if (!UtilityRoutines::SameString(Alphas(2), wpcName)) {
    1834           0 :                         ShowSevereError(state,
    1835           0 :                                         format("GetCurveInput: Invalid {} = {} in {} = ",
    1836           0 :                                                state.dataIPShortCut->cAlphaFieldNames(2),
    1837             :                                                Alphas(2),
    1838           0 :                                                CurrentModuleObject));
    1839           0 :                         ShowContinueError(state, "The valid name is " + wpcName);
    1840           0 :                         ErrorsFound = true;
    1841             :                     }
    1842             : 
    1843         113 :                     auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
    1844             : 
    1845         113 :                     thisCurve.Name = Alphas(1);
    1846         113 :                     thisCurve.numDims = 1;
    1847             : 
    1848         113 :                     thisCurve.interpolationType = InterpType::BtwxtMethod;
    1849             : 
    1850         226 :                     std::string contextString = format("{} \"{}\"", CurrentModuleObject, Alphas(1));
    1851         226 :                     std::pair<EnergyPlusData *, std::string> callbackPair{&state, contextString};
    1852         113 :                     Btwxt::setMessageCallback(Curve::BtwxtMessageCallback, &callbackPair);
    1853             : 
    1854         113 :                     thisCurve.inputLimits[0].min = 0.0;
    1855         113 :                     thisCurve.inputLimits[0].minPresent = true;
    1856         113 :                     thisCurve.inputLimits[0].max = 360.0;
    1857         113 :                     thisCurve.inputLimits[0].maxPresent = true;
    1858             : 
    1859         113 :                     thisCurve.outputLimits.min = -1.0;
    1860         113 :                     thisCurve.outputLimits.minPresent = true;
    1861         113 :                     thisCurve.outputLimits.max = 1.0;
    1862         113 :                     thisCurve.outputLimits.maxPresent = true;
    1863             : 
    1864         113 :                     MaxTableNums = NumNumbers;
    1865         113 :                     if (NumNumbers != numWindDir) {
    1866           0 :                         ShowSevereError(state, format("GetCurveInput: For {}: ", CurrentModuleObject));
    1867           0 :                         ShowContinueError(state,
    1868           0 :                                           format("The number of data entries must match the number of wind directions given in the wind pressure "
    1869             :                                                  "coefficient array. Number of data entries = {}",
    1870           0 :                                                  NumNumbers));
    1871           0 :                         ErrorsFound = true;
    1872             :                     } else {
    1873         226 :                         std::vector<double> axis;
    1874         226 :                         std::vector<double> lookupValues;
    1875             : 
    1876        1413 :                         for (int TableDataIndex = 1; TableDataIndex <= MaxTableNums; ++TableDataIndex) {
    1877        1300 :                             axis.push_back(windDirs[TableDataIndex - 1]);
    1878        1300 :                             lookupValues.push_back(Numbers(TableDataIndex));
    1879             :                         }
    1880         113 :                         if (axis[axis.size() - 1] < 360.0) {
    1881         105 :                             axis.push_back(360.0);
    1882         105 :                             lookupValues.push_back(Numbers(1));
    1883             :                         }
    1884             : 
    1885         226 :                         std::vector<Btwxt::GridAxis> gridAxes;
    1886         113 :                         gridAxes.emplace_back(axis, Btwxt::Method::LINEAR, Btwxt::Method::LINEAR, std::pair<double, double>{0.0, 360.0});
    1887             : 
    1888         113 :                         auto gridIndex = state.dataCurveManager->btwxtManager.addGrid(Alphas(1), Btwxt::GriddedData(gridAxes));
    1889         113 :                         thisCurve.TableIndex = gridIndex;
    1890         113 :                         thisCurve.GridValueIndex = state.dataCurveManager->btwxtManager.addOutputValues(gridIndex, lookupValues);
    1891             :                     }
    1892             :                 }
    1893             :             }
    1894             :         }
    1895             : 
    1896             :         // Create case insensitive references to independent variable input data
    1897         638 :         int numIndVars = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Table:IndependentVariable");
    1898         638 :         if (numIndVars > 0) {
    1899             :             // Set Btwxt Message Callback
    1900          12 :             auto const &indVarInstances = state.dataInputProcessing->inputProcessor->getObjectInstances("Table:IndependentVariable");
    1901         154 :             for (auto &instance : indVarInstances.items()) {
    1902         142 :                 auto const &fields = instance.value();
    1903         142 :                 auto const &thisObjectName = instance.key();
    1904         142 :                 state.dataInputProcessing->inputProcessor->markObjectAsUsed("Table:IndependentVariable", thisObjectName);
    1905         142 :                 state.dataCurveManager->btwxtManager.independentVarRefs.emplace(UtilityRoutines::MakeUPPERCase(thisObjectName), fields);
    1906             :             }
    1907             :         }
    1908             : 
    1909             :         // Create GridSpaces from Independent Variable List
    1910         638 :         int numIndVarLists = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Table:IndependentVariableList");
    1911             :         std::map<std::string, std::vector<std::pair<double, double>>>
    1912        1276 :             varListLimits; // ugly, but this is needed for legacy behavior (otherwise limits are reset by Btwxt if they are within bounds).
    1913        1276 :         std::map<std::string, std::vector<double>> varListNormalizeTargets;
    1914         638 :         if (numIndVarLists > 0) {
    1915          24 :             auto const indVarListInstances = state.dataInputProcessing->inputProcessor->getObjectInstances("Table:IndependentVariableList");
    1916          83 :             for (auto &instance : indVarListInstances.items()) {
    1917             : 
    1918          71 :                 auto const &fields = instance.value();
    1919          71 :                 auto const &thisObjectName = instance.key();
    1920          71 :                 state.dataInputProcessing->inputProcessor->markObjectAsUsed("Table:IndependentVariableList", thisObjectName);
    1921         142 :                 std::string varListName = UtilityRoutines::MakeUPPERCase(thisObjectName);
    1922             : 
    1923         142 :                 std::vector<Btwxt::GridAxis> gridAxes;
    1924             : 
    1925             :                 // Loop through independent variables in list and add them to the grid
    1926         213 :                 for (auto indVar : fields.at("independent_variables")) {
    1927         284 :                     std::string indVarName = UtilityRoutines::MakeUPPERCase(indVar.at("independent_variable_name").get<std::string>());
    1928         284 :                     std::string contextString = format("Table:IndependentVariable \"{}\"", indVarName);
    1929         284 :                     std::pair<EnergyPlusData *, std::string> callbackPair{&state, contextString};
    1930         142 :                     Btwxt::setMessageCallback(Curve::BtwxtMessageCallback, &callbackPair);
    1931             : 
    1932             :                     // Find independent variable input data
    1933         142 :                     if (state.dataCurveManager->btwxtManager.independentVarRefs.count(indVarName)) {
    1934             :                         // If found, read data
    1935         142 :                         auto const &indVarInstance = state.dataCurveManager->btwxtManager.independentVarRefs.at(indVarName);
    1936             : 
    1937             :                         // TODO: Actually use this to define output variable units
    1938         142 :                         if (indVarInstance.count("unit_type")) {
    1939         282 :                             std::string unitType = indVarInstance.at("unit_type").get<std::string>();
    1940         141 :                             if (!IsCurveOutputTypeValid(unitType)) {
    1941           0 :                                 ShowSevereError(state, format("{}: Unit Type [{}] is invalid", contextString, unitType));
    1942             :                             }
    1943             :                         }
    1944             : 
    1945         284 :                         std::vector<double> axis;
    1946             : 
    1947         142 :                         if (indVarInstance.count("external_file_name")) {
    1948           4 :                             std::string tmp = indVarInstance.at("external_file_name").get<std::string>();
    1949           4 :                             fs::path filePath(tmp);
    1950           2 :                             if (!indVarInstance.count("external_file_column_number")) {
    1951           0 :                                 ShowSevereError(state,
    1952           0 :                                                 format("{}: No column number defined for external file \"{}\"", contextString, filePath.string()));
    1953           0 :                                 ErrorsFound = true;
    1954             :                             }
    1955           2 :                             if (!indVarInstance.count("external_file_starting_row_number")) {
    1956           0 :                                 ShowSevereError(
    1957           0 :                                     state, format("{}: No starting row number defined for external file \"{}\"", contextString, filePath.string()));
    1958           0 :                                 ErrorsFound = true;
    1959             :                             }
    1960             : 
    1961           2 :                             std::size_t colNum = indVarInstance.at("external_file_column_number").get<std::size_t>() - 1;
    1962           2 :                             std::size_t rowNum = indVarInstance.at("external_file_starting_row_number").get<std::size_t>() - 1;
    1963             : 
    1964           2 :                             if (!state.dataCurveManager->btwxtManager.tableFiles.count(filePath)) {
    1965           2 :                                 TableFile tableFile;
    1966           1 :                                 ErrorsFound |= tableFile.load(state, filePath);
    1967           1 :                                 state.dataCurveManager->btwxtManager.tableFiles.emplace(filePath, tableFile);
    1968             :                             }
    1969             : 
    1970           2 :                             if (ErrorsFound) continue; // Unable to load file so continue on to see if there are other errors before fataling
    1971             : 
    1972           2 :                             axis = state.dataCurveManager->btwxtManager.tableFiles[filePath].getArray(state, {colNum, rowNum});
    1973             : 
    1974             :                             // remove NANs
    1975          62 :                             axis.erase(std::remove_if(axis.begin(), axis.end(), [](const double &x) { return std::isnan(x); }), axis.end());
    1976             : 
    1977             :                             // sort
    1978           2 :                             std::sort(axis.begin(), axis.end());
    1979             : 
    1980             :                             // remove duplicates
    1981           2 :                             axis.erase(std::unique(axis.begin(), axis.end()), axis.end());
    1982             : 
    1983         140 :                         } else if (indVarInstance.count("values")) {
    1984        1007 :                             for (auto const &value : indVarInstance.at("values")) {
    1985         867 :                                 axis.push_back(value.at("value").get<Real64>());
    1986             :                             }
    1987             :                         } else {
    1988           0 :                             ShowSevereError(state, format("{}: No values defined.", contextString));
    1989           0 :                             ErrorsFound = true;
    1990             :                         }
    1991             : 
    1992             :                         Btwxt::Method interpMethod, extrapMethod;
    1993         142 :                         if (indVarInstance.count("interpolation_method")) {
    1994         142 :                             interpMethod = Curve::BtwxtManager::interpMethods.at(indVarInstance.at("interpolation_method").get<std::string>());
    1995             :                         } else {
    1996           0 :                             interpMethod = Btwxt::Method::CUBIC;
    1997             :                         }
    1998             : 
    1999         142 :                         if (indVarInstance.count("extrapolation_method")) {
    2000         142 :                             if (indVarInstance.at("extrapolation_method") == "Unavailable") {
    2001           0 :                                 ShowSevereError(state, format("{}: Extrapolation method \"Unavailable\" is not yet available.", contextString));
    2002           0 :                                 ErrorsFound = true;
    2003             :                             }
    2004         142 :                             extrapMethod = Curve::BtwxtManager::extrapMethods.at(indVarInstance.at("extrapolation_method").get<std::string>());
    2005             :                         } else {
    2006           0 :                             extrapMethod = Btwxt::Method::LINEAR;
    2007             :                         }
    2008             : 
    2009         142 :                         double min_grid_value = *std::min_element(axis.begin(), axis.end());
    2010         142 :                         double max_grid_value = *std::max_element(axis.begin(), axis.end());
    2011             : 
    2012             :                         double min_val, max_val;
    2013         142 :                         if (indVarInstance.count("minimum_value")) {
    2014         142 :                             min_val = indVarInstance.at("minimum_value").get<Real64>();
    2015             :                         } else {
    2016           0 :                             min_val = min_grid_value;
    2017             :                         }
    2018             : 
    2019         142 :                         if (indVarInstance.count("maximum_value")) {
    2020         142 :                             max_val = indVarInstance.at("maximum_value").get<Real64>();
    2021             :                         } else {
    2022           0 :                             max_val = max_grid_value;
    2023             :                         }
    2024             : 
    2025         142 :                         varListLimits[varListName].emplace_back(min_val, max_val);
    2026             : 
    2027             :                         Real64 normalizationRefValue;
    2028         142 :                         if (indVarInstance.count("normalization_reference_value")) {
    2029          12 :                             normalizationRefValue = indVarInstance.at("normalization_reference_value").get<Real64>();
    2030             :                         } else {
    2031         130 :                             normalizationRefValue = std::numeric_limits<double>::quiet_NaN();
    2032             :                         }
    2033             : 
    2034         142 :                         varListNormalizeTargets[varListName].push_back(normalizationRefValue);
    2035             : 
    2036             :                         // reset limits passed to Btwxt to avoid warnings related to different handling of limits
    2037         142 :                         min_val = min(min_val, min_grid_value);
    2038         142 :                         max_val = max(max_val, max_grid_value);
    2039             : 
    2040         142 :                         gridAxes.emplace_back(axis, extrapMethod, interpMethod, std::pair<double, double>{min_val, max_val});
    2041             : 
    2042             :                     } else {
    2043             :                         // Independent variable does not exist
    2044           0 :                         ShowSevereError(state, format("{}: No Table:IndependentVariable found.", contextString));
    2045           0 :                         ErrorsFound = true;
    2046             :                     }
    2047             :                 }
    2048             :                 // Add grid to btwxtManager
    2049          71 :                 state.dataCurveManager->btwxtManager.addGrid(UtilityRoutines::MakeUPPERCase(thisObjectName), Btwxt::GriddedData(gridAxes));
    2050             :             }
    2051             :         }
    2052             : 
    2053         638 :         int numTblLookups = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, "Table:Lookup");
    2054         638 :         if (numTblLookups > 0) {
    2055          24 :             auto const lookupInstances = state.dataInputProcessing->inputProcessor->getObjectInstances("Table:Lookup");
    2056         109 :             for (auto &instance : lookupInstances.items()) {
    2057             : 
    2058          97 :                 auto const &fields = instance.value();
    2059          97 :                 auto const &thisObjectName = instance.key();
    2060          97 :                 state.dataInputProcessing->inputProcessor->markObjectAsUsed("Table:Lookup", thisObjectName);
    2061          97 :                 ++CurveNum;
    2062          97 :                 auto &thisCurve = state.dataCurveManager->PerfCurve(CurveNum);
    2063             : 
    2064          97 :                 thisCurve.Name = UtilityRoutines::MakeUPPERCase(thisObjectName);
    2065          97 :                 thisCurve.interpolationType = InterpType::BtwxtMethod;
    2066             : 
    2067         194 :                 std::string indVarListName = UtilityRoutines::MakeUPPERCase(fields.at("independent_variable_list_name").get<std::string>());
    2068             : 
    2069         194 :                 std::string contextString = format("Table:Lookup \"{}\"", thisCurve.Name);
    2070         194 :                 std::pair<EnergyPlusData *, std::string> callbackPair{&state, contextString};
    2071          97 :                 Btwxt::setMessageCallback(Curve::BtwxtMessageCallback, &callbackPair);
    2072             : 
    2073             :                 // TODO: Actually use this to define output variable units
    2074          97 :                 if (fields.count("output_unit_type")) {
    2075         194 :                     std::string unitType = fields.at("output_unit_type").get<std::string>();
    2076          97 :                     if (!IsCurveOutputTypeValid(unitType)) {
    2077           0 :                         ShowSevereError(state, format("{}: Output Unit Type [{}] is invalid", contextString, unitType));
    2078             :                     }
    2079             :                 }
    2080             : 
    2081          97 :                 int gridIndex = state.dataCurveManager->btwxtManager.getGridIndex(state, indVarListName, ErrorsFound);
    2082          97 :                 thisCurve.TableIndex = gridIndex;
    2083          97 :                 int numDims = state.dataCurveManager->btwxtManager.getNumGridDims(gridIndex);
    2084          97 :                 thisCurve.numDims = numDims;
    2085             : 
    2086         387 :                 for (int i = 1; i <= std::min(6, numDims); ++i) {
    2087             :                     double vMin, vMax;
    2088         290 :                     std::tie(vMin, vMax) = varListLimits.at(indVarListName)[i - 1];
    2089         290 :                     if (i == 1) {
    2090          97 :                         thisCurve.inputLimits[0].min = vMin;
    2091          97 :                         thisCurve.inputLimits[0].max = vMax;
    2092         193 :                     } else if (i == 2) {
    2093          59 :                         thisCurve.inputLimits[1].min = vMin;
    2094          59 :                         thisCurve.inputLimits[1].max = vMax;
    2095         134 :                     } else if (i == 3) {
    2096          42 :                         thisCurve.inputLimits[2].min = vMin;
    2097          42 :                         thisCurve.inputLimits[2].max = vMax;
    2098          92 :                     } else if (i == 4) {
    2099          31 :                         thisCurve.inputLimits[3].min = vMin;
    2100          31 :                         thisCurve.inputLimits[3].max = vMax;
    2101          61 :                     } else if (i == 5) {
    2102          31 :                         thisCurve.inputLimits[4].min = vMin;
    2103          31 :                         thisCurve.inputLimits[4].max = vMax;
    2104          30 :                     } else if (i == 6) {
    2105          30 :                         thisCurve.inputLimits[5].min = vMin;
    2106          30 :                         thisCurve.inputLimits[5].max = vMax;
    2107             :                     }
    2108             :                 }
    2109             : 
    2110          97 :                 if (fields.count("minimum_output")) {
    2111          78 :                     thisCurve.outputLimits.min = fields.at("minimum_output").get<Real64>();
    2112          78 :                     thisCurve.outputLimits.minPresent = true;
    2113             :                 } else {
    2114          19 :                     thisCurve.outputLimits.min = -DBL_MAX;
    2115          19 :                     thisCurve.outputLimits.minPresent = false;
    2116             :                 }
    2117             : 
    2118          97 :                 if (fields.count("maximum_output")) {
    2119          78 :                     thisCurve.outputLimits.max = fields.at("maximum_output").get<Real64>();
    2120          78 :                     thisCurve.outputLimits.maxPresent = true;
    2121             :                 } else {
    2122          19 :                     thisCurve.outputLimits.max = DBL_MAX;
    2123          19 :                     thisCurve.outputLimits.maxPresent = false;
    2124             :                 }
    2125             : 
    2126             :                 // Normalize data
    2127          97 :                 Real64 normalizationDivisor = 1.0;
    2128             :                 enum NormalizationMethod
    2129             :                 {
    2130             :                     NM_NONE,
    2131             :                     NM_DIVISOR_ONLY,
    2132             :                     NM_AUTO_WITH_DIVISOR
    2133             :                 };
    2134          97 :                 NormalizationMethod normalizeMethod = NM_NONE;
    2135          97 :                 if (fields.count("normalization_method")) {
    2136          48 :                     if (UtilityRoutines::SameString(fields.at("normalization_method").get<std::string>(), "DIVISORONLY")) {
    2137          44 :                         normalizeMethod = NM_DIVISOR_ONLY;
    2138           4 :                     } else if (UtilityRoutines::SameString(fields.at("normalization_method").get<std::string>(), "AUTOMATICWITHDIVISOR")) {
    2139           4 :                         normalizeMethod = NM_AUTO_WITH_DIVISOR;
    2140             :                     }
    2141             :                 }
    2142             : 
    2143          97 :                 if (normalizeMethod != NM_NONE && fields.count("normalization_divisor")) {
    2144          29 :                     normalizationDivisor = fields.at("normalization_divisor").get<Real64>();
    2145             :                 }
    2146             : 
    2147         194 :                 std::vector<double> lookupValues;
    2148          97 :                 if (fields.count("external_file_name")) {
    2149           2 :                     std::string tmp = fields.at("external_file_name").get<std::string>();
    2150           2 :                     fs::path filePath(tmp);
    2151             : 
    2152           1 :                     if (!fields.count("external_file_column_number")) {
    2153           0 :                         ShowSevereError(state, format("{}: No column number defined for external file \"{}\"", contextString, filePath.string()));
    2154           0 :                         ErrorsFound = true;
    2155             :                     }
    2156           1 :                     if (!fields.count("external_file_starting_row_number")) {
    2157           0 :                         ShowSevereError(state,
    2158           0 :                                         format("{}: No starting row number defined for external file \"{}\"", contextString, filePath.string()));
    2159           0 :                         ErrorsFound = true;
    2160             :                     }
    2161             : 
    2162           1 :                     std::size_t colNum = fields.at("external_file_column_number").get<std::size_t>() - 1;
    2163           1 :                     std::size_t rowNum = fields.at("external_file_starting_row_number").get<std::size_t>() - 1;
    2164             : 
    2165           1 :                     if (!state.dataCurveManager->btwxtManager.tableFiles.count(filePath)) {
    2166           0 :                         TableFile tableFile;
    2167           0 :                         ErrorsFound |= tableFile.load(state, filePath);
    2168           0 :                         state.dataCurveManager->btwxtManager.tableFiles.emplace(filePath, tableFile);
    2169             :                     }
    2170             : 
    2171           1 :                     if (ErrorsFound) continue; // Unable to load file so continue on to see if there are other errors before fataling
    2172             : 
    2173           1 :                     lookupValues = state.dataCurveManager->btwxtManager.tableFiles[filePath].getArray(state, {colNum, rowNum});
    2174             : 
    2175             :                     // remove NANs
    2176          31 :                     lookupValues.erase(std::remove_if(lookupValues.begin(), lookupValues.end(), [](const double &x) { return std::isnan(x); }),
    2177           2 :                                        lookupValues.end());
    2178             : 
    2179          96 :                 } else if (fields.count("values")) {
    2180       43425 :                     for (auto value : fields.at("values")) {
    2181       43329 :                         lookupValues.push_back(value.at("output_value").get<Real64>() / normalizationDivisor);
    2182             :                     }
    2183             :                 } else {
    2184           0 :                     ShowSevereError(state, format("{}: No values defined.", contextString));
    2185           0 :                     ErrorsFound = true;
    2186             :                 }
    2187             : 
    2188          97 :                 thisCurve.GridValueIndex = state.dataCurveManager->btwxtManager.addOutputValues(gridIndex, lookupValues);
    2189             : 
    2190          97 :                 if (normalizeMethod == NM_AUTO_WITH_DIVISOR) {
    2191           8 :                     auto const normalizeTarget = varListNormalizeTargets.at(indVarListName);
    2192             : 
    2193           4 :                     bool pointsSpecified = false;
    2194           4 :                     bool pointsUnspecified = false;
    2195          12 :                     for (auto value : normalizeTarget) {
    2196           8 :                         if (std::isnan(value)) {
    2197           0 :                             pointsUnspecified = true;
    2198             :                         } else {
    2199           8 :                             pointsSpecified = true;
    2200             :                         }
    2201             :                     }
    2202           4 :                     if (pointsSpecified && pointsUnspecified) {
    2203           0 :                         ShowSevereError(state,
    2204           0 :                                         format("{}: Table is to be normalized using AutomaticWithDivisor, but not all independent variables define a "
    2205             :                                                "normalization reference value. Make sure either:",
    2206           0 :                                                contextString));
    2207           0 :                         ShowContinueError(state, "  Make sure either:");
    2208           0 :                         ShowContinueError(state, "    a) a normalization reference value is defined for each independent variable, or");
    2209           0 :                         ShowContinueError(state, "    b) no normalization reference values are defined.");
    2210           0 :                         ErrorsFound = true;
    2211           4 :                     } else if (pointsSpecified) {
    2212             :                         // normalizeGridValues normalizes curve values to 1.0 at the normalization target, and returns the scalar needed to perform
    2213             :                         // this normalization. The result is multiplied by the input normalizationDivisor again for the AutomaticWithDivisor case, in
    2214             :                         // which normalizeGridValues returns a compound scalar.
    2215           4 :                         normalizationDivisor = state.dataCurveManager->btwxtManager.normalizeGridValues(
    2216             :                                                    gridIndex, thisCurve.GridValueIndex, normalizeTarget, normalizationDivisor) *
    2217             :                                                normalizationDivisor;
    2218             :                     }
    2219             :                 }
    2220             : 
    2221          97 :                 if ((normalizeMethod == NM_DIVISOR_ONLY) || (normalizeMethod == NM_AUTO_WITH_DIVISOR)) {
    2222          48 :                     if (thisCurve.outputLimits.maxPresent) {
    2223          46 :                         thisCurve.outputLimits.max = thisCurve.outputLimits.max / normalizationDivisor;
    2224             :                     }
    2225          48 :                     if (thisCurve.outputLimits.minPresent) {
    2226          46 :                         thisCurve.outputLimits.min = thisCurve.outputLimits.min / normalizationDivisor;
    2227             :                     }
    2228             :                 }
    2229             :             }
    2230             :         }
    2231         638 :         state.dataCurveManager->btwxtManager.tableFiles.clear();
    2232         638 :     }
    2233             : 
    2234          97 :     int BtwxtManager::getGridIndex(EnergyPlusData &state, std::string &indVarListName, bool &ErrorsFound)
    2235             :     {
    2236          97 :         int gridIndex = -1;
    2237          97 :         if (gridMap.count(indVarListName)) {
    2238          97 :             gridIndex = gridMap.at(indVarListName);
    2239             :         } else {
    2240             :             // Independent variable list does not exist
    2241           0 :             ShowSevereError(state, format("Table:Lookup \"{}\" : No Table:IndependentVariableList found.", indVarListName));
    2242           0 :             ErrorsFound = true;
    2243             :         }
    2244          97 :         return gridIndex;
    2245             :     }
    2246             : 
    2247         251 :     int BtwxtManager::addOutputValues(int gridIndex, std::vector<double> values)
    2248             :     {
    2249         251 :         return (int)grids[gridIndex].add_value_table(values);
    2250             :     }
    2251             : 
    2252          97 :     int BtwxtManager::getNumGridDims(int gridIndex)
    2253             :     {
    2254          97 :         return (int)grids[gridIndex].get_ndims();
    2255             :     }
    2256             : 
    2257     8880733 :     double BtwxtManager::getGridValue(int gridIndex, int outputIndex, const std::vector<double> &target)
    2258             :     {
    2259     8880733 :         return grids[gridIndex](target)[outputIndex];
    2260             :     }
    2261             : 
    2262           4 :     double BtwxtManager::normalizeGridValues(int gridIndex, int outputIndex, const std::vector<double> &target, const double scalar)
    2263             :     {
    2264           4 :         return grids[gridIndex].normalize_values_at_target(outputIndex, target, scalar);
    2265             :     }
    2266             : 
    2267           0 :     void BtwxtManager::clear()
    2268             :     {
    2269           0 :         grids.clear();
    2270           0 :         gridMap.clear();
    2271           0 :         independentVarRefs.clear();
    2272           0 :         tableFiles.clear();
    2273           0 :     }
    2274             : 
    2275           1 :     bool TableFile::load(EnergyPlusData &state, fs::path const &path)
    2276             :     {
    2277           1 :         this->filePath = path;
    2278           2 :         std::string contextString = "CurveManager::TableFile::load: ";
    2279           2 :         fs::path fullPath = DataSystemVariables::CheckForActualFilePath(state, path, contextString);
    2280           1 :         if (fullPath.empty()) {
    2281             :             // Note: we return 'ErrorsFound' apparently
    2282           0 :             return true;
    2283             :         }
    2284           2 :         std::ifstream file(fullPath);
    2285           2 :         std::string line;
    2286           1 :         numRows = 0;
    2287           1 :         numColumns = 0;
    2288          63 :         while (getline(file, line)) {
    2289          31 :             ++numRows;
    2290          31 :             std::size_t pos(0);
    2291          31 :             std::size_t colNum(1);
    2292         155 :             while ((pos = line.find(',')) != std::string::npos) {
    2293          62 :                 if (colNum > numColumns) {
    2294           2 :                     numColumns = colNum;
    2295           2 :                     contents.resize(numColumns);
    2296             :                 }
    2297          62 :                 contents[colNum - 1].push_back(line.substr(0, pos));
    2298          62 :                 line.erase(0, pos + 1);
    2299          62 :                 ++colNum;
    2300             :             }
    2301             :             // Anything after the last comma
    2302          31 :             if (!line.empty()) {
    2303          31 :                 if (colNum > numColumns) {
    2304           1 :                     numColumns = colNum;
    2305           1 :                     contents.resize(numColumns);
    2306             :                 }
    2307          31 :                 contents[colNum - 1].push_back(line);
    2308          31 :                 ++colNum;
    2309             :             }
    2310             :             // flesh out columns if row ends early
    2311          31 :             while (colNum <= numColumns) {
    2312           0 :                 contents[colNum - 1].emplace_back("");
    2313           0 :                 ++colNum;
    2314             :             }
    2315             :         }
    2316           1 :         return false;
    2317             :     }
    2318             : 
    2319           3 :     std::vector<double> &TableFile::getArray(EnergyPlusData &state, std::pair<std::size_t, std::size_t> colAndRow)
    2320             :     {
    2321           3 :         if (!arrays.count(colAndRow)) {
    2322             :             // create the column from the data if it doesn't exist already
    2323           3 :             std::size_t col = colAndRow.first;  // 0 indexed
    2324           3 :             std::size_t row = colAndRow.second; // 0 indexed
    2325           3 :             auto &content = contents[col];
    2326           3 :             if (col >= numColumns) {
    2327           0 :                 ShowFatalError(
    2328           0 :                     state, format("File \"{}\" : Requested column ({}) exceeds the number of columns ({}).", filePath.string(), col + 1, numColumns));
    2329             :             }
    2330           3 :             if (row >= numRows) {
    2331           0 :                 ShowFatalError(
    2332           0 :                     state, format("File \"{}\" : Requested starting row ({}) exceeds the number of rows ({}).", filePath.string(), row + 1, numRows));
    2333             :             }
    2334           6 :             std::vector<double> array(numRows - row);
    2335          93 :             std::transform(content.begin() + row, content.end(), array.begin(), [](std::string_view str) {
    2336             :                 // Convert strings to double
    2337          90 :                 auto first_char = str.find_first_not_of(' ');
    2338          90 :                 if (first_char != std::string_view::npos) {
    2339          41 :                     str.remove_prefix(first_char);
    2340             :                 }
    2341          90 :                 double result = 0;
    2342          90 :                 auto answer = fast_float::from_chars(str.data(), str.data() + str.size(), result);
    2343          90 :                 if (answer.ec != std::errc()) {
    2344          49 :                     return std::numeric_limits<double>::quiet_NaN();
    2345             :                 }
    2346          41 :                 return result;
    2347             :             });
    2348           3 :             arrays[colAndRow] = array;
    2349             :         }
    2350           3 :         return arrays.at(colAndRow);
    2351             :     }
    2352             : 
    2353         769 :     void InitCurveReporting(EnergyPlusData &state)
    2354             :     {
    2355             : 
    2356             :         // SUBROUTINE INFORMATION:
    2357             :         //       AUTHOR         Linda Lawrie
    2358             :         //       DATE WRITTEN   October 2011
    2359             :         //       MODIFIED       na
    2360             :         //       RE-ENGINEERED  na
    2361             : 
    2362             :         // PURPOSE OF THIS SUBROUTINE:
    2363             :         // Setting up of curve output variables caused errors in some files. Thus, separating the setup
    2364             :         // from the getinput.
    2365             : 
    2366             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2367        7272 :         for (auto &thisCurve : state.dataCurveManager->PerfCurve) {
    2368       17392 :             for (int dim = 1; dim <= thisCurve.numDims; ++dim) {
    2369       21778 :                 std::string numStr = fmt::to_string(dim);
    2370       32667 :                 SetupOutputVariable(state,
    2371       21778 :                                     format("Performance Curve Input Variable {} Value", numStr),
    2372             :                                     OutputProcessor::Unit::None,
    2373       10889 :                                     thisCurve.inputs[dim - 1],
    2374             :                                     OutputProcessor::SOVTimeStepType::HVAC,
    2375             :                                     OutputProcessor::SOVStoreType::Average,
    2376             :                                     thisCurve.Name);
    2377             :             }
    2378             :             // set the output up last so it shows up after the input in the csv file
    2379       13006 :             SetupOutputVariable(state,
    2380             :                                 "Performance Curve Output Value",
    2381             :                                 OutputProcessor::Unit::None,
    2382             :                                 thisCurve.output,
    2383             :                                 OutputProcessor::SOVTimeStepType::HVAC,
    2384             :                                 OutputProcessor::SOVStoreType::Average,
    2385        6503 :                                 thisCurve.Name);
    2386             :         }
    2387             : 
    2388         772 :         for (auto &thisPressCurve : state.dataBranchAirLoopPlant->PressureCurve) {
    2389           6 :             SetupOutputVariable(state,
    2390             :                                 "Performance Curve Input Variable 1 Value",
    2391             :                                 OutputProcessor::Unit::None,
    2392             :                                 thisPressCurve.CurveInput1,
    2393             :                                 OutputProcessor::SOVTimeStepType::HVAC,
    2394             :                                 OutputProcessor::SOVStoreType::Average,
    2395           3 :                                 thisPressCurve.Name);
    2396           6 :             SetupOutputVariable(state,
    2397             :                                 "Performance Curve Input Variable 2 Value",
    2398             :                                 OutputProcessor::Unit::None,
    2399             :                                 thisPressCurve.CurveInput2,
    2400             :                                 OutputProcessor::SOVTimeStepType::HVAC,
    2401             :                                 OutputProcessor::SOVStoreType::Average,
    2402           3 :                                 thisPressCurve.Name);
    2403           6 :             SetupOutputVariable(state,
    2404             :                                 "Performance Curve Input Variable 3 Value",
    2405             :                                 OutputProcessor::Unit::None,
    2406             :                                 thisPressCurve.CurveInput3,
    2407             :                                 OutputProcessor::SOVTimeStepType::HVAC,
    2408             :                                 OutputProcessor::SOVStoreType::Average,
    2409           3 :                                 thisPressCurve.Name);
    2410           6 :             SetupOutputVariable(state,
    2411             :                                 "Performance Curve Output Value",
    2412             :                                 OutputProcessor::Unit::None,
    2413             :                                 thisPressCurve.CurveOutput,
    2414             :                                 OutputProcessor::SOVTimeStepType::HVAC,
    2415             :                                 OutputProcessor::SOVStoreType::Average,
    2416           3 :                                 thisPressCurve.Name);
    2417             :         }
    2418             : 
    2419         769 :         if (state.dataGlobal->AnyEnergyManagementSystemInModel) { // provide hook for possible EMS control
    2420        1945 :             for (auto &thisCurve : state.dataCurveManager->PerfCurve) {
    2421        5628 :                 SetupEMSActuator(
    2422        3752 :                     state, "Curve", thisCurve.Name, "Curve Result", "[unknown]", thisCurve.EMSOverrideOn, thisCurve.EMSOverrideCurveValue);
    2423             :             } // All performance curves
    2424             :         }
    2425         769 :         if (state.dataGlobal->AnyEnergyManagementSystemInModel) { // provide hook for possible EMS control
    2426          69 :             for (auto &thisPressCurve : state.dataBranchAirLoopPlant->PressureCurve) {
    2427           0 :                 SetupEMSActuator(state,
    2428             :                                  "Curve",
    2429             :                                  thisPressCurve.Name,
    2430             :                                  "Curve Result",
    2431             :                                  "[unknown]",
    2432             :                                  thisPressCurve.EMSOverrideOn,
    2433           0 :                                  thisPressCurve.EMSOverrideCurveValue);
    2434             :             } // All pressure curves
    2435             :         }
    2436         769 :     }
    2437             : 
    2438   596628038 :     Real64 PerformanceCurveObject(EnergyPlusData &state,
    2439             :                                   int const CurveIndex,        // index of curve in curve array
    2440             :                                   Real64 const Var1,           // 1st independent variable
    2441             :                                   Optional<Real64 const> Var2, // 2nd independent variable
    2442             :                                   Optional<Real64 const> Var3, // 3rd independent variable
    2443             :                                   Optional<Real64 const> Var4, // 4th independent variable
    2444             :                                   Optional<Real64 const> Var5  // 5th independent variable
    2445             :     )
    2446             :     {
    2447             : 
    2448             :         // FUNCTION INFORMATION:
    2449             :         //       AUTHOR         Fred Buhl
    2450             :         //       DATE WRITTEN   May 2000
    2451             :         //       MODIFIED       Lixing Gu, July 2006; B. Griffith July 2006
    2452             :         //                      22Aug2010 Craig Wray, added new curves for fan component model:
    2453             :         //                          FanPressureRise, ExponentialSkewNormal, Sigmoid, RectangularHyperbola1,
    2454             :         //                          RectangularHyperbola2, ExponentialDecay
    2455             : 
    2456             :         //       RE-ENGINEERED  Autodesk: Performance tuning
    2457             : 
    2458             :         // PURPOSE OF THIS FUNCTION:
    2459             :         // Given the curve index and the values of 1 or 2 independent variables,
    2460             :         // returns the value of an equipment performance curve.
    2461             : 
    2462             :         // Return value
    2463             :         Real64 CurveValue;
    2464             : 
    2465             :         static Real64 const sqrt_2_inv(1.0 / std::sqrt(2.0)); // would be constexpr-able if std::sqrt was constexpr, but not yet
    2466             : 
    2467   596628038 :         auto const &curve(state.dataCurveManager->PerfCurve(CurveIndex));
    2468             : 
    2469   596628038 :         Real64 const V1(max(min(Var1, curve.inputLimits[0].max), curve.inputLimits[0].min)); // 1st independent variable after limits imposed
    2470   596628038 :         Real64 const V2(Var2.present() ? max(min(Var2, curve.inputLimits[1].max), curve.inputLimits[1].min)
    2471   596628038 :                                        : 0.0); // 2nd independent variable after limits imposed
    2472   596628038 :         Real64 const V3(Var3.present() ? max(min(Var3, curve.inputLimits[2].max), curve.inputLimits[2].min)
    2473   596628038 :                                        : 0.0); // 3rd independent variable after limits imposed
    2474   596628038 :         Real64 const V4(Var4.present() ? max(min(Var4, curve.inputLimits[3].max), curve.inputLimits[3].min)
    2475   596628038 :                                        : 0.0); // 4th independent variable after limits imposed
    2476   596628038 :         Real64 const V5(Var5.present() ? max(min(Var5, curve.inputLimits[4].max), curve.inputLimits[4].min)
    2477   596628038 :                                        : 0.0); // 5th independent variable after limits imposed
    2478             : 
    2479   596628038 :         switch (curve.curveType) {
    2480    20870362 :         case CurveType::Linear: {
    2481    20870362 :             CurveValue = curve.coeff[0] + V1 * curve.coeff[1];
    2482    20870362 :         } break;
    2483   199947971 :         case CurveType::Quadratic: {
    2484   199947971 :             CurveValue = curve.coeff[0] + V1 * (curve.coeff[1] + V1 * curve.coeff[2]);
    2485   199947971 :         } break;
    2486    26546886 :         case CurveType::QuadLinear: {
    2487    26546886 :             CurveValue = curve.coeff[0] + V1 * curve.coeff[1] + V2 * curve.coeff[2] + V3 * curve.coeff[3] + V4 * curve.coeff[4];
    2488    26546886 :         } break;
    2489     8141093 :         case CurveType::QuintLinear: {
    2490     8141093 :             CurveValue = curve.coeff[0] + V1 * curve.coeff[1] + V2 * curve.coeff[2] + V3 * curve.coeff[3] + V4 * curve.coeff[4] + V5 * curve.coeff[5];
    2491     8141093 :         } break;
    2492    17934466 :         case CurveType::Cubic: {
    2493    17934466 :             CurveValue = curve.coeff[0] + V1 * (curve.coeff[1] + V1 * (curve.coeff[2] + V1 * curve.coeff[3]));
    2494    17934466 :         } break;
    2495      387236 :         case CurveType::Quartic: {
    2496      387236 :             CurveValue = curve.coeff[0] + V1 * (curve.coeff[1] + V1 * (curve.coeff[2] + V1 * (curve.coeff[3] + V1 * curve.coeff[4])));
    2497      387236 :         } break;
    2498   192097609 :         case CurveType::BiQuadratic: {
    2499   192097609 :             CurveValue =
    2500   192097609 :                 curve.coeff[0] + V1 * (curve.coeff[1] + V1 * curve.coeff[2]) + V2 * (curve.coeff[3] + V2 * curve.coeff[4]) + V1 * V2 * curve.coeff[5];
    2501   192097609 :         } break;
    2502       63847 :         case CurveType::QuadraticLinear: {
    2503       63847 :             CurveValue =
    2504       63847 :                 (curve.coeff[0] + V1 * (curve.coeff[1] + V1 * curve.coeff[2])) + (curve.coeff[3] + V1 * (curve.coeff[4] + V1 * curve.coeff[5])) * V2;
    2505       63847 :         } break;
    2506        7328 :         case CurveType::CubicLinear: {
    2507        7328 :             CurveValue =
    2508        7328 :                 (curve.coeff[0] + V1 * (curve.coeff[1] + V1 * (curve.coeff[2] + V1 * curve.coeff[3]))) + (curve.coeff[4] + V1 * curve.coeff[5]) * V2;
    2509        7328 :         } break;
    2510   129966033 :         case CurveType::BiCubic: {
    2511   389898099 :             CurveValue = curve.coeff[0] + V1 * curve.coeff[1] + V1 * V1 * curve.coeff[2] + V2 * curve.coeff[3] + V2 * V2 * curve.coeff[4] +
    2512   259932066 :                          V1 * V2 * curve.coeff[5] + V1 * V1 * V1 * curve.coeff[6] + V2 * V2 * V2 * curve.coeff[7] + V1 * V1 * V2 * curve.coeff[8] +
    2513   129966033 :                          V1 * V2 * V2 * curve.coeff[9];
    2514   129966033 :         } break;
    2515      117552 :         case CurveType::ChillerPartLoadWithLift: {
    2516      352656 :             CurveValue = curve.coeff[0] + curve.coeff[1] * V1 + curve.coeff[2] * V1 * V1 + curve.coeff[3] * V2 + curve.coeff[4] * V2 * V2 +
    2517      352656 :                          curve.coeff[5] * V1 * V2 + curve.coeff[6] * V1 * V1 * V1 + curve.coeff[7] * V2 * V2 * V2 + curve.coeff[8] * V1 * V1 * V2 +
    2518      235104 :                          curve.coeff[9] * V1 * V2 * V2 + curve.coeff[10] * V1 * V1 * V2 * V2 + curve.coeff[11] * V3 * V2 * V2 * V2;
    2519      117552 :         } break;
    2520       22144 :         case CurveType::TriQuadratic: {
    2521       22144 :             auto const &Tri2ndOrder(curve.tri2ndOrder);
    2522       22144 :             auto const V1s(V1 * V1);
    2523       22144 :             auto const V2s(V2 * V2);
    2524       22144 :             auto const V3s(V3 * V3);
    2525       66432 :             CurveValue = Tri2ndOrder[0] + Tri2ndOrder[1] * V1s + Tri2ndOrder[2] * V1 + Tri2ndOrder[3] * V2s + Tri2ndOrder[4] * V2 +
    2526       66432 :                          Tri2ndOrder[5] * V3s + Tri2ndOrder[6] * V3 + Tri2ndOrder[7] * V1s * V2s + Tri2ndOrder[8] * V1 * V2 +
    2527       66432 :                          Tri2ndOrder[9] * V1 * V2s + Tri2ndOrder[10] * V1s * V2 + Tri2ndOrder[11] * V1s * V3s + Tri2ndOrder[12] * V1 * V3 +
    2528       66432 :                          Tri2ndOrder[13] * V1 * V3s + Tri2ndOrder[14] * V1s * V3 + Tri2ndOrder[15] * V2s * V3s + Tri2ndOrder[16] * V2 * V3 +
    2529       66432 :                          Tri2ndOrder[17] * V2 * V3s + Tri2ndOrder[18] * V2s * V3 + Tri2ndOrder[19] * V1s * V2s * V3s +
    2530       66432 :                          Tri2ndOrder[20] * V1s * V2s * V3 + Tri2ndOrder[21] * V1s * V2 * V3s + Tri2ndOrder[22] * V1 * V2s * V3s +
    2531       44288 :                          Tri2ndOrder[23] * V1s * V2 * V3 + Tri2ndOrder[24] * V1 * V2s * V3 + Tri2ndOrder[25] * V1 * V2 * V3s +
    2532       22144 :                          Tri2ndOrder[26] * V1 * V2 * V3;
    2533       22144 :         } break;
    2534      219495 :         case CurveType::Exponent: {
    2535      219495 :             CurveValue = curve.coeff[0] + curve.coeff[1] * std::pow(V1, curve.coeff[2]);
    2536      219495 :         } break;
    2537       47001 :         case CurveType::FanPressureRise: {
    2538       47001 :             CurveValue = V1 * (curve.coeff[0] * V1 + curve.coeff[1] + curve.coeff[2] * std::sqrt(V2)) + curve.coeff[3] * V2;
    2539       47001 :         } break;
    2540       47001 :         case CurveType::ExponentialSkewNormal: {
    2541       47001 :             Real64 CoeffZ1 = (V1 - curve.coeff[0]) / curve.coeff[1];
    2542       47001 :             Real64 CoeffZ2 = (curve.coeff[3] * V1 * std::exp(curve.coeff[2] * V1) - curve.coeff[0]) / curve.coeff[1];
    2543       47001 :             Real64 CoeffZ3 = -curve.coeff[0] / curve.coeff[1];
    2544       47001 :             Real64 CurveValueNumer = std::exp(-0.5 * (CoeffZ1 * CoeffZ1)) * (1.0 + sign(1.0, CoeffZ2) * std::erf(std::abs(CoeffZ2) * sqrt_2_inv));
    2545       47001 :             Real64 CurveValueDenom = std::exp(-0.5 * (CoeffZ3 * CoeffZ3)) * (1.0 + sign(1.0, CoeffZ3) * std::erf(std::abs(CoeffZ3) * sqrt_2_inv));
    2546       47001 :             CurveValue = CurveValueNumer / CurveValueDenom;
    2547       47001 :         } break;
    2548       47001 :         case CurveType::Sigmoid: {
    2549       47001 :             Real64 CurveValueExp = std::exp((curve.coeff[2] - V1) / curve.coeff[3]);
    2550       47001 :             CurveValue = curve.coeff[0] + curve.coeff[1] / std::pow(1.0 + CurveValueExp, curve.coeff[4]);
    2551       47001 :         } break;
    2552           4 :         case CurveType::RectangularHyperbola1: {
    2553           4 :             Real64 CurveValueNumer = curve.coeff[0] * V1;
    2554           4 :             Real64 CurveValueDenom = curve.coeff[1] + V1;
    2555           4 :             CurveValue = (CurveValueNumer / CurveValueDenom) + curve.coeff[2];
    2556           4 :         } break;
    2557      115004 :         case CurveType::RectangularHyperbola2: {
    2558      115004 :             Real64 CurveValueNumer = curve.coeff[0] * V1;
    2559      115004 :             Real64 CurveValueDenom = curve.coeff[1] + V1;
    2560      115004 :             CurveValue = (CurveValueNumer / CurveValueDenom) + (curve.coeff[2] * V1);
    2561      115004 :         } break;
    2562       43320 :         case CurveType::ExponentialDecay: {
    2563       43320 :             CurveValue = curve.coeff[0] + curve.coeff[1] * std::exp(curve.coeff[2] * V1);
    2564       43320 :         } break;
    2565        6685 :         case CurveType::DoubleExponentialDecay: {
    2566        6685 :             CurveValue = curve.coeff[0] + curve.coeff[1] * std::exp(curve.coeff[2] * V1) + curve.coeff[3] * std::exp(curve.coeff[4] * V1);
    2567        6685 :         } break;
    2568           0 :         default: {
    2569           0 :             CurveValue = 0.0;
    2570           0 :         } break;
    2571             :         }
    2572             : 
    2573   596628038 :         if (curve.outputLimits.minPresent) CurveValue = max(CurveValue, curve.outputLimits.min);
    2574   596628038 :         if (curve.outputLimits.maxPresent) CurveValue = min(CurveValue, curve.outputLimits.max);
    2575             : 
    2576   596628038 :         return CurveValue;
    2577             :     }
    2578             : 
    2579     8880733 :     Real64 BtwxtTableInterpolation(EnergyPlusData &state,
    2580             :                                    int const CurveIndex,        // index of curve in curve array
    2581             :                                    Real64 const Var1,           // 1st independent variable
    2582             :                                    Optional<Real64 const> Var2, // 2nd independent variable
    2583             :                                    Optional<Real64 const> Var3, // 3rd independent variable
    2584             :                                    Optional<Real64 const> Var4, // 4th independent variable
    2585             :                                    Optional<Real64 const> Var5, // 5th independent variable
    2586             :                                    Optional<Real64 const> Var6  // 6th independent variable
    2587             :     )
    2588             :     {
    2589     8880733 :         auto &thisCurve = state.dataCurveManager->PerfCurve(CurveIndex);
    2590             :         // TODO: Generalize for N-dims
    2591     8880733 :         Real64 var = Var1;
    2592     8880733 :         var = max(min(var, thisCurve.inputLimits[0].max), thisCurve.inputLimits[0].min);
    2593    17761466 :         std::vector<double> target{var};
    2594     8880733 :         if (present(Var2)) {
    2595     2102379 :             var = Var2;
    2596     2102379 :             var = max(min(var, thisCurve.inputLimits[1].max), thisCurve.inputLimits[1].min);
    2597     2102379 :             target.push_back(var);
    2598             :         }
    2599     8880733 :         if (present(Var3)) {
    2600     1410314 :             var = Var3;
    2601     1410314 :             var = max(min(var, thisCurve.inputLimits[2].max), thisCurve.inputLimits[2].min);
    2602     1410314 :             target.push_back(var);
    2603             :         }
    2604     8880733 :         if (present(Var4)) {
    2605     1031495 :             var = Var4;
    2606     1031495 :             var = max(min(var, thisCurve.inputLimits[3].max), thisCurve.inputLimits[3].min);
    2607     1031495 :             target.push_back(var);
    2608             :         }
    2609     8880733 :         if (present(Var5)) {
    2610     1031495 :             var = Var5;
    2611     1031495 :             var = max(min(var, thisCurve.inputLimits[4].max), thisCurve.inputLimits[4].min);
    2612     1031495 :             target.push_back(var);
    2613             :         }
    2614     8880733 :         if (present(Var6)) {
    2615     1031495 :             var = Var6;
    2616     1031495 :             var = max(min(var, thisCurve.inputLimits[5].max), thisCurve.inputLimits[5].min);
    2617     1031495 :             target.push_back(var);
    2618             :         }
    2619             : 
    2620    17761466 :         std::string contextString = format("Table:Lookup \"{}\"", thisCurve.Name);
    2621    17761465 :         std::pair<EnergyPlusData *, std::string> callbackPair{&state, contextString};
    2622     8880733 :         Btwxt::setMessageCallback(Curve::BtwxtMessageCallback, &callbackPair);
    2623     8880733 :         Real64 TableValue = state.dataCurveManager->btwxtManager.getGridValue(thisCurve.TableIndex, thisCurve.GridValueIndex, target);
    2624             : 
    2625     8880732 :         if (thisCurve.outputLimits.minPresent) TableValue = max(TableValue, thisCurve.outputLimits.min);
    2626     8880732 :         if (thisCurve.outputLimits.maxPresent) TableValue = min(TableValue, thisCurve.outputLimits.max);
    2627             : 
    2628    17761464 :         return TableValue;
    2629             :     }
    2630             : 
    2631        2878 :     bool IsCurveInputTypeValid(std::string const &InInputType) // index of curve in curve array
    2632             :     {
    2633             :         // FUNCTION INFORMATION:
    2634             :         //       AUTHOR         Jason Glazer
    2635             :         //       DATE WRITTEN   Oct 2009
    2636             :         //       MODIFIED
    2637             :         //       RE-ENGINEERED  na
    2638             : 
    2639             :         // PURPOSE OF THIS FUNCTION:
    2640             :         // Returns true if the input unit type is valid
    2641             : 
    2642             :         // currently this is a bit overkill to have an enum and string view array, but this sets it up in case we want to do more with these inputs
    2643             :         enum class CurveInputType
    2644             :         {
    2645             :             Invalid = -1,
    2646             :             Dimensionless,
    2647             :             Temperature,
    2648             :             Pressure,
    2649             :             VolumetricFlow,
    2650             :             MassFlow,
    2651             :             Power,
    2652             :             Distance,
    2653             :             Wavelength,
    2654             :             Angle,
    2655             :             Num
    2656             :         };
    2657        2878 :         constexpr std::array<std::string_view, static_cast<int>(CurveInputType::Num)> inputTypes = {
    2658             :             "DIMENSIONLESS", "TEMPERATURE", "PRESSURE", "VOLUMETRICFLOW", "MASSFLOW", "POWER", "DISTANCE", "WAVELENGTH", "ANGLE"};
    2659             : 
    2660        2878 :         if (InInputType.empty()) {
    2661           0 :             return true; // if not used it is valid
    2662             :         }
    2663        2878 :         CurveInputType found = static_cast<CurveInputType>(getEnumerationValue(inputTypes, UtilityRoutines::MakeUPPERCase(InInputType)));
    2664        2878 :         return found != CurveInputType::Invalid;
    2665             :     }
    2666             : 
    2667        1874 :     bool IsCurveOutputTypeValid(std::string const &InOutputType) // index of curve in curve array
    2668             :     {
    2669             :         // FUNCTION INFORMATION:
    2670             :         //       AUTHOR         Jason Glazer
    2671             :         //       DATE WRITTEN   Oct 2009
    2672             :         //       MODIFIED
    2673             :         //       RE-ENGINEERED  na
    2674             : 
    2675             :         // PURPOSE OF THIS FUNCTION:
    2676             :         // Returns true if the output unit type is valid
    2677             : 
    2678             :         // currently this is a bit overkill to have an enum and string view array, but this sets it up in case we want to do more with these inputs
    2679             :         enum class CurveOutputType
    2680             :         {
    2681             :             Invalid = -1,
    2682             :             Dimensionless,
    2683             :             Pressure,
    2684             :             Temperature,
    2685             :             Capacity,
    2686             :             Power,
    2687             :             Num
    2688             :         };
    2689        1874 :         constexpr std::array<std::string_view, static_cast<int>(CurveOutputType::Num)> outputTypes = {
    2690             :             "DIMENSIONLESS", "PRESSURE", "TEMPERATURE", "CAPACITY", "POWER"};
    2691        1874 :         CurveOutputType found = static_cast<CurveOutputType>(getEnumerationValue(outputTypes, UtilityRoutines::MakeUPPERCase(InOutputType)));
    2692        1874 :         return found != CurveOutputType::Invalid;
    2693             :     }
    2694             : 
    2695       11236 :     bool CheckCurveDims(EnergyPlusData &state,
    2696             :                         int const CurveIndex,
    2697             :                         std::vector<int> validDims,
    2698             :                         const std::string_view routineName,
    2699             :                         std::string_view objectType,
    2700             :                         std::string_view objectName,
    2701             :                         std::string_view curveFieldText)
    2702             :     {
    2703             :         // Returns true if errors found
    2704       11236 :         auto &thisCurve = state.dataCurveManager->PerfCurve(CurveIndex);
    2705       11236 :         int curveDim = thisCurve.numDims;
    2706       11236 :         if (std::find(validDims.begin(), validDims.end(), curveDim) != validDims.end()) {
    2707             :             // Compatible
    2708       11236 :             return false;
    2709             :         } else {
    2710             :             // Not compatible
    2711           0 :             ShowSevereError(state, fmt::format("{}{}=\"{}\"", routineName, objectType, objectName));
    2712           0 :             ShowContinueError(state, format("...Invalid curve for {}.", curveFieldText));
    2713           0 :             std::string validString = fmt::to_string(validDims[0]);
    2714           0 :             for (std::size_t i = 1; i < validDims.size(); i++) {
    2715           0 :                 validString += format(" or {}", validDims[i]);
    2716             :             }
    2717           0 :             std::string plural1 = curveDim > 1 ? "s" : "";
    2718           0 :             std::string plural2 = validDims[validDims.size() - 1] > 1 ? "s" : "";
    2719           0 :             ShowContinueError(state, format("...Input curve=\"{}\" has {} dimension{}.", thisCurve.Name, curveDim, plural1));
    2720           0 :             ShowContinueError(state, format("...Curve type must have {} dimension{}.", validString, plural2));
    2721           0 :             return true;
    2722             :         }
    2723             :     }
    2724             : 
    2725         172 :     std::string GetCurveName(EnergyPlusData &state, int const CurveIndex) // index of curve in curve array
    2726             :     {
    2727             : 
    2728             :         // FUNCTION INFORMATION:
    2729             :         //       AUTHOR         Bereket Nigusse
    2730             :         //       DATE WRITTEN   May 2010
    2731             :         //       MODIFIED       na
    2732             :         //       RE-ENGINEERED  na
    2733             : 
    2734             :         // PURPOSE OF THIS FUNCTION:
    2735             :         // Given a curve index, returns the curve name
    2736             : 
    2737         172 :         if (CurveIndex > 0) {
    2738         172 :             return state.dataCurveManager->PerfCurve(CurveIndex).Name;
    2739             :         } else {
    2740           0 :             return "";
    2741             :         }
    2742             :     }
    2743             : 
    2744       28095 :     int GetCurveIndex(EnergyPlusData &state, std::string const &CurveName) // name of the curve
    2745             :     {
    2746             : 
    2747             :         // FUNCTION INFORMATION:
    2748             :         //       AUTHOR         Fred Buhl
    2749             :         //       DATE WRITTEN   May 2000
    2750             :         //       MODIFIED       na
    2751             :         //       RE-ENGINEERED  na
    2752             : 
    2753             :         // PURPOSE OF THIS FUNCTION:
    2754             :         // Given a curve name, returns the curve index
    2755             : 
    2756             :         // METHODOLOGY EMPLOYED:
    2757             :         // uses UtilityRoutines::FindItemInList( to search the curve array for the curve name
    2758             : 
    2759             :         // First time GetCurveIndex is called, get the input for all the performance curves
    2760       28095 :         if (state.dataCurveManager->GetCurvesInputFlag) {
    2761          26 :             GetCurveInput(state);
    2762          26 :             GetPressureSystemInput(state);
    2763          26 :             state.dataCurveManager->GetCurvesInputFlag = false;
    2764             :         }
    2765             : 
    2766       28095 :         if (state.dataCurveManager->NumCurves > 0) {
    2767       24621 :             return UtilityRoutines::FindItemInList(CurveName, state.dataCurveManager->PerfCurve);
    2768             :         } else {
    2769        3474 :             return 0;
    2770             :         }
    2771             :     }
    2772             : 
    2773             :     // This utility function grabs a curve index and performs the
    2774             :     // error checking
    2775             : 
    2776          21 :     int GetCurveCheck(EnergyPlusData &state,
    2777             :                       std::string const &alph, // curve name
    2778             :                       bool &errFlag,
    2779             :                       std::string const &ObjName // parent object of curve
    2780             :     )
    2781             :     {
    2782             : 
    2783             :         // FUNCTION INFORMATION:
    2784             :         //       AUTHOR         Jason Glazer
    2785             :         //       DATE WRITTEN   March 2001
    2786             :         //       MODIFIED       na
    2787             :         //       RE-ENGINEERED  na
    2788             : 
    2789             :         // PURPOSE OF THIS FUNCTION:
    2790             :         // This function provides a simple call to both return a curve index as well
    2791             :         // as check for validity and produce an error message.
    2792          21 :         int GetCurveCheckOut = GetCurveIndex(state, alph); // convert curve name to pointer
    2793          21 :         if (GetCurveCheckOut == 0) {
    2794           0 :             ShowSevereError(state, format("Curve Not Found for Object=\"{}\" :: {}", ObjName, alph));
    2795           0 :             errFlag = true;
    2796             :         }
    2797          21 :         return GetCurveCheckOut;
    2798             :     }
    2799             : 
    2800      101846 :     void GetCurveMinMaxValues(EnergyPlusData &state,
    2801             :                               int const CurveIndex,     // index of curve in curve array
    2802             :                               Real64 &Var1Min,          // Minimum values of 1st independent variable
    2803             :                               Real64 &Var1Max,          // Maximum values of 1st independent variable
    2804             :                               Optional<Real64> Var2Min, // Minimum values of 2nd independent variable
    2805             :                               Optional<Real64> Var2Max, // Maximum values of 2nd independent variable
    2806             :                               Optional<Real64> Var3Min, // Minimum values of 3rd independent variable
    2807             :                               Optional<Real64> Var3Max, // Maximum values of 3rd independent variable
    2808             :                               Optional<Real64> Var4Min, // Minimum values of 4th independent variable
    2809             :                               Optional<Real64> Var4Max, // Maximum values of 4th independent variable
    2810             :                               Optional<Real64> Var5Min, // Minimum values of 5th independent variable
    2811             :                               Optional<Real64> Var5Max, // Maximum values of 5th independent variable
    2812             :                               Optional<Real64> Var6Min, // Minimum values of 6th independent variable
    2813             :                               Optional<Real64> Var6Max  // Maximum values of 6th independent variable
    2814             :     )
    2815             :     {
    2816             : 
    2817             :         // FUNCTION INFORMATION:
    2818             :         //       AUTHOR         Lixing Gu
    2819             :         //       DATE WRITTEN   July 2006
    2820             :         //       MODIFIED       B. Griffith Aug 2006 add third independent variable
    2821             :         //       RE-ENGINEERED  na
    2822             : 
    2823             :         // PURPOSE OF THIS FUNCTION:
    2824             :         // Given the curve index, returns the minimum and maximum values specified in the input
    2825             :         // for the independent variables of the performance curve.
    2826             : 
    2827      101846 :         auto &thisCurve = state.dataCurveManager->PerfCurve(CurveIndex);
    2828      101846 :         Var1Min = thisCurve.inputLimits[0].min;
    2829      101846 :         Var1Max = thisCurve.inputLimits[0].max;
    2830      101846 :         if (present(Var2Min)) Var2Min = thisCurve.inputLimits[1].min;
    2831      101846 :         if (present(Var2Max)) Var2Max = thisCurve.inputLimits[1].max;
    2832      101846 :         if (present(Var3Min)) Var3Min = thisCurve.inputLimits[2].min;
    2833      101846 :         if (present(Var3Max)) Var3Max = thisCurve.inputLimits[2].max;
    2834      101846 :         if (present(Var4Min)) Var4Min = thisCurve.inputLimits[3].min;
    2835      101846 :         if (present(Var4Max)) Var4Max = thisCurve.inputLimits[3].max;
    2836      101846 :         if (present(Var5Min)) Var5Min = thisCurve.inputLimits[4].min;
    2837      101846 :         if (present(Var5Max)) Var5Max = thisCurve.inputLimits[4].max;
    2838      101846 :         if (present(Var6Min)) Var6Min = thisCurve.inputLimits[5].min;
    2839      101846 :         if (present(Var6Max)) Var6Max = thisCurve.inputLimits[5].max;
    2840      101846 :     }
    2841             : 
    2842           0 :     void SetCurveOutputMinMaxValues(EnergyPlusData &state,
    2843             :                                     int const CurveIndex,            // index of curve in curve array
    2844             :                                     bool &ErrorsFound,               // TRUE when errors occur
    2845             :                                     Optional<Real64 const> CurveMin, // Minimum value of curve output
    2846             :                                     Optional<Real64 const> CurveMax  // Maximum values of curve output
    2847             :     )
    2848             :     {
    2849             : 
    2850             :         // FUNCTION INFORMATION:
    2851             :         //       AUTHOR         Richard Raustad
    2852             :         //       DATE WRITTEN   Feb 2009
    2853             :         //       MODIFIED       na
    2854             :         //       RE-ENGINEERED  na
    2855             : 
    2856             :         // PURPOSE OF THIS FUNCTION:
    2857             :         // Given the curve index, sets the minimum and maximum possible value for this curve.
    2858             :         // Certain curve types have set limits (e.g., PLF curve should not be greater than 1 or less than 0.7).
    2859             : 
    2860           0 :         if (CurveIndex > 0 && CurveIndex <= state.dataCurveManager->NumCurves) {
    2861           0 :             auto &thisCurve = state.dataCurveManager->PerfCurve(CurveIndex);
    2862           0 :             if (present(CurveMin)) {
    2863           0 :                 thisCurve.outputLimits.min = CurveMin;
    2864           0 :                 thisCurve.outputLimits.minPresent = true;
    2865             :             }
    2866           0 :             if (present(CurveMax)) {
    2867           0 :                 thisCurve.outputLimits.max = CurveMax;
    2868           0 :                 thisCurve.outputLimits.maxPresent = true;
    2869             :             }
    2870             :         } else {
    2871           0 :             ShowSevereError(
    2872             :                 state,
    2873           0 :                 format("SetCurveOutputMinMaxValues: CurveIndex=[{}] not in range of curves=[1:{}].", CurveIndex, state.dataCurveManager->NumCurves));
    2874           0 :             ErrorsFound = true;
    2875             :         }
    2876           0 :     }
    2877             : 
    2878         638 :     void GetPressureSystemInput(EnergyPlusData &state)
    2879             :     {
    2880             : 
    2881             :         // SUBROUTINE INFORMATION:
    2882             :         //       AUTHOR         Edwin Lee
    2883             :         //       DATE WRITTEN   August 2009
    2884             :         //       MODIFIED       na
    2885             :         //       RE-ENGINEERED  na
    2886             : 
    2887             :         // PURPOSE OF THIS SUBROUTINE:
    2888             :         // Currently it just reads the input for pressure curve objects
    2889             : 
    2890             :         // METHODOLOGY EMPLOYED:
    2891             :         // General EnergyPlus Methodology
    2892             : 
    2893             :         // SUBROUTINE PARAMETER DEFINITIONS:
    2894         638 :         std::string_view constexpr CurveObjectName = "Curve:Functional:PressureDrop";
    2895             : 
    2896             :         // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
    2897        1276 :         Array1D_string Alphas(1);   // Alpha items for object
    2898        1276 :         Array1D<Real64> Numbers(5); // Numeric items for object
    2899             :         int NumAlphas;              // Number of Alphas for each GetObjectItem call
    2900             :         int NumNumbers;             // Number of Numbers for each GetObjectItem call
    2901             :         int IOStatus;               // Used in GetObjectItem
    2902         638 :         bool ErrsFound(false);      // Set to true if errors in input, fatal at end of routine
    2903             : 
    2904         638 :         int NumPressure = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurveObjectName);
    2905         638 :         state.dataBranchAirLoopPlant->PressureCurve.allocate(NumPressure);
    2906         641 :         for (int CurveNum = 1; CurveNum <= NumPressure; ++CurveNum) {
    2907           3 :             auto &thisCurve = state.dataBranchAirLoopPlant->PressureCurve(CurveNum);
    2908          12 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
    2909             :                                                                      CurveObjectName,
    2910             :                                                                      CurveNum,
    2911             :                                                                      Alphas,
    2912             :                                                                      NumAlphas,
    2913             :                                                                      Numbers,
    2914             :                                                                      NumNumbers,
    2915             :                                                                      IOStatus,
    2916           3 :                                                                      state.dataIPShortCut->lNumericFieldBlanks,
    2917             :                                                                      _,
    2918           3 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
    2919           3 :                                                                      state.dataIPShortCut->cNumericFieldNames);
    2920           6 :             GlobalNames::VerifyUniqueInterObjectName(
    2921           6 :                 state, state.dataCurveManager->UniqueCurveNames, Alphas(1), CurveObjectName, state.dataIPShortCut->cAlphaFieldNames(1), ErrsFound);
    2922           3 :             thisCurve.Name = Alphas(1);
    2923           3 :             thisCurve.EquivDiameter = Numbers(1);
    2924           3 :             thisCurve.MinorLossCoeff = Numbers(2);
    2925           3 :             thisCurve.EquivLength = Numbers(3);
    2926           3 :             thisCurve.EquivRoughness = Numbers(4);
    2927           3 :             if (NumNumbers > 4 && !state.dataIPShortCut->lNumericFieldBlanks(5)) {
    2928           1 :                 if (Numbers(5) != 0.0) {
    2929           1 :                     thisCurve.ConstantFPresent = true;
    2930           1 :                     thisCurve.ConstantF = Numbers(5);
    2931             :                 }
    2932             :             }
    2933             :         }
    2934             : 
    2935         638 :         if (ErrsFound) {
    2936           0 :             ShowFatalError(state, "GetPressureCurveInput: Errors found in Curve Objects.  Preceding condition(s) cause termination.");
    2937             :         }
    2938         638 :     }
    2939             : 
    2940       14079 :     void GetPressureCurveTypeAndIndex(EnergyPlusData &state,
    2941             :                                       std::string const &PressureCurveName, // name of the curve
    2942             :                                       DataBranchAirLoopPlant::PressureCurveType &PressureCurveType,
    2943             :                                       int &PressureCurveIndex)
    2944             :     {
    2945             : 
    2946             :         // SUBROUTINE INFORMATION:
    2947             :         //       AUTHOR         Edwin Lee
    2948             :         //       DATE WRITTEN   August 2009
    2949             :         //       MODIFIED       na
    2950             :         //       RE-ENGINEERED  na
    2951             : 
    2952             :         // PURPOSE OF THIS SUBROUTINE:
    2953             :         // Given a curve name, returns the curve type and index
    2954             : 
    2955             :         // METHODOLOGY EMPLOYED:
    2956             :         // Curve types are:
    2957             :         //  PressureCurveType::Invalid     = pressure name was given, but curve is not available
    2958             :         //  PressureCurveType::None        = no pressure curve for this branch
    2959             :         //  PressureCurveType::Pressure    = pressure curve based on friction/minor loss
    2960             :         //  PressureCurveType::Generic     = curvemanager held curve which is function of flow rate
    2961             : 
    2962             :         // If input is not gotten, go ahead and get it now
    2963       14079 :         if (state.dataCurveManager->GetCurvesInputFlag) {
    2964         612 :             GetCurveInput(state);
    2965         612 :             GetPressureSystemInput(state);
    2966         612 :             state.dataCurveManager->GetCurvesInputFlag = false;
    2967             :         }
    2968             : 
    2969             :         // Initialize
    2970       14079 :         PressureCurveType = DataBranchAirLoopPlant::PressureCurveType::None;
    2971       14079 :         PressureCurveIndex = 0;
    2972             : 
    2973             :         // Try to retrieve a curve manager object
    2974       14079 :         int TempCurveIndex = GetCurveIndex(state, PressureCurveName);
    2975             : 
    2976             :         // See if it is valid
    2977       14079 :         if (TempCurveIndex > 0) {
    2978             :             // We have to check the type of curve to make sure it is single independent variable type
    2979           1 :             CurveType GenericCurveType = state.dataCurveManager->PerfCurve(TempCurveIndex).curveType;
    2980             :             {
    2981           1 :                 if (state.dataCurveManager->PerfCurve(TempCurveIndex).numDims == 1) {
    2982           1 :                     PressureCurveType = DataBranchAirLoopPlant::PressureCurveType::Generic;
    2983           1 :                     PressureCurveIndex = TempCurveIndex;
    2984             :                 } else {
    2985           0 :                     ShowSevereError(state, "Plant Pressure Simulation: Found error for curve: " + PressureCurveName);
    2986           0 :                     ShowContinueError(state, format("Curve type detected: {}", Curve::objectNames[static_cast<int>(GenericCurveType)]));
    2987           0 :                     ShowContinueError(state, "Generic curves should be single independent variable such that DeltaP = f(mdot)");
    2988           0 :                     ShowContinueError(state, " Therefore they should be of type: Linear, Quadratic, Cubic, Quartic, or Exponent");
    2989           0 :                     ShowFatalError(state, "Errors in pressure simulation input cause program termination");
    2990             :                 }
    2991             :             }
    2992           1 :             return;
    2993             :         }
    2994             : 
    2995             :         // Then try to retrieve a pressure curve object
    2996       14078 :         if (allocated(state.dataBranchAirLoopPlant->PressureCurve)) {
    2997       14078 :             if (size(state.dataBranchAirLoopPlant->PressureCurve) > 0) {
    2998          18 :                 TempCurveIndex = UtilityRoutines::FindItemInList(PressureCurveName, state.dataBranchAirLoopPlant->PressureCurve);
    2999             :             } else {
    3000       14060 :                 TempCurveIndex = 0;
    3001             :             }
    3002             :         }
    3003             : 
    3004             :         // See if it is valid
    3005       14078 :         if (TempCurveIndex > 0) {
    3006           3 :             PressureCurveType = DataBranchAirLoopPlant::PressureCurveType::Pressure;
    3007           3 :             PressureCurveIndex = TempCurveIndex;
    3008           3 :             return;
    3009             :         }
    3010             : 
    3011             :         // If we made it here, we didn't find either type of match
    3012             : 
    3013             :         // Last check, see if it is blank:
    3014       14075 :         if (PressureCurveName.empty()) {
    3015       14075 :             PressureCurveType = DataBranchAirLoopPlant::PressureCurveType::None;
    3016       14075 :             return;
    3017             :         }
    3018             : 
    3019             :         // At this point, we had a non-blank user entry with no match
    3020           0 :         PressureCurveType = DataBranchAirLoopPlant::PressureCurveType::Invalid;
    3021             :     }
    3022             : 
    3023             :     Real64
    3024       12870 :     PressureCurveValue(EnergyPlusData &state, int const PressureCurveIndex, Real64 const MassFlow, Real64 const Density, Real64 const Viscosity)
    3025             :     {
    3026             : 
    3027             :         // FUNCTION INFORMATION:
    3028             :         //       AUTHOR         Edwin Lee
    3029             :         //       DATE WRITTEN   August 2009
    3030             :         //       MODIFIED       na
    3031             :         //       RE-ENGINEERED  na
    3032             : 
    3033             :         // PURPOSE OF THIS FUNCTION:
    3034             :         // This will evaluate the pressure drop for components which use pressure information
    3035             : 
    3036             :         // METHODOLOGY EMPLOYED:
    3037             :         // Friction factor pressure drop equation:
    3038             :         // DP = [f*(L/D) + K] * (rho * V^2) / 2
    3039             : 
    3040       12870 :         auto &curve = state.dataBranchAirLoopPlant->PressureCurve(PressureCurveIndex);
    3041             : 
    3042             :         // Intermediate calculations
    3043       12870 :         Real64 const CrossSectArea = (DataGlobalConstants::Pi / 4.0) * pow_2(curve.EquivDiameter);
    3044       12870 :         Real64 const Velocity = MassFlow / (Density * CrossSectArea);
    3045       12870 :         Real64 const ReynoldsNumber = Density * curve.EquivDiameter * Velocity / Viscosity; // assuming mu here
    3046       12870 :         Real64 const RoughnessRatio = curve.EquivRoughness / curve.EquivDiameter;
    3047             : 
    3048             :         // update curve bookkeeping
    3049       12870 :         curve.CurveInput1 = MassFlow;
    3050       12870 :         curve.CurveInput2 = Density;
    3051       12870 :         curve.CurveInput3 = Velocity;
    3052             : 
    3053             :         // If we don't have any flow then exit out
    3054       12870 :         if (MassFlow < DataBranchAirLoopPlant::MassFlowTolerance) {
    3055          66 :             curve.CurveOutput = 0.0;
    3056          66 :             return 0.0;
    3057             :         }
    3058             : 
    3059             :         // Calculate the friction factor and pressure drop
    3060       12804 :         Real64 FrictionFactor = curve.ConstantFPresent ? curve.ConstantF : CalculateMoodyFrictionFactor(state, ReynoldsNumber, RoughnessRatio);
    3061       25608 :         Real64 PressureCurveValue = curve.EMSOverrideOn ? curve.EMSOverrideCurveValue
    3062       25608 :                                                         : (FrictionFactor * (curve.EquivLength / curve.EquivDiameter) + curve.MinorLossCoeff) *
    3063       25608 :                                                               (Density * pow_2(Velocity)) / 2.0;
    3064       12804 :         curve.CurveOutput = PressureCurveValue;
    3065       12804 :         return PressureCurveValue;
    3066             :     }
    3067             : 
    3068       10476 :     Real64 CalculateMoodyFrictionFactor(EnergyPlusData &state, Real64 const ReynoldsNumber, Real64 const RoughnessRatio)
    3069             :     {
    3070             : 
    3071             :         // FUNCTION INFORMATION:
    3072             :         //       AUTHOR         Edwin Lee
    3073             :         //       DATE WRITTEN   August 2009
    3074             :         //       MODIFIED       na
    3075             :         //       RE-ENGINEERED  na
    3076             : 
    3077             :         // PURPOSE OF THIS FUNCTION:
    3078             :         // This will evaluate the moody friction factor based on Reynolds number and roughness ratio
    3079             : 
    3080             :         // METHODOLOGY EMPLOYED:
    3081             :         // General empirical correlations for friction factor based on Moody Chart data
    3082             : 
    3083             :         // REFERENCES:
    3084             :         // Haaland, SE (1983). "Simple and Explicit Formulas for the Friction Factor in Turbulent Flow".
    3085             :         //   Trans. ASIVIE, J. of Fluids Engineering 103: 89-90.
    3086             : 
    3087             :         // Check for no flow or invalid roughness before calculating values
    3088       10476 :         if (ReynoldsNumber == 0.0 || RoughnessRatio == 0.0) {
    3089           0 :             return 0.0;
    3090             :         }
    3091             : 
    3092             :         // Calculate the friction factor
    3093       10476 :         Real64 const Term1 = std::pow(RoughnessRatio / 3.7, 1.11);
    3094       10476 :         Real64 const Term2 = 6.9 / ReynoldsNumber;
    3095       10476 :         Real64 const Term3 = -1.8 * std::log10(Term1 + Term2);
    3096       10476 :         if (Term3 != 0.0) {
    3097       10476 :             return std::pow(Term3, -2.0);
    3098             :         } else {
    3099           0 :             if (!state.dataCurveManager->FrictionFactorErrorHasOccurred) {
    3100           0 :                 ShowSevereError(state, "Plant Pressure System: Error in moody friction factor calculation");
    3101           0 :                 ShowContinueError(state,
    3102           0 :                                   format("Current Conditions: Roughness Ratio={:.7R}; Reynolds Number={:.1R}", RoughnessRatio, ReynoldsNumber));
    3103           0 :                 ShowContinueError(state, "These conditions resulted in an unhandled numeric issue.");
    3104           0 :                 ShowContinueError(state, "Please contact EnergyPlus support/development team to raise an alert about this issue");
    3105           0 :                 ShowContinueError(state, "This issue will occur only one time.  The friction factor has been reset to 0.04 for calculations");
    3106           0 :                 state.dataCurveManager->FrictionFactorErrorHasOccurred = true;
    3107             :             }
    3108           0 :             return 0.04;
    3109             :         }
    3110             :     }
    3111             : 
    3112        4873 :     void checkCurveIsNormalizedToOne(EnergyPlusData &state,
    3113             :                                      std::string const &callingRoutineObj, // calling routine with object type
    3114             :                                      std::string const &objectName,        // parent object where curve is used
    3115             :                                      int const curveIndex,                 // index to curve object
    3116             :                                      std::string const &cFieldName,        // object field name
    3117             :                                      std::string const &cFieldValue,       // user input curve name
    3118             :                                      Real64 const Var1,                    // required 1st independent variable
    3119             :                                      Optional<Real64 const> Var2)          // 2nd independent variable
    3120             :     {
    3121             : 
    3122             :         // FUNCTION INFORMATION:
    3123             :         //       AUTHOR         R. Raustad
    3124             :         //       DATE WRITTEN   May 2017
    3125             : 
    3126             :         // PURPOSE OF THIS FUNCTION:
    3127             :         // checks that curve output is within 10% of 1 at curve rating point
    3128             : 
    3129        4873 :         if (curveIndex > 0) {
    3130        4873 :             Real64 const CurveVal = CurveValue(state, curveIndex, Var1, Var2);
    3131        4873 :             if (CurveVal > 1.10 || CurveVal < 0.90) {
    3132          30 :                 ShowWarningError(state, format("{}=\"{}\" curve values", callingRoutineObj, objectName));
    3133          30 :                 ShowContinueError(state, format("... {} = {} output is not equal to 1.0 (+ or - 10%) at rated conditions.", cFieldName, cFieldValue));
    3134          30 :                 ShowContinueError(state, format("... Curve output at rated conditions = {:.3T}", CurveVal));
    3135             :             }
    3136             :         }
    3137        4873 :     }
    3138             : 
    3139             : } // namespace Curve
    3140             : 
    3141        2313 : } // namespace EnergyPlus

Generated by: LCOV version 1.13