LCOV - code coverage report
Current view: top level - EnergyPlus - CurveManager.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 72.7 % 1900 1381
Test Date: 2025-05-22 16:09:37 Functions: 73.7 % 57 42

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

Generated by: LCOV version 2.0-1