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