Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : #include "AirflowNetwork/Elements.hpp"
49 : #include "AirflowNetwork/Properties.hpp"
50 : #include "AirflowNetwork/Solver.hpp"
51 :
52 : #include "../../Data/EnergyPlusData.hh"
53 : #include "../../DataAirLoop.hh"
54 : #include "../../DataEnvironment.hh"
55 : #include "../../DataHVACGlobals.hh"
56 : #include "../../DataLoopNode.hh"
57 : #include "../../DataSurfaces.hh"
58 :
59 : namespace EnergyPlus {
60 :
61 : namespace AirflowNetwork {
62 :
63 : // MODULE INFORMATION:
64 : // AUTHOR Lixing Gu, Don Shirey, and Muthusamy V. Swami
65 : // DATE WRITTEN Aug. 2003
66 : // MODIFIED na
67 : // RE-ENGINEERED na
68 :
69 : // PURPOSE OF THIS MODULE:
70 : // This module should contain the information that is needed to simulate
71 : // performance of air distribution system, including pressure, temperature
72 : // and moisture levels at each node, and airflow and sensible and latent energy losses
73 : // at each element
74 :
75 490145 : static Real64 square(Real64 x)
76 : {
77 490145 : return x * x;
78 : }
79 :
80 1799403 : int Duct::calculate([[maybe_unused]] EnergyPlusData &state,
81 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
82 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
83 : [[maybe_unused]] int const i, // Linkage number
84 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
85 : [[maybe_unused]] const Real64 control, // Element control signal
86 : const AirState &propN, // Node 1 properties
87 : const AirState &propM, // Node 2 properties
88 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
89 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
90 : )
91 : {
92 :
93 : // SUBROUTINE INFORMATION:
94 : // AUTHOR George Walton
95 : // DATE WRITTEN Extracted from AIRNET
96 : // MODIFIED Lixing Gu, 2/1/04
97 : // Revised the subroutine to meet E+ needs
98 : // MODIFIED Lixing Gu, 6/8/05
99 : // RE-ENGINEERED na
100 :
101 : // PURPOSE OF THIS SUBROUTINE:
102 : // This subroutine solves airflow for a duct/pipe component using Colebrook equation for the
103 : // turbulent friction factor
104 :
105 : // SUBROUTINE PARAMETER DEFINITIONS:
106 1799403 : Real64 constexpr C(0.868589);
107 1799403 : Real64 constexpr EPS(0.001);
108 :
109 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
110 : Real64 A0;
111 : Real64 A1;
112 : Real64 A2;
113 : Real64 B;
114 : Real64 D;
115 : Real64 S2;
116 : Real64 CDM;
117 : Real64 FL; // friction factor for laminar flow.
118 : Real64 FT; // friction factor for turbulent flow.
119 : Real64 FTT;
120 : Real64 RE; // Reynolds number.
121 : Real64 ed;
122 : Real64 ld;
123 : Real64 g;
124 : Real64 AA1;
125 :
126 : // Formats
127 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
128 :
129 : // CompNum = state.afn->AirflowNetworkCompData(j).TypeNum;
130 1799403 : ed = roughness / hydraulicDiameter;
131 1799403 : ld = L / hydraulicDiameter;
132 1799403 : g = 1.14 - 0.868589 * std::log(ed);
133 1799403 : AA1 = g;
134 :
135 1799403 : if (LFLAG) {
136 : // Initialization by linear relation.
137 0 : if (PDROP >= 0.0) {
138 0 : DF[0] = (2.0 * propN.density * A * hydraulicDiameter) / (propN.viscosity * InitLamCoef * ld);
139 : } else {
140 0 : DF[0] = (2.0 * propM.density * A * hydraulicDiameter) / (propM.viscosity * InitLamCoef * ld);
141 : }
142 0 : F[0] = -DF[0] * PDROP;
143 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwi:" << i << InitLamCoef << F[0] << DF[0];
144 : } else {
145 : // Standard calculation.
146 1799403 : if (PDROP >= 0.0) {
147 : // Flow in positive direction.
148 : // Laminar flow coefficient !=0
149 1702618 : if (LamFriCoef >= 0.001) {
150 939704 : A2 = LamFriCoef / (2.0 * propN.density * A * A);
151 939704 : A1 = (propN.viscosity * LamDynCoef * ld) / (2.0 * propN.density * A * hydraulicDiameter);
152 939704 : A0 = -PDROP;
153 939704 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
154 939704 : FL = (CDM - A1) / (2.0 * A2);
155 939704 : CDM = 1.0 / CDM;
156 : } else {
157 762914 : CDM = (2.0 * propN.density * A * hydraulicDiameter) / (propN.viscosity * LamDynCoef * ld);
158 762914 : FL = CDM * PDROP;
159 : }
160 1702618 : RE = FL * hydraulicDiameter / (propN.viscosity * A);
161 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwl:" << i << PDROP << FL << CDM << RE;
162 : // Turbulent flow; test when Re>10.
163 1702618 : if (RE >= 10.0) {
164 1689985 : S2 = std::sqrt(2.0 * propN.density * PDROP) * A;
165 1689985 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
166 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << S2 << FTT << g;
167 : while (true) {
168 3788372 : FT = FTT;
169 3788372 : B = (9.3 * propN.viscosity * A) / (FT * roughness);
170 3788372 : D = 1.0 + g * B;
171 3788372 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
172 3788372 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
173 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << B << FTT << g;
174 3788372 : if (std::abs(FTT - FT) / FTT < EPS) break;
175 : }
176 1689985 : FT = FTT;
177 : } else {
178 12633 : FT = FL;
179 : }
180 : } else {
181 : // Flow in negative direction.
182 : // Laminar flow coefficient !=0
183 96785 : if (LamFriCoef >= 0.001) {
184 43450 : A2 = LamFriCoef / (2.0 * propM.density * A * A);
185 43450 : A1 = (propM.viscosity * LamDynCoef * ld) / (2.0 * propM.density * A * hydraulicDiameter);
186 43450 : A0 = PDROP;
187 43450 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
188 43450 : FL = -(CDM - A1) / (2.0 * A2);
189 43450 : CDM = 1.0 / CDM;
190 : } else {
191 53335 : CDM = (2.0 * propM.density * A * hydraulicDiameter) / (propM.viscosity * LamDynCoef * ld);
192 53335 : FL = CDM * PDROP;
193 : }
194 96785 : RE = -FL * hydraulicDiameter / (propM.viscosity * A);
195 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwl:" << i << PDROP << FL << CDM << RE;
196 : // Turbulent flow; test when Re>10.
197 96785 : if (RE >= 10.0) {
198 91387 : S2 = std::sqrt(-2.0 * propM.density * PDROP) * A;
199 91387 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
200 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << S2 << FTT << g;
201 : while (true) {
202 319448 : FT = FTT;
203 319448 : B = (9.3 * propM.viscosity * A) / (FT * roughness);
204 319448 : D = 1.0 + g * B;
205 319448 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
206 319448 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
207 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << B << FTT << g;
208 319448 : if (std::abs(FTT - FT) / FTT < EPS) break;
209 : }
210 91387 : FT = -FTT;
211 : } else {
212 5398 : FT = FL;
213 : }
214 : }
215 : // Select laminar or turbulent flow.
216 1799403 : if (std::abs(FL) <= std::abs(FT)) {
217 64777 : F[0] = FL;
218 64777 : DF[0] = CDM;
219 : } else {
220 1734626 : F[0] = FT;
221 1734626 : DF[0] = 0.5 * FT / PDROP;
222 : }
223 : }
224 1799403 : return 1;
225 : }
226 :
227 0 : int Duct::calculate([[maybe_unused]] EnergyPlusData &state,
228 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
229 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
230 : [[maybe_unused]] const Real64 control, // Element control signal
231 : const AirState &propN, // Node 1 properties
232 : const AirState &propM, // Node 2 properties
233 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
234 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
235 : )
236 : {
237 :
238 : // SUBROUTINE INFORMATION:
239 : // AUTHOR George Walton
240 : // DATE WRITTEN Extracted from AIRNET
241 : // MODIFIED Lixing Gu, 2/1/04
242 : // Revised the subroutine to meet E+ needs
243 : // MODIFIED Lixing Gu, 6/8/05
244 : // RE-ENGINEERED na
245 :
246 : // PURPOSE OF THIS SUBROUTINE:
247 : // This subroutine solves airflow for a duct/pipe component using Colebrook equation for the
248 : // turbulent friction factor
249 :
250 : // SUBROUTINE PARAMETER DEFINITIONS:
251 0 : Real64 constexpr C(0.868589);
252 0 : Real64 constexpr EPS(0.001);
253 :
254 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
255 : Real64 A0;
256 : Real64 A1;
257 : Real64 A2;
258 : Real64 B;
259 : Real64 D;
260 : Real64 S2;
261 : Real64 CDM;
262 : Real64 FL; // friction factor for laminar flow.
263 : Real64 FT; // friction factor for turbulent flow.
264 : Real64 FTT;
265 : Real64 RE; // Reynolds number.
266 : Real64 ed;
267 : Real64 ld;
268 : Real64 g;
269 : Real64 AA1;
270 :
271 : // Formats
272 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
273 :
274 : // CompNum = state.afn->AirflowNetworkCompData(j).TypeNum;
275 0 : ed = roughness / hydraulicDiameter;
276 0 : ld = L / hydraulicDiameter;
277 0 : g = 1.14 - 0.868589 * std::log(ed);
278 0 : AA1 = g;
279 :
280 : // Standard calculation.
281 0 : if (PDROP >= 0.0) {
282 : // Flow in positive direction.
283 : // Laminar flow coefficient !=0
284 0 : if (LamFriCoef >= 0.001) {
285 0 : A2 = LamFriCoef / (2.0 * propN.density * A * A);
286 0 : A1 = (propN.viscosity * LamDynCoef * ld) / (2.0 * propN.density * A * hydraulicDiameter);
287 0 : A0 = -PDROP;
288 0 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
289 0 : FL = (CDM - A1) / (2.0 * A2);
290 0 : CDM = 1.0 / CDM;
291 : } else {
292 0 : CDM = (2.0 * propN.density * A * hydraulicDiameter) / (propN.viscosity * LamDynCoef * ld);
293 0 : FL = CDM * PDROP;
294 : }
295 0 : RE = FL * hydraulicDiameter / (propN.viscosity * A);
296 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwl:" << i << PDROP << FL << CDM << RE;
297 : // Turbulent flow; test when Re>10.
298 0 : if (RE >= 10.0) {
299 0 : S2 = std::sqrt(2.0 * propN.density * PDROP) * A;
300 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
301 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << S2 << FTT << g;
302 : while (true) {
303 0 : FT = FTT;
304 0 : B = (9.3 * propN.viscosity * A) / (FT * roughness);
305 0 : D = 1.0 + g * B;
306 0 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
307 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
308 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << B << FTT << g;
309 0 : if (std::abs(FTT - FT) / FTT < EPS) break;
310 : }
311 0 : FT = FTT;
312 : } else {
313 0 : FT = FL;
314 : }
315 : } else {
316 : // Flow in negative direction.
317 : // Laminar flow coefficient !=0
318 0 : if (LamFriCoef >= 0.001) {
319 0 : A2 = LamFriCoef / (2.0 * propM.density * A * A);
320 0 : A1 = (propM.viscosity * LamDynCoef * ld) / (2.0 * propM.density * A * hydraulicDiameter);
321 0 : A0 = PDROP;
322 0 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
323 0 : FL = -(CDM - A1) / (2.0 * A2);
324 0 : CDM = 1.0 / CDM;
325 : } else {
326 0 : CDM = (2.0 * propM.density * A * hydraulicDiameter) / (propM.viscosity * LamDynCoef * ld);
327 0 : FL = CDM * PDROP;
328 : }
329 0 : RE = -FL * hydraulicDiameter / (propM.viscosity * A);
330 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwl:" << i << PDROP << FL << CDM << RE;
331 : // Turbulent flow; test when Re>10.
332 0 : if (RE >= 10.0) {
333 0 : S2 = std::sqrt(-2.0 * propM.density * PDROP) * A;
334 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
335 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << S2 << FTT << g;
336 : while (true) {
337 0 : FT = FTT;
338 0 : B = (9.3 * propM.viscosity * A) / (FT * roughness);
339 0 : D = 1.0 + g * B;
340 0 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
341 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
342 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << B << FTT << g;
343 0 : if (std::abs(FTT - FT) / FTT < EPS) break;
344 : }
345 0 : FT = -FTT;
346 : } else {
347 0 : FT = FL;
348 : }
349 : }
350 : // Select laminar or turbulent flow.
351 0 : if (std::abs(FL) <= std::abs(FT)) {
352 0 : F[0] = FL;
353 0 : DF[0] = CDM;
354 : } else {
355 0 : F[0] = FT;
356 0 : DF[0] = 0.5 * FT / PDROP;
357 : }
358 0 : return 1;
359 : }
360 :
361 2583 : int SurfaceCrack::calculate([[maybe_unused]] EnergyPlusData &state,
362 : bool const linear, // Initialization flag. If true, use linear relationship
363 : Real64 const pdrop, // Total pressure drop across a component (P1 - P2) [Pa]
364 : [[maybe_unused]] int const i, // Linkage number
365 : const Real64 multiplier, // Element multiplier
366 : const Real64 control, // Element control signal
367 : const AirState &propN, // Node 1 properties
368 : const AirState &propM, // Node 2 properties
369 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
370 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
371 : )
372 : {
373 : // SUBROUTINE INFORMATION:
374 : // AUTHOR George Walton
375 : // DATE WRITTEN Extracted from AIRNET
376 : // MODIFIED Lixing Gu, 2/1/04
377 : // Revised the subroutine to meet E+ needs
378 : // MODIFIED Lixing Gu, 6/8/05
379 : // RE-ENGINEERED Jason DeGraw
380 :
381 : // PURPOSE OF THIS SUBROUTINE:
382 : // This subroutine solves airflow for a surface crack component
383 :
384 : // Real64 rhoz_norm = AIRDENSITY(StandardP, StandardT, StandardW);
385 : // Real64 viscz_norm = 1.71432e-5 + 4.828e-8 * StandardT;
386 :
387 2583 : Real64 VisAve{0.5 * (propN.viscosity + propM.viscosity)};
388 2583 : Real64 Tave{0.5 * (propN.temperature + propM.temperature)};
389 :
390 2583 : Real64 sign{1.0};
391 2583 : Real64 upwind_temperature{propN.temperature};
392 2583 : Real64 upwind_density{propN.density};
393 2583 : Real64 upwind_viscosity{propN.viscosity};
394 2583 : Real64 upwind_sqrt_density{propN.sqrt_density};
395 2583 : Real64 abs_pdrop = pdrop;
396 :
397 2583 : if (pdrop < 0.0) {
398 614 : sign = -1.0;
399 614 : upwind_temperature = propM.temperature;
400 614 : upwind_density = propM.density;
401 614 : upwind_viscosity = propM.viscosity;
402 614 : upwind_sqrt_density = propM.sqrt_density;
403 614 : abs_pdrop = -pdrop;
404 : }
405 :
406 2583 : Real64 coef = coefficient * control * multiplier / upwind_sqrt_density;
407 :
408 : // Laminar calculation
409 2583 : Real64 RhoCor{TOKELVIN(upwind_temperature) / TOKELVIN(Tave)};
410 2583 : Real64 Ctl{std::pow(reference_density / upwind_density / RhoCor, exponent - 1.0) *
411 2583 : std::pow(reference_viscosity / VisAve, 2.0 * exponent - 1.0)};
412 2583 : Real64 CDM{coef * upwind_density / upwind_viscosity * Ctl};
413 2583 : Real64 FL{CDM * pdrop};
414 : Real64 abs_FT;
415 :
416 2583 : if (linear) {
417 2 : DF[0] = CDM;
418 2 : F[0] = FL;
419 : } else {
420 : // Turbulent flow.
421 2581 : if (exponent == 0.5) {
422 0 : abs_FT = coef * upwind_sqrt_density * std::sqrt(abs_pdrop) * Ctl;
423 : } else {
424 2581 : abs_FT = coef * upwind_sqrt_density * std::pow(abs_pdrop, exponent) * Ctl;
425 : }
426 : // Select linear or turbulent flow.
427 2581 : if (std::abs(FL) <= abs_FT) {
428 102 : F[0] = FL;
429 102 : DF[0] = CDM;
430 : } else {
431 2479 : F[0] = sign * abs_FT;
432 2479 : DF[0] = F[0] * exponent / pdrop;
433 : }
434 : }
435 2583 : return 1;
436 : }
437 :
438 0 : int SurfaceCrack::calculate(EnergyPlusData &state,
439 : Real64 const pdrop, // Total pressure drop across a component (P1 - P2) [Pa]
440 : const Real64 multiplier, // Element multiplier
441 : const Real64 control, // Element control signal
442 : const AirState &propN, // Node 1 properties
443 : const AirState &propM, // Node 2 properties
444 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
445 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
446 : )
447 : {
448 : // SUBROUTINE INFORMATION:
449 : // AUTHOR George Walton
450 : // DATE WRITTEN Extracted from AIRNET
451 : // MODIFIED Lixing Gu, 2/1/04
452 : // Revised the subroutine to meet E+ needs
453 : // MODIFIED Lixing Gu, 6/8/05
454 : // RE-ENGINEERED Jason DeGraw
455 :
456 : // PURPOSE OF THIS SUBROUTINE:
457 : // This subroutine solves airflow for a surface crack component
458 :
459 : // Real64 rhoz_norm = AIRDENSITY(StandardP, StandardT, StandardW);
460 : // Real64 viscz_norm = 1.71432e-5 + 4.828e-8 * StandardT;
461 :
462 0 : Real64 VisAve{0.5 * (propN.viscosity + propM.viscosity)};
463 0 : Real64 Tave{0.5 * (propN.temperature + propM.temperature)};
464 :
465 0 : Real64 sign{1.0};
466 0 : Real64 upwind_temperature{propN.temperature};
467 0 : Real64 upwind_density{propN.density};
468 0 : Real64 upwind_viscosity{propN.viscosity};
469 0 : Real64 upwind_sqrt_density{propN.sqrt_density};
470 0 : Real64 abs_pdrop = pdrop;
471 :
472 0 : if (pdrop < 0.0) {
473 0 : sign = -1.0;
474 0 : upwind_temperature = propM.temperature;
475 0 : upwind_density = propM.density;
476 0 : upwind_viscosity = propM.viscosity;
477 0 : upwind_sqrt_density = propM.sqrt_density;
478 0 : abs_pdrop = -pdrop;
479 : }
480 :
481 0 : Real64 coef = coefficient * control * multiplier / upwind_sqrt_density;
482 :
483 : // Laminar calculation
484 0 : Real64 RhoCor{TOKELVIN(upwind_temperature) / TOKELVIN(Tave)};
485 0 : Real64 Ctl{std::pow(reference_density / upwind_density / RhoCor, exponent - 1.0) *
486 0 : std::pow(reference_viscosity / VisAve, 2.0 * exponent - 1.0)};
487 0 : Real64 CDM{coef * upwind_density / upwind_viscosity * Ctl};
488 0 : Real64 FL{CDM * pdrop};
489 : Real64 abs_FT;
490 :
491 : // Turbulent flow.
492 0 : if (exponent == 0.5) {
493 0 : abs_FT = coef * upwind_sqrt_density * std::sqrt(abs_pdrop) * Ctl;
494 : } else {
495 0 : abs_FT = coef * upwind_sqrt_density * std::pow(abs_pdrop, exponent) * Ctl;
496 : }
497 : // Select linear or turbulent flow.
498 0 : if (std::abs(FL) <= abs_FT) {
499 0 : F[0] = FL;
500 0 : DF[0] = CDM;
501 : } else {
502 0 : F[0] = sign * abs_FT;
503 0 : DF[0] = F[0] * exponent / pdrop;
504 : }
505 :
506 0 : return 1;
507 : }
508 :
509 172 : int DuctLeak::calculate(EnergyPlusData &state,
510 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
511 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
512 : [[maybe_unused]] int const i, // Linkage number
513 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
514 : [[maybe_unused]] const Real64 control, // Element control signal
515 : const AirState &propN, // Node 1 properties
516 : const AirState &propM, // Node 2 properties
517 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
518 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
519 : )
520 : {
521 : // SUBROUTINE INFORMATION:
522 : // AUTHOR George Walton
523 : // DATE WRITTEN Extracted from AIRNET
524 : // MODIFIED Lixing Gu, 2/1/04
525 : // Revised the subroutine to meet E+ needs
526 : // MODIFIED Lixing Gu, 6/8/05
527 : // RE-ENGINEERED na
528 :
529 : // PURPOSE OF THIS SUBROUTINE:
530 : // This subroutine solves airflow for a power law resistance airflow component
531 :
532 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
533 : Real64 CDM;
534 : Real64 FL;
535 : Real64 FT;
536 : Real64 Ctl;
537 :
538 : // Formats
539 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
540 :
541 : // Crack standard condition: T=20C, p=101325 Pa and 0 g/kg
542 172 : Real64 RhozNorm = state.afn->properties.density(101325.0, 20.0, 0.0);
543 172 : Real64 VisczNorm = 1.71432e-5 + 4.828e-8 * 20.0;
544 172 : Real64 coef = FlowCoef;
545 :
546 172 : if (PDROP >= 0.0) {
547 158 : coef /= propN.sqrt_density;
548 : } else {
549 14 : coef /= propM.sqrt_density;
550 : }
551 :
552 172 : if (LFLAG) {
553 : // Initialization by linear relation.
554 0 : if (PDROP >= 0.0) {
555 0 : Ctl = std::pow(RhozNorm / propN.density, FlowExpo - 1.0) * std::pow(VisczNorm / propN.viscosity, 2.0 * FlowExpo - 1.0);
556 0 : DF[0] = coef * propN.density / propN.viscosity * Ctl;
557 : } else {
558 0 : Ctl = std::pow(RhozNorm / propM.density, FlowExpo - 1.0) * std::pow(VisczNorm / propM.viscosity, 2.0 * FlowExpo - 1.0);
559 0 : DF[0] = coef * propM.density / propM.viscosity * Ctl;
560 : }
561 0 : F[0] = -DF[0] * PDROP;
562 : } else {
563 : // Standard calculation.
564 172 : if (PDROP >= 0.0) {
565 : // Flow in positive direction for laminar flow.
566 158 : Ctl = std::pow(RhozNorm / propN.density, FlowExpo - 1.0) * std::pow(VisczNorm / propN.viscosity, 2.0 * FlowExpo - 1.0);
567 158 : CDM = coef * propN.density / propN.viscosity * Ctl;
568 158 : FL = CDM * PDROP;
569 : // Flow in positive direction for turbulent flow.
570 158 : if (FlowExpo == 0.5) {
571 0 : FT = coef * propN.sqrt_density * std::sqrt(PDROP);
572 : } else {
573 158 : FT = coef * propN.sqrt_density * std::pow(PDROP, FlowExpo);
574 : }
575 : } else {
576 : // Flow in negative direction for laminar flow
577 14 : CDM = coef * propM.density / propM.viscosity;
578 14 : FL = CDM * PDROP;
579 : // Flow in negative direction for turbulent flow
580 14 : if (FlowExpo == 0.5) {
581 0 : FT = -coef * propM.sqrt_density * std::sqrt(-PDROP);
582 : } else {
583 14 : FT = -coef * propM.sqrt_density * std::pow(-PDROP, FlowExpo);
584 : }
585 : }
586 : // Select laminar or turbulent flow.
587 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " plr: " << i << PDROP << FL << FT;
588 172 : if (std::abs(FL) <= std::abs(FT)) {
589 12 : F[0] = FL;
590 12 : DF[0] = CDM;
591 : } else {
592 160 : F[0] = FT;
593 160 : DF[0] = FT * FlowExpo / PDROP;
594 : }
595 : }
596 172 : return 1;
597 : }
598 :
599 0 : int DuctLeak::calculate(EnergyPlusData &state,
600 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
601 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
602 : [[maybe_unused]] const Real64 control, // Element control signal
603 : const AirState &propN, // Node 1 properties
604 : const AirState &propM, // Node 2 properties
605 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
606 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
607 : )
608 : {
609 : // SUBROUTINE INFORMATION:
610 : // AUTHOR George Walton
611 : // DATE WRITTEN Extracted from AIRNET
612 : // MODIFIED Lixing Gu, 2/1/04
613 : // Revised the subroutine to meet E+ needs
614 : // MODIFIED Lixing Gu, 6/8/05
615 : // RE-ENGINEERED na
616 :
617 : // PURPOSE OF THIS SUBROUTINE:
618 : // This subroutine solves airflow for a power law resistance airflow component
619 :
620 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
621 : Real64 CDM;
622 : Real64 FL;
623 : Real64 FT;
624 : Real64 Ctl;
625 :
626 : // Formats
627 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
628 :
629 : // Crack standard condition: T=20C, p=101325 Pa and 0 g/kg
630 0 : Real64 RhozNorm = state.afn->properties.density(101325.0, 20.0, 0.0);
631 0 : Real64 VisczNorm = 1.71432e-5 + 4.828e-8 * 20.0;
632 0 : Real64 coef = FlowCoef;
633 :
634 0 : if (PDROP >= 0.0) {
635 0 : coef /= propN.sqrt_density;
636 : } else {
637 0 : coef /= propM.sqrt_density;
638 : }
639 :
640 : // Standard calculation.
641 0 : if (PDROP >= 0.0) {
642 : // Flow in positive direction for laminar flow.
643 0 : Ctl = std::pow(RhozNorm / propN.density, FlowExpo - 1.0) * std::pow(VisczNorm / propN.viscosity, 2.0 * FlowExpo - 1.0);
644 0 : CDM = coef * propN.density / propN.viscosity * Ctl;
645 0 : FL = CDM * PDROP;
646 : // Flow in positive direction for turbulent flow.
647 0 : if (FlowExpo == 0.5) {
648 0 : FT = coef * propN.sqrt_density * std::sqrt(PDROP);
649 : } else {
650 0 : FT = coef * propN.sqrt_density * std::pow(PDROP, FlowExpo);
651 : }
652 : } else {
653 : // Flow in negative direction for laminar flow
654 0 : CDM = coef * propM.density / propM.viscosity;
655 0 : FL = CDM * PDROP;
656 : // Flow in negative direction for turbulent flow
657 0 : if (FlowExpo == 0.5) {
658 0 : FT = -coef * propM.sqrt_density * std::sqrt(-PDROP);
659 : } else {
660 0 : FT = -coef * propM.sqrt_density * std::pow(-PDROP, FlowExpo);
661 : }
662 : }
663 : // Select laminar or turbulent flow.
664 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " plr: " << i << PDROP << FL << FT;
665 0 : if (std::abs(FL) <= std::abs(FT)) {
666 0 : F[0] = FL;
667 0 : DF[0] = CDM;
668 : } else {
669 0 : F[0] = FT;
670 0 : DF[0] = FT * FlowExpo / PDROP;
671 : }
672 0 : return 1;
673 : }
674 :
675 163425 : int ConstantVolumeFan::calculate(EnergyPlusData &state,
676 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
677 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
678 : int const i, // Linkage number
679 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
680 : [[maybe_unused]] const Real64 control, // Element control signal
681 : const AirState &propN, // Node 1 properties
682 : const AirState &propM, // Node 2 properties
683 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
684 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
685 : )
686 : {
687 :
688 : // SUBROUTINE INFORMATION:
689 : // AUTHOR George Walton
690 : // DATE WRITTEN Extracted from AIRNET
691 : // MODIFIED Lixing Gu, 2/1/04
692 : // Revised the subroutine to meet E+ needs
693 : // MODIFIED Lixing Gu, 6/8/05
694 : // RE-ENGINEERED na
695 :
696 : // PURPOSE OF THIS SUBROUTINE:
697 : // This subroutine solves airflow for a constant flow rate airflow component -- using standard interface.
698 :
699 : // Using/Aliasing
700 163425 : auto &NumPrimaryAirSys = state.dataHVACGlobal->NumPrimaryAirSys;
701 :
702 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
703 : int k;
704 : int k1;
705 : Real64 SumTermFlow; // Sum of all Terminal flows [kg/s]
706 : Real64 SumFracSuppLeak; // Sum of all supply leaks as a fraction of supply fan flow rate
707 : int Node1;
708 : int Node2;
709 :
710 163425 : int NF(1);
711 :
712 163425 : int AirLoopNum = state.afn->AirflowNetworkLinkageData(i).AirLoopNum;
713 :
714 163425 : if (fanType == HVAC::FanType::OnOff) {
715 326586 : if (state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopFanOperationMode == HVAC::FanOp::Cycling &&
716 163293 : state.dataLoopNodes->Node(InletNode).MassFlowRate == 0.0) {
717 0 : NF = GenericDuct(0.1, 0.001, LFLAG, PDROP, propN, propM, F, DF);
718 326586 : } else if (state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopFanOperationMode == HVAC::FanOp::Cycling &&
719 163293 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOnMassFlowrate > 0.0) {
720 163293 : F[0] = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOnMassFlowrate;
721 : } else {
722 0 : F[0] = state.dataLoopNodes->Node(InletNode).MassFlowRate * Ctrl;
723 0 : if (state.afn->MultiSpeedHPIndicator == 2) {
724 0 : F[0] = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOnMassFlowrate *
725 0 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopCompCycRatio +
726 0 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOffMassFlowrate *
727 0 : (1.0 - state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopCompCycRatio);
728 : }
729 : }
730 132 : } else if (fanType == HVAC::FanType::Constant) {
731 132 : if (state.dataLoopNodes->Node(InletNode).MassFlowRate > 0.0) {
732 132 : F[0] = FlowRate * Ctrl;
733 0 : } else if (NumPrimaryAirSys > 1 && state.dataLoopNodes->Node(InletNode).MassFlowRate <= 0.0) {
734 0 : NF = GenericDuct(0.1, 0.001, LFLAG, PDROP, propN, propM, F, DF);
735 : }
736 :
737 132 : if (state.afn->MultiSpeedHPIndicator == 2) {
738 0 : F[0] = state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopSystemOnMassFlowrate;
739 : }
740 0 : } else if (fanType == HVAC::FanType::VAV) {
741 : // Check VAV termals with a damper
742 0 : SumTermFlow = 0.0;
743 0 : SumFracSuppLeak = 0.0;
744 0 : for (k = 1; k <= state.afn->ActualNumOfLinks; ++k) {
745 0 : if (state.afn->AirflowNetworkLinkageData(k).VAVTermDamper && state.afn->AirflowNetworkLinkageData(k).AirLoopNum == AirLoopNum) {
746 0 : k1 = state.afn->AirflowNetworkNodeData(state.afn->AirflowNetworkLinkageData(k).NodeNums[0]).EPlusNodeNum;
747 0 : if (state.dataLoopNodes->Node(k1).MassFlowRate > 0.0) {
748 0 : SumTermFlow += state.dataLoopNodes->Node(k1).MassFlowRate;
749 : }
750 : }
751 0 : if (state.afn->AirflowNetworkCompData(state.afn->AirflowNetworkLinkageData(k).CompNum).CompTypeNum == iComponentTypeNum::ELR) {
752 : // Calculate supply leak sensible losses
753 0 : Node1 = state.afn->AirflowNetworkLinkageData(k).NodeNums[0];
754 0 : Node2 = state.afn->AirflowNetworkLinkageData(k).NodeNums[1];
755 0 : if ((state.afn->AirflowNetworkNodeData(Node2).EPlusZoneNum > 0) && (state.afn->AirflowNetworkNodeData(Node1).EPlusNodeNum == 0) &&
756 0 : (state.afn->AirflowNetworkNodeData(Node1).AirLoopNum == AirLoopNum)) {
757 0 : SumFracSuppLeak +=
758 0 : state.afn->DisSysCompELRData(state.afn->AirflowNetworkCompData(state.afn->AirflowNetworkLinkageData(k).CompNum).TypeNum)
759 0 : .ELR;
760 : }
761 : }
762 : }
763 0 : F[0] = SumTermFlow / (1.0 - SumFracSuppLeak);
764 0 : state.afn->VAVTerminalRatio = 0.0;
765 0 : if (F[0] > MaxAirMassFlowRate) {
766 0 : state.afn->VAVTerminalRatio = MaxAirMassFlowRate / F[0];
767 0 : F[0] = MaxAirMassFlowRate;
768 : }
769 : }
770 163425 : DF[0] = 0.0;
771 163425 : return NF;
772 : }
773 :
774 0 : int DetailedFan::calculate(EnergyPlusData &state,
775 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
776 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
777 : int const i, // Linkage number
778 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
779 : const Real64 control, // Element control signal
780 : const AirState &propN, // Node 1 properties
781 : const AirState &propM, // Node 2 properties
782 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
783 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
784 : )
785 : {
786 :
787 : // SUBROUTINE INFORMATION:
788 : // AUTHOR George Walton
789 : // DATE WRITTEN Extracted from AIRNET
790 : // MODIFIED Lixing Gu, 2/1/04
791 : // Revised the subroutine to meet E+ needs
792 : // MODIFIED Lixing Gu, 6/8/05
793 : // RE-ENGINEERED na
794 :
795 : // PURPOSE OF THIS SUBROUTINE:
796 : // This subroutine solves airflow for a detailed fan component -- using standard interface.
797 :
798 : // SUBROUTINE PARAMETER DEFINITIONS:
799 0 : Real64 constexpr TOL(0.00001);
800 :
801 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
802 : int j;
803 : int k;
804 : int L;
805 : Real64 DPDF;
806 : Real64 PRISE; // pressure rise (negative of pressure drop) (Pa).
807 : Real64 BX;
808 : Real64 BY;
809 : Real64 CX;
810 : Real64 CY;
811 : Real64 CCY;
812 : Real64 DX;
813 : Real64 DY;
814 :
815 : // Formats
816 : // static gio::Fmt Format_901("(A5,I3,5E14.6)");
817 :
818 0 : int NumCur = n;
819 0 : if (control <= 0.0) {
820 : // Speed = 0; treat fan as resistance.
821 0 : generic_crack(FlowCoef, FlowExpo, LFLAG, PDROP, propN, propM, F, DF);
822 0 : return 1;
823 : }
824 : // Pressure rise at reference fan speed.
825 0 : if (control >= TranRat) {
826 0 : PRISE = -PDROP * (RhoAir / propN.density) / (control * control);
827 : } else {
828 0 : PRISE = -PDROP * (RhoAir / propN.density) / (TranRat * control);
829 : }
830 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " fan:" << i << PDROP << PRISE << AFECTL(i) << DisSysCompDetFanData(CompNum).TranRat;
831 0 : if (LFLAG) {
832 : // Initialization by linear approximation.
833 0 : F[0] = -Qfree * control * (1.0 - PRISE / Pshut);
834 0 : DPDF = -Pshut / Qfree;
835 : // if (LIST >= 4)
836 : // gio::write(Unit21, Format_901) << " fni:" << JA << DisSysCompDetFanData(CompNum).Qfree << DisSysCompDetFanData(CompNum).Pshut;
837 : } else {
838 : // Solution of the fan performance curve.
839 : // Determine curve fit range.
840 0 : j = 1;
841 0 : k = 5 * (j - 1) + 1;
842 0 : BX = Coeff(k);
843 0 : BY = Coeff(k + 1) + BX * (Coeff(k + 2) + BX * (Coeff(k + 3) + BX * Coeff(k + 4))) - PRISE;
844 0 : if (BY < 0.0) ShowFatalError(state, "Out of range, too low in an AirflowNetwork detailed Fan");
845 :
846 : while (true) {
847 0 : DX = Coeff(k + 5);
848 0 : DY = Coeff(k + 1) + DX * (Coeff(k + 2) + DX * (Coeff(k + 3) + DX * Coeff(k + 5))) - PRISE;
849 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " fp0:" << j << BX << BY << DX << DY;
850 0 : if (BY * DY <= 0.0) break;
851 0 : ++j;
852 0 : if (j > NumCur) ShowFatalError(state, "Out of range, too high (FAN) in ADS simulation");
853 0 : k += 5;
854 0 : BX = DX;
855 0 : BY = DY;
856 : }
857 : // Determine reference mass flow rate by false position method.
858 0 : L = 0;
859 0 : CY = 0.0;
860 0 : Label40:;
861 0 : ++L;
862 0 : if (L > 100) ShowFatalError(state, "Too many iterations (FAN) in AirflowNtework simulation");
863 0 : CCY = CY;
864 0 : CX = BX - BY * ((DX - BX) / (DY - BY));
865 0 : CY = Coeff(k + 1) + CX * (Coeff(k + 2) + CX * (Coeff(k + 3) + CX * Coeff(k + 4))) - PRISE;
866 0 : if (BY * CY == 0.0) goto Label90;
867 0 : if (BY * CY > 0.0) goto Label60;
868 0 : DX = CX;
869 0 : DY = CY;
870 0 : if (CY * CCY > 0.0) BY *= 0.5;
871 0 : goto Label70;
872 0 : Label60:;
873 0 : BX = CX;
874 0 : BY = CY;
875 0 : if (CY * CCY > 0.0) DY *= 0.5;
876 0 : Label70:;
877 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " fpi:" << j << BX << CX << DX << BY << DY;
878 0 : if (DX - BX < TOL * CX) goto Label80;
879 0 : if (DX - BX < TOL) goto Label80;
880 0 : goto Label40;
881 0 : Label80:;
882 0 : CX = 0.5 * (BX + DX);
883 0 : Label90:;
884 0 : F[0] = CX;
885 0 : DPDF = Coeff(k + 2) + CX * (2.0 * Coeff(k + 3) + CX * 3.0 * Coeff(k + 4));
886 : }
887 : // Convert to flow at given speed.
888 0 : F[0] *= (propN.density / RhoAir) * control;
889 : // Set derivative w/r pressure drop (-).
890 0 : if (control >= TranRat) {
891 0 : DF[0] = -control / DPDF;
892 : } else {
893 0 : DF[0] = -1.0 / DPDF;
894 : }
895 0 : return 1;
896 : }
897 :
898 0 : int DetailedFan::calculate(EnergyPlusData &state,
899 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
900 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
901 : const Real64 control, // Element control signal
902 : const AirState &propN, // Node 1 properties
903 : const AirState &propM, // Node 2 properties
904 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
905 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
906 : )
907 : {
908 :
909 : // SUBROUTINE INFORMATION:
910 : // AUTHOR George Walton
911 : // DATE WRITTEN Extracted from AIRNET
912 : // MODIFIED Lixing Gu, 2/1/04
913 : // Revised the subroutine to meet E+ needs
914 : // MODIFIED Lixing Gu, 6/8/05
915 : // RE-ENGINEERED na
916 :
917 : // PURPOSE OF THIS SUBROUTINE:
918 : // This subroutine solves airflow for a detailed fan component -- using standard interface.
919 :
920 : // SUBROUTINE PARAMETER DEFINITIONS:
921 0 : Real64 constexpr TOL(0.00001);
922 :
923 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
924 : int j;
925 : int k;
926 : int L;
927 : Real64 DPDF;
928 : Real64 PRISE; // pressure rise (negative of pressure drop) (Pa).
929 : Real64 BX;
930 : Real64 BY;
931 : Real64 CX;
932 : Real64 CY;
933 : Real64 CCY;
934 : Real64 DX;
935 : Real64 DY;
936 :
937 : // Formats
938 : // static gio::Fmt Format_901("(A5,I3,5E14.6)");
939 :
940 0 : int NumCur = n;
941 :
942 0 : if (control <= 0.0) {
943 : // Speed = 0; treat fan as resistance.
944 0 : generic_crack(FlowCoef, FlowExpo, false, PDROP, propN, propM, F, DF);
945 0 : return 1;
946 : }
947 : // Pressure rise at reference fan speed.
948 0 : if (control >= TranRat) {
949 0 : PRISE = -PDROP * (RhoAir / propN.density) / pow_2(control);
950 : } else {
951 0 : PRISE = -PDROP * (RhoAir / propN.density) / (TranRat * control);
952 : }
953 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " fan:" << i << PDROP << PRISE << AFECTL(i) << DisSysCompDetFanData(CompNum).TranRat;
954 : // if (LFLAG) {
955 : // // Initialization by linear approximation.
956 : // F[0] = -Qfree * control * (1.0 - PRISE / Pshut);
957 : // DPDF = -Pshut / Qfree;
958 : // // if (LIST >= 4)
959 : // // gio::write(Unit21, Format_901) << " fni:" << JA << DisSysCompDetFanData(CompNum).Qfree << DisSysCompDetFanData(CompNum).Pshut;
960 : //} else {
961 : // Solution of the fan performance curve.
962 : // Determine curve fit range.
963 0 : j = 1;
964 0 : k = 5 * (j - 1) + 1;
965 0 : BX = Coeff(k);
966 0 : BY = Coeff(k + 1) + BX * (Coeff(k + 2) + BX * (Coeff(k + 3) + BX * Coeff(k + 4))) - PRISE;
967 0 : if (BY < 0.0) ShowFatalError(state, "Out of range, too low in an AirflowNetwork detailed Fan");
968 :
969 : while (true) {
970 0 : DX = Coeff(k + 5);
971 0 : DY = Coeff(k + 1) + DX * (Coeff(k + 2) + DX * (Coeff(k + 3) + DX * Coeff(k + 5))) - PRISE;
972 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " fp0:" << j << BX << BY << DX << DY;
973 0 : if (BY * DY <= 0.0) break;
974 0 : ++j;
975 0 : if (j > NumCur) ShowFatalError(state, "Out of range, too high (FAN) in ADS simulation");
976 0 : k += 5;
977 0 : BX = DX;
978 0 : BY = DY;
979 : }
980 : // Determine reference mass flow rate by false position method.
981 0 : L = 0;
982 0 : CY = 0.0;
983 0 : Label40:;
984 0 : ++L;
985 0 : if (L > 100) ShowFatalError(state, "Too many iterations (FAN) in AirflowNtework simulation");
986 0 : CCY = CY;
987 0 : CX = BX - BY * ((DX - BX) / (DY - BY));
988 0 : CY = Coeff(k + 1) + CX * (Coeff(k + 2) + CX * (Coeff(k + 3) + CX * Coeff(k + 4))) - PRISE;
989 0 : if (BY * CY == 0.0) goto Label90;
990 0 : if (BY * CY > 0.0) goto Label60;
991 0 : DX = CX;
992 0 : DY = CY;
993 0 : if (CY * CCY > 0.0) BY *= 0.5;
994 0 : goto Label70;
995 0 : Label60:;
996 0 : BX = CX;
997 0 : BY = CY;
998 0 : if (CY * CCY > 0.0) DY *= 0.5;
999 0 : Label70:;
1000 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " fpi:" << j << BX << CX << DX << BY << DY;
1001 0 : if (DX - BX < TOL * CX) goto Label80;
1002 0 : if (DX - BX < TOL) goto Label80;
1003 0 : goto Label40;
1004 0 : Label80:;
1005 0 : CX = 0.5 * (BX + DX);
1006 0 : Label90:;
1007 0 : F[0] = CX;
1008 0 : DPDF = Coeff(k + 2) + CX * (2.0 * Coeff(k + 3) + CX * 3.0 * Coeff(k + 4));
1009 :
1010 : // Convert to flow at given speed.
1011 0 : F[0] *= (propN.density / RhoAir) * control;
1012 : // Set derivative w/r pressure drop (-).
1013 0 : if (control >= TranRat) {
1014 0 : DF[0] = -control / DPDF;
1015 : } else {
1016 0 : DF[0] = -1.0 / DPDF;
1017 : }
1018 0 : return 1;
1019 : }
1020 :
1021 0 : int Damper::calculate([[maybe_unused]] EnergyPlusData &state,
1022 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
1023 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
1024 : int const i, // Linkage number
1025 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
1026 : [[maybe_unused]] const Real64 control, // Element control signal
1027 : const AirState &propN, // Node 1 properties
1028 : const AirState &propM, // Node 2 properties
1029 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
1030 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
1031 : )
1032 : {
1033 :
1034 : // SUBROUTINE INFORMATION:
1035 : // AUTHOR George Walton
1036 : // DATE WRITTEN Extracted from AIRNET
1037 : // MODIFIED Lixing Gu, 2/1/04
1038 : // Revised the subroutine to meet E+ needs
1039 : // MODIFIED Lixing Gu, 6/8/05
1040 : // RE-ENGINEERED na
1041 :
1042 : // PURPOSE OF THIS SUBROUTINE:
1043 : // This subroutine solves airflow for a Controlled power law resistance airflow component (damper)
1044 :
1045 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1046 : Real64 C;
1047 :
1048 : // Formats
1049 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
1050 :
1051 0 : C = control;
1052 0 : if (C < FlowMin) C = FlowMin;
1053 0 : if (C > FlowMax) C = FlowMax;
1054 0 : C = A0 + C * (A1 + C * (A2 + C * A3));
1055 : // if (LIST >= 4)
1056 : // gio::write(Unit21, Format_901) << " Dmp:" << i << AFECTL(i) << DisSysCompDamperData(CompNum).FlowMin
1057 : // << DisSysCompDamperData(CompNum).FlowMax << C;
1058 0 : if (LFLAG || std::abs(PDROP) <= LTP) {
1059 : // Laminar flow.
1060 0 : if (PDROP >= 0.0) {
1061 0 : DF[0] = C * LamFlow * propN.density / propN.viscosity;
1062 : } else {
1063 0 : DF[0] = C * LamFlow * propM.density / propM.viscosity;
1064 : }
1065 0 : F[0] = DF[0] * PDROP;
1066 : } else {
1067 : // Turbulent flow.
1068 0 : if (PDROP >= 0.0) {
1069 0 : F[0] = C * TurFlow * propN.sqrt_density * std::pow(PDROP, FlowExpo);
1070 : } else {
1071 0 : F[0] = -C * TurFlow * propM.sqrt_density * std::pow(-PDROP, FlowExpo);
1072 : }
1073 0 : DF[0] = F[0] * FlowExpo / PDROP;
1074 : }
1075 0 : return 1;
1076 : }
1077 :
1078 0 : int Damper::calculate([[maybe_unused]] EnergyPlusData &state,
1079 : const Real64 PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
1080 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
1081 : const Real64 control, // Element control signal
1082 : const AirState &propN, // Node 1 properties
1083 : const AirState &propM, // Node 2 properties
1084 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
1085 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
1086 : )
1087 : {
1088 :
1089 : // SUBROUTINE INFORMATION:
1090 : // AUTHOR George Walton
1091 : // DATE WRITTEN Extracted from AIRNET
1092 : // MODIFIED Lixing Gu, 2/1/04
1093 : // Revised the subroutine to meet E+ needs
1094 : // MODIFIED Lixing Gu, 6/8/05
1095 : // RE-ENGINEERED na
1096 :
1097 : // PURPOSE OF THIS SUBROUTINE:
1098 : // This subroutine solves airflow for a Controlled power law resistance airflow component (damper)
1099 :
1100 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1101 : Real64 C;
1102 :
1103 : // Formats
1104 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
1105 :
1106 0 : C = control;
1107 0 : if (C < FlowMin) C = FlowMin;
1108 0 : if (C > FlowMax) C = FlowMax;
1109 0 : C = A0 + C * (A1 + C * (A2 + C * A3));
1110 : // if (LIST >= 4)
1111 : // gio::write(Unit21, Format_901) << " Dmp:" << i << AFECTL(i) << DisSysCompDamperData(CompNum).FlowMin
1112 : // << DisSysCompDamperData(CompNum).FlowMax << C;
1113 0 : if (std::abs(PDROP) <= LTP) {
1114 : // Laminar flow.
1115 0 : if (PDROP >= 0.0) {
1116 0 : DF[0] = C * LamFlow * propN.density / propN.viscosity;
1117 : } else {
1118 0 : DF[0] = C * LamFlow * propM.density / propM.viscosity;
1119 : }
1120 0 : F[0] = DF[0] * PDROP;
1121 : } else {
1122 : // Turbulent flow.
1123 0 : if (PDROP >= 0.0) {
1124 0 : F[0] = C * TurFlow * propN.sqrt_density * std::pow(PDROP, FlowExpo);
1125 : } else {
1126 0 : F[0] = -C * TurFlow * propM.sqrt_density * std::pow(-PDROP, FlowExpo);
1127 : }
1128 0 : DF[0] = F[0] * FlowExpo / PDROP;
1129 : }
1130 0 : return 1;
1131 : }
1132 :
1133 653732 : int EffectiveLeakageRatio::calculate([[maybe_unused]] EnergyPlusData &state,
1134 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
1135 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
1136 : [[maybe_unused]] int const i, // Linkage number
1137 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
1138 : [[maybe_unused]] const Real64 control, // Element control signal
1139 : const AirState &propN, // Node 1 properties
1140 : const AirState &propM, // Node 2 properties
1141 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
1142 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
1143 : )
1144 : {
1145 :
1146 : // SUBROUTINE INFORMATION:
1147 : // AUTHOR George Walton
1148 : // DATE WRITTEN Extracted from AIRNET
1149 : // MODIFIED Lixing Gu, 2/1/04
1150 : // Revised the subroutine to meet E+ needs
1151 : // MODIFIED Lixing Gu, 6/8/05
1152 : // RE-ENGINEERED na
1153 :
1154 : // PURPOSE OF THIS SUBROUTINE:
1155 : // This subroutine solves airflow for a Effective leakage ratio component
1156 :
1157 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1158 : Real64 CDM;
1159 : Real64 FL;
1160 : Real64 FT;
1161 : Real64 FlowCoef;
1162 :
1163 : // Formats
1164 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
1165 :
1166 : // Get component properties
1167 653732 : FlowCoef = ELR * FlowRate / propN.density * std::pow(RefPres, -FlowExpo);
1168 :
1169 653732 : if (LFLAG) {
1170 : // Initialization by linear relation.
1171 0 : if (PDROP >= 0.0) {
1172 0 : DF[0] = FlowCoef * propN.density / propN.viscosity;
1173 : } else {
1174 0 : DF[0] = FlowCoef * propM.density / propM.viscosity;
1175 : }
1176 0 : F[0] = -DF[0] * PDROP;
1177 : } else {
1178 : // Standard calculation.
1179 653732 : if (PDROP >= 0.0) {
1180 : // Flow in positive direction.
1181 : // Laminar flow.
1182 563553 : CDM = FlowCoef * propN.density / propN.viscosity;
1183 563553 : FL = CDM * PDROP;
1184 : // Turbulent flow.
1185 563553 : if (FlowExpo == 0.5) {
1186 0 : FT = FlowCoef * propN.sqrt_density * std::sqrt(PDROP);
1187 : } else {
1188 563553 : FT = FlowCoef * propN.sqrt_density * std::pow(PDROP, FlowExpo);
1189 : }
1190 : } else {
1191 : // Flow in negative direction.
1192 : // Laminar flow.
1193 90179 : CDM = FlowCoef * propM.density / propM.viscosity;
1194 90179 : FL = CDM * PDROP;
1195 : // Turbulent flow.
1196 90179 : if (FlowExpo == 0.5) {
1197 0 : FT = -FlowCoef * propM.sqrt_density * std::sqrt(-PDROP);
1198 : } else {
1199 90179 : FT = -FlowCoef * propM.sqrt_density * std::pow(-PDROP, FlowExpo);
1200 : }
1201 : }
1202 : // Select laminar or turbulent flow.
1203 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " plr: " << i << PDROP << FL << FT;
1204 653732 : if (std::abs(FL) <= std::abs(FT)) {
1205 50 : F[0] = FL;
1206 50 : DF[0] = CDM;
1207 : } else {
1208 653682 : F[0] = FT;
1209 653682 : DF[0] = FT * FlowExpo / PDROP;
1210 : }
1211 : }
1212 653732 : return 1;
1213 : }
1214 :
1215 0 : int EffectiveLeakageRatio::calculate([[maybe_unused]] EnergyPlusData &state,
1216 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
1217 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
1218 : [[maybe_unused]] const Real64 control, // Element control signal
1219 : const AirState &propN, // Node 1 properties
1220 : const AirState &propM, // Node 2 properties
1221 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
1222 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
1223 : )
1224 : {
1225 :
1226 : // SUBROUTINE INFORMATION:
1227 : // AUTHOR George Walton
1228 : // DATE WRITTEN Extracted from AIRNET
1229 : // MODIFIED Lixing Gu, 2/1/04
1230 : // Revised the subroutine to meet E+ needs
1231 : // MODIFIED Lixing Gu, 6/8/05
1232 : // RE-ENGINEERED na
1233 :
1234 : // PURPOSE OF THIS SUBROUTINE:
1235 : // This subroutine solves airflow for a Effective leakage ratio component
1236 :
1237 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1238 : Real64 CDM;
1239 : Real64 FL;
1240 : Real64 FT;
1241 : Real64 FlowCoef;
1242 :
1243 : // Formats
1244 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
1245 :
1246 : // Get component properties
1247 0 : FlowCoef = ELR * FlowRate / propN.density * std::pow(RefPres, -FlowExpo);
1248 :
1249 : // Standard calculation.
1250 0 : if (PDROP >= 0.0) {
1251 : // Flow in positive direction.
1252 : // Laminar flow.
1253 0 : CDM = FlowCoef * propN.density / propN.viscosity;
1254 0 : FL = CDM * PDROP;
1255 : // Turbulent flow.
1256 0 : if (FlowExpo == 0.5) {
1257 0 : FT = FlowCoef * propN.sqrt_density * std::sqrt(PDROP);
1258 : } else {
1259 0 : FT = FlowCoef * propN.sqrt_density * std::pow(PDROP, FlowExpo);
1260 : }
1261 : } else {
1262 : // Flow in negative direction.
1263 : // Laminar flow.
1264 0 : CDM = FlowCoef * propM.density / propM.viscosity;
1265 0 : FL = CDM * PDROP;
1266 : // Turbulent flow.
1267 0 : if (FlowExpo == 0.5) {
1268 0 : FT = -FlowCoef * propM.sqrt_density * std::sqrt(-PDROP);
1269 : } else {
1270 0 : FT = -FlowCoef * propM.sqrt_density * std::pow(-PDROP, FlowExpo);
1271 : }
1272 : }
1273 : // Select laminar or turbulent flow.
1274 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " plr: " << i << PDROP << FL << FT;
1275 0 : if (std::abs(FL) <= std::abs(FT)) {
1276 0 : F[0] = FL;
1277 0 : DF[0] = CDM;
1278 : } else {
1279 0 : F[0] = FT;
1280 0 : DF[0] = FT * FlowExpo / PDROP;
1281 : }
1282 0 : return 1;
1283 : }
1284 :
1285 14 : int DetailedOpening::calculate(EnergyPlusData &state,
1286 : [[maybe_unused]] bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
1287 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
1288 : int const IL, // Linkage number
1289 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
1290 : [[maybe_unused]] const Real64 control, // Element control signal
1291 : [[maybe_unused]] const AirState &propN, // Node 1 properties
1292 : [[maybe_unused]] const AirState &propM, // Node 2 properties
1293 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
1294 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
1295 : )
1296 : {
1297 :
1298 : // SUBROUTINE INFORMATION:
1299 : // AUTHOR Lixing Gu
1300 : // DATE WRITTEN Oct. 2005
1301 : // MODIFIED na
1302 : // RE-ENGINEERED This subroutine is revised based on a vertical large opening subroutine from COMIS
1303 :
1304 : // PURPOSE OF THIS SUBROUTINE:
1305 : // This subroutine simulates airflow and pressure of a detailed large opening component.
1306 :
1307 : // METHODOLOGY EMPLOYED:
1308 : // Purpose: This routine calculates the massflow and its derivative
1309 : // through a large opening in both flow directions. As input
1310 : // the density profiles RhoProfF/T are required aswell as the
1311 : // effective pressure difference profile DpProfNew, which is the
1312 : // sum of the stack pressure difference profile DpProf and the
1313 : // difference of the actual pressures at reference height. The
1314 : // profiles are calculated in the routine PresProfile.
1315 : // The massflow and its derivative are calculated for each
1316 : // interval representing a step of the pressure difference
1317 : // profile. The total flow and derivative are obtained by
1318 : // summation over the whole opening.
1319 : // The calculation is split into different cases representing
1320 : // different situations of the opening:
1321 : // - closed opening (opening factor = 0): summation of top and
1322 : // bottom crack (crack length = lwmax) plus "integration" over
1323 : // a vertically distributed crack of length (2*lhmax+lextra).
1324 : // - type 1: normal rectangular opening: "integration" over NrInt
1325 : // openings with width actlw and height actlh/NrInt
1326 : // - type 2: horizontally pivoted window: flow direction assumed
1327 : // strictly perpendicular to the plane of the opening
1328 : // -> "integration" over normal rectangular openings at top
1329 : // and bottom of LO plus a rectangular opening in series with two
1330 : // triangular openings in the middle of the LO (most general
1331 : // situation). The geometry is defined by the input parameters
1332 : // actlw(=lwmax), actlh, axisheight, opening angle.
1333 : // Assuming the massflow perpendicular to the opening plane in all
1334 : // cases the ownheightfactor has no influence on the massflow.
1335 :
1336 : // REFERENCES:
1337 : // Helmut E. Feustel and Alison Rayner-Hooson, "COMIS Fundamentals," LBL-28560,
1338 : // Lawrence Berkeley National Laboratory, Berkeley, CA, May 1990
1339 :
1340 : // USE STATEMENTS:
1341 : // Locals
1342 : // SUBROUTINE ARGUMENT DEFINITIONS:
1343 :
1344 : // SUBROUTINE PARAMETER DEFINITIONS:
1345 14 : Real64 constexpr RealMin(1e-37);
1346 : static Real64 const sqrt_1_2(std::sqrt(1.2));
1347 :
1348 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1349 : static Real64 const sqrt_2(std::sqrt(2.0));
1350 :
1351 : Real64 Width;
1352 : Real64 Height;
1353 :
1354 : Real64 fma12; // massflow in direction "from-to" [kg/s]
1355 : Real64 fma21; // massflow in direction "to-from" [kg/s]
1356 : Real64 dp1fma12; // derivative d fma12 / d Dp [kg/s/Pa]
1357 : Real64 dp1fma21; // derivative d fma21 / d Dp [kg/s/Pa]
1358 14 : Array1D<Real64> DpProfNew(NrInt + 2); // Differential pressure profile for Large Openings, taking into account fixed
1359 : // pressures and actual zone pressures at reference height
1360 : Real64 Fact; // Actual opening factor
1361 : Real64 DifLim; // Limit for the pressure difference where laminarization takes place [Pa]
1362 : Real64 Cfact;
1363 : Real64 FvVeloc;
1364 :
1365 : Real64 ActLh;
1366 : Real64 ActLw;
1367 : Real64 Lextra;
1368 : Real64 Axishght;
1369 : Real64 ActCD;
1370 : Real64 Cs;
1371 : Real64 expn;
1372 : Real64 Type;
1373 : Real64 Interval;
1374 : Real64 fmasum;
1375 : Real64 dfmasum;
1376 : Real64 Prefact;
1377 14 : Array1D<Real64> EvalHghts(NrInt + 2);
1378 : Real64 h2;
1379 : Real64 h4;
1380 : Real64 alpha;
1381 : Real64 rholink;
1382 : Real64 c1;
1383 : Real64 c2;
1384 : Real64 DpZeroOffset;
1385 : Real64 area;
1386 : Real64 WFact;
1387 : Real64 HFact;
1388 : int i;
1389 : int Loc;
1390 : int iNum;
1391 :
1392 : // Get component properties
1393 14 : DifLim = 1.0e-4;
1394 14 : Width = state.afn->MultizoneSurfaceData(IL).Width;
1395 14 : Height = state.afn->MultizoneSurfaceData(IL).Height;
1396 14 : Fact = state.afn->MultizoneSurfaceData(IL).OpenFactor;
1397 14 : Loc = (state.afn->AirflowNetworkLinkageData(IL).DetOpenNum - 1) * (NrInt + 2);
1398 14 : iNum = NumFac;
1399 14 : ActCD = 0.0;
1400 :
1401 14 : if (iNum == 2) {
1402 14 : if (Fact <= OpenFac2) {
1403 14 : WFact = WidthFac1 + (Fact - OpenFac1) / (OpenFac2 - OpenFac1) * (WidthFac2 - WidthFac1);
1404 14 : HFact = HeightFac1 + (Fact - OpenFac1) / (OpenFac2 - OpenFac1) * (HeightFac2 - HeightFac1);
1405 14 : Cfact = DischCoeff1 + (Fact - OpenFac1) / (OpenFac2 - OpenFac1) * (DischCoeff2 - DischCoeff1);
1406 : } else {
1407 0 : ShowFatalError(
1408 : state,
1409 0 : "Open Factor is above the maximum input range for opening factors in AirflowNetwork:MultiZone:Component:DetailedOpening = " +
1410 0 : name);
1411 : }
1412 : }
1413 :
1414 14 : if (iNum == 3) {
1415 0 : if (Fact <= OpenFac2) {
1416 0 : WFact = WidthFac1 + (Fact - OpenFac1) / (OpenFac2 - OpenFac1) * (WidthFac2 - WidthFac1);
1417 0 : HFact = HeightFac1 + (Fact - OpenFac1) / (OpenFac2 - OpenFac1) * (HeightFac2 - HeightFac1);
1418 0 : Cfact = DischCoeff1 + (Fact - OpenFac1) / (OpenFac2 - OpenFac1) * (DischCoeff2 - DischCoeff1);
1419 0 : } else if (Fact <= OpenFac3) {
1420 0 : WFact = WidthFac2 + (Fact - OpenFac2) / (OpenFac3 - OpenFac2) * (WidthFac3 - WidthFac2);
1421 0 : HFact = HeightFac2 + (Fact - OpenFac2) / (OpenFac3 - OpenFac2) * (HeightFac3 - HeightFac2);
1422 0 : Cfact = DischCoeff2 + (Fact - OpenFac2) / (OpenFac3 - OpenFac2) * (DischCoeff3 - DischCoeff2);
1423 : } else {
1424 0 : ShowFatalError(
1425 : state,
1426 0 : "Open Factor is above the maximum input range for opening factors in AirflowNetwork:MultiZone:Component:DetailedOpening = " +
1427 0 : name);
1428 : }
1429 : }
1430 :
1431 14 : if (iNum == 4) {
1432 0 : if (Fact <= OpenFac2) {
1433 0 : WFact = WidthFac1 + (Fact - OpenFac1) / (OpenFac2 - OpenFac1) * (WidthFac2 - WidthFac1);
1434 0 : HFact = HeightFac1 + (Fact - OpenFac1) / (OpenFac2 - OpenFac1) * (HeightFac2 - HeightFac1);
1435 0 : Cfact = DischCoeff1 + (Fact - OpenFac1) / (OpenFac2 - OpenFac1) * (DischCoeff2 - DischCoeff1);
1436 0 : } else if (Fact <= OpenFac3) {
1437 0 : WFact = WidthFac2 + (Fact - OpenFac2) / (OpenFac3 - OpenFac2) * (WidthFac3 - WidthFac2);
1438 0 : HFact = HeightFac2 + (Fact - OpenFac2) / (OpenFac3 - OpenFac2) * (HeightFac3 - HeightFac2);
1439 0 : Cfact = DischCoeff2 + (Fact - OpenFac2) / (OpenFac3 - OpenFac2) * (DischCoeff3 - DischCoeff2);
1440 0 : } else if (Fact <= OpenFac4) {
1441 0 : WFact = WidthFac3 + (Fact - OpenFac3) / (OpenFac4 - OpenFac3) * (WidthFac4 - WidthFac3);
1442 0 : HFact = HeightFac3 + (Fact - OpenFac3) / (OpenFac4 - OpenFac3) * (HeightFac4 - HeightFac3);
1443 0 : Cfact = DischCoeff3 + (Fact - OpenFac3) / (OpenFac4 - OpenFac3) * (DischCoeff4 - DischCoeff3);
1444 : } else {
1445 0 : ShowFatalError(
1446 : state,
1447 0 : "Open Factor is above the maximum input range for opening factors in AirflowNetwork:MultiZone:Component:DetailedOpening = " +
1448 0 : name);
1449 : }
1450 : }
1451 :
1452 : // calculate DpProfNew
1453 322 : for (i = 1; i <= NrInt + 2; ++i) {
1454 308 : DpProfNew(i) = PDROP + state.afn->dos.DpProf(Loc + i) - state.afn->dos.DpL(IL, 1);
1455 : }
1456 :
1457 : // Get opening data based on the opening factor
1458 14 : if (Fact == 0) {
1459 0 : ActLw = state.afn->MultizoneSurfaceData(IL).Width;
1460 0 : ActLh = state.afn->MultizoneSurfaceData(IL).Height;
1461 0 : Cfact = 0.0;
1462 : } else {
1463 14 : ActLw = state.afn->MultizoneSurfaceData(IL).Width * WFact;
1464 14 : ActLh = state.afn->MultizoneSurfaceData(IL).Height * HFact;
1465 14 : ActCD = Cfact;
1466 : }
1467 :
1468 14 : Cs = FlowCoef;
1469 14 : expn = FlowExpo;
1470 14 : Type = LVOType;
1471 14 : if (Type == 1) {
1472 14 : Lextra = LVOValue;
1473 14 : Axishght = 0.0;
1474 0 : } else if (Type == 2) {
1475 0 : Lextra = 0.0;
1476 0 : Axishght = LVOValue;
1477 0 : ActLw = state.afn->MultizoneSurfaceData(IL).Width;
1478 0 : ActLh = state.afn->MultizoneSurfaceData(IL).Height;
1479 : }
1480 :
1481 : // Add window multiplier with window close
1482 14 : if (state.afn->MultizoneSurfaceData(IL).Multiplier > 1.0) Cs *= state.afn->MultizoneSurfaceData(IL).Multiplier;
1483 : // Add window multiplier with window open
1484 14 : if (Fact > 0.0) {
1485 14 : if (state.afn->MultizoneSurfaceData(IL).Multiplier > 1.0) ActLw *= state.afn->MultizoneSurfaceData(IL).Multiplier;
1486 : // Add recurring warnings
1487 14 : if (ActLw == 0.0) {
1488 0 : ++WidthErrCount;
1489 0 : if (WidthErrCount < 2) {
1490 0 : ShowWarningError(state, "The actual width of the AirflowNetwork:MultiZone:Component:DetailedOpening of " + name + " is 0.");
1491 0 : ShowContinueError(state, "The actual width is set to 1.0E-6 m.");
1492 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
1493 : } else {
1494 0 : ShowRecurringWarningErrorAtEnd(state,
1495 0 : "The actual width of the AirflowNetwork:MultiZone:Component:DetailedOpening of " + name +
1496 : " is 0 error continues.",
1497 0 : WidthErrIndex,
1498 : ActLw,
1499 : ActLw);
1500 : }
1501 0 : ActLw = 1.0e-6;
1502 : }
1503 14 : if (ActLh == 0.0) {
1504 0 : ++HeightErrCount;
1505 0 : if (HeightErrCount < 2) {
1506 0 : ShowWarningError(state, "The actual height of the AirflowNetwork:MultiZone:Component:DetailedOpening of " + name + " is 0.");
1507 0 : ShowContinueError(state, "The actual height is set to 1.0E-6 m.");
1508 0 : ShowContinueErrorTimeStamp(state, "Occurrence info:");
1509 : } else {
1510 0 : ShowRecurringWarningErrorAtEnd(state,
1511 0 : "The actual width of the AirflowNetwork:MultiZone:Component:DetailedOpening of " + name +
1512 : " is 0 error continues.",
1513 0 : HeightErrIndex,
1514 : ActLh,
1515 : ActLh);
1516 : }
1517 0 : ActLh = 1.0e-6;
1518 : }
1519 : }
1520 : // Initialization:
1521 14 : int NF(1);
1522 14 : Interval = ActLh / NrInt;
1523 14 : fma12 = 0.0;
1524 14 : fma21 = 0.0;
1525 14 : dp1fma12 = 0.0;
1526 14 : dp1fma21 = 0.0;
1527 :
1528 : // Closed LO
1529 14 : if (Cfact == 0) {
1530 0 : DpZeroOffset = DifLim;
1531 : // bottom crack
1532 0 : if (DpProfNew(1) > 0) {
1533 0 : if (std::abs(DpProfNew(1)) <= DpZeroOffset) {
1534 0 : dfmasum = Cs * ActLw * std::pow(DpZeroOffset, expn) / DpZeroOffset;
1535 0 : fmasum = DpProfNew(1) * dfmasum;
1536 : } else {
1537 0 : fmasum = Cs * ActLw * std::pow(DpProfNew(1), expn);
1538 0 : dfmasum = fmasum * expn / DpProfNew(1);
1539 : }
1540 0 : fma12 += fmasum;
1541 0 : dp1fma12 += dfmasum;
1542 : } else {
1543 0 : if (std::abs(DpProfNew(1)) <= DpZeroOffset) {
1544 0 : dfmasum = -Cs * ActLw * std::pow(DpZeroOffset, expn) / DpZeroOffset;
1545 0 : fmasum = DpProfNew(1) * dfmasum;
1546 : } else {
1547 0 : fmasum = Cs * ActLw * std::pow(-DpProfNew(1), expn);
1548 0 : dfmasum = fmasum * expn / DpProfNew(1);
1549 : }
1550 0 : fma21 += fmasum;
1551 0 : dp1fma21 += dfmasum;
1552 : }
1553 : // top crack
1554 0 : if (DpProfNew(NrInt + 2) > 0) {
1555 0 : if (std::abs(DpProfNew(NrInt + 2)) <= DpZeroOffset) {
1556 0 : dfmasum = Cs * ActLw * std::pow(DpZeroOffset, expn) / DpZeroOffset;
1557 0 : fmasum = DpProfNew(NrInt + 2) * dfmasum;
1558 : } else {
1559 0 : fmasum = Cs * ActLw * std::pow(DpProfNew(NrInt + 2), expn);
1560 0 : dfmasum = fmasum * expn / DpProfNew(NrInt + 2);
1561 : }
1562 0 : fma12 += fmasum;
1563 0 : dp1fma12 += dfmasum;
1564 : } else {
1565 0 : if (std::abs(DpProfNew(NrInt + 2)) <= DpZeroOffset) {
1566 0 : dfmasum = -Cs * ActLw * std::pow(DpZeroOffset, expn) / DpZeroOffset;
1567 0 : fmasum = DpProfNew(NrInt + 2) * dfmasum;
1568 : } else {
1569 0 : fmasum = Cs * ActLw * std::pow(-DpProfNew(NrInt + 2), expn);
1570 0 : dfmasum = fmasum * expn / DpProfNew(NrInt + 2);
1571 : }
1572 0 : fma21 += fmasum;
1573 0 : dp1fma21 += dfmasum;
1574 : }
1575 : // side and extra cracks
1576 0 : Prefact = Interval * (2 + Lextra / ActLh) * Cs;
1577 0 : for (i = 2; i <= NrInt + 1; ++i) {
1578 0 : if (DpProfNew(i) > 0) {
1579 0 : if (std::abs(DpProfNew(i)) <= DpZeroOffset) {
1580 0 : dfmasum = Prefact * std::pow(DpZeroOffset, expn) / DpZeroOffset;
1581 0 : fmasum = DpProfNew(i) * dfmasum;
1582 : } else {
1583 0 : fmasum = Prefact * std::pow(DpProfNew(i), expn);
1584 0 : dfmasum = fmasum * expn / DpProfNew(i);
1585 : }
1586 0 : fma12 += fmasum;
1587 0 : dp1fma12 += dfmasum;
1588 : } else {
1589 0 : if (std::abs(DpProfNew(i)) <= DpZeroOffset) {
1590 0 : dfmasum = -Prefact * std::pow(DpZeroOffset, expn) / DpZeroOffset;
1591 0 : fmasum = DpProfNew(i) * dfmasum;
1592 : } else {
1593 0 : fmasum = Prefact * std::pow(-DpProfNew(i), expn);
1594 0 : dfmasum = fmasum * expn / DpProfNew(i);
1595 : }
1596 0 : fma21 += fmasum;
1597 0 : dp1fma21 += dfmasum;
1598 : }
1599 : }
1600 : }
1601 :
1602 : // Open LO, type 1
1603 14 : if ((Cfact != 0) && (Type == 1)) {
1604 14 : DpZeroOffset = DifLim * 1e-3;
1605 14 : Prefact = ActLw * ActCD * Interval * sqrt_2;
1606 294 : for (i = 2; i <= NrInt + 1; ++i) {
1607 280 : if (DpProfNew(i) > 0) {
1608 160 : if (std::abs(DpProfNew(i)) <= DpZeroOffset) {
1609 0 : dfmasum = std::sqrt(state.afn->dos.RhoProfF(Loc + i) * DpZeroOffset) / DpZeroOffset;
1610 0 : fmasum = DpProfNew(i) * dfmasum;
1611 : } else {
1612 160 : fmasum = std::sqrt(state.afn->dos.RhoProfF(Loc + i) * DpProfNew(i));
1613 160 : dfmasum = 0.5 * fmasum / DpProfNew(i);
1614 : }
1615 160 : fma12 += fmasum;
1616 160 : dp1fma12 += dfmasum;
1617 : } else {
1618 120 : if (std::abs(DpProfNew(i)) <= DpZeroOffset) {
1619 0 : dfmasum = -std::sqrt(state.afn->dos.RhoProfT(Loc + i) * DpZeroOffset) / DpZeroOffset;
1620 0 : fmasum = DpProfNew(i) * dfmasum;
1621 : } else {
1622 120 : fmasum = std::sqrt(-state.afn->dos.RhoProfT(Loc + i) * DpProfNew(i));
1623 120 : dfmasum = 0.5 * fmasum / DpProfNew(i);
1624 : }
1625 120 : fma21 += fmasum;
1626 120 : dp1fma21 += dfmasum;
1627 : }
1628 : }
1629 :
1630 14 : fma12 *= Prefact;
1631 14 : fma21 *= Prefact;
1632 14 : dp1fma12 *= Prefact;
1633 14 : dp1fma21 *= Prefact;
1634 : }
1635 :
1636 : // Open LO, type 2
1637 14 : if ((Cfact != 0) && (Type == 2)) {
1638 : // Initialization
1639 0 : DpZeroOffset = DifLim * 1e-3;
1640 : // New definition for opening factors for LVO type 2: opening angle = 90 degrees --> opening factor = 1.0
1641 : // should be PIOvr2 in below?
1642 0 : alpha = Fact * Constant::PiOvr2;
1643 0 : Real64 const cos_alpha(std::cos(alpha));
1644 0 : Real64 const tan_alpha(std::tan(alpha));
1645 0 : h2 = Axishght * (1.0 - cos_alpha);
1646 0 : h4 = Axishght + (ActLh - Axishght) * cos_alpha;
1647 0 : EvalHghts(1) = 0.0;
1648 0 : EvalHghts(NrInt + 2) = ActLh;
1649 : // New definition for opening factors for LVO type 2: pening angle = 90 degrees --> opening factor = 1.0
1650 0 : if (Fact == 1.0) {
1651 0 : h2 = Axishght;
1652 0 : h4 = Axishght;
1653 : }
1654 :
1655 0 : for (i = 2; i <= NrInt + 1; ++i) {
1656 0 : EvalHghts(i) = Interval * (i - 1.5);
1657 : }
1658 :
1659 : // Calculation of massflow and its derivative
1660 0 : for (i = 2; i <= NrInt + 1; ++i) {
1661 0 : if (DpProfNew(i) > 0) {
1662 0 : rholink = state.afn->dos.RhoProfF(Loc + i);
1663 : } else {
1664 0 : rholink = state.afn->dos.RhoProfT(Loc + i);
1665 : }
1666 :
1667 0 : if ((EvalHghts(i) <= h2) || (EvalHghts(i) >= h4)) {
1668 0 : if (std::abs(DpProfNew(i)) <= DpZeroOffset) {
1669 0 : dfmasum = ActCD * ActLw * Interval * std::sqrt(2.0 * rholink * DpZeroOffset) / DpZeroOffset * sign(1, DpProfNew(i));
1670 0 : fmasum = DpProfNew(i) * dfmasum;
1671 : } else {
1672 0 : fmasum = ActCD * ActLw * Interval * std::sqrt(2.0 * rholink * std::abs(DpProfNew(i)));
1673 0 : dfmasum = 0.5 * fmasum / DpProfNew(i);
1674 : }
1675 : } else {
1676 : // triangular opening at the side of LO
1677 0 : c1 = ActCD * ActLw * Interval * std::sqrt(2.0 * rholink);
1678 0 : c2 = 2 * ActCD * std::abs(Axishght - EvalHghts(i)) * tan_alpha * Interval * std::sqrt(2.0 * rholink);
1679 0 : if ((c1 != 0) && (c2 != 0)) {
1680 0 : if (std::abs(DpProfNew(i)) <= DpZeroOffset) {
1681 0 : dfmasum = std::sqrt(DpZeroOffset / (1 / c1 / c1 + 1 / c2 / c2)) / DpZeroOffset * sign(1, DpProfNew(i));
1682 0 : fmasum = DpProfNew(i) * dfmasum;
1683 : } else {
1684 0 : fmasum = std::sqrt(std::abs(DpProfNew(i)) / (1 / c1 / c1 + 1 / c2 / c2));
1685 0 : dfmasum = 0.5 * fmasum / DpProfNew(i);
1686 : }
1687 : } else {
1688 0 : fmasum = 0.0;
1689 0 : dfmasum = 0.0;
1690 : }
1691 : }
1692 :
1693 0 : if (DpProfNew(i) > 0) {
1694 0 : fma12 += fmasum;
1695 0 : dp1fma12 += dfmasum;
1696 : } else {
1697 0 : fma21 += fmasum;
1698 0 : dp1fma21 += dfmasum;
1699 : }
1700 : }
1701 : }
1702 :
1703 : // Calculate some velocity in the large opening
1704 14 : area = ActLh * ActLw * ActCD;
1705 14 : if (area > (Cs + RealMin)) {
1706 14 : if (area > RealMin) {
1707 14 : FvVeloc = (fma21 + fma12) / area;
1708 : } else {
1709 0 : FvVeloc = 0.0;
1710 : }
1711 : } else {
1712 : // here the average velocity over the full area, may blow half in half out.
1713 : // velocity= Fva/Nett area=Fma/Rho/(Cm/( (2**N)* SQRT(1.2) ) )
1714 0 : if (Cs > 0.0) {
1715 : // get the average Rho for this closed window
1716 0 : for (i = 2; i <= NrInt + 1; ++i) {
1717 : // rholink = 0.0;
1718 : // if (DpProfNew(i) > 0) {
1719 : // rholink = state.afn->dos.RhoProfF(Loc + i);
1720 : //} else {
1721 : // rholink = state.afn->dos.RhoProfT(Loc + i);
1722 : //}
1723 : // rholink /= NrInt;
1724 0 : rholink = 1.2;
1725 : }
1726 0 : FvVeloc = (fma21 + fma12) * std::pow(2.0, expn) * sqrt_1_2 / (rholink * Cs);
1727 : } else {
1728 0 : FvVeloc = 0.0;
1729 : }
1730 : }
1731 :
1732 : // Output mass flow rates and associated derivatives
1733 14 : F[0] = fma12 - fma21;
1734 14 : DF[0] = dp1fma12 - dp1fma21;
1735 14 : F[1] = 0.0;
1736 14 : if (fma12 != 0.0 && fma21 != 0.0) {
1737 8 : F[1] = fma21;
1738 : }
1739 14 : DF[1] = 0.0;
1740 14 : return NF;
1741 14 : }
1742 :
1743 0 : int SimpleOpening::calculate(EnergyPlusData &state,
1744 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
1745 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
1746 : int const i, // Linkage number
1747 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
1748 : [[maybe_unused]] const Real64 control, // Element control signal
1749 : const AirState &propN, // Node 1 properties
1750 : const AirState &propM, // Node 2 properties
1751 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
1752 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
1753 : )
1754 : {
1755 :
1756 : // SUBROUTINE INFORMATION:
1757 : // AUTHOR George Walton
1758 : // DATE WRITTEN Extracted from AIRNET
1759 : // MODIFIED Lixing Gu, 2/1/04
1760 : // Revised the subroutine to meet E+ needs
1761 : // MODIFIED Lixing Gu, 6/8/05
1762 : // RE-ENGINEERED na
1763 :
1764 : // PURPOSE OF THIS SUBROUTINE:
1765 : // This subroutine solves airflow for a Doorway airflow component using standard interface.
1766 : // A doorway may have two-way airflows. Heights measured relative to the bottom of the door.
1767 :
1768 : // SUBROUTINE PARAMETER DEFINITIONS:
1769 : // Replace this with the value from numbers when we have C++20
1770 0 : Real64 constexpr SQRT2(1.414213562373095);
1771 :
1772 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1773 : Real64 DPMID; // pressure drop at mid-height of doorway.
1774 : Real64 C;
1775 : Real64 DF0; // derivative factor at the bottom of the door.
1776 : Real64 DFH; // derivative factor at the top of the door.
1777 : Real64 DRHO; // difference in air densities between rooms.
1778 : Real64 GDRHO;
1779 : Real64 F0; // flow factor at the bottom of the door.
1780 : Real64 FH; // flow factor at the top of the door.
1781 : Real64 Y; // height of neutral plane rel. to bottom of door (m).
1782 : Real64 coeff;
1783 : Real64 Width;
1784 : Real64 Height;
1785 : Real64 OpenFactor;
1786 :
1787 0 : int NF(1);
1788 :
1789 : // Formats
1790 : // static gio::Fmt Format_900("(A5,9X,4E16.7)");
1791 : // static gio::Fmt Format_903("(A5,3I3,4E16.7)");
1792 :
1793 0 : Width = state.afn->MultizoneSurfaceData(i).Width;
1794 0 : Height = state.afn->MultizoneSurfaceData(i).Height;
1795 0 : coeff = FlowCoef * 2.0 * (Width + Height);
1796 0 : OpenFactor = state.afn->MultizoneSurfaceData(i).OpenFactor;
1797 0 : if (OpenFactor > 0.0) {
1798 0 : Width *= OpenFactor;
1799 0 : if (state.dataSurface->Surface(state.afn->MultizoneSurfaceData(i).SurfNum).Tilt < 90.0) {
1800 0 : Height *= state.dataSurface->Surface(state.afn->MultizoneSurfaceData(i).SurfNum).SinTilt;
1801 : }
1802 : }
1803 :
1804 0 : if (PDROP >= 0.0) {
1805 0 : coeff /= propN.sqrt_density;
1806 : } else {
1807 0 : coeff /= propM.sqrt_density;
1808 : }
1809 :
1810 : // Add window multiplier with window close
1811 0 : if (state.afn->MultizoneSurfaceData(i).Multiplier > 1.0) coeff *= state.afn->MultizoneSurfaceData(i).Multiplier;
1812 : // Add window multiplier with window open
1813 0 : if (OpenFactor > 0.0) {
1814 0 : if (state.afn->MultizoneSurfaceData(i).Multiplier > 1.0) Width *= state.afn->MultizoneSurfaceData(i).Multiplier;
1815 : }
1816 :
1817 0 : DRHO = propN.density - propM.density;
1818 0 : GDRHO = 9.8 * DRHO;
1819 : // if (LIST >= 4) gio::write(Unit21, Format_903) << " DOR:" << i << n << m << PDROP << std::abs(DRHO) << MinRhoDiff;
1820 0 : if (OpenFactor == 0.0) {
1821 0 : generic_crack(coeff, FlowExpo, LFLAG, PDROP, propN, propM, F, DF);
1822 0 : return 1;
1823 : }
1824 0 : if (std::abs(DRHO) < MinRhoDiff || LFLAG) {
1825 0 : DPMID = PDROP - 0.5 * Height * GDRHO;
1826 : // Initialization or identical temps: treat as one-way flow.
1827 0 : NF = 1;
1828 0 : generic_crack(coeff, FlowExpo, LFLAG, DPMID, propN, propM, F, DF);
1829 : // if (LIST >= 4) gio::write(Unit21, Format_900) << " Drs:" << DPMID << F[0] << DF[0];
1830 : } else {
1831 : // Possible two-way flow:
1832 0 : Y = PDROP / GDRHO;
1833 : // if (LIST >= 4) gio::write(Unit21, Format_900) << " DrY:" << PDROP << GDRHO << Y;
1834 : // F0 = lower flow, FH = upper flow.
1835 0 : C = SQRT2 * Width * DischCoeff;
1836 0 : DF0 = C * std::sqrt(std::abs(PDROP)) / std::abs(GDRHO);
1837 : // F0 = 0.666667d0*C*SQRT(ABS(GDRHO*Y))*ABS(Y)
1838 0 : F0 = (2.0 / 3.0) * C * std::sqrt(std::abs(GDRHO * Y)) * std::abs(Y);
1839 0 : DFH = C * std::sqrt(std::abs((Height - Y) / GDRHO));
1840 : // FH = 0.666667d0*DFH*ABS(GDRHO*(Height-Y))
1841 0 : FH = (2.0 / 3.0) * DFH * std::abs(GDRHO * (Height - Y));
1842 : // if (LIST >= 4) gio::write(Unit21, Format_900) << " DrF:" << F0 << DF0 << FH << DFH;
1843 0 : if (Y <= 0.0) {
1844 : // One-way flow (negative).
1845 0 : if (DRHO >= 0.0) {
1846 0 : F[0] = -propM.sqrt_density * std::abs(FH - F0);
1847 0 : DF[0] = propM.sqrt_density * std::abs(DFH - DF0);
1848 : } else {
1849 0 : F[0] = propN.sqrt_density * std::abs(FH - F0);
1850 0 : DF[0] = propN.sqrt_density * std::abs(DFH - DF0);
1851 : }
1852 : // if (LIST >= 4) gio::write(Unit21, Format_900) << " Dr1:" << C << F[0] << DF[0];
1853 0 : } else if (Y >= Height) {
1854 : // One-way flow (positive).
1855 0 : if (DRHO >= 0.0) {
1856 0 : F[0] = propN.sqrt_density * std::abs(FH - F0);
1857 0 : DF[0] = propN.sqrt_density * std::abs(DFH - DF0);
1858 : } else {
1859 0 : F[0] = -propM.sqrt_density * std::abs(FH - F0);
1860 0 : DF[0] = propM.sqrt_density * std::abs(DFH - DF0);
1861 : }
1862 : // if (LIST >= 4) gio::write(Unit21, Format_900) << " Dr2:" << C << F[0] << DF[0];
1863 : } else {
1864 : // Two-way flow.
1865 0 : NF = 2;
1866 0 : if (DRHO >= 0.0) {
1867 0 : F[0] = -propM.sqrt_density * FH;
1868 0 : DF[0] = propM.sqrt_density * DFH;
1869 0 : F[1] = propN.sqrt_density * F0;
1870 0 : DF[1] = propN.sqrt_density * DF0;
1871 : } else {
1872 0 : F[0] = propN.sqrt_density * FH;
1873 0 : DF[0] = propN.sqrt_density * DFH;
1874 0 : F[1] = -propM.sqrt_density * F0;
1875 0 : DF[1] = propM.sqrt_density * DF0;
1876 : }
1877 : // if (LIST >= 4) gio::write(Unit21, Format_900) << " Dr3:" << C << F[0] << DF[0];
1878 : // if (LIST >= 4) gio::write(Unit21, Format_900) << " Dr4:" << C << F[1] << DF[1];
1879 : }
1880 : }
1881 0 : return NF;
1882 : }
1883 :
1884 132 : int ConstantPressureDrop::calculate([[maybe_unused]] EnergyPlusData &state,
1885 : [[maybe_unused]] bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
1886 : const Real64 PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
1887 : int const i, // Linkage number
1888 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
1889 : [[maybe_unused]] const Real64 control, // Element control signal
1890 : const AirState &propN, // Node 1 properties
1891 : [[maybe_unused]] const AirState &propM, // Node 2 properties
1892 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
1893 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
1894 : )
1895 : {
1896 :
1897 : // SUBROUTINE INFORMATION:
1898 : // AUTHOR George Walton
1899 : // DATE WRITTEN Extracted from AIRNET
1900 : // MODIFIED Lixing Gu, 2/1/04
1901 : // Revised the subroutine to meet E+ needs
1902 : // MODIFIED Lixing Gu, 6/8/05
1903 :
1904 : // PURPOSE OF THIS SUBROUTINE:
1905 : // This subroutine solves airflow for a Constant pressure drop component
1906 :
1907 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1908 : // Real64 Co;
1909 :
1910 132 : int n = state.afn->AirflowNetworkLinkageData(i).NodeNums[0];
1911 132 : int m = state.afn->AirflowNetworkLinkageData(i).NodeNums[1];
1912 :
1913 : // Get component properties
1914 : // A = Cross section area [m2]
1915 : // DP = Pressure difference across the element [Pa]
1916 :
1917 132 : if (PDROP == 0.0) {
1918 12 : F[0] = std::sqrt(2.0 * propN.density) * A * std::sqrt(DP);
1919 12 : DF[0] = 0.5 * F[0] / DP;
1920 : } else {
1921 2476 : for (int k = 1; k <= state.afn->ActualNumOfLinks; ++k) {
1922 2476 : if (state.afn->AirflowNetworkLinkageData(k).NodeNums[1] == n) {
1923 120 : F[0] = state.afn->AFLOW(k);
1924 120 : break;
1925 : }
1926 : }
1927 120 : state.afn->PZ(m) = state.afn->PZ(n) - DP;
1928 : // Co = F[0] / DP; // can be deleted since it is not used
1929 120 : DF[0] = 10.e10;
1930 : }
1931 132 : return 1;
1932 : }
1933 :
1934 3536826 : int EffectiveLeakageArea::calculate([[maybe_unused]] EnergyPlusData &state,
1935 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
1936 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
1937 : [[maybe_unused]] int const i, // Linkage number
1938 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
1939 : [[maybe_unused]] const Real64 control, // Element control signal
1940 : const AirState &propN, // Node 1 properties
1941 : const AirState &propM, // Node 2 properties
1942 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
1943 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
1944 : )
1945 : {
1946 :
1947 : // SUBROUTINE INFORMATION:
1948 : // AUTHOR George Walton
1949 : // DATE WRITTEN Extracted from AIRNET
1950 : // MODIFIED Lixing Gu, 2/1/04
1951 : // Revised the subroutine to meet E+ needs
1952 : // MODIFIED Lixing Gu, 6/8/05
1953 : // RE-ENGINEERED na
1954 :
1955 : // PURPOSE OF THIS SUBROUTINE:
1956 : // This subroutine solves airflow for a Surface effective leakage area component
1957 :
1958 : // SUBROUTINE PARAMETER DEFINITIONS:
1959 : static Real64 const sqrt_2(std::sqrt(2.0));
1960 :
1961 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1962 : Real64 CDM;
1963 : Real64 FL;
1964 : Real64 FT;
1965 : Real64 FlowCoef;
1966 :
1967 : // Formats
1968 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
1969 :
1970 : // Get component properties
1971 3536826 : FlowCoef = ELA * DischCoeff * sqrt_2 * std::pow(RefDeltaP, 0.5 - FlowExpo);
1972 :
1973 3536826 : if (LFLAG) {
1974 : // Initialization by linear relation.
1975 0 : if (PDROP >= 0.0) {
1976 0 : DF[0] = FlowCoef * propN.density / propN.viscosity;
1977 : } else {
1978 0 : DF[0] = FlowCoef * propM.density / propM.viscosity;
1979 : }
1980 0 : F[0] = -DF[0] * PDROP;
1981 : } else {
1982 : // Standard calculation.
1983 3536826 : if (PDROP >= 0.0) {
1984 : // Flow in positive direction.
1985 : // Laminar flow.
1986 1813488 : CDM = FlowCoef * propN.density / propN.viscosity;
1987 1813488 : FL = CDM * PDROP;
1988 : // Turbulent flow.
1989 1813488 : if (FlowExpo == 0.5) {
1990 0 : FT = FlowCoef * propN.sqrt_density * std::sqrt(PDROP);
1991 : } else {
1992 1813488 : FT = FlowCoef * propN.sqrt_density * std::pow(PDROP, FlowExpo);
1993 : }
1994 : } else {
1995 : // Flow in negative direction.
1996 : // Laminar flow.
1997 1723338 : CDM = FlowCoef * propM.density / propM.viscosity;
1998 1723338 : FL = CDM * PDROP;
1999 : // Turbulent flow.
2000 1723338 : if (FlowExpo == 0.5) {
2001 0 : FT = -FlowCoef * propM.sqrt_density * std::sqrt(-PDROP);
2002 : } else {
2003 1723338 : FT = -FlowCoef * propM.sqrt_density * std::pow(-PDROP, FlowExpo);
2004 : }
2005 : }
2006 : // Select laminar or turbulent flow.
2007 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " plr: " << i << PDROP << FL << FT;
2008 3536826 : if (std::abs(FL) <= std::abs(FT)) {
2009 168 : F[0] = FL;
2010 168 : DF[0] = CDM;
2011 : } else {
2012 3536658 : F[0] = FT;
2013 3536658 : DF[0] = FT * FlowExpo / PDROP;
2014 : }
2015 : }
2016 3536826 : return 1;
2017 : }
2018 :
2019 0 : int EffectiveLeakageArea::calculate([[maybe_unused]] EnergyPlusData &state,
2020 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
2021 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
2022 : [[maybe_unused]] const Real64 control, // Element control signal
2023 : const AirState &propN, // Node 1 properties
2024 : const AirState &propM, // Node 2 properties
2025 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
2026 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
2027 : )
2028 : {
2029 :
2030 : // SUBROUTINE INFORMATION:
2031 : // AUTHOR George Walton
2032 : // DATE WRITTEN Extracted from AIRNET
2033 : // MODIFIED Lixing Gu, 2/1/04
2034 : // Revised the subroutine to meet E+ needs
2035 : // MODIFIED Lixing Gu, 6/8/05
2036 : // RE-ENGINEERED na
2037 :
2038 : // PURPOSE OF THIS SUBROUTINE:
2039 : // This subroutine solves airflow for a Surface effective leakage area component
2040 :
2041 : // SUBROUTINE PARAMETER DEFINITIONS:
2042 : static Real64 const sqrt_2(std::sqrt(2.0));
2043 :
2044 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2045 : Real64 CDM;
2046 : Real64 FL;
2047 : Real64 FT;
2048 : Real64 FlowCoef;
2049 :
2050 : // Formats
2051 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
2052 :
2053 : // Get component properties
2054 0 : FlowCoef = ELA * DischCoeff * sqrt_2 * std::pow(RefDeltaP, 0.5 - FlowExpo);
2055 :
2056 : // Standard calculation.
2057 0 : if (PDROP >= 0.0) {
2058 : // Flow in positive direction.
2059 : // Laminar flow.
2060 0 : CDM = FlowCoef * propN.density / propN.viscosity;
2061 0 : FL = CDM * PDROP;
2062 : // Turbulent flow.
2063 0 : if (FlowExpo == 0.5) {
2064 0 : FT = FlowCoef * propN.sqrt_density * std::sqrt(PDROP);
2065 : } else {
2066 0 : FT = FlowCoef * propN.sqrt_density * std::pow(PDROP, FlowExpo);
2067 : }
2068 : } else {
2069 : // Flow in negative direction.
2070 : // Laminar flow.
2071 0 : CDM = FlowCoef * propM.density / propM.viscosity;
2072 0 : FL = CDM * PDROP;
2073 : // Turbulent flow.
2074 0 : if (FlowExpo == 0.5) {
2075 0 : FT = -FlowCoef * propM.sqrt_density * std::sqrt(-PDROP);
2076 : } else {
2077 0 : FT = -FlowCoef * propM.sqrt_density * std::pow(-PDROP, FlowExpo);
2078 : }
2079 : }
2080 : // Select laminar or turbulent flow.
2081 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " plr: " << i << PDROP << FL << FT;
2082 0 : if (std::abs(FL) <= std::abs(FT)) {
2083 0 : F[0] = FL;
2084 0 : DF[0] = CDM;
2085 : } else {
2086 0 : F[0] = FT;
2087 0 : DF[0] = FT * FlowExpo / PDROP;
2088 : }
2089 :
2090 0 : return 1;
2091 : }
2092 :
2093 490145 : int DisSysCompCoilProp::calculate([[maybe_unused]] EnergyPlusData &state,
2094 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
2095 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
2096 : [[maybe_unused]] int const i, // Linkage number
2097 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
2098 : [[maybe_unused]] const Real64 control, // Element control signal
2099 : const AirState &propN, // Node 1 properties
2100 : const AirState &propM, // Node 2 properties
2101 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
2102 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
2103 : )
2104 : {
2105 :
2106 : // SUBROUTINE INFORMATION:
2107 : // AUTHOR George Walton
2108 : // DATE WRITTEN Extracted from AIRNET
2109 : // MODIFIED Lixing Gu, 2/1/04
2110 : // Revised the subroutine to meet E+ needs
2111 : // MODIFIED Lixing Gu, 6/8/05
2112 : // RE-ENGINEERED na
2113 :
2114 : // PURPOSE OF THIS SUBROUTINE:
2115 : // This subroutine solves airflow for a coil component
2116 :
2117 : // SUBROUTINE PARAMETER DEFINITIONS:
2118 490145 : Real64 constexpr C(0.868589);
2119 490145 : Real64 constexpr EPS(0.001);
2120 490145 : Real64 constexpr Rough(0.0001);
2121 490145 : Real64 constexpr InitLamCoef(128.0);
2122 490145 : Real64 constexpr LamDynCoef(64.0);
2123 490145 : Real64 constexpr LamFriCoef(0.0001);
2124 490145 : Real64 constexpr TurDynCoef(0.0001);
2125 :
2126 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2127 : Real64 A0;
2128 : Real64 A1;
2129 : Real64 A2;
2130 : Real64 B;
2131 : Real64 D;
2132 : Real64 S2;
2133 : Real64 CDM;
2134 : Real64 FL;
2135 : Real64 FT;
2136 : Real64 FTT;
2137 : Real64 RE;
2138 : Real64 ed;
2139 : Real64 ld;
2140 : Real64 g;
2141 : Real64 AA1;
2142 : Real64 area;
2143 :
2144 : // Formats
2145 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
2146 :
2147 : // Get component properties
2148 : // ed = Rough / DisSysCompCoilData(CompNum).hydraulicDiameter;
2149 490145 : ed = Rough / hydraulicDiameter;
2150 :
2151 490145 : area = square(hydraulicDiameter) * Constant::Pi;
2152 490145 : ld = L / hydraulicDiameter;
2153 490145 : g = 1.14 - 0.868589 * std::log(ed);
2154 490145 : AA1 = g;
2155 :
2156 490145 : if (LFLAG) {
2157 : // Initialization by linear relation.
2158 2 : if (PDROP >= 0.0) {
2159 1 : DF[0] = (2.0 * propN.density * area * hydraulicDiameter) / (propN.viscosity * InitLamCoef * ld);
2160 : } else {
2161 1 : DF[0] = (2.0 * propM.density * area * hydraulicDiameter) / (propM.viscosity * InitLamCoef * ld);
2162 : }
2163 2 : F[0] = -DF[0] * PDROP;
2164 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwi:" << i << InitLamCoef << F[0] << DF[0];
2165 : } else {
2166 : // Standard calculation.
2167 490143 : if (PDROP >= 0.0) {
2168 : // Flow in positive direction.
2169 : // Laminar flow coefficient !=0
2170 : if (LamFriCoef >= 0.001) {
2171 : A2 = LamFriCoef / (2.0 * propN.density * area * area);
2172 : A1 = (propN.viscosity * LamDynCoef * ld) / (2.0 * propN.density * area * hydraulicDiameter);
2173 : A0 = -PDROP;
2174 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
2175 : FL = (CDM - A1) / (2.0 * A2);
2176 : CDM = 1.0 / CDM;
2177 : } else {
2178 437295 : CDM = (2.0 * propN.density * area * hydraulicDiameter) / (propN.viscosity * LamDynCoef * ld);
2179 437295 : FL = CDM * PDROP;
2180 : }
2181 437295 : RE = FL * hydraulicDiameter / (propN.viscosity * area);
2182 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwl:" << i << PDROP << FL << CDM << RE;
2183 : // Turbulent flow; test when Re>10.
2184 437295 : if (RE >= 10.0) {
2185 414072 : S2 = std::sqrt(2.0 * propN.density * PDROP) * area;
2186 414072 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2187 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << S2 << FTT << g;
2188 : while (true) {
2189 1573913 : FT = FTT;
2190 1573913 : B = (9.3 * propN.viscosity * area) / (FT * Rough);
2191 1573913 : D = 1.0 + g * B;
2192 1573913 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
2193 1573913 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2194 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << B << FTT << g;
2195 1573913 : if (std::abs(FTT - FT) / FTT < EPS) break;
2196 : }
2197 414072 : FT = FTT;
2198 : } else {
2199 23223 : FT = FL;
2200 : }
2201 : } else {
2202 : // Flow in negative direction.
2203 : // Laminar flow coefficient !=0
2204 : if (LamFriCoef >= 0.001) {
2205 : A2 = LamFriCoef / (2.0 * propM.density * area * area);
2206 : A1 = (propM.viscosity * LamDynCoef * ld) / (2.0 * propM.density * area * hydraulicDiameter);
2207 : A0 = PDROP;
2208 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
2209 : FL = -(CDM - A1) / (2.0 * A2);
2210 : CDM = 1.0 / CDM;
2211 : } else {
2212 52848 : CDM = (2.0 * propM.density * area * hydraulicDiameter) / (propM.viscosity * LamDynCoef * ld);
2213 52848 : FL = CDM * PDROP;
2214 : }
2215 52848 : RE = -FL * hydraulicDiameter / (propM.viscosity * area);
2216 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwl:" << i << PDROP << FL << CDM << RE;
2217 : // Turbulent flow; test when Re>10.
2218 52848 : if (RE >= 10.0) {
2219 52848 : S2 = std::sqrt(-2.0 * propM.density * PDROP) * area;
2220 52848 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2221 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << S2 << FTT << g;
2222 : while (true) {
2223 136306 : FT = FTT;
2224 136306 : B = (9.3 * propM.viscosity * area) / (FT * Rough);
2225 136306 : D = 1.0 + g * B;
2226 136306 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
2227 136306 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2228 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << B << FTT << g;
2229 136306 : if (std::abs(FTT - FT) / FTT < EPS) break;
2230 : }
2231 52848 : FT = -FTT;
2232 : } else {
2233 0 : FT = FL;
2234 : }
2235 : }
2236 : // Select laminar or turbulent flow.
2237 490143 : if (std::abs(FL) <= std::abs(FT)) {
2238 23224 : F[0] = FL;
2239 23224 : DF[0] = CDM;
2240 : } else {
2241 466919 : F[0] = FT;
2242 466919 : DF[0] = 0.5 * FT / PDROP;
2243 : }
2244 : }
2245 490145 : return 1;
2246 : }
2247 :
2248 0 : int DisSysCompCoilProp::calculate([[maybe_unused]] EnergyPlusData &state,
2249 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
2250 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
2251 : [[maybe_unused]] const Real64 control, // Element control signal
2252 : const AirState &propN, // Node 1 properties
2253 : const AirState &propM, // Node 2 properties
2254 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
2255 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
2256 : )
2257 : {
2258 :
2259 : // SUBROUTINE INFORMATION:
2260 : // AUTHOR George Walton
2261 : // DATE WRITTEN Extracted from AIRNET
2262 : // MODIFIED Lixing Gu, 2/1/04
2263 : // Revised the subroutine to meet E+ needs
2264 : // MODIFIED Lixing Gu, 6/8/05
2265 : // RE-ENGINEERED na
2266 :
2267 : // PURPOSE OF THIS SUBROUTINE:
2268 : // This subroutine solves airflow for a coil component
2269 :
2270 : // SUBROUTINE PARAMETER DEFINITIONS:
2271 0 : Real64 constexpr C(0.868589);
2272 0 : Real64 constexpr EPS(0.001);
2273 0 : Real64 constexpr Rough(0.0001);
2274 0 : Real64 constexpr LamDynCoef(64.0);
2275 0 : Real64 constexpr LamFriCoef(0.0001);
2276 0 : Real64 constexpr TurDynCoef(0.0001);
2277 :
2278 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2279 : Real64 A0;
2280 : Real64 A1;
2281 : Real64 A2;
2282 : Real64 B;
2283 : Real64 D;
2284 : Real64 S2;
2285 : Real64 CDM;
2286 : Real64 FL;
2287 : Real64 FT;
2288 : Real64 FTT;
2289 : Real64 RE;
2290 : Real64 ed;
2291 : Real64 ld;
2292 : Real64 g;
2293 : Real64 AA1;
2294 : Real64 area;
2295 :
2296 : // Formats
2297 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
2298 :
2299 : // Get component properties
2300 : // ed = Rough / DisSysCompCoilData(CompNum).hydraulicDiameter;
2301 0 : ed = Rough / hydraulicDiameter;
2302 :
2303 0 : area = square(hydraulicDiameter) * Constant::Pi;
2304 0 : ld = L / hydraulicDiameter;
2305 0 : g = 1.14 - 0.868589 * std::log(ed);
2306 0 : AA1 = g;
2307 :
2308 : // Standard calculation.
2309 0 : if (PDROP >= 0.0) {
2310 : // Flow in positive direction.
2311 : // Laminar flow coefficient !=0
2312 : if (LamFriCoef >= 0.001) {
2313 : A2 = LamFriCoef / (2.0 * propN.density * area * area);
2314 : A1 = (propN.viscosity * LamDynCoef * ld) / (2.0 * propN.density * area * hydraulicDiameter);
2315 : A0 = -PDROP;
2316 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
2317 : FL = (CDM - A1) / (2.0 * A2);
2318 : CDM = 1.0 / CDM;
2319 : } else {
2320 0 : CDM = (2.0 * propN.density * area * hydraulicDiameter) / (propN.viscosity * LamDynCoef * ld);
2321 0 : FL = CDM * PDROP;
2322 : }
2323 0 : RE = FL * hydraulicDiameter / (propN.viscosity * area);
2324 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwl:" << i << PDROP << FL << CDM << RE;
2325 : // Turbulent flow; test when Re>10.
2326 0 : if (RE >= 10.0) {
2327 0 : S2 = std::sqrt(2.0 * propN.density * PDROP) * area;
2328 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2329 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << S2 << FTT << g;
2330 : while (true) {
2331 0 : FT = FTT;
2332 0 : B = (9.3 * propN.viscosity * area) / (FT * Rough);
2333 0 : D = 1.0 + g * B;
2334 0 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
2335 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2336 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << B << FTT << g;
2337 0 : if (std::abs(FTT - FT) / FTT < EPS) break;
2338 : }
2339 0 : FT = FTT;
2340 : } else {
2341 0 : FT = FL;
2342 : }
2343 : } else {
2344 : // Flow in negative direction.
2345 : // Laminar flow coefficient !=0
2346 : if (LamFriCoef >= 0.001) {
2347 : A2 = LamFriCoef / (2.0 * propM.density * area * area);
2348 : A1 = (propM.viscosity * LamDynCoef * ld) / (2.0 * propM.density * area * hydraulicDiameter);
2349 : A0 = PDROP;
2350 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
2351 : FL = -(CDM - A1) / (2.0 * A2);
2352 : CDM = 1.0 / CDM;
2353 : } else {
2354 0 : CDM = (2.0 * propM.density * area * hydraulicDiameter) / (propM.viscosity * LamDynCoef * ld);
2355 0 : FL = CDM * PDROP;
2356 : }
2357 0 : RE = -FL * hydraulicDiameter / (propM.viscosity * area);
2358 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwl:" << i << PDROP << FL << CDM << RE;
2359 : // Turbulent flow; test when Re>10.
2360 0 : if (RE >= 10.0) {
2361 0 : S2 = std::sqrt(-2.0 * propM.density * PDROP) * area;
2362 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2363 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << S2 << FTT << g;
2364 : while (true) {
2365 0 : FT = FTT;
2366 0 : B = (9.3 * propM.viscosity * area) / (FT * Rough);
2367 0 : D = 1.0 + g * B;
2368 0 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
2369 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2370 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << B << FTT << g;
2371 0 : if (std::abs(FTT - FT) / FTT < EPS) break;
2372 : }
2373 0 : FT = -FTT;
2374 : } else {
2375 0 : FT = FL;
2376 : }
2377 : }
2378 : // Select laminar or turbulent flow.
2379 0 : if (std::abs(FL) <= std::abs(FT)) {
2380 0 : F[0] = FL;
2381 0 : DF[0] = CDM;
2382 : } else {
2383 0 : F[0] = FT;
2384 0 : DF[0] = 0.5 * FT / PDROP;
2385 : }
2386 0 : return 1;
2387 : }
2388 :
2389 224 : int DisSysCompTermUnitProp::calculate([[maybe_unused]] EnergyPlusData &state,
2390 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
2391 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
2392 : int const i, // Linkage number
2393 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
2394 : [[maybe_unused]] const Real64 control, // Element control signal
2395 : const AirState &propN, // Node 1 properties
2396 : const AirState &propM, // Node 2 properties
2397 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
2398 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
2399 : )
2400 : {
2401 :
2402 : // SUBROUTINE INFORMATION:
2403 : // AUTHOR George Walton
2404 : // DATE WRITTEN Extracted from AIRNET
2405 : // MODIFIED Lixing Gu, 2/1/04
2406 : // Revised the subroutine to meet E+ needs
2407 : // MODIFIED Lixing Gu, 6/8/05
2408 : // RE-ENGINEERED na
2409 :
2410 : // PURPOSE OF THIS SUBROUTINE:
2411 : // This subroutine solves airflow for a terminal unit component
2412 :
2413 : // SUBROUTINE PARAMETER DEFINITIONS:
2414 224 : Real64 constexpr C(0.868589);
2415 224 : Real64 constexpr EPS(0.001);
2416 224 : Real64 constexpr Rough(0.0001);
2417 224 : Real64 constexpr InitLamCoef(128.0);
2418 224 : Real64 constexpr LamDynCoef(64.0);
2419 224 : Real64 constexpr LamFriCoef(0.0001);
2420 224 : Real64 constexpr TurDynCoef(0.0001);
2421 :
2422 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2423 : Real64 A0;
2424 : Real64 A1;
2425 : Real64 A2;
2426 : Real64 B;
2427 : Real64 D;
2428 : Real64 S2;
2429 : Real64 CDM;
2430 : Real64 FL;
2431 : Real64 FT;
2432 : Real64 FTT;
2433 : Real64 RE;
2434 : Real64 ed;
2435 : Real64 ld;
2436 : Real64 g;
2437 : Real64 AA1;
2438 : Real64 area;
2439 :
2440 : // Formats
2441 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
2442 :
2443 : // Get component properties
2444 224 : ed = Rough / hydraulicDiameter;
2445 224 : area = pow_2(hydraulicDiameter) * Constant::Pi;
2446 224 : ld = L / hydraulicDiameter;
2447 224 : g = 1.14 - 0.868589 * std::log(ed);
2448 224 : AA1 = g;
2449 :
2450 224 : if (LFLAG) {
2451 : // Initialization by linear relation.
2452 0 : if (PDROP >= 0.0) {
2453 0 : DF[0] = (2.0 * propN.density * area * hydraulicDiameter) / (propN.viscosity * InitLamCoef * ld);
2454 : } else {
2455 0 : DF[0] = (2.0 * propM.density * area * hydraulicDiameter) / (propM.viscosity * InitLamCoef * ld);
2456 : }
2457 0 : F[0] = -DF[0] * PDROP;
2458 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwi:" << i << InitLamCoef << F[0] << DF[0];
2459 : } else {
2460 : // Standard calculation.
2461 224 : if (PDROP >= 0.0) {
2462 : // Flow in positive direction.
2463 : // Laminar flow coefficient !=0
2464 : if (LamFriCoef >= 0.001) {
2465 : A2 = LamFriCoef / (2.0 * propN.density * area * area);
2466 : A1 = (propN.viscosity * LamDynCoef * ld) / (2.0 * propN.density * area * hydraulicDiameter);
2467 : A0 = -PDROP;
2468 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
2469 : FL = (CDM - A1) / (2.0 * A2);
2470 : CDM = 1.0 / CDM;
2471 : } else {
2472 224 : CDM = (2.0 * propN.density * area * hydraulicDiameter) / (propN.viscosity * LamDynCoef * ld);
2473 224 : FL = CDM * PDROP;
2474 : }
2475 224 : RE = FL * hydraulicDiameter / (propN.viscosity * area);
2476 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwl:" << i << PDROP << FL << CDM << RE;
2477 : // Turbulent flow; test when Re>10.
2478 224 : if (RE >= 10.0) {
2479 202 : S2 = std::sqrt(2.0 * propN.density * PDROP) * area;
2480 202 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2481 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << S2 << FTT << g;
2482 : while (true) {
2483 830 : FT = FTT;
2484 830 : B = (9.3 * propN.viscosity * area) / (FT * Rough);
2485 830 : D = 1.0 + g * B;
2486 830 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
2487 830 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2488 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << B << FTT << g;
2489 830 : if (std::abs(FTT - FT) / FTT < EPS) break;
2490 : }
2491 202 : FT = FTT;
2492 : } else {
2493 22 : FT = FL;
2494 : }
2495 : } else {
2496 : // Flow in negative direction.
2497 : // Laminar flow coefficient !=0
2498 : if (LamFriCoef >= 0.001) {
2499 : A2 = LamFriCoef / (2.0 * propM.density * area * area);
2500 : A1 = (propM.viscosity * LamDynCoef * ld) / (2.0 * propM.density * area * hydraulicDiameter);
2501 : A0 = PDROP;
2502 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
2503 : FL = -(CDM - A1) / (2.0 * A2);
2504 : CDM = 1.0 / CDM;
2505 : } else {
2506 0 : CDM = (2.0 * propM.density * area * hydraulicDiameter) / (propM.viscosity * LamDynCoef * ld);
2507 0 : FL = CDM * PDROP;
2508 : }
2509 0 : RE = -FL * hydraulicDiameter / (propM.viscosity * area);
2510 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwl:" << i << PDROP << FL << CDM << RE;
2511 : // Turbulent flow; test when Re>10.
2512 0 : if (RE >= 10.0) {
2513 0 : S2 = std::sqrt(-2.0 * propM.density * PDROP) * area;
2514 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2515 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << S2 << FTT << g;
2516 : while (true) {
2517 0 : FT = FTT;
2518 0 : B = (9.3 * propM.viscosity * area) / (FT * Rough);
2519 0 : D = 1.0 + g * B;
2520 0 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
2521 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2522 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " dwt:" << i << B << FTT << g;
2523 0 : if (std::abs(FTT - FT) / FTT < EPS) break;
2524 : }
2525 0 : FT = -FTT;
2526 : } else {
2527 0 : FT = FL;
2528 : }
2529 : }
2530 : // Select laminar or turbulent flow.
2531 224 : if (std::abs(FL) <= std::abs(FT)) {
2532 44 : F[0] = FL;
2533 44 : DF[0] = CDM;
2534 : } else {
2535 180 : F[0] = FT;
2536 180 : DF[0] = 0.5 * FT / PDROP;
2537 : }
2538 : }
2539 : // If damper, setup the airflows from nodal values calculated from terminal
2540 224 : if (state.afn->AirflowNetworkLinkageData(i).VAVTermDamper) {
2541 0 : F[0] = state.dataLoopNodes->Node(DamperInletNode).MassFlowRate;
2542 0 : if (state.afn->VAVTerminalRatio > 0.0) {
2543 0 : F[0] *= state.afn->VAVTerminalRatio;
2544 : }
2545 0 : DF[0] = 0.0;
2546 : }
2547 224 : return 1;
2548 : }
2549 :
2550 0 : int DisSysCompHXProp::calculate([[maybe_unused]] EnergyPlusData &state,
2551 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
2552 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
2553 : [[maybe_unused]] int const i, // Linkage number
2554 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
2555 : [[maybe_unused]] const Real64 control, // Element control signal
2556 : const AirState &propN, // Node 1 properties
2557 : const AirState &propM, // Node 2 properties
2558 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
2559 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
2560 : )
2561 : {
2562 :
2563 : // SUBROUTINE INFORMATION:
2564 : // AUTHOR George Walton
2565 : // DATE WRITTEN Extracted from AIRNET
2566 : // MODIFIED Lixing Gu, 2/1/04
2567 : // Revised the subroutine to meet E+ needs
2568 : // MODIFIED Lixing Gu, 1/18/09
2569 : // RE-ENGINEERED na
2570 :
2571 : // PURPOSE OF THIS SUBROUTINE:
2572 : // This subroutine solves airflow for a heat exchanger component
2573 :
2574 : // SUBROUTINE PARAMETER DEFINITIONS:
2575 0 : Real64 constexpr C(0.868589);
2576 0 : Real64 constexpr EPS(0.001);
2577 0 : Real64 constexpr Rough(0.0001);
2578 0 : Real64 constexpr InitLamCoef(128.0);
2579 0 : Real64 constexpr LamDynCoef(64.0);
2580 0 : Real64 constexpr LamFriCoef(0.0001);
2581 0 : Real64 constexpr TurDynCoef(0.0001);
2582 :
2583 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2584 : Real64 A0;
2585 : Real64 A1;
2586 : Real64 A2;
2587 : Real64 B;
2588 : Real64 D;
2589 : Real64 S2;
2590 : Real64 CDM;
2591 : Real64 FL;
2592 : Real64 FT;
2593 : Real64 FTT;
2594 : Real64 RE;
2595 : Real64 ed;
2596 : Real64 ld;
2597 : Real64 g;
2598 : Real64 AA1;
2599 : Real64 area;
2600 :
2601 : // Get component properties
2602 0 : ed = Rough / hydraulicDiameter;
2603 0 : area = pow_2(hydraulicDiameter) * Constant::Pi;
2604 0 : ld = L / hydraulicDiameter;
2605 0 : g = 1.14 - 0.868589 * std::log(ed);
2606 0 : AA1 = g;
2607 :
2608 0 : if (LFLAG) {
2609 : // Initialization by linear relation.
2610 0 : if (PDROP >= 0.0) {
2611 0 : DF[0] = (2.0 * propN.density * area * hydraulicDiameter) / (propN.viscosity * InitLamCoef * ld);
2612 : } else {
2613 0 : DF[0] = (2.0 * propM.density * area * hydraulicDiameter) / (propM.viscosity * InitLamCoef * ld);
2614 : }
2615 0 : F[0] = -DF[0] * PDROP;
2616 : } else {
2617 : // Standard calculation.
2618 0 : if (PDROP >= 0.0) {
2619 : // Flow in positive direction.
2620 : // Laminar flow coefficient !=0
2621 : if (LamFriCoef >= 0.001) {
2622 : A2 = LamFriCoef / (2.0 * propN.density * area * area);
2623 : A1 = (propN.viscosity * LamDynCoef * ld) / (2.0 * propN.density * area * hydraulicDiameter);
2624 : A0 = -PDROP;
2625 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
2626 : FL = (CDM - A1) / (2.0 * A2);
2627 : CDM = 1.0 / CDM;
2628 : } else {
2629 0 : CDM = (2.0 * propN.density * area * hydraulicDiameter) / (propN.viscosity * LamDynCoef * ld);
2630 0 : FL = CDM * PDROP;
2631 : }
2632 0 : RE = FL * hydraulicDiameter / (propN.viscosity * area);
2633 : // Turbulent flow; test when Re>10.
2634 0 : if (RE >= 10.0) {
2635 0 : S2 = std::sqrt(2.0 * propN.density * PDROP) * area;
2636 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2637 : while (true) {
2638 0 : FT = FTT;
2639 0 : B = (9.3 * propN.viscosity * area) / (FT * Rough);
2640 0 : D = 1.0 + g * B;
2641 0 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
2642 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2643 0 : if (std::abs(FTT - FT) / FTT < EPS) break;
2644 : }
2645 0 : FT = FTT;
2646 : } else {
2647 0 : FT = FL;
2648 : }
2649 : } else {
2650 : // Flow in negative direction.
2651 : // Laminar flow coefficient !=0
2652 : if (LamFriCoef >= 0.001) {
2653 : A2 = LamFriCoef / (2.0 * propM.density * area * area);
2654 : A1 = (propM.viscosity * LamDynCoef * ld) / (2.0 * propM.density * area * hydraulicDiameter);
2655 : A0 = PDROP;
2656 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
2657 : FL = -(CDM - A1) / (2.0 * A2);
2658 : CDM = 1.0 / CDM;
2659 : } else {
2660 0 : CDM = (2.0 * propM.density * area * hydraulicDiameter) / (propM.viscosity * LamDynCoef * ld);
2661 0 : FL = CDM * PDROP;
2662 : }
2663 0 : RE = -FL * hydraulicDiameter / (propM.viscosity * area);
2664 : // Turbulent flow; test when Re>10.
2665 0 : if (RE >= 10.0) {
2666 0 : S2 = std::sqrt(-2.0 * propM.density * PDROP) * area;
2667 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2668 : while (true) {
2669 0 : FT = FTT;
2670 0 : B = (9.3 * propM.viscosity * area) / (FT * Rough);
2671 0 : D = 1.0 + g * B;
2672 0 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
2673 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2674 0 : if (std::abs(FTT - FT) / FTT < EPS) break;
2675 : }
2676 0 : FT = -FTT;
2677 : } else {
2678 0 : FT = FL;
2679 : }
2680 : }
2681 : // Select laminar or turbulent flow.
2682 0 : if (std::abs(FL) <= std::abs(FT)) {
2683 0 : F[0] = FL;
2684 0 : DF[0] = CDM;
2685 : } else {
2686 0 : F[0] = FT;
2687 0 : DF[0] = 0.5 * FT / PDROP;
2688 : }
2689 : }
2690 0 : return 1;
2691 : }
2692 :
2693 0 : int DisSysCompHXProp::calculate([[maybe_unused]] EnergyPlusData &state,
2694 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
2695 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
2696 : [[maybe_unused]] const Real64 control, // Element control signal
2697 : const AirState &propN, // Node 1 properties
2698 : const AirState &propM, // Node 2 properties
2699 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
2700 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
2701 : )
2702 : {
2703 :
2704 : // SUBROUTINE INFORMATION:
2705 : // AUTHOR George Walton
2706 : // DATE WRITTEN Extracted from AIRNET
2707 : // MODIFIED Lixing Gu, 2/1/04
2708 : // Revised the subroutine to meet E+ needs
2709 : // MODIFIED Lixing Gu, 1/18/09
2710 : // RE-ENGINEERED na
2711 :
2712 : // PURPOSE OF THIS SUBROUTINE:
2713 : // This subroutine solves airflow for a heat exchanger component
2714 :
2715 : // SUBROUTINE PARAMETER DEFINITIONS:
2716 0 : Real64 constexpr C(0.868589);
2717 0 : Real64 constexpr EPS(0.001);
2718 0 : Real64 constexpr Rough(0.0001);
2719 0 : Real64 constexpr LamDynCoef(64.0);
2720 0 : Real64 constexpr LamFriCoef(0.0001);
2721 0 : Real64 constexpr TurDynCoef(0.0001);
2722 :
2723 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2724 : Real64 A0;
2725 : Real64 A1;
2726 : Real64 A2;
2727 : Real64 B;
2728 : Real64 D;
2729 : Real64 S2;
2730 : Real64 CDM;
2731 : Real64 FL;
2732 : Real64 FT;
2733 : Real64 FTT;
2734 : Real64 RE;
2735 : Real64 ed;
2736 : Real64 ld;
2737 : Real64 g;
2738 : Real64 AA1;
2739 : Real64 area;
2740 :
2741 : // Get component properties
2742 0 : ed = Rough / hydraulicDiameter;
2743 0 : area = pow_2(hydraulicDiameter) * Constant::Pi;
2744 0 : ld = L / hydraulicDiameter;
2745 0 : g = 1.14 - 0.868589 * std::log(ed);
2746 0 : AA1 = g;
2747 :
2748 : // Standard calculation.
2749 0 : if (PDROP >= 0.0) {
2750 : // Flow in positive direction.
2751 : // Laminar flow coefficient !=0
2752 : if (LamFriCoef >= 0.001) {
2753 : A2 = LamFriCoef / (2.0 * propN.density * area * area);
2754 : A1 = (propN.viscosity * LamDynCoef * ld) / (2.0 * propN.density * area * hydraulicDiameter);
2755 : A0 = -PDROP;
2756 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
2757 : FL = (CDM - A1) / (2.0 * A2);
2758 : CDM = 1.0 / CDM;
2759 : } else {
2760 0 : CDM = (2.0 * propN.density * area * hydraulicDiameter) / (propN.viscosity * LamDynCoef * ld);
2761 0 : FL = CDM * PDROP;
2762 : }
2763 0 : RE = FL * hydraulicDiameter / (propN.viscosity * area);
2764 : // Turbulent flow; test when Re>10.
2765 0 : if (RE >= 10.0) {
2766 0 : S2 = std::sqrt(2.0 * propN.density * PDROP) * area;
2767 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2768 : while (true) {
2769 0 : FT = FTT;
2770 0 : B = (9.3 * propN.viscosity * area) / (FT * Rough);
2771 0 : D = 1.0 + g * B;
2772 0 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
2773 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2774 0 : if (std::abs(FTT - FT) / FTT < EPS) break;
2775 : }
2776 0 : FT = FTT;
2777 : } else {
2778 0 : FT = FL;
2779 : }
2780 : } else {
2781 : // Flow in negative direction.
2782 : // Laminar flow coefficient !=0
2783 : if (LamFriCoef >= 0.001) {
2784 : A2 = LamFriCoef / (2.0 * propM.density * area * area);
2785 : A1 = (propM.viscosity * LamDynCoef * ld) / (2.0 * propM.density * area * hydraulicDiameter);
2786 : A0 = PDROP;
2787 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
2788 : FL = -(CDM - A1) / (2.0 * A2);
2789 : CDM = 1.0 / CDM;
2790 : } else {
2791 0 : CDM = (2.0 * propM.density * area * hydraulicDiameter) / (propM.viscosity * LamDynCoef * ld);
2792 0 : FL = CDM * PDROP;
2793 : }
2794 0 : RE = -FL * hydraulicDiameter / (propM.viscosity * area);
2795 : // Turbulent flow; test when Re>10.
2796 0 : if (RE >= 10.0) {
2797 0 : S2 = std::sqrt(-2.0 * propM.density * PDROP) * area;
2798 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2799 : while (true) {
2800 0 : FT = FTT;
2801 0 : B = (9.3 * propM.viscosity * area) / (FT * Rough);
2802 0 : D = 1.0 + g * B;
2803 0 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
2804 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
2805 0 : if (std::abs(FTT - FT) / FTT < EPS) break;
2806 : }
2807 0 : FT = -FTT;
2808 : } else {
2809 0 : FT = FL;
2810 : }
2811 : }
2812 : // Select laminar or turbulent flow.
2813 0 : if (std::abs(FL) <= std::abs(FT)) {
2814 0 : F[0] = FL;
2815 0 : DF[0] = CDM;
2816 : } else {
2817 0 : F[0] = FT;
2818 0 : DF[0] = 0.5 * FT / PDROP;
2819 : }
2820 0 : return 1;
2821 : }
2822 :
2823 196615 : int ZoneExhaustFan::calculate(EnergyPlusData &state,
2824 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
2825 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
2826 : int const i, // Linkage number
2827 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
2828 : [[maybe_unused]] const Real64 control, // Element control signal
2829 : const AirState &propN, // Node 1 properties
2830 : const AirState &propM, // Node 2 properties
2831 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
2832 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
2833 : )
2834 : {
2835 : // SUBROUTINE INFORMATION:
2836 : // AUTHOR George Walton
2837 : // DATE WRITTEN Extracted from AIRNET
2838 : // MODIFIED Lixing Gu, 12/17/06
2839 : // Revised for zone exhaust fan
2840 : // RE-ENGINEERED na
2841 :
2842 : // PURPOSE OF THIS SUBROUTINE:
2843 : // This subroutine solves airflow for a surface crack component
2844 :
2845 : // Using/Aliasing
2846 : using HVAC::VerySmallMassFlow;
2847 :
2848 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2849 : Real64 CDM;
2850 : Real64 FL;
2851 : Real64 FT;
2852 : Real64 RhozNorm;
2853 : Real64 VisczNorm;
2854 : Real64 expn;
2855 : Real64 Ctl;
2856 : Real64 coef;
2857 : Real64 Corr;
2858 : Real64 VisAve;
2859 : Real64 Tave;
2860 : Real64 RhoCor;
2861 : // int InletNode;
2862 :
2863 : // Formats
2864 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
2865 :
2866 196615 : if (state.dataLoopNodes->Node(InletNode).MassFlowRate > VerySmallMassFlow) {
2867 : // Treat the component as an exhaust fan
2868 180191 : if (state.afn->PressureSetFlag == PressureCtrlExhaust) {
2869 0 : F[0] = state.afn->ExhaustFanMassFlowRate;
2870 : } else {
2871 180191 : F[0] = state.dataLoopNodes->Node(InletNode).MassFlowRate;
2872 : }
2873 180191 : DF[0] = 0.0;
2874 180191 : return 1;
2875 : } else {
2876 : // Treat the component as a surface crack
2877 : // Crack standard condition from given inputs
2878 16424 : Corr = state.afn->MultizoneSurfaceData(i).Factor;
2879 16424 : RhozNorm = state.afn->properties.density(StandardP, StandardT, StandardW);
2880 16424 : VisczNorm = 1.71432e-5 + 4.828e-8 * StandardT;
2881 :
2882 16424 : expn = FlowExpo;
2883 16424 : VisAve = (propN.viscosity + propM.viscosity) / 2.0;
2884 16424 : Tave = (propN.temperature + propM.temperature) / 2.0;
2885 16424 : if (PDROP >= 0.0) {
2886 12837 : coef = FlowCoef / propN.sqrt_density * Corr;
2887 : } else {
2888 3587 : coef = FlowCoef / propM.sqrt_density * Corr;
2889 : }
2890 :
2891 16424 : if (LFLAG) {
2892 : // Initialization by linear relation.
2893 0 : if (PDROP >= 0.0) {
2894 0 : RhoCor = TOKELVIN(propN.temperature) / TOKELVIN(Tave);
2895 0 : Ctl = std::pow(RhozNorm / propN.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
2896 0 : DF[0] = coef * propN.density / propN.viscosity * Ctl;
2897 : } else {
2898 0 : RhoCor = TOKELVIN(propM.temperature) / TOKELVIN(Tave);
2899 0 : Ctl = std::pow(RhozNorm / propM.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
2900 0 : DF[0] = coef * propM.density / propM.viscosity * Ctl;
2901 : }
2902 0 : F[0] = -DF[0] * PDROP;
2903 : } else {
2904 : // Standard calculation.
2905 16424 : if (PDROP >= 0.0) {
2906 : // Flow in positive direction.
2907 : // Laminar flow.
2908 12837 : RhoCor = TOKELVIN(propN.temperature) / TOKELVIN(Tave);
2909 12837 : Ctl = std::pow(RhozNorm / propN.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
2910 12837 : CDM = coef * propN.density / propN.viscosity * Ctl;
2911 12837 : FL = CDM * PDROP;
2912 : // Turbulent flow.
2913 12837 : if (expn == 0.5) {
2914 0 : FT = coef * propN.sqrt_density * std::sqrt(PDROP) * Ctl;
2915 : } else {
2916 12837 : FT = coef * propN.sqrt_density * std::pow(PDROP, expn) * Ctl;
2917 : }
2918 : } else {
2919 : // Flow in negative direction.
2920 : // Laminar flow.
2921 3587 : RhoCor = TOKELVIN(propM.temperature) / TOKELVIN(Tave);
2922 3587 : Ctl = std::pow(RhozNorm / propM.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
2923 3587 : CDM = coef * propM.density / propM.viscosity * Ctl;
2924 3587 : FL = CDM * PDROP;
2925 : // Turbulent flow.
2926 3587 : if (expn == 0.5) {
2927 0 : FT = -coef * propM.sqrt_density * std::sqrt(-PDROP) * Ctl;
2928 : } else {
2929 3587 : FT = -coef * propM.sqrt_density * std::pow(-PDROP, expn) * Ctl;
2930 : }
2931 : }
2932 : // Select laminar or turbulent flow.
2933 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " scr: " << i << PDROP << FL << FT;
2934 16424 : if (std::abs(FL) <= std::abs(FT)) {
2935 0 : F[0] = FL;
2936 0 : DF[0] = CDM;
2937 : } else {
2938 16424 : F[0] = FT;
2939 16424 : DF[0] = FT * expn / PDROP;
2940 : }
2941 : }
2942 : }
2943 16424 : return 1;
2944 : }
2945 :
2946 0 : int ZoneExhaustFan::calculate(EnergyPlusData &state,
2947 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
2948 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
2949 : const Real64 control, // Element control signal
2950 : const AirState &propN, // Node 1 properties
2951 : const AirState &propM, // Node 2 properties
2952 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
2953 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
2954 : )
2955 : {
2956 : // SUBROUTINE INFORMATION:
2957 : // AUTHOR George Walton
2958 : // DATE WRITTEN Extracted from AIRNET
2959 : // MODIFIED Lixing Gu, 12/17/06
2960 : // Revised for zone exhaust fan
2961 : // RE-ENGINEERED na
2962 :
2963 : // PURPOSE OF THIS SUBROUTINE:
2964 : // This subroutine solves airflow for a surface crack component
2965 :
2966 : // Using/Aliasing
2967 : using HVAC::VerySmallMassFlow;
2968 :
2969 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2970 : Real64 CDM;
2971 : Real64 FL;
2972 : Real64 FT;
2973 : Real64 RhozNorm;
2974 : Real64 VisczNorm;
2975 : Real64 expn;
2976 : Real64 Ctl;
2977 : Real64 coef;
2978 : Real64 VisAve;
2979 : Real64 Tave;
2980 : Real64 RhoCor;
2981 : // int InletNode;
2982 :
2983 : // Formats
2984 : // static gio::Fmt Format_901("(A5,I3,6X,4E16.7)");
2985 :
2986 0 : if (state.dataLoopNodes->Node(InletNode).MassFlowRate > VerySmallMassFlow) {
2987 : // Treat the component as an exhaust fan
2988 0 : if (state.afn->PressureSetFlag == PressureCtrlExhaust) {
2989 0 : F[0] = state.afn->ExhaustFanMassFlowRate;
2990 : } else {
2991 0 : F[0] = state.dataLoopNodes->Node(InletNode).MassFlowRate;
2992 : }
2993 0 : DF[0] = 0.0;
2994 0 : return 1;
2995 : } else {
2996 : // Treat the component as a surface crack
2997 : // Crack standard condition from given inputs
2998 0 : RhozNorm = state.afn->properties.density(StandardP, StandardT, StandardW);
2999 0 : VisczNorm = 1.71432e-5 + 4.828e-8 * StandardT;
3000 :
3001 0 : expn = FlowExpo;
3002 0 : VisAve = (propN.viscosity + propM.viscosity) / 2.0;
3003 0 : Tave = (propN.temperature + propM.temperature) / 2.0;
3004 0 : if (PDROP >= 0.0) {
3005 0 : coef = control * FlowCoef / propN.sqrt_density;
3006 : } else {
3007 0 : coef = control * FlowCoef / propM.sqrt_density;
3008 : }
3009 :
3010 : // Standard calculation.
3011 0 : if (PDROP >= 0.0) {
3012 : // Flow in positive direction.
3013 : // Laminar flow.
3014 0 : RhoCor = TOKELVIN(propN.temperature) / TOKELVIN(Tave);
3015 0 : Ctl = std::pow(RhozNorm / propN.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
3016 0 : CDM = coef * propN.density / propN.viscosity * Ctl;
3017 0 : FL = CDM * PDROP;
3018 : // Turbulent flow.
3019 0 : if (expn == 0.5) {
3020 0 : FT = coef * propN.sqrt_density * std::sqrt(PDROP) * Ctl;
3021 : } else {
3022 0 : FT = coef * propN.sqrt_density * std::pow(PDROP, expn) * Ctl;
3023 : }
3024 : } else {
3025 : // Flow in negative direction.
3026 : // Laminar flow.
3027 0 : RhoCor = TOKELVIN(propM.temperature) / TOKELVIN(Tave);
3028 0 : Ctl = std::pow(RhozNorm / propM.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
3029 0 : CDM = coef * propM.density / propM.viscosity * Ctl;
3030 0 : FL = CDM * PDROP;
3031 : // Turbulent flow.
3032 0 : if (expn == 0.5) {
3033 0 : FT = -coef * propM.sqrt_density * std::sqrt(-PDROP) * Ctl;
3034 : } else {
3035 0 : FT = -coef * propM.sqrt_density * std::pow(-PDROP, expn) * Ctl;
3036 : }
3037 : }
3038 : // Select laminar or turbulent flow.
3039 : // if (LIST >= 4) gio::write(Unit21, Format_901) << " scr: " << i << PDROP << FL << FT;
3040 0 : if (std::abs(FL) <= std::abs(FT)) {
3041 0 : F[0] = FL;
3042 0 : DF[0] = CDM;
3043 : } else {
3044 0 : F[0] = FT;
3045 0 : DF[0] = FT * expn / PDROP;
3046 : }
3047 : }
3048 0 : return 1;
3049 : }
3050 :
3051 2 : int HorizontalOpening::calculate(EnergyPlusData &state,
3052 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
3053 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
3054 : int const i, // Linkage number
3055 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
3056 : [[maybe_unused]] const Real64 control, // Element control signal
3057 : const AirState &propN, // Node 1 properties
3058 : const AirState &propM, // Node 2 properties
3059 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
3060 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
3061 : )
3062 : {
3063 : // SUBROUTINE INFORMATION:
3064 : // AUTHOR Lixing Gu
3065 : // DATE WRITTEN Apr. 2009
3066 : // MODIFIED na
3067 : // MODIFIED na
3068 : // RE-ENGINEERED na
3069 :
3070 : // PURPOSE OF THIS SUBROUTINE:
3071 : // This subroutine solves airflow for a horizontal opening component. The subroutine was
3072 : // developed based on the subroutine AFEPLR of AIRNET.
3073 :
3074 : // METHODOLOGY EMPLOYED:
3075 : // Combine forced and buyancy airflows together with a cap
3076 :
3077 : // REFERENCES:
3078 : // Cooper, L., 1989, "Calculation of the Flow Through a Horizontal Ceiling/Floor Vent,"
3079 : // NISTIR 89-4052, National Institute of Standards and Technology, Gaithersburg, MD
3080 :
3081 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3082 : Real64 RhozAver;
3083 : Real64 expn;
3084 : Real64 coef;
3085 : Real64 Width; // Opening width
3086 : Real64 Height; // Opening height
3087 : Real64 Fact; // Opening factor
3088 : // Real64 Slope; // Opening slope
3089 : // Real64 DischCoeff; // Discharge coefficient
3090 : Real64 fma12; // massflow in direction "from-to" [kg/s]
3091 : Real64 fma21; // massflow in direction "to-from" [kg/s]
3092 : Real64 dp1fma12; // derivative d fma12 / d Dp [kg/s/Pa]
3093 : Real64 dp1fma21; // derivative d fma21 / d Dp [kg/s/Pa]
3094 : Real64 PurgedP; // Purge pressure [Pa]
3095 : Real64 BuoFlow; // Buoyancy flow rate [Pa]
3096 : Real64 BuoFlowMax; // Maximum buoyancy flow rate [Pa]
3097 : Real64 dPBuoFlow; // Derivative of buoyancy flow rate [kg/s/Pa]
3098 : Real64 DH; // Hydraulic diameter [m]
3099 : Real64 Cshape; // Shape factor [dimensionless]
3100 : Real64 OpenArea; // Opening area [m2]
3101 :
3102 : // Get information on the horizontal opening
3103 2 : RhozAver = (propN.density + propM.density) / 2.0;
3104 2 : Width = state.afn->MultizoneSurfaceData(i).Width;
3105 2 : Height = state.afn->MultizoneSurfaceData(i).Height;
3106 2 : Fact = state.afn->MultizoneSurfaceData(i).OpenFactor;
3107 2 : expn = FlowExpo;
3108 2 : coef = FlowCoef;
3109 : // Slope = MultizoneCompHorOpeningData(CompNum).Slope;
3110 : // DischCoeff = MultizoneCompHorOpeningData(CompNum).DischCoeff;
3111 2 : Cshape = 0.942 * Width / Height;
3112 2 : OpenArea = Width * Height * Fact * std::sin(Slope * Constant::Pi / 180.0) * (1.0 + std::cos(Slope * Constant::Pi / 180.0));
3113 2 : DH = 4.0 * (Width * Height) / 2.0 / (Width + Height) * Fact;
3114 :
3115 : // Check which zone is higher
3116 2 : if (Fact == 0.0) {
3117 0 : generic_crack(coef, expn, LFLAG, PDROP, propN, propM, F, DF);
3118 0 : return 1;
3119 : }
3120 :
3121 2 : fma12 = 0.0;
3122 2 : fma21 = 0.0;
3123 2 : dp1fma12 = 0.0;
3124 2 : dp1fma21 = 0.0;
3125 2 : BuoFlow = 0.0;
3126 2 : dPBuoFlow = 0.0;
3127 :
3128 2 : if (state.afn->AirflowNetworkLinkageData(i).NodeHeights[0] > state.afn->AirflowNetworkLinkageData(i).NodeHeights[1]) {
3129 : // Node N is upper zone
3130 2 : if (propN.density > propM.density) {
3131 2 : BuoFlowMax = RhozAver * 0.055 * std::sqrt(9.81 * std::abs(propN.density - propM.density) * pow_5(DH) / RhozAver);
3132 2 : PurgedP = Cshape * Cshape * 9.81 * std::abs(propN.density - propM.density) * pow_5(DH) / (2.0 * pow_2(OpenArea));
3133 2 : if (std::abs(PDROP) <= PurgedP) {
3134 2 : BuoFlow = BuoFlowMax * (1.0 - std::abs(PDROP) / PurgedP);
3135 2 : dPBuoFlow = BuoFlowMax / PurgedP;
3136 : }
3137 : }
3138 : } else {
3139 : // Node M is upper zone
3140 0 : if (propN.density < propM.density) {
3141 0 : BuoFlowMax = RhozAver * 0.055 * std::sqrt(9.81 * std::abs(propN.density - propM.density) * pow_5(DH) / RhozAver);
3142 0 : PurgedP = Cshape * Cshape * 9.81 * std::abs(propN.density - propM.density) * pow_5(DH) / (2.0 * pow_2(OpenArea));
3143 0 : if (std::abs(PDROP) <= PurgedP) {
3144 0 : BuoFlow = BuoFlowMax * (1.0 - std::abs(PDROP) / PurgedP);
3145 0 : dPBuoFlow = BuoFlowMax / PurgedP;
3146 : }
3147 : }
3148 : }
3149 :
3150 2 : if (PDROP == 0.0) {
3151 0 : fma12 = BuoFlow;
3152 0 : fma21 = BuoFlow;
3153 0 : dp1fma12 = 0.0;
3154 0 : dp1fma21 = 0.0;
3155 2 : } else if (PDROP > 0.0) {
3156 1 : fma12 = propN.density * OpenArea * Fact * DischCoeff * std::sqrt(2.0 * PDROP / RhozAver) + BuoFlow;
3157 1 : dp1fma12 = propN.density * OpenArea * DischCoeff / std::sqrt(2.0 * PDROP * RhozAver) + dPBuoFlow;
3158 1 : if (BuoFlow > 0.0) {
3159 1 : fma21 = BuoFlow;
3160 1 : dp1fma21 = dPBuoFlow;
3161 : }
3162 : } else { // PDROP.LT.0.0
3163 1 : fma21 = propM.density * OpenArea * Fact * DischCoeff * std::sqrt(2.0 * std::abs(PDROP) / RhozAver) + BuoFlow;
3164 1 : dp1fma21 = -propM.density * OpenArea * DischCoeff / std::sqrt(2.0 * std::abs(PDROP) * RhozAver) + dPBuoFlow;
3165 1 : if (BuoFlow > 0.0) {
3166 1 : fma12 = BuoFlow;
3167 1 : dp1fma12 = dPBuoFlow;
3168 : }
3169 : }
3170 :
3171 2 : F[0] = fma12 - fma21;
3172 2 : DF[0] = dp1fma12 - dp1fma21;
3173 2 : F[1] = 0.0;
3174 2 : if (fma12 != 0.0 && fma21 != 0.0) {
3175 2 : F[1] = BuoFlow;
3176 : }
3177 2 : DF[1] = 0.0;
3178 :
3179 2 : return 1;
3180 : }
3181 :
3182 4 : int SpecifiedMassFlow::calculate([[maybe_unused]] EnergyPlusData &state,
3183 : [[maybe_unused]] bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
3184 : [[maybe_unused]] Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
3185 : [[maybe_unused]] int const i, // Linkage number
3186 : const Real64 multiplier, // Element multiplier
3187 : const Real64 control, // Element control signal
3188 : [[maybe_unused]] const AirState &propN, // Node 1 properties
3189 : [[maybe_unused]] const AirState &propM, // Node 2 properties
3190 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
3191 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
3192 : )
3193 : {
3194 : // SUBROUTINE INFORMATION:
3195 : // AUTHOR Jason DeGraw and Prateek Shrestha
3196 : // DATE WRITTEN June 2021
3197 : // MODIFIED na
3198 : // MODIFIED na
3199 : // RE-ENGINEERED na
3200 :
3201 : // PURPOSE OF THIS SUBROUTINE:
3202 : // This subroutine computes airflow for a specified mass flow element.
3203 :
3204 4 : F[0] = mass_flow * control * multiplier;
3205 4 : DF[0] = 0.0;
3206 4 : F[1] = 0.0;
3207 4 : DF[1] = 0.0;
3208 :
3209 4 : return 1;
3210 : }
3211 :
3212 4 : int SpecifiedVolumeFlow::calculate([[maybe_unused]] EnergyPlusData &state,
3213 : [[maybe_unused]] bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
3214 : [[maybe_unused]] Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
3215 : [[maybe_unused]] int const i, // Linkage number
3216 : const Real64 multiplier, // Element multiplier
3217 : const Real64 control, // Element control signal
3218 : const AirState &propN, // Node 1 properties
3219 : const AirState &propM, // Node 2 properties
3220 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
3221 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
3222 : )
3223 : {
3224 : // SUBROUTINE INFORMATION:
3225 : // AUTHOR Jason DeGraw and Prateek Shrestha
3226 : // DATE WRITTEN June 2021
3227 : // MODIFIED na
3228 : // MODIFIED na
3229 : // RE-ENGINEERED na
3230 :
3231 : // PURPOSE OF THIS SUBROUTINE:
3232 : // This subroutine computes airflow for a specified volume flow element.
3233 :
3234 4 : Real64 flow = volume_flow * control * multiplier;
3235 :
3236 4 : Real64 upwind_density{propN.density};
3237 :
3238 4 : if (flow < 0.0) {
3239 0 : upwind_density = propM.density;
3240 : }
3241 :
3242 4 : F[0] = flow * upwind_density;
3243 4 : DF[0] = 0.0;
3244 4 : F[1] = 0.0;
3245 4 : DF[1] = 0.0;
3246 :
3247 4 : return 1;
3248 : }
3249 :
3250 172 : int OutdoorAirFan::calculate(EnergyPlusData &state,
3251 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
3252 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
3253 : int const i, // Linkage number
3254 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
3255 : [[maybe_unused]] const Real64 control, // Element control signal
3256 : const AirState &propN, // Node 1 properties
3257 : const AirState &propM, // Node 2 properties
3258 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
3259 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
3260 : )
3261 : {
3262 :
3263 : // PURPOSE OF THIS SUBROUTINE:
3264 : // This subroutine solves airflow for a constant flow rate airflow component -- using standard interface.
3265 :
3266 : // Using/Aliasing
3267 : using HVAC::VerySmallMassFlow;
3268 :
3269 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3270 : Real64 expn;
3271 : Real64 Ctl;
3272 : Real64 coef;
3273 : Real64 Corr;
3274 : Real64 VisAve;
3275 : Real64 Tave;
3276 : Real64 RhoCor;
3277 : // int InletNode;
3278 : Real64 RhozNorm;
3279 : Real64 VisczNorm;
3280 : Real64 CDM;
3281 : Real64 FL;
3282 : Real64 FT;
3283 :
3284 172 : int AirLoopNum = state.afn->AirflowNetworkLinkageData(i).AirLoopNum;
3285 :
3286 172 : if (state.dataLoopNodes->Node(InletNode).MassFlowRate > VerySmallMassFlow) {
3287 : // Treat the component as an exhaust fan
3288 172 : F[0] = state.dataLoopNodes->Node(InletNode).MassFlowRate;
3289 172 : DF[0] = 0.0;
3290 212 : if (state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopFanOperationMode == HVAC::FanOp::Cycling &&
3291 40 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio > 0.0) {
3292 40 : F[0] = F[0] / state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio;
3293 : }
3294 172 : return 1;
3295 : } else {
3296 : // Treat the component as a surface crack
3297 : // Crack standard condition from given inputs
3298 0 : Corr = 1.0;
3299 0 : RhozNorm = state.afn->properties.density(StandardP, StandardT, StandardW);
3300 0 : VisczNorm = 1.71432e-5 + 4.828e-8 * StandardT;
3301 :
3302 0 : expn = FlowExpo;
3303 0 : VisAve = (propN.viscosity + propM.viscosity) / 2.0;
3304 0 : Tave = (propN.temperature + propM.temperature) / 2.0;
3305 0 : if (PDROP >= 0.0) {
3306 0 : coef = FlowCoef / propN.sqrt_density * Corr;
3307 : } else {
3308 0 : coef = FlowCoef / propM.sqrt_density * Corr;
3309 : }
3310 :
3311 0 : if (LFLAG) {
3312 : // Initialization by linear relation.
3313 0 : if (PDROP >= 0.0) {
3314 0 : RhoCor = TOKELVIN(propN.temperature) / TOKELVIN(Tave);
3315 0 : Ctl = std::pow(RhozNorm / propN.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
3316 0 : DF[0] = coef * propN.density / propN.viscosity * Ctl;
3317 : } else {
3318 0 : RhoCor = TOKELVIN(propM.temperature) / TOKELVIN(Tave);
3319 0 : Ctl = std::pow(RhozNorm / propM.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
3320 0 : DF[0] = coef * propM.density / propM.viscosity * Ctl;
3321 : }
3322 0 : F[0] = -DF[0] * PDROP;
3323 : } else {
3324 : // Standard calculation.
3325 0 : if (PDROP >= 0.0) {
3326 : // Flow in positive direction.
3327 : // Laminar flow.
3328 0 : RhoCor = TOKELVIN(propN.temperature) / TOKELVIN(Tave);
3329 0 : Ctl = std::pow(RhozNorm / propN.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
3330 0 : CDM = coef * propN.density / propN.viscosity * Ctl;
3331 0 : FL = CDM * PDROP;
3332 : // Turbulent flow.
3333 0 : if (expn == 0.5) {
3334 0 : FT = coef * propN.sqrt_density * std::sqrt(PDROP) * Ctl;
3335 : } else {
3336 0 : FT = coef * propN.sqrt_density * std::pow(PDROP, expn) * Ctl;
3337 : }
3338 : } else {
3339 : // Flow in negative direction.
3340 : // Laminar flow.
3341 0 : RhoCor = TOKELVIN(propM.temperature) / TOKELVIN(Tave);
3342 0 : Ctl = std::pow(RhozNorm / propM.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
3343 0 : CDM = coef * propM.density / propM.viscosity * Ctl;
3344 0 : FL = CDM * PDROP;
3345 : // Turbulent flow.
3346 0 : if (expn == 0.5) {
3347 0 : FT = -coef * propM.sqrt_density * std::sqrt(-PDROP) * Ctl;
3348 : } else {
3349 0 : FT = -coef * propM.sqrt_density * std::pow(-PDROP, expn) * Ctl;
3350 : }
3351 : }
3352 : // Select laminar or turbulent flow.
3353 0 : if (std::abs(FL) <= std::abs(FT)) {
3354 0 : F[0] = FL;
3355 0 : DF[0] = CDM;
3356 : } else {
3357 0 : F[0] = FT;
3358 0 : DF[0] = FT * expn / PDROP;
3359 : }
3360 : }
3361 : }
3362 0 : return 1;
3363 : }
3364 :
3365 132 : int ReliefFlow::calculate(EnergyPlusData &state,
3366 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
3367 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
3368 : int const i, // Linkage number
3369 : [[maybe_unused]] const Real64 multiplier, // Element multiplier
3370 : [[maybe_unused]] const Real64 control, // Element control signal
3371 : const AirState &propN, // Node 1 properties
3372 : const AirState &propM, // Node 2 properties
3373 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
3374 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
3375 : )
3376 : {
3377 :
3378 : // PURPOSE OF THIS SUBROUTINE:
3379 : // This subroutine solves airflow for a constant flow rate airflow component -- using standard interface.
3380 :
3381 : // Using/Aliasing
3382 : using HVAC::VerySmallMassFlow;
3383 :
3384 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3385 : Real64 expn;
3386 : Real64 Ctl;
3387 : Real64 coef;
3388 : Real64 Corr;
3389 : Real64 VisAve;
3390 : Real64 Tave;
3391 : Real64 RhoCor;
3392 : Real64 RhozNorm;
3393 : Real64 VisczNorm;
3394 : Real64 CDM;
3395 : Real64 FL;
3396 : Real64 FT;
3397 :
3398 132 : int AirLoopNum = state.afn->AirflowNetworkLinkageData(i).AirLoopNum;
3399 :
3400 132 : if (state.dataLoopNodes->Node(OutletNode).MassFlowRate > VerySmallMassFlow) {
3401 : // Treat the component as an exhaust fan
3402 132 : DF[0] = 0.0;
3403 132 : if (state.afn->PressureSetFlag == PressureCtrlRelief) {
3404 92 : F[0] = state.afn->ReliefMassFlowRate;
3405 : } else {
3406 40 : F[0] = state.dataLoopNodes->Node(OutletNode).MassFlowRate;
3407 40 : if (state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopFanOperationMode == HVAC::FanOp::Cycling &&
3408 0 : state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio > 0.0) {
3409 0 : F[0] = F[0] / state.dataAirLoop->AirLoopAFNInfo(AirLoopNum).LoopOnOffFanPartLoadRatio;
3410 : }
3411 : }
3412 132 : return 1;
3413 : } else {
3414 : // Treat the component as a surface crack
3415 : // Crack standard condition from given inputs
3416 0 : Corr = 1.0;
3417 0 : RhozNorm = state.afn->properties.density(StandardP, StandardT, StandardW);
3418 0 : VisczNorm = 1.71432e-5 + 4.828e-8 * StandardT;
3419 :
3420 0 : expn = FlowExpo;
3421 0 : VisAve = (propN.viscosity + propM.viscosity) / 2.0;
3422 0 : Tave = (propN.temperature + propM.temperature) / 2.0;
3423 0 : if (PDROP >= 0.0) {
3424 0 : coef = FlowCoef / propN.sqrt_density * Corr;
3425 : } else {
3426 0 : coef = FlowCoef / propM.sqrt_density * Corr;
3427 : }
3428 :
3429 0 : if (LFLAG) {
3430 : // Initialization by linear relation.
3431 0 : if (PDROP >= 0.0) {
3432 0 : RhoCor = TOKELVIN(propN.temperature) / TOKELVIN(Tave);
3433 0 : Ctl = std::pow(RhozNorm / propN.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
3434 0 : DF[0] = coef * propN.density / propN.viscosity * Ctl;
3435 : } else {
3436 0 : RhoCor = TOKELVIN(propM.temperature) / TOKELVIN(Tave);
3437 0 : Ctl = std::pow(RhozNorm / propM.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
3438 0 : DF[0] = coef * propM.density / propM.viscosity * Ctl;
3439 : }
3440 0 : F[0] = -DF[0] * PDROP;
3441 : } else {
3442 : // Standard calculation.
3443 0 : if (PDROP >= 0.0) {
3444 : // Flow in positive direction.
3445 : // Laminar flow.
3446 0 : RhoCor = TOKELVIN(propN.temperature) / TOKELVIN(Tave);
3447 0 : Ctl = std::pow(RhozNorm / propN.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
3448 0 : CDM = coef * propN.density / propN.viscosity * Ctl;
3449 0 : FL = CDM * PDROP;
3450 : // Turbulent flow.
3451 0 : if (expn == 0.5) {
3452 0 : FT = coef * propN.sqrt_density * std::sqrt(PDROP) * Ctl;
3453 : } else {
3454 0 : FT = coef * propN.sqrt_density * std::pow(PDROP, expn) * Ctl;
3455 : }
3456 : } else {
3457 : // Flow in negative direction.
3458 : // Laminar flow.
3459 0 : RhoCor = TOKELVIN(propM.temperature) / TOKELVIN(Tave);
3460 0 : Ctl = std::pow(RhozNorm / propM.density / RhoCor, expn - 1.0) * std::pow(VisczNorm / VisAve, 2.0 * expn - 1.0);
3461 0 : CDM = coef * propM.density / propM.viscosity * Ctl;
3462 0 : FL = CDM * PDROP;
3463 : // Turbulent flow.
3464 0 : if (expn == 0.5) {
3465 0 : FT = -coef * propM.sqrt_density * std::sqrt(-PDROP) * Ctl;
3466 : } else {
3467 0 : FT = -coef * propM.sqrt_density * std::pow(-PDROP, expn) * Ctl;
3468 : }
3469 : }
3470 : // Select laminar or turbulent flow.
3471 0 : if (std::abs(FL) <= std::abs(FT)) {
3472 0 : F[0] = FL;
3473 0 : DF[0] = CDM;
3474 : } else {
3475 0 : F[0] = FT;
3476 0 : DF[0] = FT * expn / PDROP;
3477 : }
3478 : }
3479 : }
3480 0 : return 1;
3481 : }
3482 :
3483 4 : void generic_crack(Real64 const coefficient, // Flow coefficient
3484 : Real64 const exponent, // Flow exponent
3485 : bool const linear, // Initialization flag. If true, use linear relationship
3486 : Real64 const pdrop, // Total pressure drop across a component (P1 - P2) [Pa]
3487 : const AirState &propN, // Node 1 properties
3488 : const AirState &propM, // Node 2 properties
3489 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
3490 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
3491 : )
3492 : {
3493 : // SUBROUTINE INFORMATION:
3494 : // AUTHOR George Walton
3495 : // DATE WRITTEN Extracted from AIRNET
3496 : // MODIFIED Lixing Gu, 2/1/04
3497 : // Revised the subroutine to meet E+ needs
3498 : // MODIFIED Lixing Gu, 6/8/05
3499 : // RE-ENGINEERED This subroutine is revised from AFEPLR developed by George Walton, NIST
3500 : // Jason DeGraw
3501 :
3502 : // PURPOSE OF THIS SUBROUTINE:
3503 : // This subroutine solves airflow for a power law component
3504 :
3505 : // METHODOLOGY EMPLOYED:
3506 : // Using Q=C(dP)^n
3507 :
3508 : // FLOW:
3509 : // Calculate normal density and viscocity at reference conditions
3510 4 : constexpr Real64 reference_density = AIRDENSITY_CONSTEXPR(101325.0, 20.0, 0.0);
3511 4 : constexpr Real64 reference_viscosity = 1.71432e-5 + 4.828e-8 * 20.0;
3512 :
3513 4 : Real64 VisAve{0.5 * (propN.viscosity + propM.viscosity)};
3514 4 : Real64 Tave{0.5 * (propN.temperature + propM.temperature)};
3515 :
3516 4 : Real64 sign{1.0};
3517 4 : Real64 upwind_temperature{propN.temperature};
3518 4 : Real64 upwind_density{propN.density};
3519 4 : Real64 upwind_viscosity{propN.viscosity};
3520 4 : Real64 upwind_sqrt_density{propN.sqrt_density};
3521 4 : Real64 abs_pdrop = pdrop;
3522 :
3523 4 : if (pdrop < 0.0) {
3524 2 : sign = -1.0;
3525 2 : upwind_temperature = propM.temperature;
3526 2 : upwind_density = propM.density;
3527 2 : upwind_viscosity = propM.viscosity;
3528 2 : upwind_sqrt_density = propM.sqrt_density;
3529 2 : abs_pdrop = -pdrop;
3530 : }
3531 :
3532 4 : Real64 coef = coefficient / upwind_sqrt_density;
3533 :
3534 : // Laminar calculation
3535 4 : Real64 RhoCor{TOKELVIN(upwind_temperature) / TOKELVIN(Tave)};
3536 4 : Real64 Ctl{std::pow(reference_density / upwind_density / RhoCor, exponent - 1.0) *
3537 4 : std::pow(reference_viscosity / VisAve, 2.0 * exponent - 1.0)};
3538 4 : Real64 CDM{coef * upwind_density / upwind_viscosity * Ctl};
3539 4 : Real64 FL{CDM * pdrop};
3540 :
3541 4 : if (linear) {
3542 2 : DF[0] = CDM;
3543 2 : F[0] = FL;
3544 : } else {
3545 : // Turbulent flow.
3546 : Real64 abs_FT;
3547 2 : if (exponent == 0.5) {
3548 0 : abs_FT = coef * upwind_sqrt_density * std::sqrt(abs_pdrop) * Ctl;
3549 : } else {
3550 2 : abs_FT = coef * upwind_sqrt_density * std::pow(abs_pdrop, exponent) * Ctl;
3551 : }
3552 : // Select linear or nonlinear flow.
3553 2 : if (std::abs(FL) <= abs_FT) {
3554 0 : F[0] = FL;
3555 0 : DF[0] = CDM;
3556 : } else {
3557 2 : F[0] = sign * abs_FT;
3558 2 : DF[0] = F[0] * exponent / pdrop;
3559 : }
3560 : }
3561 4 : }
3562 :
3563 0 : int GenericDuct(Real64 const Length, // Duct length
3564 : Real64 const Diameter, // Duct diameter
3565 : bool const LFLAG, // Initialization flag.If = 1, use laminar relationship
3566 : Real64 const PDROP, // Total pressure drop across a component (P1 - P2) [Pa]
3567 : const AirState &propN, // Node 1 properties
3568 : const AirState &propM, // Node 2 properties
3569 : std::array<Real64, 2> &F, // Airflow through the component [kg/s]
3570 : std::array<Real64, 2> &DF // Partial derivative: DF/DP
3571 : )
3572 : {
3573 :
3574 : // This subroutine solve air flow as a duct if fan has zero flow rate
3575 :
3576 : // SUBROUTINE PARAMETER DEFINITIONS:
3577 0 : Real64 constexpr C(0.868589);
3578 0 : Real64 constexpr EPS(0.001);
3579 0 : Real64 constexpr Rough(0.0001);
3580 0 : Real64 constexpr InitLamCoef(128.0);
3581 0 : Real64 constexpr LamDynCoef(64.0);
3582 0 : Real64 constexpr LamFriCoef(0.0001);
3583 0 : Real64 constexpr TurDynCoef(0.0001);
3584 :
3585 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3586 : Real64 A0;
3587 : Real64 A1;
3588 : Real64 A2;
3589 : Real64 B;
3590 : Real64 D;
3591 : Real64 S2;
3592 : Real64 CDM;
3593 : Real64 FL;
3594 : Real64 FT;
3595 : Real64 FTT;
3596 : Real64 RE;
3597 :
3598 : // Get component properties
3599 0 : Real64 ed = Rough / Diameter;
3600 0 : Real64 area = Diameter * Diameter * Constant::Pi / 4.0;
3601 0 : Real64 ld = Length / Diameter;
3602 0 : Real64 g = 1.14 - 0.868589 * std::log(ed);
3603 0 : Real64 AA1 = g;
3604 :
3605 0 : if (LFLAG) {
3606 : // Initialization by linear relation.
3607 0 : if (PDROP >= 0.0) {
3608 0 : DF[0] = (2.0 * propN.density * area * Diameter) / (propN.viscosity * InitLamCoef * ld);
3609 : } else {
3610 0 : DF[0] = (2.0 * propM.density * area * Diameter) / (propM.viscosity * InitLamCoef * ld);
3611 : }
3612 0 : F[0] = -DF[0] * PDROP;
3613 : } else {
3614 : // Standard calculation.
3615 0 : if (PDROP >= 0.0) {
3616 : // Flow in positive direction.
3617 : // Laminar flow coefficient !=0
3618 : if (LamFriCoef >= 0.001) {
3619 : A2 = LamFriCoef / (2.0 * propN.density * area * area);
3620 : A1 = (propN.viscosity * LamDynCoef * ld) / (2.0 * propN.density * area * Diameter);
3621 : A0 = -PDROP;
3622 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
3623 : FL = (CDM - A1) / (2.0 * A2);
3624 : CDM = 1.0 / CDM;
3625 : } else {
3626 0 : CDM = (2.0 * propN.density * area * Diameter) / (propN.viscosity * LamDynCoef * ld);
3627 0 : FL = CDM * PDROP;
3628 : }
3629 0 : RE = FL * Diameter / (propN.viscosity * area);
3630 : // Turbulent flow; test when Re>10.
3631 0 : if (RE >= 10.0) {
3632 0 : S2 = std::sqrt(2.0 * propN.density * PDROP) * area;
3633 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
3634 : while (true) {
3635 0 : FT = FTT;
3636 0 : B = (9.3 * propN.viscosity * area) / (FT * Rough);
3637 0 : D = 1.0 + g * B;
3638 0 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
3639 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
3640 0 : if (std::abs(FTT - FT) / FTT < EPS) break;
3641 : }
3642 0 : FT = FTT;
3643 : } else {
3644 0 : FT = FL;
3645 : }
3646 : } else {
3647 : // Flow in negative direction.
3648 : // Laminar flow coefficient !=0
3649 : if (LamFriCoef >= 0.001) {
3650 : A2 = LamFriCoef / (2.0 * propM.density * area * area);
3651 : A1 = (propM.viscosity * LamDynCoef * ld) / (2.0 * propM.density * area * Diameter);
3652 : A0 = PDROP;
3653 : CDM = std::sqrt(A1 * A1 - 4.0 * A2 * A0);
3654 : FL = -(CDM - A1) / (2.0 * A2);
3655 : CDM = 1.0 / CDM;
3656 : } else {
3657 0 : CDM = (2.0 * propM.density * area * Diameter) / (propM.viscosity * LamDynCoef * ld);
3658 0 : FL = CDM * PDROP;
3659 : }
3660 0 : RE = -FL * Diameter / (propM.viscosity * area);
3661 : // Turbulent flow; test when Re>10.
3662 0 : if (RE >= 10.0) {
3663 0 : S2 = std::sqrt(-2.0 * propM.density * PDROP) * area;
3664 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
3665 : while (true) {
3666 0 : FT = FTT;
3667 0 : B = (9.3 * propM.viscosity * area) / (FT * Rough);
3668 0 : D = 1.0 + g * B;
3669 0 : g -= (g - AA1 + C * std::log(D)) / (1.0 + C * B / D);
3670 0 : FTT = S2 / std::sqrt(ld / pow_2(g) + TurDynCoef);
3671 0 : if (std::abs(FTT - FT) / FTT < EPS) break;
3672 : }
3673 0 : FT = -FTT;
3674 : } else {
3675 0 : FT = FL;
3676 : }
3677 : }
3678 : // Select laminar or turbulent flow.
3679 0 : if (std::abs(FL) <= std::abs(FT)) {
3680 0 : F[0] = FL;
3681 0 : DF[0] = CDM;
3682 : } else {
3683 0 : F[0] = FT;
3684 0 : DF[0] = 0.5 * FT / PDROP;
3685 : }
3686 : }
3687 0 : return 1;
3688 : }
3689 :
3690 2 : void DetailedOpeningSolver::presprofile(EnergyPlusData &state,
3691 : int const il, // Linkage number
3692 : int const Pprof, // Opening number
3693 : Real64 const G, // gravitation field strength [N/kg]
3694 : const Array1D<Real64> &DpF, // Stack pressures at start heights of Layers
3695 : const Array1D<Real64> &DpT, // Stack pressures at start heights of Layers
3696 : const Array1D<Real64> &BetaF, // Density gradients in the FROM zone (starting at linkheight) [Kg/m3/m]
3697 : const Array1D<Real64> &BetaT, // Density gradients in the TO zone (starting at linkheight) [Kg/m3/m]
3698 : const Array1D<Real64> &RhoStF, // Density at the start heights of Layers in the FROM zone
3699 : const Array1D<Real64> &RhoStT, // Density at the start heights of Layers in the TO zone
3700 : int const From, // Number of FROM zone
3701 : int const To, // Number of To zone
3702 : Real64 const ActLh, // Actual height of opening [m]
3703 : Real64 const OwnHeightFactor // Cosine of deviation angle of the opening plane from the vertical direction
3704 : )
3705 : {
3706 :
3707 : // SUBROUTINE INFORMATION:
3708 : // AUTHOR Lixing Gu
3709 : // DATE WRITTEN Oct. 2005
3710 : // MODIFIED na
3711 : // RE-ENGINEERED This subroutine is revised based on PresProfile subroutine from COMIS
3712 :
3713 : // PURPOSE OF THIS SUBROUTINE:
3714 : // This subroutine calculates for a large opening profiles of stack pressure difference and
3715 : // densities in the zones linked by the a detailed opening cmponent.
3716 :
3717 : // METHODOLOGY EMPLOYED:
3718 : // The profiles are obtained in the following
3719 : // way: - the opening is divided into NrInt vertical intervals
3720 : // - the stack pressure difference and densities in From-
3721 : // and To-zone are calculated at the centre of each
3722 : // interval aswell as at the top and bottom of the LO
3723 : // - these values are stored in the (NrInt+2)-dimensional
3724 : // arrays DpProf, RhoProfF, RhoProfT.
3725 : // The calculation of stack pressure and density in the two zones
3726 : // is based on the arrays DpF/T, RhoStF/T, BetaF/T. These arrays
3727 : // are calculated in the COMIS routine Lclimb. They contain the
3728 : // values of stack pressure and density at the startheight of the
3729 : // opening and at startheights of all layers lying inside the
3730 : // opening, and the density gradients across the layers.
3731 : // The effective startheight zl(1/2) in the From/To zone and the
3732 : // effective length actLh of the LO take into account the
3733 : // startheightfactor, heightfactor and ownheightfactor. Thus for
3734 : // slanted windows the range of the profiles is the vertical
3735 : // projection of the actual opening.
3736 :
3737 : // REFERENCES:
3738 : // Helmut E. Feustel and Alison Rayner-Hooson, "COMIS Fundamentals," LBL-28560,
3739 : // Lawrence Berkeley National Laboratory, Berkeley, CA, May 1990
3740 :
3741 : // Argument array dimensioning
3742 2 : EP_SIZE_CHECK(DpF, 2);
3743 2 : EP_SIZE_CHECK(DpT, 2);
3744 2 : EP_SIZE_CHECK(BetaF, 2);
3745 2 : EP_SIZE_CHECK(BetaT, 2);
3746 2 : EP_SIZE_CHECK(RhoStF, 2);
3747 2 : EP_SIZE_CHECK(RhoStT, 2);
3748 :
3749 : // Locals
3750 : // SUBROUTINE ARGUMENT DEFINITIONS:
3751 : // in the FROM zone (starting at linkheight) [Pa]
3752 : // (starting at linkheight) [Kg/m3]
3753 : // (starting at linkheight) [Kg/m3]
3754 :
3755 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3756 2 : Array1D<Real64> zF(2); // Startheights of layers in FROM-, TO-zone
3757 2 : Array1D<Real64> zT(2);
3758 2 : Array1D<Real64> zStF(2); // Startheights of layers within the LO, starting with the actual startheight of the LO.
3759 2 : Array1D<Real64> zStT(2);
3760 : // The values in the arrays DpF, DpT, BetaF, BetaT, RhoStF, RhoStT are calculated at these heights.
3761 : Real64 hghtsFR;
3762 : Real64 hghtsTR;
3763 2 : Array1D<Real64> hghtsF(NrInt + 2); // Heights of evaluation points for pressure and density profiles
3764 2 : Array1D<Real64> hghtsT(NrInt + 2);
3765 : Real64 Interval; // Distance between two evaluation points
3766 : Real64 delzF; // Interval between actual evaluation point and startheight of actual layer in FROM-, TO-zone
3767 : Real64 delzT;
3768 : int AnzLayF; // Number of layers in FROM-, TO-zone
3769 : int AnzLayT;
3770 : int lF; // Actual index for DpF/T, BetaF/T, RhoStF/T, zStF/T
3771 : int lT;
3772 : int n;
3773 : int i;
3774 : int k;
3775 :
3776 : // Initialization
3777 2 : delzF = 0.0;
3778 2 : delzT = 0.0;
3779 2 : Interval = ActLh * OwnHeightFactor / NrInt;
3780 :
3781 42 : for (n = 1; n <= NrInt; ++n) {
3782 40 : hghtsF(n + 1) = state.afn->AirflowNetworkLinkageData(il).NodeHeights[0] + Interval * (n - 0.5);
3783 40 : hghtsT(n + 1) = state.afn->AirflowNetworkLinkageData(il).NodeHeights[1] + Interval * (n - 0.5);
3784 : }
3785 2 : hghtsF(1) = state.afn->AirflowNetworkLinkageData(il).NodeHeights[0];
3786 2 : hghtsT(1) = state.afn->AirflowNetworkLinkageData(il).NodeHeights[1];
3787 2 : hghtsF(NrInt + 2) = state.afn->AirflowNetworkLinkageData(il).NodeHeights[0] + ActLh * OwnHeightFactor;
3788 2 : hghtsT(NrInt + 2) = state.afn->AirflowNetworkLinkageData(il).NodeHeights[1] + ActLh * OwnHeightFactor;
3789 :
3790 2 : lF = 1;
3791 2 : lT = 1;
3792 2 : if (From == 0) {
3793 0 : AnzLayF = 1;
3794 : } else {
3795 2 : AnzLayF = 0;
3796 : }
3797 2 : if (To == 0) {
3798 2 : AnzLayT = 1;
3799 : } else {
3800 0 : AnzLayT = 0;
3801 : }
3802 :
3803 2 : if (AnzLayF > 0) {
3804 0 : for (n = 1; n <= AnzLayF; ++n) {
3805 0 : zF(n) = 0.0;
3806 0 : if (hghtsF(1) < 0.0) zF(n) = hghtsF(1);
3807 : }
3808 : }
3809 :
3810 2 : if (AnzLayT > 0) {
3811 4 : for (n = 1; n <= AnzLayT; ++n) {
3812 2 : zT(n) = 0.0;
3813 2 : if (hghtsT(1) < 0.0) zT(n) = hghtsT(1);
3814 : }
3815 : }
3816 :
3817 2 : zStF(1) = state.afn->AirflowNetworkLinkageData(il).NodeHeights[0];
3818 2 : i = 2;
3819 2 : k = 1;
3820 :
3821 2 : while (k <= AnzLayF) {
3822 0 : if (zF(k) > zStF(1)) break;
3823 0 : ++k;
3824 : }
3825 :
3826 2 : while (k <= AnzLayF) {
3827 0 : if (zF(k) > hghtsF(NrInt)) break;
3828 0 : zStF(i) = zF(k); // Autodesk:BoundsViolation zStF(i) @ i>2 and zF(k) @ k>2
3829 0 : ++i;
3830 0 : ++k;
3831 : }
3832 :
3833 2 : zStF(i) = state.afn->AirflowNetworkLinkageData(il).NodeHeights[0] + ActLh * OwnHeightFactor; // Autodesk:BoundsViolation zStF(i) @ i>2
3834 2 : zStT(1) = state.afn->AirflowNetworkLinkageData(il).NodeHeights[1];
3835 2 : i = 2;
3836 2 : k = 1;
3837 :
3838 4 : while (k <= AnzLayT) {
3839 2 : if (zT(k) > zStT(1)) break;
3840 2 : ++k;
3841 : }
3842 :
3843 2 : while (k <= AnzLayT) {
3844 0 : if (zT(k) > hghtsT(NrInt)) break; // Autodesk:BoundsViolation zT(k) @ k>2
3845 0 : zStT(i) = zT(k); // Autodesk:BoundsViolation zStF(i) @ i>2 and zT(k) @ k>2
3846 0 : ++i;
3847 0 : ++k;
3848 : }
3849 :
3850 2 : zStT(i) = state.afn->AirflowNetworkLinkageData(il).NodeHeights[1] + ActLh * OwnHeightFactor; // Autodesk:BoundsViolation zStT(i) @ i>2
3851 :
3852 : // Calculation of DpProf, RhoProfF, RhoProfT
3853 46 : for (i = 1; i <= NrInt + 2; ++i) {
3854 44 : hghtsFR = hghtsF(i);
3855 44 : hghtsTR = hghtsT(i);
3856 :
3857 : while (true) {
3858 44 : if (hghtsFR > zStF(lF + 1)) {
3859 0 : if (lF > 2) break;
3860 0 : ++lF;
3861 : }
3862 44 : if (hghtsFR <= zStF(lF + 1)) break;
3863 : }
3864 :
3865 : while (true) {
3866 44 : if (hghtsTR > zStT(lT + 1)) {
3867 0 : ++lT;
3868 : }
3869 44 : if (hghtsTR <= zStT(lT + 1)) break;
3870 : }
3871 :
3872 44 : delzF = hghtsF(i) - zStF(lF);
3873 44 : delzT = hghtsT(i) - zStT(lT);
3874 :
3875 44 : RhoProfF(i + Pprof) = RhoStF(lF) + BetaF(lF) * delzF;
3876 44 : RhoProfT(i + Pprof) = RhoStT(lT) + BetaT(lT) * delzT;
3877 :
3878 88 : DpProf(i + Pprof) = DpF(lF) - DpT(lT) - G * (RhoStF(lF) * delzF + BetaF(lF) * pow_2(delzF) / 2.0) +
3879 44 : G * (RhoStT(lT) * delzT + BetaT(lT) * pow_2(delzT) / 2.0);
3880 : }
3881 2 : }
3882 :
3883 16873 : void DetailedOpeningSolver::pstack(EnergyPlusData &state, std::vector<AirflowNetwork::AirState> &props, Array1D<Real64> &pz)
3884 : {
3885 :
3886 : // SUBROUTINE INFORMATION:
3887 : // AUTHOR Lixing Gu
3888 : // DATE WRITTEN Oct. 2005
3889 : // MODIFIED na
3890 : // RE-ENGINEERED This subroutine is revised based on PresProfile subroutine from COMIS
3891 :
3892 : // PURPOSE OF THIS SUBROUTINE:
3893 : // This subroutine calculates the stack pressures for a link between two zones
3894 :
3895 : // REFERENCES:
3896 : // Helmut E. Feustel and Alison Rayner-Hooson, "COMIS Fundamentals," LBL-28560,
3897 : // Lawrence Berkeley National Laboratory, Berkeley, CA, May 1990
3898 :
3899 : // USE STATEMENTS:
3900 : // Locals
3901 : // SUBROUTINE ARGUMENT DEFINITIONS:
3902 : // na
3903 :
3904 : // SUBROUTINE PARAMETER DEFINITIONS:
3905 16873 : Real64 constexpr PSea(101325.0);
3906 :
3907 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
3908 : // REAL(r64) RhoOut ! air density outside [kg/m3]
3909 : Real64 G; // gravity field strength [N/kg]
3910 : Real64 Pbz; // Pbarom at entrance level [Pa]
3911 16873 : Array2D<Real64> RhoDrL(state.afn->NumOfLinksMultiZone, 2); // dry air density on both sides of the link [kg/m3]
3912 : Real64 TempL1; // Temp in From and To zone at link level [C]
3913 : Real64 TempL2;
3914 : // REAL(r64) Tout ! outside temperature [C]
3915 : Real64 Xhl1; // Humidity in From and To zone at link level [kg/kg]
3916 : Real64 Xhl2;
3917 : // REAL(r64) Xhout ! outside humidity [kg/kg]
3918 16873 : Array1D<Real64> Hfl(state.afn->NumOfLinksMultiZone); // Own height factor for large (slanted) openings
3919 : int Nl; // number of links
3920 :
3921 16873 : Array1D<Real64> DpF(2);
3922 : Real64 DpP;
3923 16873 : Array1D<Real64> DpT(2);
3924 : Real64 H;
3925 16873 : Array1D<Real64> RhoStF(2);
3926 16873 : Array1D<Real64> RhoStT(2);
3927 : Real64 RhoDrDummi;
3928 16873 : Array1D<Real64> BetaStF(2);
3929 16873 : Array1D<Real64> BetaStT(2);
3930 : Real64 T;
3931 : Real64 X;
3932 16873 : Array1D<Real64> HSt(2);
3933 : Real64 TzFrom;
3934 : Real64 XhzFrom;
3935 : Real64 TzTo;
3936 : Real64 XhzTo;
3937 : Real64 ActLh;
3938 : Real64 ActLOwnh;
3939 : Real64 Pref;
3940 : Real64 PzFrom;
3941 : Real64 PzTo;
3942 16873 : Array1D<Real64> RhoLd(2);
3943 : Real64 RhoStd;
3944 : int Fromz;
3945 : int Toz;
3946 : iComponentTypeNum Ltyp;
3947 : int i;
3948 : int ll;
3949 : int Pprof;
3950 : int OpenNum;
3951 :
3952 : Real64 RhoREF;
3953 : Real64 CONV;
3954 :
3955 16873 : RhoREF = state.afn->properties.density(PSea, state.dataEnvrn->OutDryBulbTemp, state.dataEnvrn->OutHumRat);
3956 :
3957 16873 : CONV = state.dataEnvrn->Latitude * 2.0 * Constant::Pi / 360.0;
3958 16873 : G = 9.780373 * (1.0 + 0.0052891 * pow_2(std::sin(CONV)) - 0.0000059 * pow_2(std::sin(2.0 * CONV)));
3959 :
3960 16873 : Hfl = 1.0;
3961 16873 : Pbz = state.dataEnvrn->OutBaroPress;
3962 16873 : Nl = state.afn->NumOfLinksMultiZone;
3963 16873 : OpenNum = 0;
3964 16873 : RhoLd(1) = 1.2;
3965 16873 : RhoLd(2) = 1.2;
3966 16873 : RhoStd = 1.2;
3967 :
3968 337332 : for (i = 1; i <= Nl; ++i) {
3969 : // Check surface tilt
3970 320459 : if (i <= Nl - state.afn->NumOfLinksIntraZone) { // Revised by L.Gu, on 9 / 29 / 10
3971 320461 : if (state.afn->AirflowNetworkLinkageData(i).DetOpenNum > 0 &&
3972 2 : state.dataSurface->Surface(state.afn->MultizoneSurfaceData(i).SurfNum).Tilt < 90) {
3973 0 : Hfl(i) = state.dataSurface->Surface(state.afn->MultizoneSurfaceData(i).SurfNum).SinTilt;
3974 : }
3975 : }
3976 : // Initialisation
3977 320459 : int From = state.afn->AirflowNetworkLinkageData(i).NodeNums[0];
3978 320459 : int To = state.afn->AirflowNetworkLinkageData(i).NodeNums[1];
3979 320459 : if (state.afn->AirflowNetworkNodeData(From).EPlusZoneNum > 0 && state.afn->AirflowNetworkNodeData(To).EPlusZoneNum > 0) {
3980 33810 : ll = 0;
3981 286649 : } else if (state.afn->AirflowNetworkNodeData(From).EPlusZoneNum == 0 && state.afn->AirflowNetworkNodeData(To).EPlusZoneNum > 0) {
3982 0 : ll = 1;
3983 : } else {
3984 286649 : ll = 3;
3985 : }
3986 :
3987 320459 : Ltyp = state.afn->AirflowNetworkCompData(state.afn->AirflowNetworkLinkageData(i).CompNum).CompTypeNum;
3988 320459 : if (Ltyp == iComponentTypeNum::DOP) {
3989 2 : ActLh = state.afn->MultizoneSurfaceData(i).Height;
3990 2 : ActLOwnh = ActLh * 1.0;
3991 : } else {
3992 320457 : ActLh = 0.0;
3993 320457 : ActLOwnh = 0.0;
3994 : }
3995 :
3996 320459 : TempL1 = props[From].temperature;
3997 320459 : Xhl1 = props[From].humidity_ratio;
3998 320459 : TzFrom = props[From].temperature;
3999 320459 : XhzFrom = props[From].humidity_ratio;
4000 : // RhoL1 = props[From].density;
4001 320459 : if (ll == 0 || ll == 3) {
4002 320459 : PzFrom = pz(From);
4003 : } else {
4004 0 : PzFrom = 0.0;
4005 0 : From = 0;
4006 : }
4007 :
4008 320459 : int ilayptr = 0;
4009 320459 : if (From == 0) ilayptr = 1;
4010 320459 : if (ilayptr == 0) {
4011 320459 : Fromz = 0;
4012 : } else {
4013 0 : Fromz = From;
4014 : }
4015 :
4016 320459 : TempL2 = props[To].temperature;
4017 320459 : Xhl2 = props[To].humidity_ratio;
4018 320459 : TzTo = props[To].temperature;
4019 320459 : XhzTo = props[To].humidity_ratio;
4020 : // RhoL2 = props[To].density;
4021 :
4022 320459 : if (ll < 3) {
4023 33810 : PzTo = pz(To);
4024 : } else {
4025 286649 : PzTo = 0.0;
4026 286649 : To = 0;
4027 : }
4028 320459 : ilayptr = 0;
4029 320459 : if (To == 0) ilayptr = 1;
4030 320459 : if (ilayptr == 0) {
4031 33810 : Toz = 0;
4032 : } else {
4033 286649 : Toz = To;
4034 : }
4035 :
4036 : // RhoDrL is Rho at link level without pollutant but with humidity
4037 320459 : RhoDrL(i, 1) = state.afn->properties.density(state.dataEnvrn->OutBaroPress + PzFrom, TempL1, Xhl1);
4038 320459 : RhoDrL(i, 2) = state.afn->properties.density(state.dataEnvrn->OutBaroPress + PzTo, TempL2, Xhl2);
4039 :
4040 : // End initialisation
4041 :
4042 : // calculate DpF the difference between Pz and P at Node 1 height
4043 320459 : ilayptr = 0;
4044 320459 : if (Fromz == 0) ilayptr = 1;
4045 320459 : int j = ilayptr;
4046 320459 : int k = 1;
4047 320459 : lclimb(state, G, RhoLd(1), state.afn->AirflowNetworkLinkageData(i).NodeHeights[0], TempL1, Xhl1, DpF(k), Toz, PzTo, Pbz, RhoDrL(i, 1));
4048 320459 : Real64 RhoL1 = RhoLd(1);
4049 : // For large openings calculate the stack pressure difference profile and the
4050 : // density profile within the the top- and the bottom- height of the large opening
4051 320459 : if (ActLOwnh > 0.0) {
4052 2 : HSt(k) = state.afn->AirflowNetworkLinkageData(i).NodeHeights[0];
4053 2 : RhoStF(k) = RhoL1;
4054 2 : ++k;
4055 2 : HSt(k) = 0.0;
4056 2 : if (HSt(k - 1) < 0.0) HSt(k) = HSt(k - 1);
4057 :
4058 : // Search for the first startheight of a layer which is within the top- and the
4059 : // bottom- height of the large opening.
4060 : while (true) {
4061 4 : ilayptr = 0;
4062 4 : if (Fromz == 0) ilayptr = 9;
4063 4 : if ((j > ilayptr) || (HSt(k) > state.afn->AirflowNetworkLinkageData(i).NodeHeights[0])) break;
4064 2 : j += 9;
4065 2 : HSt(k) = 0.0;
4066 2 : if (HSt(k - 1) < 0.0) HSt(k) = HSt(k - 1);
4067 : }
4068 :
4069 : // Calculate Rho and stack pressure for every StartHeight of a layer which is
4070 : // within the top- and the bottom-height of the large opening.
4071 : while (true) {
4072 2 : ilayptr = 0;
4073 2 : if (Fromz == 0) ilayptr = 9;
4074 2 : if ((j > ilayptr) || (HSt(k) >= (state.afn->AirflowNetworkLinkageData(i).NodeHeights[0] + ActLOwnh)))
4075 2 : break; // Autodesk:BoundsViolation HSt(k) @ k>2
4076 0 : T = TzFrom;
4077 0 : X = XhzFrom;
4078 0 : lclimb(
4079 0 : state, G, RhoStd, HSt(k), T, X, DpF(k), Fromz, PzFrom, Pbz, RhoDrDummi); // Autodesk:BoundsViolation HSt(k) and DpF(k) @ k>2
4080 0 : RhoStF(k) = RhoStd; // Autodesk:BoundsViolation RhoStF(k) @ k>2
4081 0 : j += 9;
4082 0 : ++k; // Autodesk:Note k>2 now
4083 0 : HSt(k) = 0.0; // Autodesk:BoundsViolation @ k>2
4084 0 : if (HSt(k - 1) < 0.0) HSt(k) = HSt(k - 1); // Autodesk:BoundsViolation @ k>2
4085 : }
4086 : // Stack pressure difference and rho for top-height of the large opening
4087 2 : HSt(k) = state.afn->AirflowNetworkLinkageData(i).NodeHeights[0] + ActLOwnh; // Autodesk:BoundsViolation k>2 poss
4088 2 : T = TzFrom;
4089 2 : X = XhzFrom;
4090 2 : lclimb(state, G, RhoStd, HSt(k), T, X, DpF(k), Fromz, PzFrom, Pbz, RhoDrDummi); // Autodesk:BoundsViolation k>2 poss
4091 2 : RhoStF(k) = RhoStd; // Autodesk:BoundsViolation k >= 3 poss
4092 :
4093 4 : for (j = 1; j <= (k - 1); ++j) {
4094 2 : BetaStF(j) = (RhoStF(j + 1) - RhoStF(j)) / (HSt(j + 1) - HSt(j));
4095 : }
4096 : }
4097 :
4098 : // repeat procedure for the "To" node, DpT
4099 320459 : ilayptr = 0;
4100 320459 : if (Toz == 0) ilayptr = 1;
4101 320459 : j = ilayptr;
4102 : // Calculate Rho at link height only if we have large openings or layered zones.
4103 320459 : k = 1;
4104 320459 : lclimb(state, G, RhoLd(2), state.afn->AirflowNetworkLinkageData(i).NodeHeights[1], TempL2, Xhl2, DpT(k), Toz, PzTo, Pbz, RhoDrL(i, 2));
4105 320459 : Real64 RhoL2 = RhoLd(2);
4106 :
4107 : // For large openings calculate the stack pressure difference profile and the
4108 : // density profile within the the top- and the bottom- height of the large opening
4109 320459 : if (ActLOwnh > 0.0) {
4110 2 : HSt(k) = state.afn->AirflowNetworkLinkageData(i).NodeHeights[1];
4111 2 : RhoStT(k) = RhoL2;
4112 2 : ++k;
4113 2 : HSt(k) = 0.0;
4114 2 : if (HSt(k - 1) < 0.0) HSt(k) = HSt(k - 1);
4115 : while (true) {
4116 4 : ilayptr = 0;
4117 4 : if (Toz == 0) ilayptr = 9;
4118 4 : if ((j > ilayptr) || (HSt(k) > state.afn->AirflowNetworkLinkageData(i).NodeHeights[1])) break;
4119 2 : j += 9;
4120 2 : HSt(k) = 0.0;
4121 2 : if (HSt(k - 1) < 0.0) HSt(k) = HSt(k - 1);
4122 : }
4123 : // Calculate Rho and stack pressure for every StartHeight of a layer which is
4124 : // within the top- and the bottom-height of the large opening.
4125 : while (true) {
4126 2 : ilayptr = 0;
4127 2 : if (Toz == 0) ilayptr = 9;
4128 2 : if ((j > ilayptr) || (HSt(k) >= (state.afn->AirflowNetworkLinkageData(i).NodeHeights[1] + ActLOwnh)))
4129 2 : break; // Autodesk:BoundsViolation Hst(k) @ k>2
4130 0 : T = TzTo;
4131 0 : X = XhzTo;
4132 0 : lclimb(state, G, RhoStd, HSt(k), T, X, DpT(k), Toz, PzTo, Pbz, RhoDrDummi); // Autodesk:BoundsViolation HSt(k) and DpT(k) @ k>2
4133 0 : RhoStT(k) = RhoStd; // Autodesk:BoundsViolation RhoStT(k) @ k>2
4134 0 : j += 9;
4135 0 : ++k; // Autodesk:Note k>2 now
4136 0 : HSt(k) = 0.0; // Autodesk:BoundsViolation @ k>2
4137 0 : if (HSt(k - 1) < 0.0) HSt(k) = HSt(k - 1); // Autodesk:BoundsViolation @ k>2
4138 : }
4139 : // Stack pressure difference and rho for top-height of the large opening
4140 2 : HSt(k) = state.afn->AirflowNetworkLinkageData(i).NodeHeights[1] + ActLOwnh; // Autodesk:BoundsViolation k>2 poss
4141 2 : T = TzTo;
4142 2 : X = XhzTo;
4143 2 : lclimb(state, G, RhoStd, HSt(k), T, X, DpT(k), Toz, PzTo, Pbz, RhoDrDummi); // Autodesk:BoundsViolation k>2 poss
4144 2 : RhoStT(k) = RhoStd; // Autodesk:BoundsViolation k>2 poss
4145 :
4146 4 : for (j = 1; j <= (k - 1); ++j) {
4147 2 : BetaStT(j) = (RhoStT(j + 1) - RhoStT(j)) / (HSt(j + 1) - HSt(j));
4148 : }
4149 : }
4150 :
4151 : // CALCULATE STACK PRESSURE FOR THE PATH ITSELF for different flow directions
4152 320459 : H = double(state.afn->AirflowNetworkLinkageData(i).NodeHeights[1]) - double(state.afn->AirflowNetworkLinkageData(i).NodeHeights[0]);
4153 320459 : if (ll == 0 || ll == 3 || ll == 6) {
4154 320459 : H -= state.afn->AirflowNetworkNodeData(From).NodeHeight;
4155 : }
4156 320459 : if (ll < 3) {
4157 33810 : H += state.afn->AirflowNetworkNodeData(To).NodeHeight;
4158 : }
4159 :
4160 : // IF AIR FLOWS from "From" to "To"
4161 320459 : Pref = Pbz + PzFrom + DpF(1);
4162 320459 : DpP = psz(Pref, RhoLd(1), 0.0, 0.0, H, G);
4163 320459 : DpL(i, 1) = (DpF(1) - DpT(1) + DpP);
4164 :
4165 : // IF AIR FLOWS from "To" to "From"
4166 320459 : Pref = Pbz + PzTo + DpT(1);
4167 320459 : DpP = -psz(Pref, RhoLd(2), 0.0, 0.0, -H, G);
4168 320459 : DpL(i, 2) = (DpF(1) - DpT(1) + DpP);
4169 :
4170 320459 : if (Ltyp == iComponentTypeNum::DOP) {
4171 2 : Pprof = OpenNum * (NrInt + 2);
4172 2 : presprofile(state, i, Pprof, G, DpF, DpT, BetaStF, BetaStT, RhoStF, RhoStT, From, To, ActLh, Hfl(i));
4173 2 : ++OpenNum;
4174 : }
4175 : }
4176 16873 : }
4177 :
4178 1281840 : Real64 DetailedOpeningSolver::psz(Real64 const Pz0, // Pressure at altitude z0 [Pa]
4179 : Real64 const Rho0, // density at altitude z0 [kg/m3]
4180 : Real64 const beta, // density gradient [kg/m4]
4181 : Real64 const z0, // reference altitude [m]
4182 : Real64 const z, // altitude[m]
4183 : Real64 const g // gravity field strength [N/kg]
4184 : )
4185 : {
4186 :
4187 : // FUNCTION INFORMATION:
4188 : // AUTHOR Lixing Gu
4189 : // DATE WRITTEN Oct. 2005
4190 : // MODIFIED na
4191 : // RE-ENGINEERED This subroutine is revised based on psz function from COMIS
4192 :
4193 : // PURPOSE OF THIS SUBROUTINE:
4194 : // This function determines the pressure due to buoyancy in a stratified density environment
4195 :
4196 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4197 : Real64 dz;
4198 : Real64 rho;
4199 :
4200 1281840 : dz = z - z0;
4201 1281840 : rho = (Rho0 + beta * dz / 2.0);
4202 1281840 : return -Pz0 * (1.0 - std::exp(-dz * rho * g / Pz0)); // Differential pressure from z to z0 [Pa]
4203 : }
4204 :
4205 640922 : void DetailedOpeningSolver::lclimb(EnergyPlusData &state,
4206 : Real64 const G, // gravity field strength [N/kg]
4207 : Real64 &Rho, // Density link level (initialized with rho zone) [kg/m3]
4208 : Real64 const Z, // Height of the link above the zone reference [m]
4209 : Real64 &T, // temperature at link level [C]
4210 : Real64 &X, // absolute humidity at link level [kg/kg]
4211 : Real64 &Dp, // Stackpressure to the linklevel [Pa]
4212 : int const zone, // Zone number
4213 : Real64 const PZ, // Zone Pressure (reflevel) [Pa]
4214 : Real64 const Pbz, // Barometric pressure at entrance level [Pa]
4215 : Real64 &RhoDr // Air density of dry air on the link level used
4216 : )
4217 : {
4218 :
4219 : // FUNCTION INFORMATION:
4220 : // AUTHOR Lixing Gu
4221 : // DATE WRITTEN Oct. 2005
4222 : // MODIFIED na
4223 : // RE-ENGINEERED This subroutine is revised based on subroutine IClimb from COMIS
4224 :
4225 : // PURPOSE OF THIS SUBROUTINE:
4226 : // This function the differential pressure from the reflevel in a zone To Z, the level of a link
4227 :
4228 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
4229 : Real64 H; // Start Height of the layer
4230 : Real64 BetaT; // Temperature gradient of this layer
4231 : Real64 BetaXfct; // Humidity gradient factor of this layer
4232 : Real64 BetaCfct; // Concentration 1 gradient factor of this layer
4233 : Real64 X0;
4234 : Real64 P;
4235 : Real64 Htop;
4236 : Real64 Hbot;
4237 : Real64 Rho0;
4238 : Real64 Rho1;
4239 : Real64 BetaRho;
4240 : static int L(0);
4241 : static int ilayptr(0);
4242 :
4243 640922 : Dp = 0.0;
4244 640922 : Rho0 = Rho;
4245 640922 : X0 = X;
4246 640922 : if (Z > 0.0) {
4247 : // initialize start values
4248 640922 : H = 0.0;
4249 640922 : BetaT = 0.0;
4250 640922 : BetaXfct = 0.0;
4251 640922 : BetaCfct = 0.0;
4252 640922 : BetaRho = 0.0;
4253 640922 : Hbot = 0.0;
4254 :
4255 640922 : while (H < 0.0) {
4256 : // loop until H>0 ; The start of the layer is above 0
4257 0 : BetaT = 0.0;
4258 0 : BetaXfct = 0.0;
4259 0 : BetaCfct = 0.0;
4260 0 : L += 9;
4261 0 : ilayptr = 0;
4262 0 : if (zone == 0) ilayptr = 9;
4263 0 : if (L >= ilayptr) {
4264 0 : H = Z + 1.0;
4265 : } else {
4266 0 : H = 0.0;
4267 : }
4268 : }
4269 :
4270 : // The link is in this layer also if it is on the top of it.
4271 :
4272 : while (true) {
4273 1281844 : if (H >= Z) {
4274 : // the link ends in this layer , we reached the final Dp and BetaRho
4275 640922 : Htop = Z;
4276 640922 : P = PZ + Dp;
4277 640922 : if (Htop != Hbot) {
4278 640922 : Rho0 = state.afn->properties.density(Pbz + P, T, X);
4279 640922 : T += (Htop - Hbot) * BetaT;
4280 640922 : X += (Htop - Hbot) * BetaXfct * X0;
4281 640922 : Rho1 = state.afn->properties.density(Pbz + P, T, X);
4282 640922 : BetaRho = (Rho1 - Rho0) / (Htop - Hbot);
4283 640922 : Dp += psz(Pbz + P, Rho0, BetaRho, Hbot, Htop, G);
4284 : }
4285 640922 : RhoDr = state.afn->properties.density(Pbz + PZ + Dp, T, X);
4286 640922 : Rho = state.afn->properties.density(Pbz + PZ + Dp, T, X);
4287 640922 : return;
4288 :
4289 : } else {
4290 : // bottom of the layer is below Z (Z above ref)
4291 640922 : Htop = H;
4292 : // P is the pressure up to the start height of the layer we just reached
4293 640922 : P = PZ + Dp;
4294 640922 : if (Htop != Hbot) {
4295 0 : Rho0 = state.afn->properties.density(Pbz + P, T, X);
4296 0 : T += (Htop - Hbot) * BetaT;
4297 0 : X += (Htop - Hbot) * BetaXfct * X0;
4298 0 : Rho1 = state.afn->properties.density(Pbz + P, T, X);
4299 0 : BetaRho = (Rho1 - Rho0) / (Htop - Hbot);
4300 0 : Dp += psz(Pbz + P, Rho0, BetaRho, Hbot, Htop, G);
4301 : }
4302 :
4303 640922 : RhoDr = state.afn->properties.density(Pbz + PZ + Dp, T, X);
4304 640922 : Rho = state.afn->properties.density(Pbz + PZ + Dp, T, X);
4305 :
4306 : // place current values Hbot and Beta's
4307 640922 : Hbot = H;
4308 640922 : BetaT = 0.0;
4309 640922 : BetaXfct = 0.0;
4310 640922 : BetaCfct = 0.0;
4311 640922 : L += 9;
4312 640922 : ilayptr = 0;
4313 640922 : if (zone == 0) ilayptr = 9;
4314 640922 : if (L >= ilayptr) {
4315 640922 : H = Z + 1.0;
4316 : } else {
4317 0 : H = 0.0;
4318 : }
4319 : }
4320 : }
4321 :
4322 : } else {
4323 : // This is the ELSE for negative linkheights Z below the refplane
4324 0 : H = 0.0;
4325 0 : BetaT = 0.0;
4326 0 : BetaXfct = 0.0;
4327 0 : BetaCfct = 0.0;
4328 0 : BetaRho = 0.0;
4329 0 : Htop = 0.0;
4330 0 : while (H > 0.0) {
4331 : // loop until H<0 ; The start of the layer is below the zone refplane
4332 0 : L -= 9;
4333 0 : ilayptr = 0;
4334 0 : if (zone == 0) ilayptr = 1;
4335 0 : if (L < ilayptr) {
4336 : // with H=Z (negative) this loop will exit, no data for interval Z-refplane
4337 0 : H = Z;
4338 0 : BetaT = 0.0;
4339 0 : BetaXfct = 0.0;
4340 0 : BetaCfct = 0.0;
4341 0 : BetaRho = 0.0;
4342 : } else {
4343 0 : H = 0.0;
4344 0 : BetaT = 0.0;
4345 0 : BetaXfct = 0.0;
4346 0 : BetaCfct = 0.0;
4347 : }
4348 : }
4349 :
4350 : // The link is in this layer also if it is on the bottom of it.
4351 : while (true) {
4352 0 : if (H <= Z) {
4353 0 : Hbot = Z;
4354 0 : P = PZ + Dp;
4355 0 : if (Htop != Hbot) {
4356 0 : Rho1 = state.afn->properties.density(Pbz + P, T, X);
4357 0 : T += (Hbot - Htop) * BetaT;
4358 0 : X += (Hbot - Htop) * BetaXfct * X0;
4359 0 : Rho0 = state.afn->properties.density(Pbz + P, T, X);
4360 0 : BetaRho = (Rho1 - Rho0) / (Htop - Hbot);
4361 0 : Dp -= psz(Pbz + P, Rho0, BetaRho, Hbot, Htop, G);
4362 : }
4363 0 : RhoDr = state.afn->properties.density(Pbz + PZ + Dp, T, X);
4364 0 : Rho = state.afn->properties.density(Pbz + PZ + Dp, T, X);
4365 0 : return;
4366 : } else {
4367 : // bottom of the layer is below Z (Z below ref)
4368 0 : Hbot = H;
4369 0 : P = PZ + Dp;
4370 0 : if (Htop != Hbot) {
4371 0 : Rho1 = state.afn->properties.density(Pbz + P, T, X);
4372 : // T,X,C calculated for the lower height
4373 0 : T += (Hbot - Htop) * BetaT;
4374 0 : X += (Hbot - Htop) * BetaXfct * X0;
4375 0 : Rho0 = state.afn->properties.density(Pbz + P, T, X);
4376 0 : BetaRho = (Rho1 - Rho0) / (Htop - Hbot);
4377 0 : Dp -= psz(Pbz + P, Rho0, BetaRho, Hbot, Htop, G);
4378 : }
4379 0 : RhoDr = state.afn->properties.density(Pbz + PZ + Dp, T, X);
4380 0 : Rho = state.afn->properties.density(Pbz + PZ + Dp, T, X);
4381 :
4382 : // place current values Hbot and Beta's
4383 0 : Htop = H;
4384 0 : L -= 9;
4385 0 : ilayptr = 0;
4386 0 : if (zone == 0) ilayptr = 1;
4387 0 : if (L < ilayptr) {
4388 0 : H = Z - 1.0;
4389 0 : BetaT = 0.0;
4390 0 : BetaXfct = 0.0;
4391 0 : BetaCfct = 0.0;
4392 : } else {
4393 0 : H = 0.0;
4394 0 : BetaT = 0.0;
4395 0 : BetaXfct = 0.0;
4396 0 : BetaCfct = 0.0;
4397 : }
4398 : }
4399 : // ENDIF H<Z
4400 : }
4401 : }
4402 : }
4403 :
4404 : } // namespace AirflowNetwork
4405 :
4406 : } // namespace EnergyPlus
|