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 <cassert>
50 : #include <cmath>
51 : #include <cstdlib>
52 :
53 : // ObjexxFCL Headers
54 : #include <ObjexxFCL/Fmath.hh>
55 : #include <ObjexxFCL/string.functions.hh>
56 :
57 : // EnergyPlus Headers
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataEnvironment.hh>
60 : #include <EnergyPlus/DataHVACGlobals.hh>
61 : #include <EnergyPlus/DataIPShortCuts.hh>
62 : #include <EnergyPlus/DataRuntimeLanguage.hh>
63 : #include <EnergyPlus/DataSurfaces.hh>
64 : #include <EnergyPlus/General.hh>
65 : #include <EnergyPlus/HVACSystemRootFindingAlgorithm.hh>
66 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
67 : #include <EnergyPlus/OutputProcessor.hh>
68 : #include <EnergyPlus/UtilityRoutines.hh>
69 : #include <EnergyPlus/WeatherManager.hh>
70 :
71 : #if defined(_WIN32) && _MSC_VER < 1900
72 : #define snprintf _snprintf
73 : #endif
74 :
75 : namespace EnergyPlus::General {
76 :
77 : // Module containing routines for general use
78 :
79 : // MODULE INFORMATION:
80 : // AUTHOR Fred Buhl, Linda Lawrie
81 : // DATE WRITTEN December 2001
82 : // MODIFIED na
83 : // RE-ENGINEERED na
84 :
85 : // PURPOSE OF THIS MODULE:
86 : // contains routines (most likely numeric) that may be needed in several parts
87 : // of EnergyPlus
88 :
89 : // Using/Aliasing
90 : using DataHVACGlobals::Bisection;
91 :
92 : // MODULE PARAMETER DEFINITIONS
93 : static constexpr std::string_view BlankString;
94 :
95 : enum class ReportType
96 : {
97 : Invalid = -1,
98 : DXF,
99 : DXFWireFrame,
100 : VRML,
101 : Num
102 : };
103 :
104 : constexpr std::array<std::string_view, static_cast<int>(ReportType::Num)> ReportTypeNamesUC{"DXF", "DXF:WIREFRAME", "VRML"};
105 :
106 : enum class AvailRpt
107 : {
108 : Invalid = -1,
109 : None,
110 : NotByUniqueKeyNames,
111 : Verbose,
112 : Num
113 : };
114 :
115 : constexpr std::array<std::string_view, static_cast<int>(AvailRpt::Num)> AvailRptNamesUC{"NONE", "NOTBYUNIQUEKEYNAMES", "VERBOSE"};
116 :
117 : enum class ERLdebugOutputLevel
118 : {
119 : Invalid = -1,
120 : None,
121 : ErrorsOnly,
122 : Verbose,
123 : Num
124 : };
125 :
126 : constexpr std::array<std::string_view, static_cast<int>(ERLdebugOutputLevel::Num)> ERLdebugOutputLevelNamesUC{"NONE", "ERRORSONLY", "VERBOSE"};
127 :
128 : enum class ReportName
129 : {
130 : Invalid = -1,
131 : Constructions,
132 : Viewfactorinfo,
133 : Variabledictionary,
134 : Surfaces,
135 : Energymanagementsystem,
136 : Num
137 : };
138 :
139 : constexpr std::array<std::string_view, static_cast<int>(ReportName::Num)> ReportNamesUC{
140 : "CONSTRUCTIONS", "VIEWFACTORINFO", "VARIABLEDICTIONARY", "SURFACES", "ENERGYMANAGEMENTSYSTEM"};
141 :
142 : enum class RptKey
143 : {
144 : Invalid = -1,
145 : Costinfo,
146 : DXF,
147 : DXFwireframe,
148 : VRML,
149 : Vertices,
150 : Details,
151 : DetailsWithVertices,
152 : Lines,
153 : Num
154 : };
155 :
156 : constexpr std::array<std::string_view, static_cast<int>(RptKey::Num)> RptKeyNamesUC{
157 : "COSTINFO", "DXF", "DXF:WIREFRAME", "VRML", "VERTICES", "DETAILS", "DETAILSWITHVERTICES", "LINES"};
158 :
159 : // A second version that does not require a payload -- use lambdas
160 14597785 : void SolveRoot(EnergyPlusData &state,
161 : Real64 Eps, // required absolute accuracy
162 : int MaxIte, // maximum number of allowed iterations
163 : int &Flag, // integer storing exit status
164 : Real64 &XRes, // value of x that solves f(x,Par) = 0
165 : const std::function<Real64(Real64)> &f,
166 : Real64 X_0, // 1st bound of interval that contains the solution
167 : Real64 X_1) // 2nd bound of interval that contains the solution
168 : {
169 : // SUBROUTINE INFORMATION:
170 : // AUTHOR Michael Wetter
171 : // DATE WRITTEN March 1999
172 : // MODIFIED Fred Buhl November 2000, R. Raustad October 2006 - made subroutine RECURSIVE
173 : // L. Gu, May 2017 - allow both Bisection and RegulaFalsi
174 :
175 : // PURPOSE OF THIS SUBROUTINE:
176 : // Find the value of x between x0 and x1 such that f(x,Par)
177 : // is equal to zero.
178 :
179 : // METHODOLOGY EMPLOYED:
180 : // Uses the Regula Falsi (false position) method (similar to secant method)
181 :
182 : // REFERENCES:
183 : // See Press et al., Numerical Recipes in Fortran, Cambridge University Press,
184 : // 2nd edition, 1992. Page 347 ff.
185 :
186 : // SUBROUTINE ARGUMENT DEFINITIONS:
187 : // = -2: f(x0) and f(x1) have the same sign
188 : // = -1: no convergence
189 : // > 0: number of iterations performed
190 :
191 14597785 : Real64 constexpr SMALL(1.e-10);
192 14597785 : Real64 X0 = X_0; // present 1st bound
193 14597785 : Real64 X1 = X_1; // present 2nd bound
194 14597785 : Real64 XTemp = X0; // new estimate
195 14597785 : int NIte = 0; // number of interations
196 14597785 : int AltIte = 0; // an accounter used for Alternation choice
197 :
198 14597785 : Real64 Y0 = f(X0); // f at X0
199 14597785 : Real64 Y1 = f(X1); // f at X1
200 : // check initial values
201 14597785 : if (Y0 * Y1 > 0) {
202 326196 : Flag = -2;
203 326196 : XRes = X0;
204 326196 : return;
205 : }
206 14271589 : XRes = XTemp;
207 :
208 : while (true) {
209 :
210 28793024 : Real64 DY = Y0 - Y1;
211 28793024 : if (std::abs(DY) < SMALL) DY = SMALL;
212 28793024 : if (std::abs(X1 - X0) < SMALL) {
213 6780 : break;
214 : }
215 : // new estimation
216 28786244 : switch (state.dataRootFinder->HVACSystemRootFinding.HVACSystemRootSolver) {
217 28780649 : case HVACSystemRootSolverAlgorithm::RegulaFalsi: {
218 28780649 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
219 28780649 : break;
220 : }
221 0 : case HVACSystemRootSolverAlgorithm::Bisection: {
222 0 : XTemp = (X1 + X0) / 2.0;
223 0 : break;
224 : }
225 5595 : case HVACSystemRootSolverAlgorithm::RegulaFalsiThenBisection: {
226 5595 : if (NIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
227 95 : XTemp = (X1 + X0) / 2.0;
228 : } else {
229 5500 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
230 : }
231 5595 : break;
232 : }
233 0 : case HVACSystemRootSolverAlgorithm::BisectionThenRegulaFalsi: {
234 0 : if (NIte <= state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
235 0 : XTemp = (X1 + X0) / 2.0;
236 : } else {
237 0 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
238 : }
239 0 : break;
240 : }
241 0 : case HVACSystemRootSolverAlgorithm::Alternation: {
242 0 : if (AltIte > state.dataRootFinder->HVACSystemRootFinding.NumOfIter) {
243 0 : XTemp = (X1 + X0) / 2.0;
244 0 : if (AltIte >= 2 * state.dataRootFinder->HVACSystemRootFinding.NumOfIter) AltIte = 0;
245 : } else {
246 0 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
247 : }
248 0 : break;
249 : }
250 0 : default: {
251 0 : XTemp = (Y0 * X1 - Y1 * X0) / DY;
252 : }
253 : }
254 :
255 28786244 : Real64 const YTemp = f(XTemp);
256 :
257 28786244 : ++NIte;
258 28786244 : ++AltIte;
259 :
260 : // check convergence
261 28786244 : if (std::abs(YTemp) < Eps) {
262 14264677 : Flag = NIte;
263 14264677 : XRes = XTemp;
264 14264677 : return;
265 : };
266 :
267 : // OK, so we didn't converge, lets check max iterations to see if we should break early
268 14521567 : if (NIte > MaxIte) break;
269 :
270 : // Finally, if we make it here, we have not converged, and we still have iterations left, so continue
271 : // and reassign values (only if further iteration required)
272 14521435 : if (Y0 < 0.0) {
273 12643219 : if (YTemp < 0.0) {
274 5876724 : X0 = XTemp;
275 5876724 : Y0 = YTemp;
276 : } else {
277 6766495 : X1 = XTemp;
278 6766495 : Y1 = YTemp;
279 : }
280 : } else {
281 1878216 : if (YTemp < 0.0) {
282 1201193 : X1 = XTemp;
283 1201193 : Y1 = YTemp;
284 : } else {
285 677023 : X0 = XTemp;
286 677023 : Y0 = YTemp;
287 : }
288 : } // ( Y0 < 0 )
289 14521435 : } // Cont
290 :
291 : // if we make it here we haven't converged, so just set the flag and leave
292 6912 : Flag = -1;
293 6912 : XRes = XTemp;
294 : }
295 :
296 10656 : Real64 InterpProfAng(Real64 const ProfAng, // Profile angle (rad)
297 : Array1S<Real64> const PropArray // Array of blind properties
298 : )
299 : {
300 :
301 : // SUBROUTINE INFORMATION:
302 : // AUTHOR Fred Winkelmann
303 : // DATE WRITTEN May 2001
304 : // MODIFIED na
305 : // RE-ENGINEERED na
306 :
307 : // PURPOSE OF THIS SUBROUTINE:
308 : // Does profile-angle interpolation of window blind solar-thermal properties
309 :
310 : // METHODOLOGY EMPLOYED:
311 : // Linear interpolation.
312 :
313 : // Return value
314 : Real64 InterpProfAng;
315 :
316 : // FUNCTION PARAMETER DEFINITIONS:
317 10656 : Real64 const DeltaAngRad(DataGlobalConstants::Pi / 36.0); // Profile angle increment (rad)
318 :
319 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
320 : Real64 InterpFac; // Interpolation factor
321 : int IAlpha; // Profile angle index
322 :
323 : // DeltaAng = Pi/36
324 10656 : if (ProfAng > DataGlobalConstants::PiOvr2 || ProfAng < -DataGlobalConstants::PiOvr2) {
325 0 : InterpProfAng = 0.0;
326 : } else {
327 10656 : IAlpha = 1 + int((ProfAng + DataGlobalConstants::PiOvr2) / DeltaAngRad);
328 10656 : InterpFac = (ProfAng - (-DataGlobalConstants::PiOvr2 + DeltaAngRad * (IAlpha - 1))) / DeltaAngRad;
329 10656 : InterpProfAng = (1.0 - InterpFac) * PropArray(IAlpha) + InterpFac * PropArray(IAlpha + 1);
330 : }
331 10656 : return InterpProfAng;
332 : }
333 :
334 5517 : Real64 InterpSlatAng(Real64 const SlatAng, // Slat angle (rad)
335 : bool const VarSlats, // True if slat angle is variable
336 : Array1S<Real64> const PropArray // Array of blind properties as function of slat angle
337 : )
338 : {
339 :
340 : // SUBROUTINE INFORMATION:
341 : // AUTHOR Fred Winkelmann
342 : // DATE WRITTEN Dec 2001
343 : // MODIFIED na
344 : // RE-ENGINEERED na
345 :
346 : // PURPOSE OF THIS SUBROUTINE:
347 : // Does slat-angle interpolation of window blind solar-thermal properties that
348 : // do not depend on profile angle
349 :
350 : // METHODOLOGY EMPLOYED:
351 : // Linear interpolation.
352 :
353 : // Using/Aliasing
354 : using DataSurfaces::MaxSlatAngs;
355 :
356 : // Return value
357 : Real64 InterpSlatAng;
358 :
359 : // FUNCTION PARAMETER DEFINITIONS:
360 : static Real64 const DeltaAng(DataGlobalConstants::Pi / (double(MaxSlatAngs) - 1.0));
361 : static Real64 const DeltaAng_inv((double(MaxSlatAngs) - 1.0) / DataGlobalConstants::Pi);
362 :
363 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
364 : Real64 InterpFac; // Interpolation factor
365 : int IBeta; // Slat angle index
366 : Real64 SlatAng1;
367 :
368 5517 : if (SlatAng > DataGlobalConstants::Pi || SlatAng < 0.0) {
369 0 : SlatAng1 = min(max(SlatAng, 0.0), DataGlobalConstants::Pi);
370 : } else {
371 5517 : SlatAng1 = SlatAng;
372 : }
373 :
374 5517 : if (VarSlats) { // Variable-angle slats
375 21 : IBeta = 1 + int(SlatAng1 * DeltaAng_inv);
376 21 : InterpFac = (SlatAng1 - DeltaAng * (IBeta - 1)) * DeltaAng_inv;
377 21 : InterpSlatAng = PropArray(IBeta) + InterpFac * (PropArray(min(MaxSlatAngs, IBeta + 1)) - PropArray(IBeta));
378 : } else { // Fixed-angle slats or shade
379 5496 : InterpSlatAng = PropArray(1);
380 : }
381 :
382 5517 : return InterpSlatAng;
383 : }
384 :
385 129 : Real64 InterpProfSlatAng(Real64 const ProfAng, // Profile angle (rad)
386 : Real64 const SlatAng, // Slat angle (rad)
387 : bool const VarSlats, // True if variable-angle slats
388 : Array2A<Real64> const PropArray // Array of blind properties
389 : )
390 : {
391 :
392 : // SUBROUTINE INFORMATION:
393 : // AUTHOR Fred Winkelmann
394 : // DATE WRITTEN Dec 2001
395 : // MODIFIED na
396 : // RE-ENGINEERED na
397 :
398 : // PURPOSE OF THIS SUBROUTINE:
399 : // Does simultaneous profile-angle and slat-angle interpolation of window
400 : // blind solar-thermal properties that depend on profile angle and slat angle
401 :
402 : // METHODOLOGY EMPLOYED:
403 : // Linear interpolation.
404 :
405 : // Using/Aliasing
406 : using DataSurfaces::MaxSlatAngs;
407 :
408 : // Return value
409 : Real64 InterpProfSlatAng;
410 :
411 : // Argument array dimensioning
412 129 : PropArray.dim(MaxSlatAngs, 37);
413 :
414 : // FUNCTION PARAMETER DEFINITIONS:
415 129 : Real64 const DeltaProfAng(DataGlobalConstants::Pi / 36.0);
416 129 : Real64 const DeltaSlatAng(DataGlobalConstants::Pi / (double(MaxSlatAngs) - 1.0));
417 :
418 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
419 : Real64 ProfAngRatio; // Profile angle interpolation factor
420 : Real64 SlatAngRatio; // Slat angle interpolation factor
421 : int IAlpha; // Profile angle index
422 : int IBeta; // Slat angle index
423 : Real64 Val1; // Property values at points enclosing the given ProfAngle and SlatAngle
424 : Real64 Val2;
425 : Real64 Val3;
426 : Real64 Val4;
427 : Real64 ValA; // Property values at given SlatAngle to be interpolated in profile angle
428 : Real64 ValB;
429 : Real64 SlatAng1;
430 : Real64 ProfAng1;
431 :
432 129 : if (SlatAng > DataGlobalConstants::Pi || SlatAng < 0.0 || ProfAng > DataGlobalConstants::PiOvr2 || ProfAng < -DataGlobalConstants::PiOvr2) {
433 0 : SlatAng1 = min(max(SlatAng, 0.0), DataGlobalConstants::Pi);
434 :
435 : // This is not correct, fixed 2/17/2010
436 : // ProfAng1 = MIN(MAX(SlatAng,-PiOvr2),PiOvr2)
437 0 : ProfAng1 = min(max(ProfAng, -DataGlobalConstants::PiOvr2), DataGlobalConstants::PiOvr2);
438 : } else {
439 129 : SlatAng1 = SlatAng;
440 129 : ProfAng1 = ProfAng;
441 : }
442 :
443 129 : IAlpha = int((ProfAng1 + DataGlobalConstants::PiOvr2) / DeltaProfAng) + 1;
444 129 : ProfAngRatio = (ProfAng1 + DataGlobalConstants::PiOvr2 - (IAlpha - 1) * DeltaProfAng) / DeltaProfAng;
445 :
446 129 : if (VarSlats) { // Variable-angle slats: interpolate in profile angle and slat angle
447 27 : IBeta = int(SlatAng1 / DeltaSlatAng) + 1;
448 27 : SlatAngRatio = (SlatAng1 - (IBeta - 1) * DeltaSlatAng) / DeltaSlatAng;
449 27 : Val1 = PropArray(IBeta, IAlpha);
450 27 : Val2 = PropArray(min(MaxSlatAngs, IBeta + 1), IAlpha);
451 27 : Val3 = PropArray(IBeta, min(37, IAlpha + 1));
452 27 : Val4 = PropArray(min(MaxSlatAngs, IBeta + 1), min(37, IAlpha + 1));
453 27 : ValA = Val1 + SlatAngRatio * (Val2 - Val1);
454 27 : ValB = Val3 + SlatAngRatio * (Val4 - Val3);
455 27 : InterpProfSlatAng = ValA + ProfAngRatio * (ValB - ValA);
456 : } else { // Fixed-angle slats: interpolate only in profile angle
457 102 : Val1 = PropArray(1, IAlpha);
458 102 : Val2 = PropArray(1, min(37, IAlpha + 1));
459 102 : InterpProfSlatAng = Val1 + ProfAngRatio * (Val2 - Val1);
460 : }
461 :
462 129 : return InterpProfSlatAng;
463 : }
464 :
465 41235 : Real64 BlindBeamBeamTrans(Real64 const ProfAng, // Solar profile angle (rad)
466 : Real64 const SlatAng, // Slat angle (rad)
467 : Real64 const SlatWidth, // Slat width (m)
468 : Real64 const SlatSeparation, // Slat separation (distance between surfaces of adjacent slats) (m)
469 : Real64 const SlatThickness // Slat thickness (m)
470 : )
471 : {
472 :
473 : // FUNCTION INFORMATION:
474 : // AUTHOR Fred Winkelmann
475 : // DATE WRITTEN Jan 2002
476 : // MODIFIED na
477 : // RE-ENGINEERED na
478 :
479 : // PURPOSE OF THIS SUBROUTINE:
480 : // Calculates beam-to-beam transmittance of a window blind
481 :
482 : // METHODOLOGY EMPLOYED:
483 : // Based on solar profile angle and slat geometry
484 :
485 : // Return value
486 : Real64 BlindBeamBeamTrans;
487 :
488 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
489 : Real64 fEdge; // Slat edge correction factor
490 : Real64 wbar; // Intermediate variable
491 : Real64 gamma; // Intermediate variable
492 : Real64 fEdge1; // Intermediate variable
493 : Real64 CosProfAng; // Cosine of profile angle
494 :
495 41235 : CosProfAng = std::cos(ProfAng);
496 41235 : gamma = SlatAng - ProfAng;
497 41235 : wbar = SlatSeparation;
498 41235 : if (CosProfAng != 0.0) wbar = SlatWidth * std::cos(gamma) / CosProfAng;
499 41235 : BlindBeamBeamTrans = max(0.0, 1.0 - std::abs(wbar / SlatSeparation));
500 :
501 41235 : if (BlindBeamBeamTrans > 0.0) {
502 :
503 : // Correction factor that accounts for finite thickness of slats. It is used to modify the
504 : // blind transmittance to account for reflection and absorption by the slat edges.
505 : // fEdge is ratio of area subtended by edge of slat to area between tops of adjacent slats.
506 :
507 4554 : fEdge = 0.0;
508 4554 : fEdge1 = 0.0;
509 4554 : if (std::abs(std::sin(gamma)) > 0.01) {
510 4554 : if ((SlatAng > 0.0 && SlatAng <= DataGlobalConstants::PiOvr2 && ProfAng <= SlatAng) ||
511 2512 : (SlatAng > DataGlobalConstants::PiOvr2 && SlatAng <= DataGlobalConstants::Pi && ProfAng > -(DataGlobalConstants::Pi - SlatAng)))
512 4554 : fEdge1 = SlatThickness * std::abs(std::sin(gamma)) / ((SlatSeparation + SlatThickness / std::abs(std::sin(SlatAng))) * CosProfAng);
513 4554 : fEdge = min(1.0, std::abs(fEdge1));
514 : }
515 4554 : BlindBeamBeamTrans *= (1.0 - fEdge);
516 : }
517 :
518 41235 : return BlindBeamBeamTrans;
519 : }
520 :
521 808 : std::string &strip_trailing_zeros(std::string &InputString)
522 : {
523 : // FUNCTION INFORMATION:
524 : // AUTHOR Stuart Mentzer (in-place version of RemoveTrailingZeros by Linda Lawrie)
525 : // DATE WRITTEN July 2014
526 : // MODIFIED na
527 : // RE-ENGINEERED na
528 :
529 : // PURPOSE OF THIS FUNCTION:
530 : // Remove trailing fractional zeros from floating point representation strings in place.
531 :
532 : static constexpr std::string_view ED("ED");
533 : static constexpr std::string_view zero_string("0.");
534 :
535 808 : assert(!has_any_of(InputString, "ed")); // Pre Not using lowercase exponent letter
536 808 : assert(InputString == stripped(InputString)); // Pre Already stripped surrounding spaces
537 :
538 808 : if (has(InputString, '.') && (!has_any_of(InputString, ED))) { // Has decimal point and no exponent part
539 645 : std::string::size_type const pos(InputString.find_last_not_of('0'));
540 645 : if (pos + 1 < InputString.length()) {
541 170 : switch (pos) { // Handle [+/-].000... format
542 0 : case 0u: // .0*
543 0 : InputString = zero_string;
544 0 : break;
545 24 : case 1u:
546 24 : if (InputString[1] == '.') {
547 24 : char const c0(InputString[0]);
548 24 : if ((c0 == '+') || (c0 == '-')) {
549 0 : InputString = zero_string;
550 0 : break;
551 : }
552 : }
553 : // fallthrough
554 : default:
555 170 : InputString.erase(pos + 1);
556 : }
557 : }
558 : }
559 808 : return InputString; // Allows chaining
560 : }
561 :
562 183696 : void MovingAvg(Array1D<Real64> &DataIn, int const NumItemsInAvg)
563 : {
564 183696 : if (NumItemsInAvg <= 1) return; // no need to average/smooth
565 :
566 362976 : Array1D<Real64> TempData(2 * DataIn.size()); // a scratch array twice the size, bottom end duplicate of top end
567 :
568 22625328 : for (std::size_t i = 1; i <= DataIn.size(); ++i) {
569 22443840 : TempData(i) = TempData(DataIn.size() + i) = DataIn(i); // initialize both bottom and top end
570 22443840 : DataIn(i) = 0.0;
571 : }
572 :
573 22625328 : for (std::size_t i = 1; i <= DataIn.size(); ++i) {
574 220349376 : for (int j = 1; j <= NumItemsInAvg; ++j) {
575 197905536 : DataIn(i) += TempData(DataIn.size() - NumItemsInAvg + i + j); // sum top end including NumItemsInAvg history terms
576 : }
577 22443840 : DataIn(i) /= NumItemsInAvg; // average to smooth over NumItemsInAvg window
578 : }
579 : }
580 :
581 34638 : void ProcessDateString(EnergyPlusData &state,
582 : std::string const &String,
583 : int &PMonth,
584 : int &PDay,
585 : int &PWeekDay,
586 : WeatherManager::DateType &DateType, // DateType found (-1=invalid, 1=month/day, 2=nth day in month, 3=last day in month)
587 : bool &ErrorsFound,
588 : Optional_int PYear)
589 : {
590 :
591 : // SUBROUTINE INFORMATION:
592 : // AUTHOR Linda Lawrie
593 : // DATE WRITTEN December 1999
594 : // MODIFIED na
595 : // RE-ENGINEERED na
596 :
597 : // PURPOSE OF THIS SUBROUTINE:
598 : // This subroutine will process a date from a string and determine
599 : // the proper month and day for that date string.
600 :
601 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
602 34638 : int FstNum{};
603 34638 : bool errFlag{};
604 34638 : int NumTokens{};
605 34638 : int TokenDay{};
606 34638 : int TokenMonth{};
607 34638 : int TokenWeekday{};
608 :
609 34638 : FstNum = int(UtilityRoutines::ProcessNumber(String, errFlag));
610 34638 : DateType = WeatherManager::DateType::Invalid;
611 34638 : if (!errFlag) {
612 : // Entered single number, do inverse JDay
613 1520 : if (FstNum == 0) {
614 1520 : PMonth = 0;
615 1520 : PDay = 0;
616 1520 : DateType = WeatherManager::DateType::MonthDay;
617 0 : } else if (FstNum < 0 || FstNum > 366) {
618 0 : ShowSevereError(state, "Invalid Julian date Entered=" + String);
619 0 : ErrorsFound = true;
620 : } else {
621 0 : InvOrdinalDay(FstNum, PMonth, PDay, 0);
622 0 : DateType = WeatherManager::DateType::LastDayInMonth;
623 : }
624 : } else {
625 : // Error when processing as number, try x/x
626 33118 : if (!present(PYear)) {
627 31596 : DetermineDateTokens(state, String, NumTokens, TokenDay, TokenMonth, TokenWeekday, DateType, ErrorsFound);
628 : } else {
629 1522 : int TokenYear = 0;
630 1522 : DetermineDateTokens(state, String, NumTokens, TokenDay, TokenMonth, TokenWeekday, DateType, ErrorsFound, TokenYear);
631 1522 : PYear = TokenYear;
632 : }
633 33118 : if (DateType == WeatherManager::DateType::MonthDay) {
634 32024 : PDay = TokenDay;
635 32024 : PMonth = TokenMonth;
636 1094 : } else if (DateType == WeatherManager::DateType::NthDayInMonth || DateType == WeatherManager::DateType::LastDayInMonth) {
637 : // interpret as TokenDay TokenWeekday in TokenMonth
638 1094 : PDay = TokenDay;
639 1094 : PMonth = TokenMonth;
640 1094 : PWeekDay = TokenWeekday;
641 : }
642 : }
643 34638 : }
644 :
645 33118 : void DetermineDateTokens(EnergyPlusData &state,
646 : std::string const &String,
647 : int &NumTokens, // Number of tokens found in string
648 : int &TokenDay, // Value of numeric field found
649 : int &TokenMonth, // Value of Month field found (1=Jan, 2=Feb, etc)
650 : int &TokenWeekday, // Value of Weekday field found (1=Sunday, 2=Monday, etc), 0 if none
651 : WeatherManager::DateType &DateType, // DateType found (-1=invalid, 1=month/day, 2=nth day in month, 3=last day in month)
652 : bool &ErrorsFound, // Set to true if cannot process this string as a date
653 : Optional_int TokenYear // Value of Year if one appears to be present and this argument is present
654 : )
655 : {
656 :
657 : // SUBROUTINE INFORMATION:
658 : // AUTHOR Linda Lawrie
659 : // DATE WRITTEN August 2000
660 : // MODIFIED na
661 : // RE-ENGINEERED na
662 :
663 : // PURPOSE OF THIS SUBROUTINE:
664 : // This subroutine is invoked for date fields that appear to be strings (give
665 : // error when ProcessNumber is used).
666 :
667 : // METHODOLOGY EMPLOYED:
668 : // Delete everything that is extraneous to the date information needed. Process what
669 : // is left.
670 :
671 : // SUBROUTINE PARAMETER DEFINITIONS:
672 : static constexpr int NumSingleChars(3);
673 : static constexpr std::array<std::string_view, NumSingleChars> SingleChars{"/", ":", "-"};
674 : static constexpr int NumDoubleChars(6);
675 : static constexpr std::array<std::string_view, NumDoubleChars> DoubleChars{
676 : "ST ", "ND ", "RD ", "TH ", "OF ", "IN "}; // Need trailing spaces: Want thse only at end of words
677 : static constexpr std::array<std::string_view, 12> Months{"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
678 : static constexpr std::array<std::string_view, 7> Weekdays{"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
679 :
680 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
681 66236 : std::string CurrentString = String;
682 33118 : int Loop{};
683 66236 : Array1D_string Fields(3);
684 33118 : int NumField1{};
685 33118 : int NumField2{};
686 33118 : int NumField3{};
687 33118 : bool errFlag{};
688 33118 : bool InternalError = false;
689 33118 : bool WkDayInMonth = false;
690 :
691 33118 : NumTokens = 0;
692 33118 : TokenDay = 0;
693 33118 : TokenMonth = 0;
694 33118 : TokenWeekday = 0;
695 33118 : DateType = WeatherManager::DateType::Invalid;
696 33118 : if (present(TokenYear)) TokenYear = 0;
697 : // Take out separator characters, other extraneous stuff
698 :
699 132472 : for (Loop = 0; Loop < NumSingleChars; ++Loop) {
700 99354 : auto Pos = index(CurrentString, SingleChars[Loop]);
701 162398 : while (Pos != std::string::npos) {
702 31522 : CurrentString[Pos] = ' ';
703 31522 : Pos = index(CurrentString, SingleChars[Loop]);
704 : }
705 : }
706 :
707 231826 : for (Loop = 0; Loop < NumDoubleChars; ++Loop) {
708 198708 : auto Pos = index(CurrentString, DoubleChars[Loop]);
709 203084 : while (Pos != std::string::npos) {
710 2188 : CurrentString.replace(Pos, 2, " ");
711 2188 : Pos = index(CurrentString, DoubleChars[Loop]);
712 2188 : WkDayInMonth = true;
713 : }
714 : }
715 :
716 33118 : strip(CurrentString);
717 33118 : if (CurrentString == BlankString) {
718 0 : ShowSevereError(state, "Invalid date field=" + String);
719 0 : ErrorsFound = true;
720 : } else {
721 33118 : Loop = 0;
722 167778 : while (Loop < 3) { // Max of 3 fields
723 99354 : if (CurrentString == BlankString) break;
724 67330 : auto Pos = index(CurrentString, ' ');
725 67330 : ++Loop;
726 67330 : if (Pos == std::string::npos) Pos = CurrentString.length();
727 67330 : Fields(Loop) = CurrentString.substr(0, Pos);
728 67330 : CurrentString.erase(0, Pos);
729 67330 : strip(CurrentString);
730 : }
731 33118 : if (not_blank(CurrentString)) {
732 0 : ShowSevereError(state, "Invalid date field=" + String);
733 0 : ErrorsFound = true;
734 33118 : } else if (Loop == 2) {
735 : // Field must be Day Month or Month Day (if both numeric, mon / day)
736 32024 : InternalError = false;
737 32024 : NumField1 = int(UtilityRoutines::ProcessNumber(Fields(1), errFlag));
738 32024 : if (errFlag) {
739 : // Month day, but first field is not numeric, 2nd must be
740 483 : NumField2 = int(UtilityRoutines::ProcessNumber(Fields(2), errFlag));
741 483 : if (errFlag) {
742 0 : ShowSevereError(state, "Invalid date field=" + String);
743 0 : InternalError = true;
744 : } else {
745 483 : TokenDay = NumField2;
746 : }
747 483 : TokenMonth = UtilityRoutines::FindItemInList(Fields(1).substr(0, 3), Months.begin(), Months.end());
748 483 : ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
749 483 : if (!InternalError) {
750 483 : DateType = WeatherManager::DateType::MonthDay;
751 : } else {
752 0 : ErrorsFound = true;
753 : }
754 : } else {
755 : // Month Day, first field was numeric, if 2nd is, then it's month<num> day<num>
756 31541 : NumField2 = int(UtilityRoutines::ProcessNumber(Fields(2), errFlag));
757 31541 : if (!errFlag) {
758 31516 : TokenMonth = NumField1;
759 31516 : TokenDay = NumField2;
760 31516 : ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
761 31516 : if (!InternalError) {
762 31516 : DateType = WeatherManager::DateType::MonthDay;
763 : } else {
764 0 : ErrorsFound = true;
765 : }
766 : } else { // 2nd field was not numeric. Must be Month
767 25 : TokenDay = NumField1;
768 25 : TokenMonth = UtilityRoutines::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
769 25 : ValidateMonthDay(state, String, TokenDay, TokenMonth, InternalError);
770 25 : if (!InternalError) {
771 25 : DateType = WeatherManager::DateType::MonthDay;
772 25 : NumTokens = 2;
773 : } else {
774 0 : ErrorsFound = true;
775 : }
776 : }
777 : }
778 1094 : } else if (Loop == 3) {
779 : // Field must be some combination of <num> Weekday Month (if WkDayInMonth true)
780 1094 : if (WkDayInMonth) {
781 1094 : NumField1 = int(UtilityRoutines::ProcessNumber(Fields(1), errFlag));
782 1094 : if (!errFlag) { // the expected result
783 902 : TokenDay = NumField1;
784 902 : TokenWeekday = UtilityRoutines::FindItemInList(Fields(2).substr(0, 3), Weekdays.begin(), Weekdays.end());
785 902 : if (TokenWeekday == 0) {
786 0 : TokenMonth = UtilityRoutines::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
787 0 : TokenWeekday = UtilityRoutines::FindItemInList(Fields(3).substr(0, 3), Weekdays.begin(), Weekdays.end());
788 0 : if (TokenMonth == 0 || TokenWeekday == 0) InternalError = true;
789 : } else {
790 902 : TokenMonth = UtilityRoutines::FindItemInList(Fields(3).substr(0, 3), Months.begin(), Months.end());
791 902 : if (TokenMonth == 0) InternalError = true;
792 : }
793 902 : DateType = WeatherManager::DateType::NthDayInMonth;
794 902 : NumTokens = 3;
795 902 : if (TokenDay < 0 || TokenDay > 5) InternalError = true;
796 : } else { // first field was not numeric....
797 192 : if (Fields(1) == "LA") {
798 192 : DateType = WeatherManager::DateType::LastDayInMonth;
799 192 : NumTokens = 3;
800 192 : TokenWeekday = UtilityRoutines::FindItemInList(Fields(2).substr(0, 3), Weekdays.begin(), Weekdays.end());
801 192 : if (TokenWeekday == 0) {
802 0 : TokenMonth = UtilityRoutines::FindItemInList(Fields(2).substr(0, 3), Months.begin(), Months.end());
803 0 : TokenWeekday = UtilityRoutines::FindItemInList(Fields(3).substr(0, 3), Weekdays.begin(), Weekdays.end());
804 0 : if (TokenMonth == 0 || TokenWeekday == 0) InternalError = true;
805 : } else {
806 192 : TokenMonth = UtilityRoutines::FindItemInList(Fields(3).substr(0, 3), Months.begin(), Months.end());
807 192 : if (TokenMonth == 0) InternalError = true;
808 : }
809 : } else { // error....
810 0 : ShowSevereError(state, "First date field not numeric, field=" + String);
811 : }
812 : }
813 : } else { // mm/dd/yyyy or yyyy/mm/dd
814 0 : NumField1 = int(UtilityRoutines::ProcessNumber(Fields(1), errFlag));
815 0 : NumField2 = int(UtilityRoutines::ProcessNumber(Fields(2), errFlag));
816 0 : NumField3 = int(UtilityRoutines::ProcessNumber(Fields(3), errFlag));
817 0 : DateType = WeatherManager::DateType::MonthDay;
818 : // error detection later..
819 0 : if (NumField1 > 100) {
820 0 : if (present(TokenYear)) {
821 0 : TokenYear = NumField1;
822 : }
823 0 : TokenMonth = NumField2;
824 0 : TokenDay = NumField3;
825 0 : } else if (NumField3 > 100) {
826 0 : if (present(TokenYear)) {
827 0 : TokenYear = NumField3;
828 : }
829 0 : TokenMonth = NumField1;
830 0 : TokenDay = NumField2;
831 : }
832 : }
833 : } else {
834 : // Not enough or too many fields
835 0 : ShowSevereError(state, "Invalid date field=" + String);
836 0 : ErrorsFound = true;
837 : }
838 : }
839 :
840 33118 : if (InternalError) {
841 0 : DateType = WeatherManager::DateType::Invalid;
842 0 : ErrorsFound = true;
843 : }
844 33118 : }
845 :
846 32024 : void ValidateMonthDay(EnergyPlusData &state,
847 : std::string const &String, // REAL(r64) string being processed
848 : int const Day,
849 : int const Month,
850 : bool &ErrorsFound)
851 : {
852 :
853 : // SUBROUTINE INFORMATION:
854 : // AUTHOR Linda Lawrie
855 : // DATE WRITTEN August 2000
856 : // MODIFIED na
857 : // RE-ENGINEERED na
858 :
859 : // PURPOSE OF THIS SUBROUTINE:
860 : // This subroutine validates a potential Day, Month values, produces an error
861 : // message when not valid, and sets error flag.
862 :
863 : // SUBROUTINE PARAMETER DEFINITIONS:
864 : static constexpr std::array<int, 12> EndMonthDay = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
865 :
866 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
867 : bool InternalError;
868 :
869 32024 : InternalError = false;
870 32024 : if (Month < 1 || Month > 12) InternalError = true;
871 32024 : if (!InternalError) {
872 32024 : if (Day < 1 || Day > EndMonthDay[Month - 1]) InternalError = true;
873 : }
874 32024 : if (InternalError) {
875 0 : ShowSevereError(state, "Invalid Month Day date format=" + String);
876 0 : ErrorsFound = true;
877 : } else {
878 32024 : ErrorsFound = false;
879 : }
880 32024 : }
881 :
882 175227 : int OrdinalDay(int const Month, // Month, 1..12
883 : int const Day, // Day of Month, not validated by month
884 : int const LeapYearValue // 1 if leap year indicated, 0 if not
885 : )
886 : {
887 :
888 : // FUNCTION INFORMATION:
889 : // AUTHOR Linda K. Lawrie
890 : // DATE WRITTEN September 1997
891 : // MODIFIED na
892 : // RE-ENGINEERED from JDAYF in BLAST/IBLAST
893 :
894 : // PURPOSE OF THIS SUBROUTINE:
895 : // This subroutine returns the appropriate Julian Day value for the input
896 : // Month and Day.
897 :
898 : // Return value
899 : int JulianDay;
900 :
901 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
902 : static constexpr std::array<int, 12> EndDayofMonth = {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
903 : // End day numbers of each month (without Leap Year)
904 :
905 175227 : if (Month == 1) {
906 : // CASE 1: JANUARY
907 58347 : JulianDay = Day;
908 :
909 116880 : } else if (Month == 2) {
910 : // CASE 2: FEBRUARY
911 2189 : JulianDay = Day + EndDayofMonth[0];
912 :
913 114691 : } else if ((Month >= 3) && (Month <= 12)) {
914 : // CASE 3: REMAINING MONTHS
915 114691 : JulianDay = Day + EndDayofMonth[Month - 2] + LeapYearValue;
916 :
917 : } else {
918 0 : JulianDay = 0;
919 : }
920 :
921 175227 : return JulianDay;
922 : }
923 :
924 76765 : void InvOrdinalDay(int const Number, int &PMonth, int &PDay, int const LeapYr)
925 : {
926 :
927 : // SUBROUTINE INFORMATION:
928 : // AUTHOR Linda Lawrie
929 : // DATE WRITTEN December 1999
930 : // MODIFIED na
931 : // RE-ENGINEERED na
932 :
933 : // PURPOSE OF THIS SUBROUTINE:
934 : // This subroutine performs and inverse Julian Day
935 : // calculation, using an input JulianDay and returning
936 : // appropriate Month and Day.
937 :
938 : // SUBROUTINE PARAMETER DEFINITIONS:
939 : static constexpr std::array<int, 13> EndOfMonth = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
940 :
941 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
942 : int WMonth;
943 : int LeapAddPrev;
944 : int LeapAddCur;
945 :
946 76765 : if (Number < 0 || Number > 366) return;
947 496305 : for (WMonth = 1; WMonth <= 12; ++WMonth) {
948 496305 : if (WMonth == 1) {
949 76765 : LeapAddPrev = 0;
950 76765 : LeapAddCur = 0;
951 419540 : } else if (WMonth == 2) {
952 69420 : LeapAddPrev = 0;
953 69420 : LeapAddCur = LeapYr;
954 : } else {
955 350120 : LeapAddPrev = LeapYr;
956 350120 : LeapAddCur = LeapYr;
957 : }
958 496305 : if (Number > (EndOfMonth[WMonth - 1] + LeapAddPrev) && Number <= (EndOfMonth[WMonth] + LeapAddCur)) break;
959 : }
960 76765 : PMonth = WMonth;
961 76765 : PDay = Number - (EndOfMonth[WMonth - 1] + LeapAddCur);
962 : }
963 :
964 6912 : bool BetweenDateHoursLeftInclusive(
965 : int const TestDate, int const TestHour, int const StartDate, int const StartHour, int const EndDate, int const EndHour)
966 : {
967 6912 : Real64 TestRatioOfDay = TestHour / 24.0;
968 6912 : Real64 StartRatioOfDay = StartHour / 24.0;
969 6912 : Real64 EndRatioOfDay = EndHour / 24.0;
970 :
971 6912 : if (StartDate + StartRatioOfDay <= EndDate + EndRatioOfDay) { // Start Date <= End Date
972 5376 : return (StartDate + StartRatioOfDay <= TestDate + TestRatioOfDay) && (TestDate + TestRatioOfDay <= EndDate + EndRatioOfDay);
973 : } else { // EndDate < StartDate
974 1536 : return (EndDate + EndRatioOfDay <= TestDate + TestRatioOfDay) && (TestDate + TestRatioOfDay <= StartDate + StartRatioOfDay);
975 : }
976 : }
977 :
978 16 : bool BetweenDates(int const TestDate, // Date to test
979 : int const StartDate, // Start date in sequence
980 : int const EndDate // End date in sequence
981 : )
982 : {
983 :
984 : // FUNCTION INFORMATION:
985 : // AUTHOR Linda K. Lawrie
986 : // DATE WRITTEN June 2000
987 : // MODIFIED na
988 : // RE-ENGINEERED na
989 :
990 : // PURPOSE OF THIS FUNCTION:
991 : // This function returns true if the TestDate is between
992 : // (StartDate <= TestDate <= EndDate).
993 :
994 : // METHODOLOGY EMPLOYED:
995 : // The input dates are Julian Day format, year is irrelevant.
996 : // Thus, if StartDate > EndDate (i.e. StartDate = 1Dec and EndDate = 31Jan),
997 : // this routine accomodates.
998 :
999 : // REFERENCES:
1000 : // Adapted from BLAST BTWEEN function.
1001 :
1002 : // Return value
1003 : bool BetweenDates;
1004 :
1005 16 : BetweenDates = false; // Default case
1006 :
1007 16 : if (StartDate <= EndDate) { // Start Date <= End Date
1008 0 : if (TestDate >= StartDate && TestDate <= EndDate) BetweenDates = true;
1009 : } else { // EndDate <= StartDate
1010 16 : if (TestDate <= EndDate || TestDate >= StartDate) BetweenDates = true;
1011 : }
1012 :
1013 16 : return BetweenDates;
1014 : }
1015 :
1016 1920347 : std::string CreateSysTimeIntervalString(EnergyPlusData &state)
1017 : {
1018 :
1019 : // FUNCTION INFORMATION:
1020 : // AUTHOR Linda K. Lawrie
1021 : // DATE WRITTEN April 2003
1022 : // MODIFIED na
1023 : // RE-ENGINEERED na
1024 :
1025 : // PURPOSE OF THIS FUNCTION:
1026 : // This function creates the current time interval of the system
1027 : // time step.
1028 :
1029 : // Using/Aliasing
1030 1920347 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
1031 1920347 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
1032 :
1033 : // Return value
1034 1920347 : std::string OutputString;
1035 :
1036 1920347 : Real64 constexpr FracToMin(60.0);
1037 :
1038 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1039 : Real64 ActualTimeS; // Start of current interval (HVAC time step)
1040 : Real64 ActualTimeE; // End of current interval (HVAC time step)
1041 : int ActualTimeHrS;
1042 : // INTEGER ActualTimeHrE
1043 : int ActualTimeMinS;
1044 :
1045 : // ActualTimeS=INT(CurrentTime)+(SysTimeElapsed+(CurrentTime - INT(CurrentTime)))
1046 : // CR6902 ActualTimeS=INT(CurrentTime-TimeStepZone)+SysTimeElapsed
1047 : // [DC] TODO: Improve display accuracy up to fractional seconds using hh:mm:ss.0 format
1048 1920347 : ActualTimeS = state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone + SysTimeElapsed;
1049 1920347 : ActualTimeE = ActualTimeS + TimeStepSys;
1050 1920347 : ActualTimeHrS = int(ActualTimeS);
1051 : // ActualTimeHrE=INT(ActualTimeE)
1052 1920347 : ActualTimeMinS = nint((ActualTimeS - ActualTimeHrS) * FracToMin);
1053 :
1054 1920347 : if (ActualTimeMinS == 60) {
1055 5684 : ++ActualTimeHrS;
1056 5684 : ActualTimeMinS = 0;
1057 : }
1058 3840694 : const auto TimeStmpS = format("{:02}:{:02}", ActualTimeHrS, ActualTimeMinS);
1059 1920347 : auto minutes = ((ActualTimeE - static_cast<int>(ActualTimeE)) * FracToMin);
1060 :
1061 3840694 : auto TimeStmpE = format("{:02}:{:2.0F}", static_cast<int>(ActualTimeE), minutes);
1062 :
1063 1920347 : if (TimeStmpE[3] == ' ') {
1064 344554 : TimeStmpE[3] = '0';
1065 : }
1066 1920347 : OutputString = TimeStmpS + " - " + TimeStmpE;
1067 :
1068 3840694 : return OutputString;
1069 : }
1070 :
1071 : // returns the Julian date for the first, second, etc. day of week for a given month
1072 3604 : int nthDayOfWeekOfMonth(EnergyPlusData &state,
1073 : int const dayOfWeek, // day of week (Sunday=1, Monday=2, ...)
1074 : int const nthTime, // nth time the day of the week occurs (first monday, third tuesday, ..)
1075 : int const monthNumber // January = 1
1076 : )
1077 : {
1078 : // J. Glazer - August 2017
1079 3604 : int firstDayOfMonth = OrdinalDay(monthNumber, 1, state.dataEnvrn->CurrentYearIsLeapYear);
1080 3604 : int dayOfWeekForFirstDay = (state.dataEnvrn->RunPeriodStartDayOfWeek + firstDayOfMonth - 1) % 7;
1081 : int jdatForNth;
1082 3604 : if (dayOfWeek >= dayOfWeekForFirstDay) {
1083 1818 : jdatForNth = firstDayOfMonth + (dayOfWeek - dayOfWeekForFirstDay) + 7 * (nthTime - 1);
1084 : } else {
1085 1786 : jdatForNth = firstDayOfMonth + ((dayOfWeek + 7) - dayOfWeekForFirstDay) + 7 * (nthTime - 1);
1086 : }
1087 3604 : return jdatForNth;
1088 : }
1089 :
1090 12214865 : Real64 SafeDivide(Real64 const a, Real64 const b)
1091 : {
1092 :
1093 : // returns a / b while preventing division by zero
1094 :
1095 : // Return value
1096 : Real64 c;
1097 :
1098 : // Locals
1099 12214865 : Real64 constexpr SMALL(1.E-10);
1100 :
1101 12214865 : if (std::abs(b) >= SMALL) {
1102 12213741 : c = a / b;
1103 : } else {
1104 1124 : c = a / sign(SMALL, b);
1105 : }
1106 12214865 : return c;
1107 : }
1108 :
1109 255955274 : void Iterate(Real64 &ResultX, // ResultX is the final Iteration result passed back to the calling routine
1110 : Real64 const Tol, // Tolerance for Convergence
1111 : Real64 const X0, // Current value of X
1112 : Real64 const Y0, // Current value of the function Y(X)
1113 : Real64 &X1, // First Previous values of X
1114 : Real64 &Y1, // First Previous values of Y(X1)
1115 : int const Iter, // Number of iterations
1116 : int &Cnvg // Convergence flag Cnvg = 0: Not converged
1117 : )
1118 : {
1119 :
1120 : // SUBROUTINE INFORMATION:
1121 : // AUTHOR Richard Liesen
1122 : // DATE WRITTEN March 2004
1123 : // MODIFIED na
1124 : // RE-ENGINEERED na
1125 :
1126 : // PURPOSE OF THIS SUBROUTINE:
1127 : // Iterately solves for the value of X which satisfies Y(X)=0.
1128 : // The subroutine tests for convergence and provides a new guess for the value of the
1129 : // independent variable X.
1130 :
1131 : // REFERENCES:
1132 : // Linear Correction based on the RegulaFalsi routine in EnergyPlus
1133 :
1134 : // SUBROUTINE PARAMETER DEFINITIONS:
1135 255955274 : Real64 constexpr small(1.e-9); // Small Number used to approximate zero
1136 255955274 : Real64 constexpr Perturb(0.1); // Perturbation applied to X to initialize iteration
1137 :
1138 : Real64 DY; // Linear fit result
1139 :
1140 : // Check for convergence by comparing change in X
1141 255955274 : if (Iter != 1) {
1142 231641992 : if (std::abs(X0 - X1) < Tol || Y0 == 0.0) {
1143 24313222 : ResultX = X0;
1144 24313222 : Cnvg = 1;
1145 24313222 : return;
1146 : }
1147 : }
1148 :
1149 : // Not converged.
1150 231642052 : Cnvg = 0;
1151 231642052 : if (Iter == 1) {
1152 :
1153 : // New guess is specified by Perturb
1154 24313282 : if (std::abs(X0) > small) {
1155 24312766 : ResultX = X0 * (1.0 + Perturb);
1156 : } else {
1157 516 : ResultX = Perturb;
1158 : }
1159 :
1160 : } else {
1161 :
1162 : // New guess calculated from LINEAR FIT of most recent two points
1163 207328770 : DY = Y0 - Y1;
1164 207328770 : if (std::abs(DY) < small) {
1165 0 : DY = small;
1166 : }
1167 : // new estimation
1168 :
1169 207328770 : ResultX = (Y0 * X1 - Y1 * X0) / DY;
1170 : }
1171 :
1172 231642052 : X1 = X0;
1173 231642052 : Y1 = Y0;
1174 : }
1175 :
1176 40820 : int FindNumberInList(int const WhichNumber, Array1A_int const ListOfItems, int const NumItems)
1177 : {
1178 :
1179 : // FUNCTION INFORMATION:
1180 : // AUTHOR Linda K. Lawrie
1181 : // DATE WRITTEN September 2001
1182 : // MODIFIED na
1183 : // RE-ENGINEERED na
1184 :
1185 : // PURPOSE OF THIS FUNCTION:
1186 : // This function looks up a number(integer) in a similar list of
1187 : // items and returns the index of the item in the list, if
1188 : // found.
1189 :
1190 : // Return value
1191 : int FindNumberInList;
1192 :
1193 : // Argument array dimensioning
1194 40820 : ListOfItems.dim(_);
1195 :
1196 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1197 : int Count;
1198 :
1199 40820 : FindNumberInList = 0;
1200 :
1201 357346 : for (Count = 1; Count <= NumItems; ++Count) {
1202 323951 : if (WhichNumber == ListOfItems(Count)) {
1203 7425 : FindNumberInList = Count;
1204 7425 : break;
1205 : }
1206 : }
1207 :
1208 40820 : return FindNumberInList;
1209 : }
1210 :
1211 297313 : void DecodeMonDayHrMin(int const Item, // word containing encoded month, day, hour, minute
1212 : int &Month, // month in integer format (1-12)
1213 : int &Day, // day in integer format (1-31)
1214 : int &Hour, // hour in integer format (1-24)
1215 : int &Minute // minute in integer format (0:59)
1216 : )
1217 : {
1218 :
1219 : // SUBROUTINE INFORMATION:
1220 : // AUTHOR Linda Lawrie
1221 : // DATE WRITTEN March 2000
1222 : // MODIFIED na
1223 : // RE-ENGINEERED na
1224 :
1225 : // PURPOSE OF THIS SUBROUTINE:
1226 : // This subroutine decodes the "packed" integer representation of
1227 : // the Month, Day, Hour, and Minute. Packed integers are used to
1228 : // save memory allocation. Original idea for this routine is contained
1229 : // in DECMDH, BLAST code, by Jean Baugh.
1230 :
1231 : // METHODOLOGY EMPLOYED:
1232 : // Using maximum integer concept the original date can be decoded
1233 : // from the packed single word. This relies on 4 byte integer representation
1234 : // as a minimum (capable of representing up to 2,147,483,647).
1235 :
1236 : // SUBROUTINE PARAMETER DEFINITIONS:
1237 : static constexpr int DecMon(100 * 100 * 100);
1238 : static constexpr int DecDay(100 * 100);
1239 : static constexpr int DecHr(100);
1240 :
1241 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1242 : int TmpItem;
1243 :
1244 297313 : TmpItem = Item;
1245 297313 : Month = TmpItem / DecMon;
1246 297313 : TmpItem = (TmpItem - Month * DecMon);
1247 297313 : Day = TmpItem / DecDay;
1248 297313 : TmpItem -= Day * DecDay;
1249 297313 : Hour = TmpItem / DecHr;
1250 297313 : Minute = mod(TmpItem, DecHr);
1251 297313 : }
1252 :
1253 2133 : int DetermineMinuteForReporting(EnergyPlusData &state, OutputProcessor::TimeStepType t_timeStepType) // kind of reporting, Zone Timestep or System
1254 : {
1255 :
1256 : // FUNCTION INFORMATION:
1257 : // AUTHOR Linda Lawrie
1258 : // DATE WRITTEN January 2012
1259 : // MODIFIED na
1260 : // RE-ENGINEERED na
1261 :
1262 : // PURPOSE OF THIS FUNCTION:
1263 : // When reporting peaks, minutes are used but not necessarily easily calculated.
1264 :
1265 : // METHODOLOGY EMPLOYED:
1266 : // Could use the access to the minute as OP (OutputProcessor) does but uses
1267 : // external calculation.
1268 :
1269 : // Using/Aliasing
1270 2133 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
1271 2133 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
1272 :
1273 : // Return value
1274 : int ActualTimeMin; // calculated Minute for reporting
1275 :
1276 : // FUNCTION PARAMETER DEFINITIONS:
1277 2133 : Real64 constexpr FracToMin(60.0);
1278 :
1279 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1280 : Real64 ActualTimeS; // Start of current interval (HVAC time step)
1281 : Real64 ActualTimeE; // End of current interval (HVAC time step)
1282 : int ActualTimeHrS;
1283 :
1284 2133 : if (t_timeStepType == OutputProcessor::TimeStepType::System) {
1285 1931 : ActualTimeS = state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone + SysTimeElapsed;
1286 1931 : ActualTimeE = ActualTimeS + TimeStepSys;
1287 1931 : ActualTimeHrS = int(ActualTimeS);
1288 1931 : ActualTimeMin = nint((ActualTimeE - ActualTimeHrS) * FracToMin);
1289 : } else {
1290 202 : ActualTimeMin = (state.dataGlobal->CurrentTime - int(state.dataGlobal->CurrentTime)) * FracToMin;
1291 : }
1292 :
1293 2133 : return ActualTimeMin;
1294 : }
1295 :
1296 692612 : void EncodeMonDayHrMin(int &Item, // word containing encoded month, day, hour, minute
1297 : int const Month, // month in integer format (1:12)
1298 : int const Day, // day in integer format (1:31)
1299 : int const Hour, // hour in integer format (1:24)
1300 : int const Minute // minute in integer format (0:59)
1301 : )
1302 : {
1303 :
1304 : // SUBROUTINE INFORMATION:
1305 : // AUTHOR Linda Lawrie
1306 : // DATE WRITTEN March 2000
1307 : // MODIFIED na
1308 : // RE-ENGINEERED na
1309 :
1310 : // PURPOSE OF THIS SUBROUTINE:
1311 : // This subroutine encodes the "packed" integer representation of
1312 : // the Month, Day, Hour, and Minute. Packed integers are used to
1313 : // save memory allocation. Original idea for this routine is contained
1314 : // in DECMDH, BLAST code, by Jean Baugh.
1315 :
1316 : // METHODOLOGY EMPLOYED:
1317 : // Using maximum integer concept the original date can be decoded
1318 : // from the packed single word. This relies on 4 byte integer representation
1319 : // as a minimum (capable of representing up to 2,147,483,647).
1320 :
1321 692612 : Item = ((Month * 100 + Day) * 100 + Hour) * 100 + Minute;
1322 692612 : }
1323 :
1324 0 : int LogicalToInteger(bool const Flag)
1325 : {
1326 : // SUBROUTINE INFORMATION:
1327 : // AUTHOR Dimitri Curtil
1328 : // DATE WRITTEN November 2004
1329 : // MODIFIED na
1330 : // RE-ENGINEERED na
1331 :
1332 : // PURPOSE OF THIS FUNCTION:
1333 : // This subroutine uses an input logical and makes
1334 : // an integer (true=1, false=0)
1335 :
1336 : // Return value
1337 : int LogicalToInteger;
1338 :
1339 0 : if (Flag) {
1340 0 : LogicalToInteger = 1;
1341 : } else {
1342 0 : LogicalToInteger = 0;
1343 : }
1344 :
1345 0 : return LogicalToInteger;
1346 : }
1347 :
1348 0 : Real64 GetCurrentHVACTime(EnergyPlusData &state)
1349 : {
1350 : // SUBROUTINE INFORMATION:
1351 : // AUTHOR Dimitri Curtil
1352 : // DATE WRITTEN November 2004
1353 : // MODIFIED na
1354 : // RE-ENGINEERED na
1355 :
1356 : // PURPOSE OF THIS FUNCTION:
1357 : // This routine returns the time in seconds at the end of the current HVAC step.
1358 :
1359 : // Using/Aliasing
1360 0 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
1361 0 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
1362 :
1363 : // Return value
1364 : Real64 GetCurrentHVACTime;
1365 :
1366 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1367 : Real64 CurrentHVACTime;
1368 :
1369 : // This is the correct formula that does not use MinutesPerSystemTimeStep, which would
1370 : // erronously truncate all sub-minute system time steps down to the closest full minute.
1371 : // Maybe later TimeStepZone, TimeStepSys and SysTimeElapsed could also be specified
1372 : // as real.
1373 0 : CurrentHVACTime = (state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone) + SysTimeElapsed + TimeStepSys;
1374 0 : GetCurrentHVACTime = CurrentHVACTime * DataGlobalConstants::SecInHour;
1375 :
1376 0 : return GetCurrentHVACTime;
1377 : }
1378 :
1379 2638872 : Real64 GetPreviousHVACTime(EnergyPlusData &state)
1380 : {
1381 : // SUBROUTINE INFORMATION:
1382 : // AUTHOR Dimitri Curtil
1383 : // DATE WRITTEN November 2004
1384 : // MODIFIED na
1385 : // RE-ENGINEERED na
1386 :
1387 : // PURPOSE OF THIS FUNCTION:
1388 : // This routine returns the time in seconds at the beginning of the current HVAC step.
1389 :
1390 : // Using/Aliasing
1391 2638872 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
1392 :
1393 : // Return value
1394 : Real64 GetPreviousHVACTime;
1395 :
1396 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1397 : Real64 PreviousHVACTime;
1398 :
1399 : // This is the correct formula that does not use MinutesPerSystemTimeStep, which would
1400 : // erronously truncate all sub-minute system time steps down to the closest full minute.
1401 2638872 : PreviousHVACTime = (state.dataGlobal->CurrentTime - state.dataGlobal->TimeStepZone) + SysTimeElapsed;
1402 2638872 : GetPreviousHVACTime = PreviousHVACTime * DataGlobalConstants::SecInHour;
1403 :
1404 2638872 : return GetPreviousHVACTime;
1405 : }
1406 :
1407 0 : std::string CreateHVACTimeIntervalString(EnergyPlusData &state)
1408 : {
1409 :
1410 : // FUNCTION INFORMATION:
1411 : // AUTHOR Dimitri Curtil
1412 : // DATE WRITTEN January 2005
1413 : // MODIFIED na
1414 : // RE-ENGINEERED na
1415 :
1416 : // PURPOSE OF THIS FUNCTION:
1417 : // This function creates the time stamp with the current time interval for the HVAC
1418 : // time step.
1419 :
1420 : // Return value
1421 0 : std::string OutputString;
1422 :
1423 0 : OutputString = CreateTimeIntervalString(GetPreviousHVACTime(state), GetCurrentHVACTime(state));
1424 :
1425 0 : return OutputString;
1426 : }
1427 :
1428 0 : std::string CreateTimeString(Real64 const Time) // Time in seconds
1429 : {
1430 :
1431 : // FUNCTION INFORMATION:
1432 : // AUTHOR Dimitri Curtil
1433 : // DATE WRITTEN January 2005
1434 : // MODIFIED na
1435 : // RE-ENGINEERED na
1436 :
1437 : // PURPOSE OF THIS FUNCTION:
1438 : // This function creates the time stamp string from the time value specified in seconds.
1439 : // Inspired by similar function CreateSysTimeIntervalString() in General.cc
1440 : // However, this function provides better accuracy for sub-minute time steps
1441 : // by also showing information down to the 10th of a second.
1442 : // Note that Time is expected to be specified in REAL(r64).
1443 :
1444 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1445 : int Hours; // Number of hours <= 24
1446 : int Minutes; // Remaining minutes < 60
1447 : Real64 Seconds; // Remaining seconds < 60
1448 :
1449 0 : ParseTime(Time, Hours, Minutes, Seconds);
1450 :
1451 : // TimeStamp written with formatting
1452 : // "hh:mm:ss.s"
1453 0 : return fmt::format("{:02d}:{:02d}:{:04.1f}", Hours, Minutes, Seconds);
1454 : }
1455 :
1456 0 : std::string CreateTimeIntervalString(Real64 const StartTime, // Start of current interval in seconds
1457 : Real64 const EndTime // End of current interval in seconds
1458 : )
1459 : {
1460 :
1461 : // FUNCTION INFORMATION:
1462 : // AUTHOR Dimitri Curtil
1463 : // DATE WRITTEN January 2005
1464 : // MODIFIED na
1465 : // RE-ENGINEERED na
1466 :
1467 : // PURPOSE OF THIS FUNCTION:
1468 : // This function creates the time stamp with the current time interval from start and end
1469 : // time values specified in seconds.
1470 : // Inspired by similar function CreateSysTimeIntervalString() in General.cc
1471 :
1472 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1473 0 : std::string TimeStmpS; // Character representation of start of interval
1474 0 : std::string TimeStmpE; // Character representation of end of interval
1475 :
1476 0 : TimeStmpS = CreateTimeString(StartTime);
1477 0 : TimeStmpE = CreateTimeString(EndTime);
1478 :
1479 0 : return TimeStmpS + " - " + TimeStmpE;
1480 : }
1481 :
1482 0 : void ParseTime(Real64 const Time, // Time value in seconds
1483 : int &Hours, // Number of hours
1484 : int &Minutes, // Number of minutes < 60
1485 : Real64 &Seconds // Number of seconds < 60
1486 : )
1487 : {
1488 : // FUNCTION INFORMATION:
1489 : // AUTHOR Dimitri Curtil
1490 : // DATE WRITTEN January 2005
1491 : // MODIFIED na
1492 : // RE-ENGINEERED na
1493 :
1494 : // PURPOSE OF THIS FUNCTION:
1495 : // This subroutine decomposes a time value specified in seconds
1496 : // into a triplet { hours : minutes : seconds } such that
1497 : // - minutes < 60
1498 : // - seconds < 60
1499 :
1500 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1501 0 : int constexpr MinToSec(60);
1502 0 : int const HourToSec(MinToSec * 60);
1503 :
1504 : // Get number of hours
1505 : // This might undershoot the actual number of hours. See DO WHILE loop.
1506 0 : Hours = int(Time) / HourToSec;
1507 :
1508 : // Compute remainder in seconds
1509 0 : Real64 Remainder = (Time - Hours * HourToSec);
1510 :
1511 : // Compute minutes
1512 0 : Minutes = int(Remainder) / MinToSec;
1513 :
1514 : // Compute remainder in seconds
1515 0 : Remainder -= Minutes * MinToSec;
1516 :
1517 : // Compute seconds
1518 0 : Seconds = Remainder;
1519 0 : }
1520 :
1521 12335 : void ScanForReports(EnergyPlusData &state,
1522 : std::string const &reportName,
1523 : bool &DoReport,
1524 : Optional_string_const ReportKey,
1525 : Optional_string Option1,
1526 : Optional_string Option2)
1527 : {
1528 :
1529 : // SUBROUTINE INFORMATION:
1530 : // AUTHOR Linda Lawrie
1531 : // DATE WRITTEN March 2009
1532 : // MODIFIED na
1533 : // RE-ENGINEERED na
1534 :
1535 : // PURPOSE OF THIS SUBROUTINE:
1536 : // This routine scans for the global "reports" settings, such as Variable Dictionary,
1537 : // Surfaces (and options), Constructions, etc.
1538 :
1539 : // METHODOLOGY EMPLOYED:
1540 : // First time routine is called, all the viable combinations/settings for the reports are
1541 : // stored in SAVEd variables. Later callings will retrieve those.
1542 :
1543 : // Using/Aliasing
1544 :
1545 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1546 : int NumReports;
1547 : int RepNum;
1548 : int NumNames;
1549 : int NumNumbers;
1550 : int IOStat;
1551 12335 : auto &DXFOption1 = state.dataGeneral->DXFOption1;
1552 12335 : auto &DXFOption2 = state.dataGeneral->DXFOption2;
1553 12335 : auto &DXFWFOption1 = state.dataGeneral->DXFWFOption1;
1554 12335 : auto &DXFWFOption2 = state.dataGeneral->DXFWFOption2;
1555 12335 : auto &VRMLOption1 = state.dataGeneral->VRMLOption1;
1556 12335 : auto &VRMLOption2 = state.dataGeneral->VRMLOption2;
1557 12335 : auto &ViewRptOption1 = state.dataGeneral->ViewRptOption1;
1558 12335 : auto &LineRptOption1 = state.dataGeneral->LineRptOption1;
1559 12335 : auto &VarDictOption1 = state.dataGeneral->VarDictOption1;
1560 12335 : auto &VarDictOption2 = state.dataGeneral->VarDictOption2;
1561 12335 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
1562 :
1563 12335 : if (state.dataGeneral->GetReportInput) {
1564 :
1565 771 : cCurrentModuleObject = "Output:Surfaces:List";
1566 :
1567 771 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1568 :
1569 : enum
1570 : {
1571 : EMPTY,
1572 : LINES,
1573 : VERTICES,
1574 : DETAILS,
1575 : DETAILSWITHVERTICES,
1576 : COSTINFO,
1577 : VIEWFACTORINFO,
1578 : DECAYCURVESFROMCOMPONENTLOADSSUMMARY
1579 : };
1580 : std::map<std::string, int> localMap = {{"", EMPTY},
1581 : {"LINES", LINES},
1582 : {"VERTICES", VERTICES},
1583 : {"DETAILS", DETAILS},
1584 : {"DETAILED", DETAILS},
1585 : {"DETAIL", DETAILS},
1586 : {"DETAILSWITHVERTICES", DETAILSWITHVERTICES},
1587 : {"DETAILVERTICES", DETAILSWITHVERTICES},
1588 : {"COSTINFO", COSTINFO},
1589 : {"VIEWFACTORINFO", VIEWFACTORINFO},
1590 1542 : {"DECAYCURVESFROMCOMPONENTLOADSSUMMARY", DECAYCURVESFROMCOMPONENTLOADSSUMMARY}};
1591 :
1592 1017 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1593 1722 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1594 : cCurrentModuleObject,
1595 : RepNum,
1596 246 : state.dataIPShortCut->cAlphaArgs,
1597 : NumNames,
1598 246 : state.dataIPShortCut->rNumericArgs,
1599 : NumNumbers,
1600 : IOStat,
1601 246 : state.dataIPShortCut->lNumericFieldBlanks,
1602 246 : state.dataIPShortCut->lAlphaFieldBlanks,
1603 246 : state.dataIPShortCut->cAlphaFieldNames,
1604 246 : state.dataIPShortCut->cNumericFieldNames);
1605 :
1606 : try {
1607 246 : int value = localMap[state.dataIPShortCut->cAlphaArgs(1)];
1608 246 : switch (value) {
1609 50 : case LINES:
1610 50 : state.dataGeneral->LineRpt = true;
1611 50 : LineRptOption1 = state.dataIPShortCut->cAlphaArgs(2);
1612 50 : break;
1613 5 : case VERTICES:
1614 5 : state.dataGeneral->SurfVert = true;
1615 5 : break;
1616 140 : case DETAILS:
1617 140 : state.dataGeneral->SurfDet = true;
1618 140 : break;
1619 31 : case DETAILSWITHVERTICES:
1620 31 : state.dataGeneral->SurfDetWVert = true;
1621 31 : break;
1622 7 : case COSTINFO:
1623 : // Custom case for reporting surface info for cost estimates (for first costs in opitimzing)
1624 7 : state.dataGeneral->CostInfo = true;
1625 7 : break;
1626 8 : case VIEWFACTORINFO: // actual reporting is in HeatBalanceIntRadExchange
1627 8 : state.dataGeneral->ViewFactorInfo = true;
1628 8 : ViewRptOption1 = state.dataIPShortCut->cAlphaArgs(2);
1629 8 : break;
1630 5 : case DECAYCURVESFROMCOMPONENTLOADSSUMMARY: // Should the Radiant to Convective Decay Curves from the
1631 : // load component report appear in the EIO file
1632 5 : state.dataGlobal->ShowDecayCurvesInEIO = true;
1633 5 : break;
1634 0 : default: // including empty
1635 0 : ShowWarningError(state, cCurrentModuleObject + ": No " + state.dataIPShortCut->cAlphaFieldNames(1) + " supplied.");
1636 0 : ShowContinueError(state,
1637 : R"( Legal values are: "Lines", "Vertices", "Details", "DetailsWithVertices", "CostInfo", "ViewFactorIinfo".)");
1638 : }
1639 0 : } catch (int e) {
1640 0 : ShowWarningError(state,
1641 0 : cCurrentModuleObject + ": Invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=\"" +
1642 0 : state.dataIPShortCut->cAlphaArgs(1) + "\" supplied.");
1643 0 : ShowContinueError(state,
1644 : R"( Legal values are: "Lines", "Vertices", "Details", "DetailsWithVertices", "CostInfo", "ViewFactorIinfo".)");
1645 : }
1646 : }
1647 :
1648 771 : cCurrentModuleObject = "Output:Surfaces:Drawing";
1649 :
1650 771 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1651 1299 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1652 3696 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1653 : cCurrentModuleObject,
1654 : RepNum,
1655 528 : state.dataIPShortCut->cAlphaArgs,
1656 : NumNames,
1657 528 : state.dataIPShortCut->rNumericArgs,
1658 : NumNumbers,
1659 : IOStat,
1660 528 : state.dataIPShortCut->lNumericFieldBlanks,
1661 528 : state.dataIPShortCut->lAlphaFieldBlanks,
1662 528 : state.dataIPShortCut->cAlphaFieldNames,
1663 528 : state.dataIPShortCut->cNumericFieldNames);
1664 :
1665 : ReportType checkReportType =
1666 528 : static_cast<ReportType>(getEnumerationValue(ReportTypeNamesUC, UtilityRoutines::MakeUPPERCase(state.dataIPShortCut->cAlphaArgs(1))));
1667 :
1668 528 : switch (checkReportType) {
1669 468 : case ReportType::DXF: {
1670 468 : state.dataGeneral->DXFReport = true;
1671 468 : DXFOption1 = state.dataIPShortCut->cAlphaArgs(2);
1672 468 : DXFOption2 = state.dataIPShortCut->cAlphaArgs(3);
1673 468 : } break;
1674 27 : case ReportType::DXFWireFrame: {
1675 27 : state.dataGeneral->DXFWFReport = true;
1676 27 : DXFWFOption1 = state.dataIPShortCut->cAlphaArgs(2);
1677 27 : DXFWFOption2 = state.dataIPShortCut->cAlphaArgs(3);
1678 27 : } break;
1679 33 : case ReportType::VRML: {
1680 33 : state.dataGeneral->VRMLReport = true;
1681 33 : VRMLOption1 = state.dataIPShortCut->cAlphaArgs(2);
1682 33 : VRMLOption2 = state.dataIPShortCut->cAlphaArgs(3);
1683 33 : } break;
1684 0 : default:
1685 0 : break;
1686 : }
1687 : }
1688 :
1689 771 : RepNum = state.dataInputProcessing->inputProcessor->getNumSectionsFound("Report Variable Dictionary");
1690 771 : if (RepNum > 0) {
1691 0 : state.dataGeneral->VarDict = true;
1692 0 : VarDictOption1 = "REGULAR";
1693 0 : VarDictOption2 = "";
1694 : }
1695 :
1696 771 : cCurrentModuleObject = "Output:VariableDictionary";
1697 :
1698 771 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1699 1537 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1700 5362 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1701 : cCurrentModuleObject,
1702 : RepNum,
1703 766 : state.dataIPShortCut->cAlphaArgs,
1704 : NumNames,
1705 766 : state.dataIPShortCut->rNumericArgs,
1706 : NumNumbers,
1707 : IOStat,
1708 766 : state.dataIPShortCut->lNumericFieldBlanks,
1709 766 : state.dataIPShortCut->lAlphaFieldBlanks,
1710 766 : state.dataIPShortCut->cAlphaFieldNames,
1711 766 : state.dataIPShortCut->cNumericFieldNames);
1712 766 : state.dataGeneral->VarDict = true;
1713 766 : VarDictOption1 = state.dataIPShortCut->cAlphaArgs(1);
1714 766 : VarDictOption2 = state.dataIPShortCut->cAlphaArgs(2);
1715 : }
1716 :
1717 771 : cCurrentModuleObject = "Output:Constructions";
1718 771 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1719 1080 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1720 2163 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1721 : cCurrentModuleObject,
1722 : RepNum,
1723 309 : state.dataIPShortCut->cAlphaArgs,
1724 : NumNames,
1725 309 : state.dataIPShortCut->rNumericArgs,
1726 : NumNumbers,
1727 : IOStat,
1728 309 : state.dataIPShortCut->lNumericFieldBlanks,
1729 309 : state.dataIPShortCut->lAlphaFieldBlanks,
1730 309 : state.dataIPShortCut->cAlphaFieldNames,
1731 309 : state.dataIPShortCut->cNumericFieldNames);
1732 309 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(1), "CONSTRUCTIONS")) {
1733 298 : state.dataGeneral->Constructions = true;
1734 11 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(1), "MATERIALS")) {
1735 11 : state.dataGeneral->Materials = true;
1736 : }
1737 309 : if (NumNames > 1) {
1738 2 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(2), "CONSTRUCTIONS")) {
1739 0 : state.dataGeneral->Constructions = true;
1740 2 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(2), "MATERIALS")) {
1741 2 : state.dataGeneral->Materials = true;
1742 : }
1743 : }
1744 : }
1745 :
1746 771 : cCurrentModuleObject = "Output:EnergyManagementSystem";
1747 771 : NumReports = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1748 810 : for (RepNum = 1; RepNum <= NumReports; ++RepNum) {
1749 273 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1750 : cCurrentModuleObject,
1751 : RepNum,
1752 39 : state.dataIPShortCut->cAlphaArgs,
1753 : NumNames,
1754 39 : state.dataIPShortCut->rNumericArgs,
1755 : NumNumbers,
1756 : IOStat,
1757 39 : state.dataIPShortCut->lNumericFieldBlanks,
1758 39 : state.dataIPShortCut->lAlphaFieldBlanks,
1759 39 : state.dataIPShortCut->cAlphaFieldNames,
1760 39 : state.dataIPShortCut->cNumericFieldNames);
1761 :
1762 39 : state.dataGeneral->EMSoutput = true;
1763 :
1764 : AvailRpt CheckAvailRpt =
1765 39 : static_cast<AvailRpt>(getEnumerationValue(AvailRptNamesUC, UtilityRoutines::MakeUPPERCase(state.dataIPShortCut->cAlphaArgs(1))));
1766 39 : state.dataRuntimeLang->OutputEMSActuatorAvailSmall = (CheckAvailRpt == AvailRpt::NotByUniqueKeyNames);
1767 39 : state.dataRuntimeLang->OutputEMSActuatorAvailFull = (CheckAvailRpt == AvailRpt::Verbose);
1768 :
1769 39 : CheckAvailRpt =
1770 78 : static_cast<AvailRpt>(getEnumerationValue(AvailRptNamesUC, UtilityRoutines::MakeUPPERCase(state.dataIPShortCut->cAlphaArgs(2))));
1771 39 : state.dataRuntimeLang->OutputEMSInternalVarsSmall = (CheckAvailRpt == AvailRpt::NotByUniqueKeyNames);
1772 39 : state.dataRuntimeLang->OutputEMSInternalVarsFull = (CheckAvailRpt == AvailRpt::Verbose);
1773 :
1774 : ERLdebugOutputLevel CheckERLlevel = static_cast<ERLdebugOutputLevel>(
1775 39 : getEnumerationValue(ERLdebugOutputLevelNamesUC, UtilityRoutines::MakeUPPERCase(state.dataIPShortCut->cAlphaArgs(3))));
1776 39 : state.dataRuntimeLang->OutputEMSErrors =
1777 39 : (CheckERLlevel == ERLdebugOutputLevel::ErrorsOnly || CheckERLlevel == ERLdebugOutputLevel::Verbose);
1778 39 : state.dataRuntimeLang->OutputFullEMSTrace = (CheckERLlevel == ERLdebugOutputLevel::Verbose);
1779 : }
1780 :
1781 771 : state.dataGeneral->GetReportInput = false;
1782 : }
1783 :
1784 : // Process the Scan Request
1785 12335 : DoReport = false;
1786 :
1787 : ReportName rptName =
1788 12335 : static_cast<ReportName>(getEnumerationValue(ReportNamesUC, UtilityRoutines::MakeUPPERCase(UtilityRoutines::MakeUPPERCase(reportName))));
1789 12335 : switch (rptName) {
1790 2314 : case ReportName::Constructions: {
1791 2314 : if (present(ReportKey)) {
1792 2314 : if (UtilityRoutines::SameString(ReportKey(), "Constructions")) DoReport = state.dataGeneral->Constructions;
1793 2314 : if (UtilityRoutines::SameString(ReportKey(), "Materials")) DoReport = state.dataGeneral->Materials;
1794 : }
1795 2314 : } break;
1796 1542 : case ReportName::Viewfactorinfo: {
1797 1542 : DoReport = state.dataGeneral->ViewFactorInfo;
1798 1542 : if (present(Option1)) Option1 = ViewRptOption1;
1799 1542 : } break;
1800 769 : case ReportName::Variabledictionary: {
1801 769 : DoReport = state.dataGeneral->VarDict;
1802 769 : if (present(Option1)) Option1 = VarDictOption1;
1803 769 : if (present(Option2)) Option2 = VarDictOption2;
1804 : // CASE ('SCHEDULES')
1805 : // DoReport=SchRpt
1806 : // IF (PRESENT(Option1)) Option1=SchRptOption
1807 769 : } break;
1808 6939 : case ReportName::Surfaces: {
1809 6939 : RptKey rptKey = static_cast<RptKey>(getEnumerationValue(RptKeyNamesUC, UtilityRoutines::MakeUPPERCase(ReportKey())));
1810 6939 : switch (rptKey) { // Autodesk:OPTIONAL ReportKey used without PRESENT check
1811 771 : case RptKey::Costinfo: {
1812 771 : DoReport = state.dataGeneral->CostInfo;
1813 771 : } break;
1814 771 : case RptKey::DXF: {
1815 771 : DoReport = state.dataGeneral->DXFReport;
1816 771 : if (present(Option1)) Option1 = DXFOption1;
1817 771 : if (present(Option2)) Option2 = DXFOption2;
1818 771 : } break;
1819 771 : case RptKey::DXFwireframe: {
1820 771 : DoReport = state.dataGeneral->DXFWFReport;
1821 771 : if (present(Option1)) Option1 = DXFWFOption1;
1822 771 : if (present(Option2)) Option2 = DXFWFOption2;
1823 771 : } break;
1824 771 : case RptKey::VRML: {
1825 771 : DoReport = state.dataGeneral->VRMLReport;
1826 771 : if (present(Option1)) Option1 = VRMLOption1;
1827 771 : if (present(Option2)) Option2 = VRMLOption2;
1828 771 : } break;
1829 771 : case RptKey::Vertices: {
1830 771 : DoReport = state.dataGeneral->SurfVert;
1831 771 : } break;
1832 1542 : case RptKey::Details: {
1833 1542 : DoReport = state.dataGeneral->SurfDet;
1834 1542 : } break;
1835 771 : case RptKey::DetailsWithVertices: {
1836 771 : DoReport = state.dataGeneral->SurfDetWVert;
1837 771 : } break;
1838 771 : case RptKey::Lines: {
1839 771 : DoReport = state.dataGeneral->LineRpt;
1840 771 : if (present(Option1)) Option1 = LineRptOption1;
1841 771 : } break;
1842 0 : default:
1843 0 : break;
1844 : }
1845 6939 : } break;
1846 771 : case ReportName::Energymanagementsystem: {
1847 771 : DoReport = state.dataGeneral->EMSoutput;
1848 771 : } break;
1849 0 : default:
1850 0 : break;
1851 : }
1852 12335 : }
1853 :
1854 49 : void CheckCreatedZoneItemName(EnergyPlusData &state,
1855 : std::string_view const calledFrom, // routine called from
1856 : std::string const &CurrentObject, // object being parsed
1857 : std::string const &ZoneName, // Zone Name associated
1858 : std::string::size_type const MaxZoneNameLength, // maximum length of zonelist zone names
1859 : std::string const &ItemName, // Item name (People, Lights, etc object)
1860 : Array1_string const &ItemNames, // Item Names to check for duplication
1861 : int const NumItems, // Number of items in ItemNames array
1862 : std::string &ResultName, // Resultant name
1863 : bool &errFlag // Error flag set to true if error found here.
1864 : )
1865 : {
1866 :
1867 : // SUBROUTINE INFORMATION:
1868 : // AUTHOR Linda Lawrie
1869 : // DATE WRITTEN December 2012
1870 : // MODIFIED na
1871 : // RE-ENGINEERED na
1872 :
1873 : // PURPOSE OF THIS SUBROUTINE:
1874 : // This routine checks "global" objects (that is, ones with ZoneList used in the name
1875 : // specification) along with a specific name for the current object for length and duplication
1876 : // with previous objects of that class.
1877 :
1878 49 : errFlag = false;
1879 49 : std::string::size_type const ItemNameLength = len(ItemName);
1880 49 : std::string::size_type const ItemLength = len(ZoneName) + ItemNameLength;
1881 49 : ResultName = ZoneName + ' ' + ItemName;
1882 49 : bool TooLong = false;
1883 49 : if (ItemLength > DataGlobalConstants::MaxNameLength) {
1884 0 : ShowWarningError(state, fmt::format("{}{} Combination of ZoneList and Object Name generate a name too long.", calledFrom, CurrentObject));
1885 0 : ShowContinueError(state, "Object Name=\"" + ItemName + "\".");
1886 0 : ShowContinueError(state, "ZoneList/Zone Name=\"" + ZoneName + "\".");
1887 0 : ShowContinueError(
1888 : state,
1889 0 : format("Item length=[{}] > Maximum Length=[{}]. You may need to shorten the names.", ItemLength, DataGlobalConstants::MaxNameLength));
1890 0 : ShowContinueError(state,
1891 0 : format("Shortening the Object Name by [{}] characters will assure uniqueness for this ZoneList.",
1892 0 : MaxZoneNameLength + 1 + ItemNameLength - DataGlobalConstants::MaxNameLength));
1893 0 : ShowContinueError(state, "name that will be used (may be needed in reporting)=\"" + ResultName + "\".");
1894 0 : TooLong = true;
1895 : }
1896 :
1897 49 : int FoundItem = UtilityRoutines::FindItemInList(ResultName, ItemNames, NumItems);
1898 :
1899 49 : if (FoundItem != 0) {
1900 0 : ShowSevereError(state, fmt::format("{}{}=\"{}\", Duplicate Generated name encountered.", calledFrom, CurrentObject, ItemName));
1901 0 : ShowContinueError(state, format("name=\"{}\" has already been generated or entered as {} item=[{}].", ResultName, CurrentObject, FoundItem));
1902 0 : if (TooLong) ShowContinueError(state, "Duplicate name likely caused by the previous \"too long\" warning.");
1903 0 : ResultName = "xxxxxxx";
1904 0 : errFlag = true;
1905 : }
1906 49 : }
1907 :
1908 : // This is from OpenStudio
1909 0 : std::vector<std::string> splitString(const std::string &string, char delimiter)
1910 : {
1911 0 : std::vector<std::string> results;
1912 0 : if (!string.empty()) { // Only do work if there is work to do
1913 0 : std::stringstream stream(string);
1914 0 : std::string substring;
1915 0 : while (std::getline(stream, substring, delimiter)) { // Loop and fill the results vector
1916 0 : results.push_back(substring);
1917 : }
1918 0 : if (*(string.end() - 1) == ',') { // Add an empty string if the last char is the delimiter
1919 0 : results.emplace_back();
1920 : }
1921 : }
1922 0 : return results;
1923 : }
1924 :
1925 0 : bool isReportPeriodBeginning(EnergyPlusData &state, const int periodIdx)
1926 : {
1927 : int currentDate;
1928 0 : int reportStartDate = state.dataWeatherManager->ReportPeriodInput(periodIdx).startJulianDate;
1929 0 : int reportStartHour = state.dataWeatherManager->ReportPeriodInput(periodIdx).startHour;
1930 0 : if (state.dataWeatherManager->ReportPeriodInput(periodIdx).startYear > 0) {
1931 0 : currentDate = WeatherManager::computeJulianDate(state.dataEnvrn->Year, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
1932 : } else {
1933 0 : currentDate = WeatherManager::computeJulianDate(0, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
1934 : }
1935 0 : return (currentDate == reportStartDate && state.dataGlobal->HourOfDay == reportStartHour);
1936 : }
1937 :
1938 5376 : void findReportPeriodIdx(EnergyPlusData &state,
1939 : const Array1D<WeatherManager::ReportPeriodData> &ReportPeriodInputData,
1940 : const int nReportPeriods,
1941 : Array1D_bool &inReportPeriodFlags)
1942 : {
1943 : // return an array of flags, indicating whether the current time is in reporting period i
1944 : int currentDate;
1945 12288 : for (int i = 1; i <= nReportPeriods; i++) {
1946 6912 : int reportStartDate = ReportPeriodInputData(i).startJulianDate;
1947 6912 : int reportStartHour = ReportPeriodInputData(i).startHour;
1948 6912 : int reportEndDate = ReportPeriodInputData(i).endJulianDate;
1949 6912 : int reportEndHour = ReportPeriodInputData(i).endHour;
1950 6912 : if (ReportPeriodInputData(i).startYear > 0) {
1951 0 : currentDate = WeatherManager::computeJulianDate(state.dataEnvrn->Year, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
1952 : } else {
1953 6912 : currentDate = WeatherManager::computeJulianDate(0, state.dataEnvrn->Month, state.dataEnvrn->DayOfMonth);
1954 : }
1955 6912 : if (General::BetweenDateHoursLeftInclusive(
1956 6912 : currentDate, state.dataGlobal->HourOfDay, reportStartDate, reportStartHour, reportEndDate, reportEndHour)) {
1957 0 : inReportPeriodFlags(i) = true;
1958 : }
1959 : }
1960 5376 : }
1961 :
1962 2313 : } // namespace EnergyPlus::General
|