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