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