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