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