Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cassert>
50 : #include <cmath>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Array.functions.hh>
54 : #include <ObjexxFCL/member.functions.hh>
55 :
56 : // EnergyPlus Headers
57 : #include <EnergyPlus/BranchNodeConnections.hh>
58 : #include <EnergyPlus/Construction.hh>
59 : #include <EnergyPlus/ConvectionCoefficients.hh>
60 : #include <EnergyPlus/Data/EnergyPlusData.hh>
61 : #include <EnergyPlus/DataEnvironment.hh>
62 : #include <EnergyPlus/DataHVACGlobals.hh>
63 : #include <EnergyPlus/DataHeatBalSurface.hh>
64 : #include <EnergyPlus/DataHeatBalance.hh>
65 : #include <EnergyPlus/DataIPShortCuts.hh>
66 : #include <EnergyPlus/DataLoopNode.hh>
67 : #include <EnergyPlus/DataSurfaces.hh>
68 : #include <EnergyPlus/EMSManager.hh>
69 : #include <EnergyPlus/General.hh>
70 : #include <EnergyPlus/GeneralRoutines.hh>
71 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
72 : #include <EnergyPlus/Material.hh>
73 : #include <EnergyPlus/NodeInputManager.hh>
74 : #include <EnergyPlus/OutputProcessor.hh>
75 : #include <EnergyPlus/Psychrometrics.hh>
76 : #include <EnergyPlus/ScheduleManager.hh>
77 : #include <EnergyPlus/SolarCollectors.hh>
78 : #include <EnergyPlus/TranspiredCollector.hh>
79 : #include <EnergyPlus/UtilityRoutines.hh>
80 :
81 : namespace EnergyPlus {
82 :
83 : namespace TranspiredCollector {
84 :
85 : // Module containing routines and data dealing with the Transpired Collectors
86 :
87 : // MODULE INFORMATION:
88 : // AUTHOR B.T. Griffith
89 : // DATE WRITTEN November 2004
90 : // MODIFIED na
91 : // RE-ENGINEERED na
92 :
93 : // PURPOSE OF THIS MODULE:
94 : // Encapsulates data and routines for simulating unglazed transpired solar collectors (UTSC)
95 : // as a component on the HVAC air system.
96 :
97 : // METHODOLOGY EMPLOYED:
98 : // Two modes, passive and active. Active is when air is purposely drawn through collector.
99 : // Passive is when air exchanges are driven by Natural Ventilation rather than outside air system
100 :
101 : // REFERENCES:
102 : // Heat Exchange effectiveness relations:
103 : // Kutscher, C.F. 1994. Heat exchange effectiveness and pressure drop for air flow through perforated plates
104 : // with and without crosswind. Journal of Heat Transfer. May 1994, Vol. 116, p. 391.
105 : // American Society of Mechanical Engineers.
106 : // Van Decker, G.W.E., K.G.T. Hollands, and A.P. Brunger. 2001. Heat-exchange relations for unglazed transpired
107 : // solar collectors with circular holes on a square of triangular pitch. Solar Energy. Vol. 71, No. 1. pp 33-45, 2001.
108 : // .
109 :
110 : // OTHER NOTES:
111 : // EnergyPlus implementation is unique and adds new modeling not described in Literature.
112 : // See EngineeringReference for details
113 :
114 : // Using/Aliasing
115 : using DataVectorTypes::Vector;
116 :
117 : int constexpr Layout_Square = 1;
118 : int constexpr Layout_Triangle = 2;
119 : int constexpr Correlation_Kutscher1994 = 1;
120 : int constexpr Correlation_VanDeckerHollandsBrunger2001 = 2;
121 :
122 0 : void SimTranspiredCollector(EnergyPlusData &state,
123 : std::string_view CompName, // component name
124 : int &CompIndex // component index (to reduce string compares during simulation)
125 : )
126 : {
127 :
128 : // SUBROUTINE INFORMATION:
129 : // AUTHOR B.T. Griffith
130 : // DATE WRITTEN November 2004
131 : // MODIFIED na
132 : // RE-ENGINEERED na
133 :
134 : // PURPOSE OF THIS SUBROUTINE:
135 : // Manage simulation of Transpired Collectors
136 :
137 : // METHODOLOGY EMPLOYED:
138 : // Setup to avoid string comparisons after first call
139 :
140 : // Using/Aliasing
141 : using HVAC::TempControlTol;
142 :
143 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
144 :
145 0 : int UTSCNum(0); // local number index for UTSC
146 :
147 0 : if (state.dataTranspiredCollector->GetInputFlag) {
148 0 : GetTranspiredCollectorInput(state);
149 0 : state.dataTranspiredCollector->GetInputFlag = false;
150 : }
151 :
152 : // Find the correct transpired collector with the Component name and/or index
153 0 : if (CompIndex == 0) {
154 0 : UTSCNum = Util::FindItemInList(CompName, state.dataTranspiredCollector->UTSC);
155 0 : if (UTSCNum == 0) {
156 0 : ShowFatalError(state, format("Transpired Collector not found={}", CompName));
157 : }
158 0 : CompIndex = UTSCNum;
159 : } else {
160 0 : UTSCNum = CompIndex;
161 0 : if (UTSCNum > state.dataTranspiredCollector->NumUTSC || UTSCNum < 1) {
162 0 : ShowFatalError(state,
163 0 : format("SimTranspiredCollector: Invalid CompIndex passed={}, Number of Transpired Collectors={}, UTSC name={}",
164 : UTSCNum,
165 0 : state.dataTranspiredCollector->NumUTSC,
166 : CompName));
167 : }
168 0 : if (state.dataTranspiredCollector->CheckEquipName(UTSCNum)) {
169 0 : if (CompName != state.dataTranspiredCollector->UTSC(UTSCNum).Name) {
170 0 : ShowFatalError(state,
171 0 : format("SimTranspiredCollector: Invalid CompIndex passed={}, Transpired Collector name={}, stored Transpired "
172 : "Collector Name for that index={}",
173 : UTSCNum,
174 : CompName,
175 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Name));
176 : }
177 0 : state.dataTranspiredCollector->CheckEquipName(UTSCNum) = false;
178 : }
179 : }
180 :
181 0 : InitTranspiredCollector(state, CompIndex);
182 :
183 : // Control point of deciding if transpired collector is active or not.
184 0 : auto &UTSC_CI = state.dataTranspiredCollector->UTSC(CompIndex);
185 0 : auto &InletNode = UTSC_CI.InletNode;
186 0 : auto &ControlNode = UTSC_CI.ControlNode;
187 0 : UTSC_CI.IsOn = false;
188 0 : if ((UTSC_CI.availSched->getCurrentVal() > 0.0) && (UTSC_CI.InletMDot > 0.0)) { // availability Schedule | OA system is setting mass flow
189 0 : bool ControlLTSet(false);
190 0 : bool ControlLTSchedule(false);
191 0 : bool ZoneLTSchedule(false);
192 0 : assert(equal_dimensions(InletNode, ControlNode));
193 0 : assert(equal_dimensions(InletNode, UTSC_CI.ZoneNode));
194 0 : for (int i = InletNode.l(), e = InletNode.u(); i <= e; ++i) {
195 0 : if (state.dataLoopNodes->Node(InletNode(i)).Temp + TempControlTol < state.dataLoopNodes->Node(ControlNode(i)).TempSetPoint)
196 0 : ControlLTSet = true;
197 0 : if (state.dataLoopNodes->Node(InletNode(i)).Temp + TempControlTol < UTSC_CI.freeHeatSetPointSched->getCurrentVal())
198 0 : ControlLTSchedule = true;
199 0 : if (state.dataLoopNodes->Node(UTSC_CI.ZoneNode(i)).Temp + TempControlTol < UTSC_CI.freeHeatSetPointSched->getCurrentVal())
200 0 : ZoneLTSchedule = true;
201 : }
202 0 : if (ControlLTSet || (ControlLTSchedule && ZoneLTSchedule))
203 0 : UTSC_CI.IsOn = true; // heating required | free heating helpful | free heating helpful
204 : }
205 :
206 0 : if (state.dataTranspiredCollector->UTSC(UTSCNum).IsOn) {
207 0 : CalcActiveTranspiredCollector(state, UTSCNum);
208 : } else {
209 0 : CalcPassiveTranspiredCollector(state, UTSCNum);
210 : }
211 :
212 0 : UpdateTranspiredCollector(state, UTSCNum);
213 0 : }
214 :
215 1 : void GetTranspiredCollectorInput(EnergyPlusData &state)
216 : {
217 :
218 : // SUBROUTINE INFORMATION:
219 : // AUTHOR B.T. Griffith
220 : // DATE WRITTEN November 2004
221 : // MODIFIED na
222 : // RE-ENGINEERED na
223 :
224 : // PURPOSE OF THIS SUBROUTINE:
225 : // Retrieve user input and set up data structure
226 :
227 : // METHODOLOGY EMPLOYED:
228 : // usual EnergyPlus input
229 : // Extensible UTSC object for underlying heat transfer surfaces and for multisystem
230 :
231 : static constexpr std::string_view routineName = "GetTranspiredCollectorInput";
232 :
233 : // Using/Aliasing
234 : using BranchNodeConnections::TestCompSet;
235 : using DataLoopNode::ObjectIsNotParent;
236 : using DataSurfaces::OtherSideCondModeledExt;
237 : using DataSurfaces::SurfaceData;
238 : using NodeInputManager::GetOnlySingleNode;
239 :
240 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
241 :
242 1 : Array1D_string Alphas; // Alpha items for extensible
243 : // Solar Collectors:Unglazed Transpired object
244 : int Item; // Item to be "gotten"
245 1 : Array1D<Real64> Numbers(11); // Numeric items for object
246 : int NumAlphas; // Number of Alphas for each GetObjectItem call
247 : int NumNumbers; // Number of Numbers for each GetObjectItem call
248 : int MaxNumAlphas; // argument for call to GetObjectDefMaxArgs
249 : int MaxNumNumbers; // argument for call to GetObjectDefMaxArgs
250 : int Dummy; // argument for call to GetObjectDefMaxArgs
251 : int IOStatus; // Used in GetObjectItem
252 1 : bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
253 : int Found;
254 : int AlphaOffset; // local temp var
255 1 : std::string Roughness;
256 : int ThisSurf; // do loop counter
257 : Real64 AvgAzimuth; // temp for error checking
258 : Real64 AvgTilt; // temp for error checking
259 : int SurfID; // local surface "pointer"
260 : Real64 TiltRads; // average tilt of collector in radians
261 : Real64 tempHdeltaNPL; // temporary variable for buoyancy length scale
262 1 : int NumUTSCSplitter(0);
263 1 : Array1D_string AlphasSplit; // Alpha items for extensible
264 : // Solar Collectors:Unglazed Transpired object
265 : int ItemSplit; // Item to be "gotten"
266 1 : Array1D<Real64> NumbersSplit(1); // Numeric items for object
267 : int NumAlphasSplit; // Number of Alphas for each GetObjectItem call
268 : int NumNumbersSplit; // Number of Numbers for each GetObjectItem call
269 : int MaxNumAlphasSplit; // argument for call to GetObjectDefMaxArgs
270 : int MaxNumNumbersSplit; // argument for call to GetObjectDefMaxArgs
271 : int IOStatusSplit; // Used in GetObjectItem
272 : int NumOASys; // do loop counter
273 : int ACountBase; // counter for alhpasSplit
274 1 : Array1D_bool SplitterNameOK; // check for correct association of
275 1 : std::string CurrentModuleObject; // for ease in renaming.
276 1 : std::string CurrentModuleMultiObject; // for ease in renaming.
277 :
278 1 : CurrentModuleObject = "SolarCollector:UnglazedTranspired";
279 1 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, Dummy, MaxNumAlphas, MaxNumNumbers);
280 :
281 1 : if (MaxNumNumbers != 11) {
282 0 : ShowSevereError(state,
283 0 : format("GetTranspiredCollectorInput: {} Object Definition indicates not = 11 Number Objects, Number Indicated={}",
284 : CurrentModuleObject,
285 : MaxNumNumbers));
286 0 : ErrorsFound = true;
287 : }
288 1 : Alphas.allocate(MaxNumAlphas);
289 1 : Numbers = 0.0;
290 1 : Alphas = "";
291 :
292 1 : state.dataTranspiredCollector->NumUTSC = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
293 1 : CurrentModuleMultiObject = "SolarCollector:UnglazedTranspired:Multisystem";
294 1 : NumUTSCSplitter = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleMultiObject);
295 :
296 1 : state.dataTranspiredCollector->UTSC.allocate(state.dataTranspiredCollector->NumUTSC);
297 1 : state.dataTranspiredCollector->CheckEquipName.dimension(state.dataTranspiredCollector->NumUTSC, true);
298 1 : SplitterNameOK.dimension(NumUTSCSplitter, false);
299 :
300 2 : for (Item = 1; Item <= state.dataTranspiredCollector->NumUTSC; ++Item) {
301 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
302 : CurrentModuleObject,
303 : Item,
304 : Alphas,
305 : NumAlphas,
306 : Numbers,
307 : NumNumbers,
308 : IOStatus,
309 1 : state.dataIPShortCut->lNumericFieldBlanks,
310 1 : state.dataIPShortCut->lAlphaFieldBlanks,
311 1 : state.dataIPShortCut->cAlphaFieldNames,
312 1 : state.dataIPShortCut->cNumericFieldNames);
313 :
314 1 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
315 :
316 : // first handle alphas
317 1 : state.dataTranspiredCollector->UTSC(Item).Name = Alphas(1);
318 :
319 : // now check for multisystem
320 1 : if (NumUTSCSplitter > 0) {
321 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(
322 : state, CurrentModuleMultiObject, Dummy, MaxNumAlphasSplit, MaxNumNumbersSplit);
323 :
324 0 : if (MaxNumNumbersSplit != 0) {
325 0 : ShowSevereError(state,
326 0 : format("GetTranspiredCollectorInput: {} Object Definition indicates not = 0 Number Objects, Number Indicated={}",
327 : CurrentModuleMultiObject,
328 : MaxNumNumbersSplit));
329 0 : ErrorsFound = true;
330 : }
331 0 : if (!allocated(AlphasSplit)) AlphasSplit.allocate(MaxNumAlphasSplit);
332 0 : NumbersSplit = 0.0;
333 0 : AlphasSplit = "";
334 0 : for (ItemSplit = 1; ItemSplit <= NumUTSCSplitter; ++ItemSplit) {
335 0 : state.dataInputProcessing->inputProcessor->getObjectItem(
336 : state, CurrentModuleMultiObject, ItemSplit, AlphasSplit, NumAlphasSplit, NumbersSplit, NumNumbersSplit, IOStatusSplit);
337 0 : if (!(Util::SameString(AlphasSplit(1), Alphas(1)))) continue;
338 0 : SplitterNameOK(ItemSplit) = true;
339 0 : state.dataTranspiredCollector->UTSC(Item).NumOASysAttached = std::floor(NumAlphasSplit / 4.0);
340 0 : if (mod((NumAlphasSplit), 4) != 1) {
341 0 : ShowSevereError(state,
342 0 : format("GetTranspiredCollectorInput: {} Object Definition indicates not uniform quadtuples of nodes for {}",
343 : CurrentModuleMultiObject,
344 : AlphasSplit(1)));
345 0 : ErrorsFound = true;
346 : }
347 0 : state.dataTranspiredCollector->UTSC(Item).InletNode.allocate(state.dataTranspiredCollector->UTSC(Item).NumOASysAttached);
348 0 : state.dataTranspiredCollector->UTSC(Item).InletNode = 0;
349 0 : state.dataTranspiredCollector->UTSC(Item).OutletNode.allocate(state.dataTranspiredCollector->UTSC(Item).NumOASysAttached);
350 0 : state.dataTranspiredCollector->UTSC(Item).OutletNode = 0;
351 0 : state.dataTranspiredCollector->UTSC(Item).ControlNode.allocate(state.dataTranspiredCollector->UTSC(Item).NumOASysAttached);
352 0 : state.dataTranspiredCollector->UTSC(Item).ControlNode = 0;
353 0 : state.dataTranspiredCollector->UTSC(Item).ZoneNode.allocate(state.dataTranspiredCollector->UTSC(Item).NumOASysAttached);
354 0 : state.dataTranspiredCollector->UTSC(Item).ZoneNode = 0;
355 0 : for (NumOASys = 1; NumOASys <= state.dataTranspiredCollector->UTSC(Item).NumOASysAttached; ++NumOASys) {
356 0 : ACountBase = (NumOASys - 1) * 4 + 2;
357 0 : state.dataTranspiredCollector->UTSC(Item).InletNode(NumOASys) =
358 0 : GetOnlySingleNode(state,
359 0 : AlphasSplit(ACountBase),
360 : ErrorsFound,
361 : DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
362 0 : AlphasSplit(1),
363 : DataLoopNode::NodeFluidType::Air,
364 : DataLoopNode::ConnectionType::Inlet,
365 : static_cast<NodeInputManager::CompFluidStream>(NumOASys),
366 : ObjectIsNotParent);
367 :
368 0 : state.dataTranspiredCollector->UTSC(Item).OutletNode(NumOASys) =
369 0 : GetOnlySingleNode(state,
370 0 : AlphasSplit(ACountBase + 1),
371 : ErrorsFound,
372 : DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
373 0 : AlphasSplit(1),
374 : DataLoopNode::NodeFluidType::Air,
375 : DataLoopNode::ConnectionType::Outlet,
376 : static_cast<NodeInputManager::CompFluidStream>(NumOASys),
377 : ObjectIsNotParent);
378 0 : TestCompSet(state,
379 : CurrentModuleObject,
380 0 : AlphasSplit(1),
381 0 : AlphasSplit(ACountBase),
382 0 : AlphasSplit(ACountBase + 1),
383 : "Transpired Collector Air Nodes"); // appears that test fails by design??
384 0 : state.dataTranspiredCollector->UTSC(Item).ControlNode(NumOASys) =
385 0 : GetOnlySingleNode(state,
386 0 : AlphasSplit(ACountBase + 2),
387 : ErrorsFound,
388 : DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
389 0 : AlphasSplit(1),
390 : DataLoopNode::NodeFluidType::Air,
391 : DataLoopNode::ConnectionType::Sensor,
392 : NodeInputManager::CompFluidStream::Primary,
393 : ObjectIsNotParent);
394 :
395 0 : state.dataTranspiredCollector->UTSC(Item).ZoneNode(NumOASys) =
396 0 : GetOnlySingleNode(state,
397 0 : AlphasSplit(ACountBase + 3),
398 : ErrorsFound,
399 : DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
400 0 : AlphasSplit(1),
401 : DataLoopNode::NodeFluidType::Air,
402 : DataLoopNode::ConnectionType::Sensor,
403 : NodeInputManager::CompFluidStream::Primary,
404 : ObjectIsNotParent);
405 :
406 : } // Each OA System in a Multisystem
407 : // DEALLOCATE(AlphasSplit)
408 : } // each Multisystem present
409 : } // any UTSC Multisystem present
410 :
411 1 : state.dataTranspiredCollector->UTSC(Item).OSCMName = Alphas(2);
412 1 : Found = Util::FindItemInList(state.dataTranspiredCollector->UTSC(Item).OSCMName, state.dataSurface->OSCM);
413 1 : if (Found == 0) {
414 0 : ShowSevereError(state,
415 0 : format("{} not found={} in {} ={}",
416 0 : state.dataIPShortCut->cAlphaFieldNames(2),
417 0 : state.dataTranspiredCollector->UTSC(Item).OSCMName,
418 : CurrentModuleObject,
419 0 : state.dataTranspiredCollector->UTSC(Item).Name));
420 0 : ErrorsFound = true;
421 : }
422 1 : state.dataTranspiredCollector->UTSC(Item).OSCMPtr = Found;
423 1 : if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
424 0 : state.dataTranspiredCollector->UTSC(Item).availSched = Sched::GetScheduleAlwaysOn(state);
425 1 : } else if ((state.dataTranspiredCollector->UTSC(Item).availSched = Sched::GetSchedule(state, Alphas(3))) == nullptr) {
426 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(3), Alphas(3));
427 0 : ErrorsFound = true;
428 0 : continue;
429 : }
430 :
431 : // now if UTSC(Item)%NumOASysAttached still not set, assume no multisystem
432 1 : if (state.dataTranspiredCollector->UTSC(Item).NumOASysAttached == 0) {
433 1 : state.dataTranspiredCollector->UTSC(Item).NumOASysAttached = 1;
434 1 : state.dataTranspiredCollector->UTSC(Item).InletNode.allocate(1);
435 1 : state.dataTranspiredCollector->UTSC(Item).InletNode(1) = 0;
436 1 : state.dataTranspiredCollector->UTSC(Item).OutletNode.allocate(1);
437 1 : state.dataTranspiredCollector->UTSC(Item).OutletNode(1) = 0;
438 1 : state.dataTranspiredCollector->UTSC(Item).ControlNode.allocate(1);
439 1 : state.dataTranspiredCollector->UTSC(Item).ControlNode(1) = 0;
440 1 : state.dataTranspiredCollector->UTSC(Item).ZoneNode.allocate(1);
441 1 : state.dataTranspiredCollector->UTSC(Item).ZoneNode(1) = 0;
442 :
443 1 : state.dataTranspiredCollector->UTSC(Item).InletNode(1) =
444 2 : GetOnlySingleNode(state,
445 1 : Alphas(4),
446 : ErrorsFound,
447 : DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
448 1 : Alphas(1),
449 : DataLoopNode::NodeFluidType::Air,
450 : DataLoopNode::ConnectionType::Inlet,
451 : NodeInputManager::CompFluidStream::Primary,
452 : ObjectIsNotParent);
453 1 : state.dataTranspiredCollector->UTSC(Item).OutletNode(1) =
454 3 : GetOnlySingleNode(state,
455 1 : Alphas(5),
456 : ErrorsFound,
457 : DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
458 1 : Alphas(1),
459 : DataLoopNode::NodeFluidType::Air,
460 : DataLoopNode::ConnectionType::Outlet,
461 : NodeInputManager::CompFluidStream::Primary,
462 : ObjectIsNotParent);
463 1 : TestCompSet(state, CurrentModuleObject, Alphas(1), Alphas(4), Alphas(5), "Transpired Collector Air Nodes");
464 :
465 1 : state.dataTranspiredCollector->UTSC(Item).ControlNode(1) =
466 2 : GetOnlySingleNode(state,
467 1 : Alphas(6),
468 : ErrorsFound,
469 : DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
470 1 : Alphas(1),
471 : DataLoopNode::NodeFluidType::Air,
472 : DataLoopNode::ConnectionType::Sensor,
473 : NodeInputManager::CompFluidStream::Primary,
474 : ObjectIsNotParent);
475 1 : state.dataTranspiredCollector->UTSC(Item).ZoneNode(1) =
476 3 : GetOnlySingleNode(state,
477 1 : Alphas(7),
478 : ErrorsFound,
479 : DataLoopNode::ConnectionObjectType::SolarCollectorUnglazedTranspired,
480 1 : Alphas(1),
481 : DataLoopNode::NodeFluidType::Air,
482 : DataLoopNode::ConnectionType::Sensor,
483 : NodeInputManager::CompFluidStream::Primary,
484 : ObjectIsNotParent);
485 : } // no splitter
486 :
487 1 : if (state.dataIPShortCut->lAlphaFieldBlanks(8)) {
488 0 : ShowSevereEmptyField(state, eoh, state.dataIPShortCut->cAlphaFieldNames(8));
489 0 : ErrorsFound = true;
490 1 : } else if ((state.dataTranspiredCollector->UTSC(Item).freeHeatSetPointSched = Sched::GetSchedule(state, Alphas(8))) == nullptr) {
491 0 : ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(8), Alphas(8));
492 0 : ErrorsFound = true;
493 0 : continue;
494 : }
495 :
496 1 : if (Util::SameString(Alphas(9), "Triangle")) {
497 1 : state.dataTranspiredCollector->UTSC(Item).Layout = Layout_Triangle;
498 0 : } else if (Util::SameString(Alphas(9), "Square")) {
499 0 : state.dataTranspiredCollector->UTSC(Item).Layout = Layout_Square;
500 : } else {
501 0 : ShowSevereError(state,
502 0 : format("{} has incorrect entry of {} in {} ={}",
503 0 : state.dataIPShortCut->cAlphaFieldNames(9),
504 : Alphas(9),
505 : CurrentModuleObject,
506 0 : state.dataTranspiredCollector->UTSC(Item).Name));
507 0 : ErrorsFound = true;
508 0 : continue;
509 : }
510 :
511 1 : if (Util::SameString(Alphas(10), "Kutscher1994")) {
512 1 : state.dataTranspiredCollector->UTSC(Item).Correlation = Correlation_Kutscher1994;
513 0 : } else if (Util::SameString(Alphas(10), "VanDeckerHollandsBrunger2001")) {
514 0 : state.dataTranspiredCollector->UTSC(Item).Correlation = Correlation_VanDeckerHollandsBrunger2001;
515 : } else {
516 0 : ShowSevereError(state,
517 0 : format("{} has incorrect entry of {} in {} ={}",
518 0 : state.dataIPShortCut->cAlphaFieldNames(10),
519 : Alphas(9),
520 : CurrentModuleObject,
521 0 : state.dataTranspiredCollector->UTSC(Item).Name));
522 0 : ErrorsFound = true;
523 0 : continue;
524 : }
525 :
526 1 : Roughness = Alphas(11);
527 : // Select the correct Number for the associated ascii name for the roughness type
528 1 : if (Util::SameString(Roughness, "VeryRough"))
529 0 : state.dataTranspiredCollector->UTSC(Item).CollRoughness = Material::SurfaceRoughness::VeryRough;
530 1 : if (Util::SameString(Roughness, "Rough")) state.dataTranspiredCollector->UTSC(Item).CollRoughness = Material::SurfaceRoughness::Rough;
531 1 : if (Util::SameString(Roughness, "MediumRough"))
532 1 : state.dataTranspiredCollector->UTSC(Item).CollRoughness = Material::SurfaceRoughness::MediumRough;
533 1 : if (Util::SameString(Roughness, "MediumSmooth"))
534 0 : state.dataTranspiredCollector->UTSC(Item).CollRoughness = Material::SurfaceRoughness::MediumSmooth;
535 1 : if (Util::SameString(Roughness, "Smooth")) state.dataTranspiredCollector->UTSC(Item).CollRoughness = Material::SurfaceRoughness::Smooth;
536 1 : if (Util::SameString(Roughness, "VerySmooth"))
537 0 : state.dataTranspiredCollector->UTSC(Item).CollRoughness = Material::SurfaceRoughness::VerySmooth;
538 :
539 : // Was it set?
540 1 : if (state.dataTranspiredCollector->UTSC(Item).CollRoughness == Material::SurfaceRoughness::Invalid) {
541 0 : ShowSevereError(state,
542 0 : format("{} has incorrect entry of {} in {} ={}",
543 0 : state.dataIPShortCut->cAlphaFieldNames(11),
544 : Alphas(11),
545 : CurrentModuleObject,
546 0 : state.dataTranspiredCollector->UTSC(Item).Name));
547 0 : ErrorsFound = true;
548 : }
549 :
550 1 : AlphaOffset = 11;
551 1 : state.dataTranspiredCollector->UTSC(Item).NumSurfs = NumAlphas - AlphaOffset;
552 1 : if (state.dataTranspiredCollector->UTSC(Item).NumSurfs == 0) {
553 0 : ShowSevereError(
554 0 : state, format("No underlying surfaces specified in {} ={}", CurrentModuleObject, state.dataTranspiredCollector->UTSC(Item).Name));
555 0 : ErrorsFound = true;
556 0 : continue;
557 : }
558 1 : state.dataTranspiredCollector->UTSC(Item).SurfPtrs.allocate(state.dataTranspiredCollector->UTSC(Item).NumSurfs);
559 1 : state.dataTranspiredCollector->UTSC(Item).SurfPtrs = 0;
560 3 : for (ThisSurf = 1; ThisSurf <= state.dataTranspiredCollector->UTSC(Item).NumSurfs; ++ThisSurf) {
561 2 : Found = Util::FindItemInList(Alphas(ThisSurf + AlphaOffset), state.dataSurface->Surface);
562 2 : if (Found == 0) {
563 0 : ShowSevereError(state,
564 0 : format("Surface Name not found={} in {} ={}",
565 : Alphas(ThisSurf + AlphaOffset),
566 : CurrentModuleObject,
567 0 : state.dataTranspiredCollector->UTSC(Item).Name));
568 0 : ErrorsFound = true;
569 0 : continue;
570 : }
571 : // check that surface is appropriate, Heat transfer, Sun, Wind,
572 2 : if (!state.dataSurface->Surface(Found).HeatTransSurf) {
573 0 : ShowSevereError(state,
574 0 : format("Surface {} not of Heat Transfer type in {} ={}",
575 : Alphas(ThisSurf + AlphaOffset),
576 : CurrentModuleObject,
577 0 : state.dataTranspiredCollector->UTSC(Item).Name));
578 0 : ErrorsFound = true;
579 0 : continue;
580 : }
581 2 : if (!state.dataSurface->Surface(Found).ExtSolar) {
582 0 : ShowSevereError(state,
583 0 : format("Surface {} not exposed to sun in {} ={}",
584 : Alphas(ThisSurf + AlphaOffset),
585 : CurrentModuleObject,
586 0 : state.dataTranspiredCollector->UTSC(Item).Name));
587 0 : ErrorsFound = true;
588 0 : continue;
589 : }
590 2 : if (!state.dataSurface->Surface(Found).ExtWind) {
591 0 : ShowSevereError(state,
592 0 : format("Surface {} not exposed to wind in {} ={}",
593 : Alphas(ThisSurf + AlphaOffset),
594 : CurrentModuleObject,
595 0 : state.dataTranspiredCollector->UTSC(Item).Name));
596 0 : ErrorsFound = true;
597 0 : continue;
598 : }
599 2 : if (state.dataSurface->Surface(Found).ExtBoundCond != OtherSideCondModeledExt) {
600 0 : ShowSevereError(state,
601 0 : format("Surface {} does not have OtherSideConditionsModel for exterior boundary conditions in {} ={}",
602 : Alphas(ThisSurf + AlphaOffset),
603 : CurrentModuleObject,
604 0 : state.dataTranspiredCollector->UTSC(Item).Name));
605 0 : ErrorsFound = true;
606 0 : continue;
607 : }
608 : // check surface orientation, warn if upside down
609 2 : if ((state.dataSurface->Surface(Found).Tilt < -95.0) || (state.dataSurface->Surface(Found).Tilt > 95.0)) {
610 0 : ShowWarningError(state, format("Suspected input problem with collector surface = {}", Alphas(ThisSurf + AlphaOffset)));
611 0 : ShowContinueError(
612 : state,
613 0 : format("Entered in {} = {}", state.dataIPShortCut->cCurrentModuleObject, state.dataTranspiredCollector->UTSC(Item).Name));
614 0 : ShowContinueError(state, "Surface used for solar collector faces down");
615 0 : ShowContinueError(
616 0 : state, format("Surface tilt angle (degrees from ground outward normal) = {:.2R}", state.dataSurface->Surface(Found).Tilt));
617 : }
618 :
619 2 : state.dataTranspiredCollector->UTSC(Item).SurfPtrs(ThisSurf) = Found;
620 : }
621 :
622 1 : if (ErrorsFound) continue; // previous inner do loop may have detected problems that need to be cycle'd again to avoid crash
623 :
624 : // now that we should have all the surfaces, do some preparations and checks.
625 :
626 : // are they all similar tilt and azimuth? Issue warnings so people can do it if they really want
627 1 : Real64 const surfaceArea(sum_sub(state.dataSurface->Surface, &SurfaceData::Area, state.dataTranspiredCollector->UTSC(Item).SurfPtrs));
628 : // AvgAzimuth = sum( Surface( UTSC( Item ).SurfPtrs ).Azimuth * Surface( UTSC( Item ).SurfPtrs ).Area ) / sum( Surface(
629 : // UTSC( Item
630 : //).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
631 1 : AvgAzimuth =
632 2 : sum_product_sub(
633 1 : state.dataSurface->Surface, &SurfaceData::Azimuth, &SurfaceData::Area, state.dataTranspiredCollector->UTSC(Item).SurfPtrs) /
634 : surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
635 : // AvgTilt = sum( Surface( UTSC( Item ).SurfPtrs ).Tilt * Surface( UTSC( Item ).SurfPtrs ).Area ) / sum( Surface( UTSC(
636 : // Item
637 : //).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
638 2 : AvgTilt = sum_product_sub(
639 1 : state.dataSurface->Surface, &SurfaceData::Tilt, &SurfaceData::Area, state.dataTranspiredCollector->UTSC(Item).SurfPtrs) /
640 : surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
641 3 : for (ThisSurf = 1; ThisSurf <= state.dataTranspiredCollector->UTSC(Item).NumSurfs; ++ThisSurf) {
642 2 : SurfID = state.dataTranspiredCollector->UTSC(Item).SurfPtrs(ThisSurf);
643 2 : if (General::rotAzmDiffDeg(state.dataSurface->Surface(SurfID).Azimuth, AvgAzimuth) > 15.0) {
644 0 : ShowWarningError(state,
645 0 : format("Surface {} has Azimuth different from others in the group associated with {} ={}",
646 0 : state.dataSurface->Surface(SurfID).Name,
647 : CurrentModuleObject,
648 0 : state.dataTranspiredCollector->UTSC(Item).Name));
649 : }
650 2 : if (std::abs(state.dataSurface->Surface(SurfID).Tilt - AvgTilt) > 10.0) {
651 0 : ShowWarningError(state,
652 0 : format("Surface {} has Tilt different from others in the group associated with {} ={}",
653 0 : state.dataSurface->Surface(SurfID).Name,
654 : CurrentModuleObject,
655 0 : state.dataTranspiredCollector->UTSC(Item).Name));
656 : }
657 :
658 : // test that there are no windows. Now allow windows
659 : // If (Surface(SurfID)%GrossArea > Surface(SurfID)%Area) Then
660 : // Call ShowWarningError(state, 'Surface '//TRIM(Surface(SurfID)%name)//' has a subsurface whose area is not being ' &
661 : // //'subtracted in the group of surfaces associated with '//TRIM(UTSC(Item)%Name))
662 : // endif
663 : }
664 1 : state.dataTranspiredCollector->UTSC(Item).Tilt = AvgTilt;
665 1 : state.dataTranspiredCollector->UTSC(Item).Azimuth = AvgAzimuth;
666 :
667 : // find area weighted centroid.
668 : // UTSC(Item)%Centroid%x = SUM(Surface(UTSC(Item)%SurfPtrs)%Centroid%x*Surface(UTSC(Item)%SurfPtrs)%Area) &
669 : // /SUM(Surface(UTSC(Item)%SurfPtrs)%Area)
670 : // UTSC(Item)%Centroid%y = SUM(Surface(UTSC(Item)%SurfPtrs)%Centroid%y*Surface(UTSC(Item)%SurfPtrs)%Area) &
671 : // /SUM(Surface(UTSC(Item)%SurfPtrs)%Area)
672 : // UTSC( Item ).Centroid.z = sum( Surface( UTSC( Item ).SurfPtrs ).Centroid.z * Surface( UTSC( Item ).SurfPtrs ).Area ) /
673 : // sum( Surface( UTSC( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
674 2 : state.dataTranspiredCollector->UTSC(Item).Centroid.z = sum_product_sub(state.dataSurface->Surface,
675 : &SurfaceData::Centroid,
676 : &Vector::z,
677 1 : state.dataSurface->Surface,
678 : &SurfaceData::Area,
679 2 : state.dataTranspiredCollector->UTSC(Item).SurfPtrs) /
680 : surfaceArea; // Autodesk:F2C++ Functions handle array subscript usage
681 :
682 : // now handle numbers from input object
683 1 : state.dataTranspiredCollector->UTSC(Item).HoleDia = Numbers(1);
684 1 : state.dataTranspiredCollector->UTSC(Item).Pitch = Numbers(2);
685 1 : state.dataTranspiredCollector->UTSC(Item).LWEmitt = Numbers(3);
686 1 : state.dataTranspiredCollector->UTSC(Item).SolAbsorp = Numbers(4);
687 1 : state.dataTranspiredCollector->UTSC(Item).Height = Numbers(5);
688 1 : state.dataTranspiredCollector->UTSC(Item).PlenGapThick = Numbers(6);
689 1 : if (state.dataTranspiredCollector->UTSC(Item).PlenGapThick <= 0.0) {
690 0 : ShowSevereError(
691 : state,
692 0 : format("Plenum gap must be greater than Zero in {} ={}", CurrentModuleObject, state.dataTranspiredCollector->UTSC(Item).Name));
693 0 : continue;
694 : }
695 1 : state.dataTranspiredCollector->UTSC(Item).PlenCrossArea = Numbers(7);
696 1 : state.dataTranspiredCollector->UTSC(Item).AreaRatio = Numbers(8);
697 1 : state.dataTranspiredCollector->UTSC(Item).CollectThick = Numbers(9);
698 1 : state.dataTranspiredCollector->UTSC(Item).Cv = Numbers(10);
699 1 : state.dataTranspiredCollector->UTSC(Item).Cd = Numbers(11);
700 :
701 : // Fill out data we now know
702 : // sum areas of HT surface areas
703 : // UTSC( Item ).ProjArea = sum( Surface( UTSC( Item ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced
704 : // by below
705 1 : state.dataTranspiredCollector->UTSC(Item).ProjArea = surfaceArea;
706 1 : if (state.dataTranspiredCollector->UTSC(Item).ProjArea == 0) {
707 0 : ShowSevereError(state,
708 0 : format("Gross area of underlying surfaces is zero in {} ={}",
709 : CurrentModuleObject,
710 0 : state.dataTranspiredCollector->UTSC(Item).Name));
711 0 : continue;
712 : }
713 1 : state.dataTranspiredCollector->UTSC(Item).ActualArea =
714 1 : state.dataTranspiredCollector->UTSC(Item).ProjArea * state.dataTranspiredCollector->UTSC(Item).AreaRatio;
715 : // need to update this for slots as well as holes
716 1 : switch (state.dataTranspiredCollector->UTSC(Item).Layout) {
717 1 : case Layout_Triangle: { // 'TRIANGLE'
718 1 : state.dataTranspiredCollector->UTSC(Item).Porosity =
719 2 : 0.907 * pow_2(state.dataTranspiredCollector->UTSC(Item).HoleDia /
720 1 : state.dataTranspiredCollector->UTSC(Item).Pitch); // Kutscher equation, Triangle layout
721 1 : } break;
722 0 : case Layout_Square: { // 'SQUARE'
723 0 : state.dataTranspiredCollector->UTSC(Item).Porosity =
724 0 : (Constant::Pi / 4.0) * pow_2(state.dataTranspiredCollector->UTSC(Item).HoleDia) /
725 0 : pow_2(state.dataTranspiredCollector->UTSC(Item).Pitch); // Waterloo equation, square layout
726 0 : } break;
727 0 : default:
728 0 : break;
729 : }
730 1 : TiltRads = std::abs(AvgTilt) * Constant::DegToRad;
731 1 : tempHdeltaNPL = std::sin(TiltRads) * state.dataTranspiredCollector->UTSC(Item).Height / 4.0;
732 1 : state.dataTranspiredCollector->UTSC(Item).HdeltaNPL = max(tempHdeltaNPL, state.dataTranspiredCollector->UTSC(Item).PlenGapThick);
733 :
734 2 : SetupOutputVariable(state,
735 : "Solar Collector Heat Exchanger Effectiveness",
736 : Constant::Units::None,
737 1 : state.dataTranspiredCollector->UTSC(Item).HXeff,
738 : OutputProcessor::TimeStepType::System,
739 : OutputProcessor::StoreType::Average,
740 1 : state.dataTranspiredCollector->UTSC(Item).Name);
741 2 : SetupOutputVariable(state,
742 : "Solar Collector Leaving Air Temperature",
743 : Constant::Units::C,
744 1 : state.dataTranspiredCollector->UTSC(Item).TairHX,
745 : OutputProcessor::TimeStepType::System,
746 : OutputProcessor::StoreType::Average,
747 1 : state.dataTranspiredCollector->UTSC(Item).Name);
748 2 : SetupOutputVariable(state,
749 : "Solar Collector Outside Face Suction Velocity",
750 : Constant::Units::m_s,
751 1 : state.dataTranspiredCollector->UTSC(Item).Vsuction,
752 : OutputProcessor::TimeStepType::System,
753 : OutputProcessor::StoreType::Average,
754 1 : state.dataTranspiredCollector->UTSC(Item).Name);
755 2 : SetupOutputVariable(state,
756 : "Solar Collector Surface Temperature",
757 : Constant::Units::C,
758 1 : state.dataTranspiredCollector->UTSC(Item).Tcoll,
759 : OutputProcessor::TimeStepType::System,
760 : OutputProcessor::StoreType::Average,
761 1 : state.dataTranspiredCollector->UTSC(Item).Name);
762 2 : SetupOutputVariable(state,
763 : "Solar Collector Plenum Air Temperature",
764 : Constant::Units::C,
765 1 : state.dataTranspiredCollector->UTSC(Item).Tplen,
766 : OutputProcessor::TimeStepType::System,
767 : OutputProcessor::StoreType::Average,
768 1 : state.dataTranspiredCollector->UTSC(Item).Name);
769 2 : SetupOutputVariable(state,
770 : "Solar Collector Sensible Heating Rate",
771 : Constant::Units::W,
772 1 : state.dataTranspiredCollector->UTSC(Item).SensHeatingRate,
773 : OutputProcessor::TimeStepType::System,
774 : OutputProcessor::StoreType::Average,
775 1 : state.dataTranspiredCollector->UTSC(Item).Name);
776 2 : SetupOutputVariable(state,
777 : "Solar Collector Sensible Heating Energy",
778 : Constant::Units::J,
779 1 : state.dataTranspiredCollector->UTSC(Item).SensHeatingEnergy,
780 : OutputProcessor::TimeStepType::System,
781 : OutputProcessor::StoreType::Sum,
782 1 : state.dataTranspiredCollector->UTSC(Item).Name,
783 : Constant::eResource::SolarAir,
784 : OutputProcessor::Group::HVAC,
785 : OutputProcessor::EndUseCat::HeatProduced);
786 :
787 2 : SetupOutputVariable(state,
788 : "Solar Collector Natural Ventilation Air Change Rate",
789 : Constant::Units::ach,
790 1 : state.dataTranspiredCollector->UTSC(Item).PassiveACH,
791 : OutputProcessor::TimeStepType::System,
792 : OutputProcessor::StoreType::Average,
793 1 : state.dataTranspiredCollector->UTSC(Item).Name);
794 2 : SetupOutputVariable(state,
795 : "Solar Collector Natural Ventilation Mass Flow Rate",
796 : Constant::Units::kg_s,
797 1 : state.dataTranspiredCollector->UTSC(Item).PassiveMdotVent,
798 : OutputProcessor::TimeStepType::System,
799 : OutputProcessor::StoreType::Average,
800 1 : state.dataTranspiredCollector->UTSC(Item).Name);
801 2 : SetupOutputVariable(state,
802 : "Solar Collector Wind Natural Ventilation Mass Flow Rate",
803 : Constant::Units::kg_s,
804 1 : state.dataTranspiredCollector->UTSC(Item).PassiveMdotWind,
805 : OutputProcessor::TimeStepType::System,
806 : OutputProcessor::StoreType::Average,
807 1 : state.dataTranspiredCollector->UTSC(Item).Name);
808 2 : SetupOutputVariable(state,
809 : "Solar Collector Buoyancy Natural Ventilation Mass Flow Rate",
810 : Constant::Units::kg_s,
811 1 : state.dataTranspiredCollector->UTSC(Item).PassiveMdotTherm,
812 : OutputProcessor::TimeStepType::System,
813 : OutputProcessor::StoreType::Average,
814 1 : state.dataTranspiredCollector->UTSC(Item).Name);
815 2 : SetupOutputVariable(state,
816 : "Solar Collector Incident Solar Radiation",
817 : Constant::Units::W_m2,
818 1 : state.dataTranspiredCollector->UTSC(Item).Isc,
819 : OutputProcessor::TimeStepType::System,
820 : OutputProcessor::StoreType::Average,
821 1 : state.dataTranspiredCollector->UTSC(Item).Name);
822 2 : SetupOutputVariable(state,
823 : "Solar Collector System Efficiency",
824 : Constant::Units::None,
825 1 : state.dataTranspiredCollector->UTSC(Item).UTSCEfficiency,
826 : OutputProcessor::TimeStepType::System,
827 : OutputProcessor::StoreType::Average,
828 1 : state.dataTranspiredCollector->UTSC(Item).Name);
829 2 : SetupOutputVariable(state,
830 : "Solar Collector Surface Efficiency",
831 : Constant::Units::None,
832 1 : state.dataTranspiredCollector->UTSC(Item).UTSCCollEff,
833 : OutputProcessor::TimeStepType::System,
834 : OutputProcessor::StoreType::Average,
835 1 : state.dataTranspiredCollector->UTSC(Item).Name);
836 : }
837 :
838 1 : for (ItemSplit = 1; ItemSplit <= NumUTSCSplitter; ++ItemSplit) {
839 0 : if (!SplitterNameOK(ItemSplit)) {
840 0 : ShowSevereError(state, "Did not find a match, check names for Solar Collectors:Transpired Collector:Multisystem");
841 0 : ErrorsFound = true;
842 : }
843 : }
844 :
845 1 : if (ErrorsFound) {
846 0 : ShowFatalError(state, "GetTranspiredCollectorInput: Errors found in input");
847 : }
848 :
849 1 : Alphas.deallocate();
850 1 : }
851 :
852 1 : void InitTranspiredCollector(EnergyPlusData &state, int const UTSCNum) // compindex already checked in calling routine
853 : {
854 :
855 : // SUBROUTINE INFORMATION:
856 : // AUTHOR B.T. Griffith
857 : // DATE WRITTEN November 2004
858 : // MODIFIED B. Griffith, May 2009, added EMS setpoint check
859 : // RE-ENGINEERED na
860 :
861 : // Using/Aliasing
862 1 : bool DoSetPointTest = state.dataHVACGlobal->DoSetPointTest;
863 : using namespace DataLoopNode;
864 : using DataSurfaces::SurfaceData;
865 : using EMSManager::CheckIfNodeSetPointManagedByEMS;
866 :
867 : int UTSCUnitNum;
868 : int ControlNode;
869 : int SplitBranch;
870 : int thisUTSC;
871 : Real64 Tamb;
872 :
873 1 : if (state.dataTranspiredCollector->MyOneTimeFlag) {
874 : // do various one time setups and pitch adjustments across all UTSC
875 2 : for (thisUTSC = 1; thisUTSC <= state.dataTranspiredCollector->NumUTSC; ++thisUTSC) {
876 1 : if (state.dataTranspiredCollector->UTSC(thisUTSC).Layout == Layout_Triangle) {
877 1 : switch (state.dataTranspiredCollector->UTSC(thisUTSC).Correlation) {
878 1 : case Correlation_Kutscher1994: { // Kutscher1994
879 1 : state.dataTranspiredCollector->UTSC(thisUTSC).Pitch = state.dataTranspiredCollector->UTSC(thisUTSC).Pitch;
880 1 : } break;
881 0 : case Correlation_VanDeckerHollandsBrunger2001: { // VanDeckerHollandsBrunger2001
882 0 : state.dataTranspiredCollector->UTSC(thisUTSC).Pitch /= 1.6;
883 0 : } break;
884 0 : default:
885 0 : break;
886 : }
887 : }
888 1 : if (state.dataTranspiredCollector->UTSC(thisUTSC).Layout == Layout_Square) {
889 0 : switch (state.dataTranspiredCollector->UTSC(thisUTSC).Correlation) {
890 0 : case Correlation_Kutscher1994: { // Kutscher1994
891 0 : state.dataTranspiredCollector->UTSC(thisUTSC).Pitch *= 1.6;
892 0 : } break;
893 0 : case Correlation_VanDeckerHollandsBrunger2001: { // VanDeckerHollandsBrunger2001
894 0 : state.dataTranspiredCollector->UTSC(thisUTSC).Pitch = state.dataTranspiredCollector->UTSC(thisUTSC).Pitch;
895 0 : } break;
896 0 : default:
897 0 : break;
898 : }
899 : }
900 : }
901 :
902 1 : state.dataTranspiredCollector->MyEnvrnFlag.dimension(state.dataTranspiredCollector->NumUTSC, true);
903 1 : state.dataTranspiredCollector->MyOneTimeFlag = false;
904 : } // first time
905 :
906 : // Check that setpoint is active (from test by RJL in HVACEvapComponent)
907 1 : if (!state.dataGlobal->SysSizingCalc && state.dataTranspiredCollector->MySetPointCheckFlag && DoSetPointTest) {
908 0 : for (UTSCUnitNum = 1; UTSCUnitNum <= state.dataTranspiredCollector->NumUTSC; ++UTSCUnitNum) {
909 0 : for (SplitBranch = 1; SplitBranch <= state.dataTranspiredCollector->UTSC(UTSCUnitNum).NumOASysAttached; ++SplitBranch) {
910 0 : ControlNode = state.dataTranspiredCollector->UTSC(UTSCUnitNum).ControlNode(SplitBranch);
911 0 : if (ControlNode > 0) {
912 0 : if (state.dataLoopNodes->Node(ControlNode).TempSetPoint == SensedNodeFlagValue) {
913 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
914 0 : ShowSevereError(
915 0 : state, format("Missing temperature setpoint for UTSC {}", state.dataTranspiredCollector->UTSC(UTSCUnitNum).Name));
916 0 : ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the unit control node.");
917 0 : state.dataHVACGlobal->SetPointErrorFlag = true;
918 : } else {
919 : // need call to EMS to check node
920 0 : CheckIfNodeSetPointManagedByEMS(state, ControlNode, HVAC::CtrlVarType::Temp, state.dataHVACGlobal->SetPointErrorFlag);
921 0 : if (state.dataHVACGlobal->SetPointErrorFlag) {
922 0 : ShowSevereError(
923 : state,
924 0 : format("Missing temperature setpoint for UTSC {}", state.dataTranspiredCollector->UTSC(UTSCUnitNum).Name));
925 0 : ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the unit control node.");
926 0 : ShowContinueError(state, "Or add EMS Actuator to provide temperature setpoint at this node");
927 : }
928 : }
929 : }
930 : }
931 : }
932 : }
933 0 : state.dataTranspiredCollector->MySetPointCheckFlag = false;
934 : }
935 :
936 1 : if (state.dataGlobal->BeginEnvrnFlag && state.dataTranspiredCollector->MyEnvrnFlag(UTSCNum)) {
937 1 : state.dataTranspiredCollector->UTSC(UTSCNum).TplenLast = 22.5;
938 1 : state.dataTranspiredCollector->UTSC(UTSCNum).TcollLast = 22.0;
939 :
940 1 : state.dataTranspiredCollector->MyEnvrnFlag(UTSCNum) = false;
941 : }
942 1 : if (!state.dataGlobal->BeginEnvrnFlag) {
943 0 : state.dataTranspiredCollector->MyEnvrnFlag(UTSCNum) = true;
944 : }
945 :
946 : // determine average ambient temperature
947 1 : Real64 sum_area = 0.0;
948 3 : for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
949 2 : sum_area += state.dataSurface->Surface(SurfNum).Area;
950 : }
951 1 : if (!state.dataEnvrn->IsRain) {
952 1 : Real64 sum_produc_area_drybulb = 0.0;
953 3 : for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
954 2 : sum_produc_area_drybulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutDryBulbTemp(SurfNum);
955 : }
956 1 : Tamb = sum_produc_area_drybulb / sum_area;
957 : } else { // when raining we use wet bulb not drybulb
958 0 : Real64 sum_produc_area_wetbulb = 0.0;
959 0 : for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
960 0 : sum_produc_area_wetbulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutWetBulbTemp(SurfNum);
961 : }
962 0 : Tamb = sum_produc_area_wetbulb / sum_area;
963 : }
964 :
965 : // inits for each iteration
966 : // UTSC( UTSCNum ).InletMDot = sum( Node( UTSC( UTSCNum ).InletNode ).MassFlowRate ); //Autodesk:F2C++ Array subscript usage:
967 : // Replaced by below
968 1 : state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot =
969 1 : sum_sub(state.dataLoopNodes->Node,
970 : &DataLoopNode::NodeData::MassFlowRate,
971 1 : state.dataTranspiredCollector->UTSC(UTSCNum).InletNode); // Autodesk:F2C++ Functions handle array subscript usage
972 1 : state.dataTranspiredCollector->UTSC(UTSCNum).IsOn = false; // initialize then turn on if appropriate
973 1 : state.dataTranspiredCollector->UTSC(UTSCNum).Tplen = state.dataTranspiredCollector->UTSC(UTSCNum).TplenLast;
974 1 : state.dataTranspiredCollector->UTSC(UTSCNum).Tcoll = state.dataTranspiredCollector->UTSC(UTSCNum).TcollLast;
975 1 : state.dataTranspiredCollector->UTSC(UTSCNum).TairHX = Tamb;
976 1 : state.dataTranspiredCollector->UTSC(UTSCNum).MdotVent = 0.0;
977 1 : state.dataTranspiredCollector->UTSC(UTSCNum).HXeff = 0.0;
978 1 : state.dataTranspiredCollector->UTSC(UTSCNum).Isc = 0.0;
979 :
980 1 : state.dataTranspiredCollector->UTSC(UTSCNum).UTSCEfficiency = 0.0;
981 1 : state.dataTranspiredCollector->UTSC(UTSCNum).UTSCCollEff = 0.0;
982 1 : }
983 :
984 0 : void CalcActiveTranspiredCollector(EnergyPlusData &state, int const UTSCNum)
985 : {
986 :
987 : // SUBROUTINE INFORMATION:
988 : // AUTHOR B.T. Griffith
989 : // DATE WRITTEN November 2004
990 : // MODIFIED na
991 : // RE-ENGINEERED na
992 :
993 : // Using/Aliasing
994 0 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
995 : using DataSurfaces::SurfaceData;
996 : using Psychrometrics::PsyCpAirFnW;
997 : using Psychrometrics::PsyHFnTdbW;
998 : using Psychrometrics::PsyRhoAirFnPbTdbW;
999 : using namespace DataHeatBalance; // , ONLY: SurfQRadSWOutIncident, Construct, Material
1000 :
1001 : // SUBROUTINE PARAMETER DEFINITIONS:
1002 0 : Real64 constexpr nu(15.66e-6); // kinematic viscosity (m**2/s) for air at 300 K
1003 : // (Mills 1999 Heat Transfer)
1004 0 : Real64 constexpr k(0.0267); // thermal conductivity (W/m K) for air at 300 K
1005 : // (Mills 1999 Heat Transfer)
1006 0 : Real64 constexpr Sigma(5.6697e-08); // Stefan-Boltzmann constant
1007 :
1008 : // following arrays are used to temporarily hold results from multiple underlying surfaces
1009 0 : Array1D<Real64> HSkyARR;
1010 0 : Array1D<Real64> HGroundARR;
1011 0 : Array1D<Real64> HAirARR;
1012 0 : Array1D<Real64> HPlenARR;
1013 0 : Array1D<Real64> LocalWindArr;
1014 0 : Array1D<Real64> HSrdSurfARR;
1015 :
1016 : // working variables
1017 : Real64 RhoAir; // density of air
1018 : Real64 CpAir; // specific heat of air
1019 : Real64 holeArea; // area of perforations, includes corrugation of surface
1020 : Real64 Tamb; // outdoor drybulb
1021 : Real64 A; // projected area of collector, from sum of underlying surfaces
1022 : Real64 Vholes; // mean velocity of air as it passes through collector holes
1023 : Real64 Vsuction; // mean velocity of air as is approaches the collector
1024 : Real64 Vplen; // mean velocity of air inside plenum
1025 : Real64 HcPlen; // surface convection heat transfer coefficient for plenum surfaces
1026 : Real64 D; // hole diameter
1027 : Real64 ReD; // Reynolds number for holes
1028 : Real64 P; // pitch, distance between holes
1029 : Real64 Por; // porosity, area fraction of collector that is open because of holes
1030 : Real64 Mdot; // mass flow rate of suction air
1031 : Real64 QdotSource; // energy flux for source/sink inside collector surface (for hybrid PV UTSC)
1032 : int ThisSurf; // do loop counter
1033 : int NumSurfs; // number of underlying HT surfaces associated with UTSC
1034 : Material::SurfaceRoughness Roughness; // parameters for surface roughness, defined in DataHeatBalance
1035 : Real64 SolAbs; // solar absorptivity of collector
1036 : Real64 AbsExt; // thermal emittance of collector
1037 : Real64 TempExt; // collector temperature
1038 : int SurfPtr; // index of surface in main surface structure
1039 : Real64 HMovInsul; // dummy for call to InitExteriorConvectionCoeff
1040 : Real64 HExt; // dummy for call to InitExteriorConvectionCoeff
1041 : int ConstrNum; // index of construction in main construction structure
1042 : Real64 AbsThermSurf; // thermal emittance of underlying wall.
1043 : Real64 TsoK; // underlying surface temperature in Kelvin
1044 : Real64 TscollK; // collector temperature in Kelvin (lagged)
1045 : Real64 AreaSum; // sum of contributing surfaces for area-weighted averages.
1046 : Real64 Vwind; // localized, and area-weighted average for wind speed
1047 : Real64 HrSky; // radiation coeff for sky, area-weighted average
1048 : Real64 HrGround; // radiation coeff for ground, area-weighted average
1049 : Real64 HrAtm; // radiation coeff for air (bulk atmosphere), area-weighted average
1050 : Real64 Isc; // Incoming combined solar radiation, area-weighted average
1051 : Real64 HrPlen; // radiation coeff for plenum surfaces, area-weighted average
1052 : Real64 Tso; // temperature of underlying surface, area-weighted average
1053 : Real64 HcWind; // convection coeff for high speed wind situations
1054 : Real64 NuD; // nusselt number for Reynolds based on hole
1055 : Real64 U; // overall heat exchanger coefficient
1056 : Real64 HXeff; // effectiveness for heat exchanger
1057 : Real64 t; // collector thickness
1058 : Real64 ReS; // Reynolds number based on suction velocity and pitch
1059 : Real64 ReW; // Reynolds number based on Wind and pitch
1060 : Real64 ReB; // Reynolds number based on hole velocity and pitch
1061 : Real64 ReH; // Reynolds number based on hole velocity and diameter
1062 : Real64 Tscoll; // temperature of collector
1063 : Real64 TaHX; // leaving air temperature from heat exchanger (entering plenum)
1064 : Real64 Taplen; // Air temperature in plen and outlet node.
1065 : Real64 SensHeatingRate; // Rate at which the system is heating outdoor air
1066 : Real64 AlessHoles; // Area for Kutscher's relation
1067 :
1068 0 : auto &s_mat = state.dataMaterial;
1069 : // Active UTSC calculation
1070 : // first do common things for both correlations
1071 0 : Real64 sum_area = 0.0;
1072 0 : for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
1073 0 : sum_area += state.dataSurface->Surface(SurfNum).Area;
1074 : }
1075 0 : if (!state.dataEnvrn->IsRain) {
1076 0 : Real64 sum_produc_area_drybulb = 0.0;
1077 0 : for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
1078 0 : sum_produc_area_drybulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutDryBulbTemp(SurfNum);
1079 : }
1080 0 : Tamb = sum_produc_area_drybulb / sum_area;
1081 : } else { // when raining we use wet bulb not drybulb
1082 0 : Real64 sum_produc_area_wetbulb = 0.0;
1083 0 : for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
1084 0 : sum_produc_area_wetbulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutWetBulbTemp(SurfNum);
1085 : }
1086 0 : Tamb = sum_produc_area_wetbulb / sum_area;
1087 : }
1088 :
1089 0 : RhoAir = PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, Tamb, state.dataEnvrn->OutHumRat);
1090 :
1091 0 : CpAir = PsyCpAirFnW(state.dataEnvrn->OutHumRat);
1092 :
1093 0 : holeArea = state.dataTranspiredCollector->UTSC(UTSCNum).ActualArea * state.dataTranspiredCollector->UTSC(UTSCNum).Porosity;
1094 :
1095 0 : A = state.dataTranspiredCollector->UTSC(UTSCNum).ProjArea;
1096 :
1097 0 : Vholes = state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot / RhoAir / holeArea;
1098 :
1099 0 : Vplen = state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot / RhoAir / state.dataTranspiredCollector->UTSC(UTSCNum).PlenCrossArea;
1100 :
1101 0 : Vsuction = state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot / RhoAir / A;
1102 :
1103 0 : if ((Vsuction < 0.001) || (Vsuction > 0.08)) { // warn that collector is not sized well
1104 0 : if (state.dataTranspiredCollector->UTSC(UTSCNum).VsucErrIndex == 0) {
1105 0 : ShowWarningMessage(state,
1106 0 : format("Solar Collector:Unglazed Transpired=\"{}\", Suction velocity is outside of range for a good design",
1107 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Name));
1108 0 : ShowContinueErrorTimeStamp(state, format("Suction velocity ={:.4R}", Vsuction));
1109 0 : if (Vsuction < 0.003) {
1110 0 : ShowContinueError(state, "Velocity is low -- suggest decreasing area of transpired collector");
1111 : }
1112 0 : if (Vsuction > 0.08) {
1113 0 : ShowContinueError(state, "Velocity is high -- suggest increasing area of transpired collector");
1114 : }
1115 0 : ShowContinueError(state, "Occasional suction velocity messages are not unexpected when simulating actual conditions");
1116 : }
1117 0 : ShowRecurringWarningErrorAtEnd(state,
1118 0 : "Solar Collector:Unglazed Transpired=\"" + state.dataTranspiredCollector->UTSC(UTSCNum).Name +
1119 : "\", Suction velocity is outside of range",
1120 0 : state.dataTranspiredCollector->UTSC(UTSCNum).VsucErrIndex,
1121 : Vsuction,
1122 : Vsuction,
1123 : _,
1124 : "[m/s]",
1125 : "[m/s]");
1126 : }
1127 :
1128 0 : HcPlen = 5.62 + 3.92 * Vplen;
1129 :
1130 0 : D = state.dataTranspiredCollector->UTSC(UTSCNum).HoleDia;
1131 :
1132 0 : ReD = Vholes * D / nu;
1133 :
1134 0 : P = state.dataTranspiredCollector->UTSC(UTSCNum).Pitch;
1135 :
1136 0 : Por = state.dataTranspiredCollector->UTSC(UTSCNum).Porosity;
1137 :
1138 0 : Mdot = state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot;
1139 :
1140 0 : QdotSource = state.dataTranspiredCollector->UTSC(UTSCNum).QdotSource; // for hybrid PV transpired collectors
1141 :
1142 : // loop through underlying surfaces and collect needed data
1143 : // now collect average values for things associated with the underlying surface(s)
1144 0 : NumSurfs = state.dataTranspiredCollector->UTSC(UTSCNum).NumSurfs;
1145 0 : HSkyARR.dimension(NumSurfs, 0.0);
1146 0 : HGroundARR.dimension(NumSurfs, 0.0);
1147 0 : HAirARR.dimension(NumSurfs, 0.0);
1148 0 : LocalWindArr.dimension(NumSurfs, 0.0);
1149 : // ALLOCATE(IscARR(NumSurfs))
1150 : // IscARR = 0.0
1151 0 : HPlenARR.dimension(NumSurfs, 0.0);
1152 : // ALLOCATE(TsoARR(NumSurfs))
1153 : // TsoARR = 0.0
1154 0 : HSrdSurfARR.dimension(NumSurfs, 0.0);
1155 :
1156 0 : Roughness = state.dataTranspiredCollector->UTSC(UTSCNum).CollRoughness;
1157 0 : SolAbs = state.dataTranspiredCollector->UTSC(UTSCNum).SolAbsorp;
1158 0 : AbsExt = state.dataTranspiredCollector->UTSC(UTSCNum).LWEmitt;
1159 0 : TempExt = state.dataTranspiredCollector->UTSC(UTSCNum).TcollLast;
1160 0 : for (ThisSurf = 1; ThisSurf <= NumSurfs; ++ThisSurf) {
1161 0 : SurfPtr = state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs(ThisSurf);
1162 : // Initializations for this surface
1163 0 : HMovInsul = 0.0;
1164 0 : HExt = 0.0;
1165 0 : LocalWindArr(ThisSurf) = state.dataSurface->SurfOutWindSpeed(SurfPtr);
1166 0 : Convect::InitExtConvCoeff(state,
1167 : SurfPtr,
1168 : HMovInsul,
1169 : Roughness,
1170 : AbsExt,
1171 : TempExt,
1172 : HExt,
1173 0 : HSkyARR(ThisSurf),
1174 0 : HGroundARR(ThisSurf),
1175 0 : HAirARR(ThisSurf),
1176 0 : HSrdSurfARR(ThisSurf));
1177 0 : ConstrNum = state.dataSurface->Surface(SurfPtr).Construction;
1178 0 : AbsThermSurf = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(1))->AbsorpThermal;
1179 0 : TsoK = state.dataHeatBalSurf->SurfOutsideTempHist(1)(SurfPtr) + Constant::Kelvin;
1180 0 : TscollK = state.dataTranspiredCollector->UTSC(UTSCNum).TcollLast + Constant::Kelvin;
1181 0 : HPlenARR(ThisSurf) = Sigma * AbsExt * AbsThermSurf * (pow_4(TscollK) - pow_4(TsoK)) / (TscollK - TsoK);
1182 : }
1183 : // AreaSum = sum( Surface( UTSC( UTSCNum ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
1184 : auto Area = // (AUTO_OK_OBJ)
1185 0 : array_sub(state.dataSurface->Surface,
1186 : &SurfaceData::Area,
1187 0 : state.dataTranspiredCollector->UTSC(UTSCNum)
1188 0 : .SurfPtrs); // Autodesk:F2C++ Copy of subscripted Area array for use below: This makes a copy so review wrt performance
1189 0 : AreaSum = sum(Area);
1190 : // now figure area-weighted averages from underlying surfaces.
1191 : // Vwind = sum( LocalWindArr * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum; //Autodesk:F2C++ Array subscript usage:
1192 : // Replaced by below
1193 0 : Vwind = sum(LocalWindArr * Area) / AreaSum;
1194 0 : LocalWindArr.deallocate();
1195 : // HrSky = sum( HSkyARR * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum; //Autodesk:F2C++ Array subscript usage: Replaced
1196 : // by below
1197 0 : HrSky = sum(HSkyARR * Area) / AreaSum;
1198 0 : HSkyARR.deallocate();
1199 : // HrGround = sum( HGroundARR * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum; //Autodesk:F2C++ Array subscript usage:
1200 : // Replaced by below
1201 0 : HrGround = sum(HGroundARR * Area) / AreaSum;
1202 0 : HGroundARR.deallocate();
1203 : // HrAtm = sum( HAirARR * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum; //Autodesk:F2C++ Array subscript usage: Replaced
1204 : // by below
1205 0 : HrAtm = sum(HAirARR * Area) / AreaSum;
1206 0 : HAirARR.deallocate();
1207 : // HrPlen = sum( HPlenARR * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum; //Autodesk:F2C++ Array subscript usage:
1208 : // Replaced by below
1209 0 : HrPlen = sum(HPlenARR * Area) / AreaSum;
1210 0 : HPlenARR.deallocate();
1211 :
1212 : // Isc = sum( SurfQRadSWOutIncident( UTSC( UTSCNum ).SurfPtrs ) * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum;
1213 : ////Autodesk:F2C++ Array subscript usage: Replaced by below
1214 0 : Isc = sum_product_sub(state.dataHeatBal->SurfQRadSWOutIncident,
1215 0 : state.dataSurface->Surface,
1216 : &SurfaceData::Area,
1217 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) /
1218 : AreaSum; // Autodesk:F2C++ Functions handle array subscript usage
1219 : // Tso = sum( TH( UTSC( UTSCNum ).SurfPtrs, 1, 1 ) * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / AreaSum; //Autodesk:F2C++ Array
1220 : // subscript usage: Replaced by below
1221 0 : Tso = sum_product_sub(state.dataHeatBalSurf->SurfOutsideTempHist(1),
1222 0 : state.dataSurface->Surface,
1223 : &SurfaceData::Area,
1224 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) /
1225 : AreaSum; // Autodesk:F2C++ Functions handle array subscript usage
1226 :
1227 0 : if (Vwind > 5.0) {
1228 0 : HcWind = 5.62 + 3.9 * (Vwind - 5.0); // McAdams forced convection correlation
1229 : } else {
1230 0 : HcWind = 0.0;
1231 : }
1232 :
1233 0 : if (state.dataEnvrn->IsRain) HcWind = 1000.0;
1234 :
1235 0 : HXeff = 0.0; // init
1236 :
1237 0 : switch (state.dataTranspiredCollector->UTSC(UTSCNum).Correlation) {
1238 0 : case Correlation_Kutscher1994: { // Kutscher1994
1239 0 : AlessHoles = A - holeArea;
1240 :
1241 0 : NuD = 2.75 * ((std::pow(P / D, -1.2) * std::pow(ReD, 0.43)) + (0.011 * Por * ReD * std::pow(Vwind / Vsuction, 0.48)));
1242 0 : U = k * NuD / D;
1243 0 : HXeff = 1.0 - std::exp(-1.0 * ((U * AlessHoles) / (Mdot * CpAir)));
1244 0 : } break;
1245 0 : case Correlation_VanDeckerHollandsBrunger2001: { // VanDeckerHollandsBrunger2001
1246 0 : t = state.dataTranspiredCollector->UTSC(UTSCNum).CollectThick;
1247 0 : ReS = Vsuction * P / nu;
1248 0 : ReW = Vwind * P / nu;
1249 0 : ReB = Vholes * P / nu;
1250 0 : ReH = (Vsuction * D) / (nu * Por);
1251 0 : if (ReD > 0.0) {
1252 0 : if (ReW > 0.0) {
1253 0 : HXeff = (1.0 - std::pow(1.0 + ReS * max(1.733 * std::pow(ReW, -0.5), 0.02136), -1.0)) *
1254 0 : (1.0 - std::pow(1.0 + 0.2273 * std::sqrt(ReB), -1.0)) * std::exp(-0.01895 * (P / D) - (20.62 / ReH) * (t / D));
1255 : } else {
1256 0 : HXeff = (1.0 - std::pow(1.0 + ReS * 0.02136, -1.0)) * (1.0 - std::pow(1.0 + 0.2273 * std::sqrt(ReB), -1.0)) *
1257 0 : std::exp(-0.01895 * (P / D) - (20.62 / ReH) * (t / D));
1258 : }
1259 : } else {
1260 0 : HXeff = 0.0;
1261 : }
1262 0 : } break;
1263 0 : default:
1264 0 : break;
1265 : }
1266 :
1267 : // now calculate collector temperature
1268 :
1269 0 : Tscoll = (Isc * SolAbs + HrAtm * Tamb + HrSky * state.dataEnvrn->SkyTemp + HrGround * Tamb + HrPlen * Tso + HcWind * Tamb +
1270 0 : (Mdot * CpAir / A) * Tamb - (Mdot * CpAir / A) * (1.0 - HXeff) * Tamb + QdotSource) /
1271 0 : (HrAtm + HrSky + HrGround + HrPlen + HcWind + (Mdot * CpAir / A) * HXeff);
1272 :
1273 : // Heat exchanger leaving temperature
1274 0 : TaHX = HXeff * Tscoll + (1.0 - HXeff) * Tamb;
1275 :
1276 : // now calculate plenum air temperature
1277 :
1278 0 : Taplen = (Mdot * CpAir * TaHX + HcPlen * A * Tso) / (Mdot * CpAir + HcPlen * A);
1279 :
1280 : // calculate Sensible Heating Rate
1281 0 : if (Taplen > Tamb) {
1282 0 : SensHeatingRate = Mdot * CpAir * (Taplen - Tamb);
1283 : } else {
1284 0 : SensHeatingRate = 0.0;
1285 : }
1286 :
1287 : // now fill results into derived types
1288 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Isc = Isc;
1289 0 : state.dataTranspiredCollector->UTSC(UTSCNum).HXeff = HXeff;
1290 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Tplen = Taplen;
1291 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Tcoll = Tscoll;
1292 0 : state.dataTranspiredCollector->UTSC(UTSCNum).HrPlen = HrPlen;
1293 0 : state.dataTranspiredCollector->UTSC(UTSCNum).HcPlen = HcPlen;
1294 0 : state.dataTranspiredCollector->UTSC(UTSCNum).TairHX = TaHX;
1295 0 : state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot = Mdot;
1296 0 : state.dataTranspiredCollector->UTSC(UTSCNum).InletTempDB = Tamb;
1297 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Vsuction = Vsuction;
1298 0 : state.dataTranspiredCollector->UTSC(UTSCNum).PlenumVelocity = Vplen;
1299 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SupOutTemp = Taplen;
1300 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SupOutHumRat = state.dataEnvrn->OutHumRat; // stays the same with sensible heating
1301 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SupOutEnth =
1302 0 : PsyHFnTdbW(state.dataTranspiredCollector->UTSC(UTSCNum).SupOutTemp, state.dataTranspiredCollector->UTSC(UTSCNum).SupOutHumRat);
1303 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SupOutMassFlow = Mdot;
1304 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SensHeatingRate = SensHeatingRate;
1305 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SensHeatingEnergy = SensHeatingRate * TimeStepSysSec;
1306 0 : state.dataTranspiredCollector->UTSC(UTSCNum).PassiveACH = 0.0;
1307 0 : state.dataTranspiredCollector->UTSC(UTSCNum).PassiveMdotVent = 0.0;
1308 0 : state.dataTranspiredCollector->UTSC(UTSCNum).PassiveMdotWind = 0.0;
1309 0 : state.dataTranspiredCollector->UTSC(UTSCNum).PassiveMdotTherm = 0.0;
1310 0 : if (Isc > 10.0) {
1311 0 : state.dataTranspiredCollector->UTSC(UTSCNum).UTSCEfficiency = SensHeatingRate / (Isc * A);
1312 0 : if (TaHX > Tamb) {
1313 0 : state.dataTranspiredCollector->UTSC(UTSCNum).UTSCCollEff = Mdot * CpAir * (TaHX - Tamb) / (Isc * A);
1314 : } else {
1315 0 : state.dataTranspiredCollector->UTSC(UTSCNum).UTSCCollEff = 0.0;
1316 : }
1317 : } else {
1318 0 : state.dataTranspiredCollector->UTSC(UTSCNum).UTSCEfficiency = 0.0;
1319 0 : state.dataTranspiredCollector->UTSC(UTSCNum).UTSCCollEff = 0.0;
1320 : }
1321 0 : }
1322 :
1323 0 : void CalcPassiveTranspiredCollector(EnergyPlusData &state, int const UTSCNum)
1324 : {
1325 :
1326 : // SUBROUTINE INFORMATION:
1327 : // AUTHOR B.T. Griffith
1328 : // DATE WRITTEN November 2004
1329 : // MODIFIED na
1330 : // RE-ENGINEERED na
1331 :
1332 : // PURPOSE OF THIS SUBROUTINE:
1333 : // model the effect of the a ventilated baffle covering the outside of a heat transfer surface.
1334 :
1335 : // METHODOLOGY EMPLOYED:
1336 : // All the work is done in a subroutine .
1337 :
1338 : // REFERENCES:
1339 : // Nat. Vent. equations from ASHRAE HoF 2001 Chapt. 26
1340 :
1341 : // Using/Aliasing
1342 : using DataSurfaces::SurfaceData;
1343 : using Psychrometrics::PsyHFnTdbW;
1344 : using Psychrometrics::PsyRhoAirFnPbTdbW;
1345 : using Psychrometrics::PsyWFnTdbTwbPb;
1346 :
1347 : // local working variables
1348 : Real64 AspRat; // Aspect Ratio of gap
1349 : Real64 TmpTscoll;
1350 : Real64 TmpTaPlen;
1351 : Real64 RhoAir;
1352 : Real64 holeArea;
1353 : Real64 Tamb;
1354 : Real64 HrPlen;
1355 : Real64 HcPlen;
1356 : Real64 Isc;
1357 : Real64 MdotVent;
1358 : Real64 VdotWind;
1359 : Real64 VdotThermal;
1360 : Real64 Twbamb;
1361 : Real64 OutHumRatAmb;
1362 :
1363 : // Tamb = sum( Surface( UTSC( UTSCNum ).SurfPtrs ).OutDryBulbTemp * Surface( UTSC( UTSCNum ).SurfPtrs ).Area ) / sum( Surface(
1364 : // UTSC( UTSCNum ).SurfPtrs ).Area ); //Autodesk:F2C++ Array subscript usage: Replaced by below
1365 0 : Real64 sum_area = 0.0;
1366 0 : Real64 sum_produc_area_drybulb = 0.0;
1367 0 : Real64 sum_produc_area_wetbulb = 0.0;
1368 0 : for (int SurfNum : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs) {
1369 0 : sum_area += state.dataSurface->Surface(SurfNum).Area;
1370 0 : sum_produc_area_wetbulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutWetBulbTemp(SurfNum);
1371 0 : sum_produc_area_drybulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutDryBulbTemp(SurfNum);
1372 : }
1373 0 : Tamb = sum_produc_area_drybulb / sum_area;
1374 0 : Twbamb = sum_produc_area_wetbulb / sum_area;
1375 :
1376 0 : OutHumRatAmb = PsyWFnTdbTwbPb(state, Tamb, Twbamb, state.dataEnvrn->OutBaroPress);
1377 :
1378 0 : RhoAir = PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, Tamb, OutHumRatAmb);
1379 0 : holeArea = state.dataTranspiredCollector->UTSC(UTSCNum).ActualArea * state.dataTranspiredCollector->UTSC(UTSCNum).Porosity;
1380 :
1381 0 : AspRat = state.dataTranspiredCollector->UTSC(UTSCNum).Height / state.dataTranspiredCollector->UTSC(UTSCNum).PlenGapThick;
1382 0 : TmpTscoll = state.dataTranspiredCollector->UTSC(UTSCNum).TcollLast;
1383 0 : TmpTaPlen = state.dataTranspiredCollector->UTSC(UTSCNum).TplenLast;
1384 :
1385 : // all the work is done in this routine located in GeneralRoutines.cc
1386 :
1387 0 : CalcPassiveExteriorBaffleGap(state,
1388 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SurfPtrs,
1389 : holeArea,
1390 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Cv,
1391 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Cd,
1392 0 : state.dataTranspiredCollector->UTSC(UTSCNum).HdeltaNPL,
1393 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SolAbsorp,
1394 0 : state.dataTranspiredCollector->UTSC(UTSCNum).LWEmitt,
1395 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Tilt,
1396 : AspRat,
1397 0 : state.dataTranspiredCollector->UTSC(UTSCNum).PlenGapThick,
1398 0 : state.dataTranspiredCollector->UTSC(UTSCNum).CollRoughness,
1399 0 : state.dataTranspiredCollector->UTSC(UTSCNum).QdotSource,
1400 : TmpTscoll,
1401 : TmpTaPlen,
1402 : HcPlen,
1403 : HrPlen,
1404 : Isc,
1405 : MdotVent,
1406 : VdotWind,
1407 : VdotThermal);
1408 :
1409 : // now fill results into derived types
1410 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Isc = Isc;
1411 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Tplen = TmpTaPlen;
1412 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Tcoll = TmpTscoll;
1413 0 : state.dataTranspiredCollector->UTSC(UTSCNum).HrPlen = HrPlen;
1414 0 : state.dataTranspiredCollector->UTSC(UTSCNum).HcPlen = HcPlen;
1415 0 : state.dataTranspiredCollector->UTSC(UTSCNum).TairHX = Tamb;
1416 0 : state.dataTranspiredCollector->UTSC(UTSCNum).InletMDot = 0.0;
1417 0 : state.dataTranspiredCollector->UTSC(UTSCNum).InletTempDB = Tamb;
1418 0 : state.dataTranspiredCollector->UTSC(UTSCNum).Vsuction = 0.0;
1419 0 : state.dataTranspiredCollector->UTSC(UTSCNum).PlenumVelocity = 0.0;
1420 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SupOutTemp = TmpTaPlen;
1421 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SupOutHumRat = OutHumRatAmb;
1422 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SupOutEnth = PsyHFnTdbW(TmpTaPlen, OutHumRatAmb);
1423 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SupOutMassFlow = 0.0;
1424 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SensHeatingRate = 0.0;
1425 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SensHeatingEnergy = 0.0;
1426 0 : state.dataTranspiredCollector->UTSC(UTSCNum).PassiveACH =
1427 0 : (MdotVent / RhoAir) *
1428 0 : (1.0 / (state.dataTranspiredCollector->UTSC(UTSCNum).ProjArea * state.dataTranspiredCollector->UTSC(UTSCNum).PlenGapThick)) *
1429 : Constant::rSecsInHour;
1430 0 : state.dataTranspiredCollector->UTSC(UTSCNum).PassiveMdotVent = MdotVent;
1431 0 : state.dataTranspiredCollector->UTSC(UTSCNum).PassiveMdotWind = VdotWind * RhoAir;
1432 0 : state.dataTranspiredCollector->UTSC(UTSCNum).PassiveMdotTherm = VdotThermal * RhoAir;
1433 0 : state.dataTranspiredCollector->UTSC(UTSCNum).UTSCEfficiency = 0.0;
1434 0 : }
1435 :
1436 0 : void UpdateTranspiredCollector(EnergyPlusData &state, int const UTSCNum)
1437 : {
1438 :
1439 : // SUBROUTINE INFORMATION:
1440 : // AUTHOR B.T. Griffith
1441 : // DATE WRITTEN November 2004
1442 : // MODIFIED na
1443 : // RE-ENGINEERED na
1444 :
1445 : int OutletNode;
1446 : int InletNode;
1447 : int thisOSCM;
1448 : int thisOASys;
1449 :
1450 : // update "last" values in Derived type
1451 0 : state.dataTranspiredCollector->UTSC(UTSCNum).TplenLast = state.dataTranspiredCollector->UTSC(UTSCNum).Tplen;
1452 0 : state.dataTranspiredCollector->UTSC(UTSCNum).TcollLast = state.dataTranspiredCollector->UTSC(UTSCNum).Tcoll;
1453 :
1454 : // Set the outlet air nodes of the UTSC
1455 :
1456 0 : if (state.dataTranspiredCollector->UTSC(UTSCNum).IsOn) { // Active
1457 0 : if (state.dataTranspiredCollector->UTSC(UTSCNum).NumOASysAttached == 1) {
1458 0 : OutletNode = state.dataTranspiredCollector->UTSC(UTSCNum).OutletNode(1);
1459 0 : InletNode = state.dataTranspiredCollector->UTSC(UTSCNum).InletNode(1);
1460 0 : state.dataLoopNodes->Node(OutletNode).MassFlowRate = state.dataTranspiredCollector->UTSC(UTSCNum).SupOutMassFlow;
1461 0 : state.dataLoopNodes->Node(OutletNode).Temp = state.dataTranspiredCollector->UTSC(UTSCNum).SupOutTemp;
1462 0 : state.dataLoopNodes->Node(OutletNode).HumRat = state.dataTranspiredCollector->UTSC(UTSCNum).SupOutHumRat;
1463 0 : state.dataLoopNodes->Node(OutletNode).Enthalpy = state.dataTranspiredCollector->UTSC(UTSCNum).SupOutEnth;
1464 0 : } else if (state.dataTranspiredCollector->UTSC(UTSCNum).NumOASysAttached > 1) {
1465 0 : for (thisOASys = 1; thisOASys <= state.dataTranspiredCollector->UTSC(UTSCNum).NumOASysAttached; ++thisOASys) {
1466 0 : state.dataLoopNodes->Node(state.dataTranspiredCollector->UTSC(UTSCNum).OutletNode(thisOASys)).MassFlowRate =
1467 0 : state.dataLoopNodes->Node(state.dataTranspiredCollector->UTSC(UTSCNum).InletNode(thisOASys))
1468 0 : .MassFlowRate; // system gets what it asked for at inlet
1469 0 : state.dataLoopNodes->Node(state.dataTranspiredCollector->UTSC(UTSCNum).OutletNode(thisOASys)).Temp =
1470 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SupOutTemp;
1471 0 : state.dataLoopNodes->Node(state.dataTranspiredCollector->UTSC(UTSCNum).OutletNode(thisOASys)).HumRat =
1472 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SupOutHumRat;
1473 0 : state.dataLoopNodes->Node(state.dataTranspiredCollector->UTSC(UTSCNum).OutletNode(thisOASys)).Enthalpy =
1474 0 : state.dataTranspiredCollector->UTSC(UTSCNum).SupOutEnth;
1475 : }
1476 : }
1477 : } else { // Passive and/or bypassed Note Array assignments in following
1478 : // Autodesk:F2C++ Array subscript usage: Replaced by below
1479 : // Node( UTSC( UTSCNum ).OutletNode ).MassFlowRate = Node( UTSC( UTSCNum ).InletNode ).MassFlowRate;
1480 : // Node( UTSC( UTSCNum ).OutletNode ).Temp = Node( UTSC( UTSCNum ).InletNode ).Temp;
1481 : // Node( UTSC( UTSCNum ).OutletNode ).HumRat = Node( UTSC( UTSCNum ).InletNode ).HumRat;
1482 : // Node( UTSC( UTSCNum ).OutletNode ).Enthalpy = Node( UTSC( UTSCNum ).InletNode ).Enthalpy;
1483 0 : auto const &OutletNode = state.dataTranspiredCollector->UTSC(UTSCNum).OutletNode;
1484 0 : auto const &InletNode = state.dataTranspiredCollector->UTSC(UTSCNum).InletNode;
1485 0 : assert(OutletNode.size() == InletNode.size());
1486 0 : for (int io = OutletNode.l(), ii = InletNode.l(), eo = OutletNode.u(); io <= eo; ++io, ++ii) {
1487 0 : auto &outNode = state.dataLoopNodes->Node(OutletNode(io));
1488 0 : auto const &inNode = state.dataLoopNodes->Node(InletNode(ii));
1489 0 : outNode.MassFlowRate = inNode.MassFlowRate;
1490 0 : outNode.Temp = inNode.Temp;
1491 0 : outNode.HumRat = inNode.HumRat;
1492 0 : outNode.Enthalpy = inNode.Enthalpy;
1493 : }
1494 : }
1495 :
1496 : // update the OtherSideConditionsModel coefficients.
1497 0 : thisOSCM = state.dataTranspiredCollector->UTSC(UTSCNum).OSCMPtr;
1498 :
1499 0 : state.dataSurface->OSCM(thisOSCM).TConv = state.dataTranspiredCollector->UTSC(UTSCNum).Tplen;
1500 0 : state.dataSurface->OSCM(thisOSCM).HConv = state.dataTranspiredCollector->UTSC(UTSCNum).HcPlen;
1501 0 : state.dataSurface->OSCM(thisOSCM).TRad = state.dataTranspiredCollector->UTSC(UTSCNum).Tcoll;
1502 0 : state.dataSurface->OSCM(thisOSCM).HRad = state.dataTranspiredCollector->UTSC(UTSCNum).HrPlen;
1503 0 : }
1504 :
1505 0 : void SetUTSCQdotSource(EnergyPlusData &state,
1506 : int const UTSCNum,
1507 : Real64 const QSource // source term in Watts
1508 : )
1509 : {
1510 :
1511 : // SUBROUTINE INFORMATION:
1512 : // AUTHOR B. Griffith
1513 : // DATE WRITTEN November 2004
1514 : // MODIFIED na
1515 : // RE-ENGINEERED na
1516 :
1517 : // PURPOSE OF THIS SUBROUTINE:
1518 : // object oriented "Set" routine for updating sink term without exposing variables
1519 :
1520 : // METHODOLOGY EMPLOYED:
1521 : // update derived type with new data , turn power into W/m2
1522 :
1523 0 : state.dataTranspiredCollector->UTSC(UTSCNum).QdotSource = QSource / state.dataTranspiredCollector->UTSC(UTSCNum).ProjArea;
1524 0 : }
1525 :
1526 0 : void GetTranspiredCollectorIndex(EnergyPlusData &state, int const SurfacePtr, int &UTSCIndex)
1527 : {
1528 :
1529 : // SUBROUTINE INFORMATION:
1530 : // AUTHOR B. Griffith
1531 : // DATE WRITTEN November 2004
1532 : // MODIFIED na
1533 : // RE-ENGINEERED na
1534 :
1535 : // PURPOSE OF THIS SUBROUTINE:
1536 : // object oriented "Get" routine for establishing correct integer index from outside this module
1537 :
1538 : // METHODOLOGY EMPLOYED:
1539 : // mine Surface derived type for correct index/number of surface
1540 : // mine UTSC derived type that has the surface.
1541 :
1542 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1543 : int UTSCNum; // temporary
1544 : int ThisSurf; // temporary
1545 : int thisUTSC;
1546 : bool Found;
1547 :
1548 0 : if (state.dataTranspiredCollector->GetInputFlag) {
1549 0 : GetTranspiredCollectorInput(state);
1550 0 : state.dataTranspiredCollector->GetInputFlag = false;
1551 : }
1552 :
1553 0 : if (SurfacePtr == 0) {
1554 0 : ShowFatalError(
1555 : state,
1556 0 : format("Invalid surface passed to GetTranspiredCollectorIndex, Surface name = {}", state.dataSurface->Surface(SurfacePtr).Name));
1557 : }
1558 :
1559 0 : UTSCNum = 0;
1560 0 : Found = false;
1561 0 : for (thisUTSC = 1; thisUTSC <= state.dataTranspiredCollector->NumUTSC; ++thisUTSC) {
1562 0 : for (ThisSurf = 1; ThisSurf <= state.dataTranspiredCollector->UTSC(thisUTSC).NumSurfs; ++ThisSurf) {
1563 0 : if (SurfacePtr == state.dataTranspiredCollector->UTSC(thisUTSC).SurfPtrs(ThisSurf)) {
1564 0 : Found = true;
1565 0 : UTSCNum = thisUTSC;
1566 : }
1567 : }
1568 : }
1569 :
1570 0 : if (!Found) {
1571 0 : ShowFatalError(state,
1572 0 : format("Did not find surface in UTSC description in GetTranspiredCollectorIndex, Surface name = {}",
1573 0 : state.dataSurface->Surface(SurfacePtr).Name));
1574 : } else {
1575 :
1576 0 : UTSCIndex = UTSCNum;
1577 : }
1578 0 : }
1579 :
1580 0 : void GetUTSCTsColl(EnergyPlusData &state, int const UTSCNum, Real64 &TsColl)
1581 : {
1582 :
1583 : // SUBROUTINE INFORMATION:
1584 : // AUTHOR <author>
1585 : // DATE WRITTEN <date_written>
1586 : // MODIFIED na
1587 : // RE-ENGINEERED na
1588 :
1589 : // PURPOSE OF THIS SUBROUTINE:
1590 : // object oriented "Get" routine for collector surface temperature
1591 :
1592 : // METHODOLOGY EMPLOYED:
1593 : // access derived type
1594 :
1595 0 : TsColl = state.dataTranspiredCollector->UTSC(UTSCNum).Tcoll;
1596 0 : }
1597 :
1598 0 : int GetAirInletNodeNum(EnergyPlusData &state, std::string const &UTSCName, bool &ErrorsFound)
1599 : {
1600 : // FUNCTION INFORMATION:
1601 : // AUTHOR Lixing Gu
1602 : // DATE WRITTEN May 2019
1603 : // MODIFIED na
1604 : // RE-ENGINEERED na
1605 :
1606 : // PURPOSE OF THIS FUNCTION:
1607 : // This function looks up the given UTSC and returns the air inlet node number.
1608 : // If incorrect UTSC name is given, ErrorsFound is returned as true and node number as zero.
1609 :
1610 : // Return value
1611 : int NodeNum; // node number returned
1612 :
1613 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1614 : int WhichUTSC;
1615 :
1616 0 : if (state.dataTranspiredCollector->GetInputFlag) {
1617 0 : GetTranspiredCollectorInput(state);
1618 0 : state.dataTranspiredCollector->GetInputFlag = false;
1619 : }
1620 :
1621 0 : WhichUTSC = Util::FindItemInList(UTSCName, state.dataTranspiredCollector->UTSC);
1622 0 : if (WhichUTSC != 0) {
1623 0 : NodeNum = state.dataTranspiredCollector->UTSC(WhichUTSC).InletNode(1);
1624 : } else {
1625 0 : ShowSevereError(state, format("GetAirInletNodeNum: Could not find TranspiredCollector = \"{}\"", UTSCName));
1626 0 : ErrorsFound = true;
1627 0 : NodeNum = 0;
1628 : }
1629 :
1630 0 : return NodeNum;
1631 : }
1632 :
1633 0 : int GetAirOutletNodeNum(EnergyPlusData &state, std::string const &UTSCName, bool &ErrorsFound)
1634 : {
1635 : // FUNCTION INFORMATION:
1636 : // AUTHOR Lixing Gu
1637 : // DATE WRITTEN May 2019
1638 : // MODIFIED na
1639 : // RE-ENGINEERED na
1640 :
1641 : // PURPOSE OF THIS FUNCTION:
1642 : // This function looks up the given UTSC and returns the air outlet node number.
1643 : // If incorrect UTSC name is given, ErrorsFound is returned as true and node number as zero.
1644 :
1645 : // Return value
1646 : int NodeNum; // node number returned
1647 :
1648 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
1649 : int WhichUTSC;
1650 :
1651 0 : if (state.dataTranspiredCollector->GetInputFlag) {
1652 0 : GetTranspiredCollectorInput(state);
1653 0 : state.dataTranspiredCollector->GetInputFlag = false;
1654 : }
1655 :
1656 0 : WhichUTSC = Util::FindItemInList(UTSCName, state.dataTranspiredCollector->UTSC);
1657 0 : if (WhichUTSC != 0) {
1658 0 : NodeNum = state.dataTranspiredCollector->UTSC(WhichUTSC).OutletNode(1);
1659 : } else {
1660 0 : ShowSevereError(state, format("GetAirOutletNodeNum: Could not find TranspiredCollector = \"{}\"", UTSCName));
1661 0 : ErrorsFound = true;
1662 0 : NodeNum = 0;
1663 : }
1664 :
1665 0 : return NodeNum;
1666 : }
1667 :
1668 1 : void CalcPassiveExteriorBaffleGap(EnergyPlusData &state,
1669 : const Array1D_int &SurfPtrARR, // Array of indexes pointing to Surface structure in DataSurfaces
1670 : Real64 const VentArea, // Area available for venting the gap [m2]
1671 : Real64 const Cv, // Orifice coefficient for volume-based discharge, wind-driven [--]
1672 : Real64 const Cd, // Orifice coefficient for discharge, buoyancy-driven [--]
1673 : Real64 const HdeltaNPL, // Height difference from neutral pressure level [m]
1674 : Real64 const SolAbs, // solar absorptivity of baffle [--]
1675 : Real64 const AbsExt, // thermal absorptance/emittance of baffle material [--]
1676 : Real64 const Tilt, // Tilt of gap [Degrees]
1677 : Real64 const AspRat, // aspect ratio of gap Height/gap [--]
1678 : Real64 const GapThick, // Thickness of air space between baffle and underlying heat transfer surface
1679 : Material::SurfaceRoughness const Roughness, // Roughness index (1-6), see DataHeatBalance parameters
1680 : Real64 const QdotSource, // Source/sink term, e.g. electricity exported from solar cell [W]
1681 : Real64 &TsBaffle, // Temperature of baffle (both sides) use lagged value on input [C]
1682 : Real64 &TaGap, // Temperature of air gap (assumed mixed) use lagged value on input [C]
1683 : ObjexxFCL::Optional<Real64> HcGapRpt,
1684 : ObjexxFCL::Optional<Real64> HrGapRpt,
1685 : ObjexxFCL::Optional<Real64> IscRpt,
1686 : ObjexxFCL::Optional<Real64> MdotVentRpt,
1687 : ObjexxFCL::Optional<Real64> VdotWindRpt,
1688 : ObjexxFCL::Optional<Real64> VdotBuoyRpt)
1689 : {
1690 :
1691 : // SUBROUTINE INFORMATION:
1692 : // AUTHOR B.T. Griffith
1693 : // DATE WRITTEN November 2004
1694 : // MODIFIED BG March 2007 outdoor conditions from surface for height-dependent conditions
1695 :
1696 : // PURPOSE OF THIS SUBROUTINE:
1697 : // model the effect of the a ventilated baffle covering the outside of a heat transfer surface.
1698 : // return calculated temperatures and certain intermediate values for reporting
1699 :
1700 : // METHODOLOGY EMPLOYED:
1701 : // Heat balances on baffle and air space.
1702 : // Natural ventilation calculations use buoyancy and wind.
1703 :
1704 : // REFERENCES:
1705 : // Nat. Vent. equations from ASHRAE HoF 2001 Chapt. 26
1706 :
1707 : // SUBROUTINE PARAMETER DEFINITIONS:
1708 1 : Real64 constexpr g = 9.807; // gravitational constant (m/s**2)
1709 1 : Real64 constexpr nu = 15.66e-6; // kinematic viscosity (m**2/s) for air at 300 K (Mills 1999 Heat Transfer)
1710 1 : Real64 constexpr k = 0.0267; // thermal conductivity (W/m K) for air at 300 K (Mills 1999 Heat Transfer)
1711 1 : Real64 constexpr Sigma = 5.6697e-08; // Stefan-Boltzmann constant
1712 : static constexpr std::string_view RoutineName = "CalcPassiveExteriorBaffleGap";
1713 : // INTERFACE BLOCK SPECIFICATIONS:
1714 :
1715 : // DERIVED TYPE DEFINITIONS:
1716 :
1717 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1718 :
1719 : // following arrays are used to temporarily hold results from multiple underlying surfaces
1720 1 : Array1D<Real64> HSkyARR;
1721 1 : Array1D<Real64> HGroundARR;
1722 1 : Array1D<Real64> HAirARR;
1723 1 : Array1D<Real64> HPlenARR;
1724 1 : Array1D<Real64> HExtARR;
1725 1 : Array1D<Real64> LocalWindArr;
1726 1 : Array1D<Real64> HSrdSurfARR;
1727 :
1728 : // local working variables
1729 : Real64 Tamb; // outdoor drybulb
1730 : Real64 VdotThermal; // Volume flow rate of nat. vent due to buoyancy
1731 : Real64 LocalOutDryBulbTemp; // OutDryBulbTemp for here
1732 : Real64 LocalWetBulbTemp; // OutWetBulbTemp for here
1733 : Real64 LocalOutHumRat; // OutHumRat for here
1734 1 : bool ICSCollectorIsOn(false); // ICS collector has OSCM on
1735 : int CollectorNum; // current solar collector index
1736 : Real64 ICSWaterTemp; // ICS solar collector water temp
1737 : Real64 ICSULossbottom; // ICS solar collector bottom loss Conductance
1738 1 : Real64 sum_area = 0.0;
1739 1 : Real64 sum_produc_area_drybulb = 0.0;
1740 1 : Real64 sum_produc_area_wetbulb = 0.0;
1741 :
1742 1 : auto &s_mat = state.dataMaterial;
1743 :
1744 2 : for (int SurfNum : SurfPtrARR) {
1745 1 : sum_area += state.dataSurface->Surface(SurfNum).Area;
1746 1 : sum_produc_area_drybulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutDryBulbTemp(SurfNum);
1747 1 : sum_produc_area_wetbulb += state.dataSurface->Surface(SurfNum).Area * state.dataSurface->SurfOutWetBulbTemp(SurfNum);
1748 : }
1749 : // LocalOutDryBulbTemp = sum( Surface( SurfPtrARR ).Area * Surface( SurfPtrARR ).OutDryBulbTemp ) / sum( Surface( SurfPtrARR ).Area );
1750 1 : LocalOutDryBulbTemp = sum_produc_area_drybulb / sum_area; // Autodesk:F2C++ Functions handle array subscript usage
1751 : // LocalWetBulbTemp = sum( Surface( SurfPtrARR ).Area * Surface( SurfPtrARR ).OutWetBulbTemp ) / sum( Surface( SurfPtrARR ).Area );
1752 1 : LocalWetBulbTemp = sum_produc_area_wetbulb / sum_area;
1753 :
1754 1 : LocalOutHumRat = Psychrometrics::PsyWFnTdbTwbPb(state, LocalOutDryBulbTemp, LocalWetBulbTemp, state.dataEnvrn->OutBaroPress, RoutineName);
1755 :
1756 1 : Real64 RhoAir = Psychrometrics::PsyRhoAirFnPbTdbW(state, state.dataEnvrn->OutBaroPress, LocalOutDryBulbTemp, LocalOutHumRat, RoutineName);
1757 1 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(LocalOutHumRat);
1758 1 : if (!state.dataEnvrn->IsRain) {
1759 1 : Tamb = LocalOutDryBulbTemp;
1760 : } else { // when raining we use wetbulb not drybulb
1761 0 : Tamb = LocalWetBulbTemp;
1762 : }
1763 1 : Real64 A = sum_area; // projected area of baffle from sum of underlying surfaces
1764 1 : Real64 TmpTsBaf = TsBaffle; // baffle temperature
1765 :
1766 : // loop through underlying surfaces and collect needed data
1767 1 : int NumSurfs = size(SurfPtrARR); // number of underlying HT surfaces associated with UTSC
1768 1 : HSkyARR.dimension(NumSurfs, 0.0);
1769 1 : HGroundARR.dimension(NumSurfs, 0.0);
1770 1 : HAirARR.dimension(NumSurfs, 0.0);
1771 1 : LocalWindArr.dimension(NumSurfs, 0.0);
1772 1 : HPlenARR.dimension(NumSurfs, 0.0);
1773 1 : HExtARR.dimension(NumSurfs, 0.0);
1774 1 : HSrdSurfARR.dimension(NumSurfs, 0.0);
1775 :
1776 2 : for (int ThisSurf = 1; ThisSurf <= NumSurfs; ++ThisSurf) {
1777 1 : int SurfPtr = SurfPtrARR(ThisSurf);
1778 : // Initializations for this surface
1779 1 : Real64 HMovInsul = 0.0;
1780 1 : LocalWindArr(ThisSurf) = state.dataSurface->SurfOutWindSpeed(SurfPtr);
1781 1 : Convect::InitExtConvCoeff(state,
1782 : SurfPtr,
1783 : HMovInsul,
1784 : Roughness,
1785 : AbsExt,
1786 : TmpTsBaf,
1787 1 : HExtARR(ThisSurf),
1788 1 : HSkyARR(ThisSurf),
1789 1 : HGroundARR(ThisSurf),
1790 1 : HAirARR(ThisSurf),
1791 1 : HSrdSurfARR(ThisSurf));
1792 1 : int ConstrNum = state.dataSurface->Surface(SurfPtr).Construction;
1793 1 : Real64 AbsThermSurf = s_mat->materials(state.dataConstruction->Construct(ConstrNum).LayerPoint(1))->AbsorpThermal;
1794 1 : Real64 TsoK = state.dataHeatBalSurf->SurfOutsideTempHist(1)(SurfPtr) + Constant::Kelvin;
1795 1 : Real64 TsBaffK = TmpTsBaf + Constant::Kelvin;
1796 1 : if (TsBaffK == TsoK) { // avoid divide by zero
1797 0 : HPlenARR(ThisSurf) = 0.0; // no net heat transfer if same temperature
1798 : } else {
1799 1 : HPlenARR(ThisSurf) = Sigma * AbsExt * AbsThermSurf * (pow_4(TsBaffK) - pow_4(TsoK)) / (TsBaffK - TsoK);
1800 : }
1801 : // Added for ICS collector OSCM
1802 1 : if (state.dataSurface->SurfIsICS(SurfPtr)) {
1803 1 : ICSCollectorIsOn = true;
1804 1 : CollectorNum = state.dataSurface->SurfICSPtr(SurfPtr);
1805 : }
1806 : }
1807 :
1808 1 : if (ICSCollectorIsOn) {
1809 1 : if (state.dataGlobal->BeginEnvrnFlag && state.dataGeneralRoutines->MyICSEnvrnFlag) {
1810 1 : ICSULossbottom = 0.40;
1811 1 : ICSWaterTemp = 20.0;
1812 : } else {
1813 0 : if (!state.dataSolarCollectors->Collector.allocated()) {
1814 0 : ICSULossbottom = 0.40;
1815 0 : ICSWaterTemp = 20.0;
1816 : } else {
1817 0 : ICSULossbottom = state.dataSolarCollectors->Collector(CollectorNum).UbLoss;
1818 0 : ICSWaterTemp = state.dataSolarCollectors->Collector(CollectorNum).TempOfWater;
1819 0 : state.dataGeneralRoutines->MyICSEnvrnFlag = false;
1820 : }
1821 : }
1822 : }
1823 1 : if (!state.dataGlobal->BeginEnvrnFlag) {
1824 0 : state.dataGeneralRoutines->MyICSEnvrnFlag = true;
1825 : }
1826 : if (A == 0.0) { // should have been caught earlier
1827 : }
1828 : Array1D<Real64> Area(
1829 1 : array_sub(state.dataSurface->Surface,
1830 : &DataSurfaces::SurfaceData::Area,
1831 1 : SurfPtrARR)); // Autodesk:F2C++ Copy of subscripted Area array for use below: This makes a copy so review wrt performance
1832 : // now figure area-weighted averages from underlying surfaces.
1833 1 : Real64 Vwind = sum(LocalWindArr * Area) / A; // area weighted average of wind velocity
1834 1 : LocalWindArr.deallocate();
1835 1 : Real64 HrSky = sum(HSkyARR * Area) / A; // radiation coeff for sky, area-weighted average
1836 1 : HSkyARR.deallocate();
1837 1 : Real64 HrGround = sum(HGroundARR * Area) / A; // radiation coeff for ground, area-weighted average
1838 1 : HGroundARR.deallocate();
1839 1 : Real64 HrAtm = sum(HAirARR * Area) / A; // radiation coeff for air (bulk atmosphere), area-weighted average
1840 1 : HAirARR.deallocate();
1841 1 : Real64 HrPlen = sum(HPlenARR * Area) / A; // radiation coeff for plenum surfaces, area-weighted average
1842 1 : HPlenARR.deallocate();
1843 1 : Real64 HExt = sum(HExtARR * Area) / A; // dummy for call to InitExteriorConvectionCoeff
1844 1 : HExtARR.deallocate();
1845 1 : HSrdSurfARR.deallocate();
1846 :
1847 1 : if (state.dataEnvrn->IsRain) HExt = 1000.0;
1848 :
1849 : // temperature of underlying surface, area-weighted average
1850 : Real64 Tso =
1851 1 : sum_product_sub(state.dataHeatBalSurf->SurfOutsideTempHist(1), state.dataSurface->Surface, &DataSurfaces::SurfaceData::Area, SurfPtrARR) /
1852 1 : A;
1853 : // Incoming combined solar radiation, area-weighted average
1854 : Real64 Isc =
1855 1 : sum_product_sub(state.dataHeatBal->SurfQRadSWOutIncident, state.dataSurface->Surface, &DataSurfaces::SurfaceData::Area, SurfPtrARR) / A;
1856 : // average of surface temps , for Beta in Grashoff no.
1857 1 : Real64 TmeanK = 0.5 * (TmpTsBaf + Tso) + Constant::Kelvin;
1858 : // Grasshof number for natural convection calc
1859 1 : Real64 Gr = g * pow_3(GapThick) * std::abs(Tso - TmpTsBaf) * pow_2(RhoAir) / (TmeanK * pow_2(nu));
1860 :
1861 1 : Real64 NuPlen = PassiveGapNusseltNumber(AspRat, Tilt, TmpTsBaf, Tso, Gr); // intentionally switch Tso to Tsi
1862 1 : Real64 HcPlen = NuPlen * (k / GapThick); // surface convection heat transfer coefficient for plenum surfaces
1863 :
1864 : // now model natural ventilation of plenum gap.
1865 1 : Real64 VdotWind = Cv * (VentArea / 2.0) * Vwind; // volume flow rate of nat. vent due to wind
1866 :
1867 1 : if (TaGap > Tamb) {
1868 1 : VdotThermal = Cd * (VentArea / 2.0) * std::sqrt(2.0 * g * HdeltaNPL * (TaGap - Tamb) / (TaGap + Constant::Kelvin));
1869 0 : } else if (TaGap == Tamb) {
1870 0 : VdotThermal = 0.0;
1871 : } else {
1872 0 : if ((std::abs(Tilt) < 5.0) || (std::abs(Tilt - 180.0) < 5.0)) {
1873 0 : VdotThermal = 0.0; // stable buoyancy situation
1874 : } else {
1875 0 : VdotThermal = Cd * (VentArea / 2.0) * std::sqrt(2.0 * g * HdeltaNPL * (Tamb - TaGap) / (Tamb + Constant::Kelvin));
1876 : }
1877 : }
1878 :
1879 1 : Real64 VdotVent = VdotWind + VdotThermal; // total volume flow rate of nat vent
1880 1 : Real64 MdotVent = VdotVent * RhoAir; // total mass flow rate of nat vent
1881 :
1882 : // now calculate baffle temperature
1883 1 : if (!ICSCollectorIsOn) {
1884 0 : TsBaffle = (Isc * SolAbs + HExt * Tamb + HrAtm * Tamb + HrSky * state.dataEnvrn->SkyTemp + HrGround * Tamb + HrPlen * Tso +
1885 0 : HcPlen * TaGap + QdotSource) /
1886 0 : (HExt + HrAtm + HrSky + HrGround + HrPlen + HcPlen);
1887 : } else {
1888 :
1889 1 : TsBaffle = (ICSULossbottom * ICSWaterTemp + HrPlen * Tso + HcPlen * TaGap + QdotSource) / (ICSULossbottom + HrPlen + HcPlen);
1890 : }
1891 : // now calculate gap air temperature
1892 :
1893 1 : TaGap = (HcPlen * A * Tso + MdotVent * CpAir * Tamb + HcPlen * A * TsBaffle) / (HcPlen * A + MdotVent * CpAir + HcPlen * A);
1894 :
1895 1 : if (present(HcGapRpt)) HcGapRpt = HcPlen;
1896 1 : if (present(HrGapRpt)) HrGapRpt = HrPlen;
1897 1 : if (present(IscRpt)) IscRpt = Isc;
1898 1 : if (present(MdotVentRpt)) MdotVentRpt = MdotVent;
1899 1 : if (present(VdotWindRpt)) VdotWindRpt = VdotWind;
1900 1 : if (present(VdotBuoyRpt)) VdotBuoyRpt = VdotThermal;
1901 1 : }
1902 :
1903 : //****************************************************************************
1904 :
1905 1 : Real64 PassiveGapNusseltNumber(Real64 const AspRat, // Aspect Ratio of Gap height to gap width
1906 : Real64 const Tilt, // Tilt of gap, degrees
1907 : Real64 const Tso, // Temperature of gap surface closest to outside (K)
1908 : Real64 const Tsi, // Temperature of gap surface closest to zone (K)
1909 : Real64 const Gr // Gap gas Grashof number
1910 : )
1911 : {
1912 :
1913 : // SUBROUTINE INFORMATION:
1914 : // AUTHOR Adapted by B. Griffith from Fred Winkelmann's from NusseltNumber in WindowManager.cc
1915 : // DATE WRITTEN September 2001
1916 : // MODIFIED B. Griffith November 2004 (same models but slightly different for general use)
1917 :
1918 : // PURPOSE OF THIS SUBROUTINE:
1919 : // Finds the Nusselt number for air-filled gaps between isothermal solid layers.
1920 :
1921 : // METHODOLOGY EMPLOYED:
1922 : // Based on methodology in Chapter 5 of the July 18, 2001 draft of ISO 15099,
1923 : // "Thermal Performance of Windows, Doors and Shading Devices--Detailed Calculations."
1924 : // The equation numbers below correspond to those in the standard.
1925 :
1926 : // REFERENCES:
1927 : // Window5 source code; ISO 15099
1928 :
1929 : // SUBROUTINE PARAMETER DEFINITIONS:
1930 1 : Real64 constexpr Pr(0.71); // Prandtl number for air
1931 :
1932 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS
1933 : Real64 gnu901; // Nusselt number temporary variables for
1934 :
1935 1 : Real64 tiltr = Tilt * Constant::DegToRad;
1936 1 : Real64 Ra = Gr * Pr; // Rayleigh number
1937 :
1938 1 : if (Ra <= 1.0e4) {
1939 0 : gnu901 = 1.0 + 1.7596678e-10 * std::pow(Ra, 2.2984755); // eq. 51
1940 : }
1941 1 : if (Ra > 1.0e4 && Ra <= 5.0e4) gnu901 = 0.028154 * std::pow(Ra, 0.4134); // eq. 50
1942 1 : if (Ra > 5.0e4) gnu901 = 0.0673838 * std::pow(Ra, 1.0 / 3.0); // eq. 49
1943 :
1944 1 : Real64 gnu902 = 0.242 * std::pow(Ra / AspRat, 0.272); // eq. 52
1945 1 : Real64 gnu90 = max(gnu901, gnu902);
1946 :
1947 1 : if (Tso > Tsi) { // window heated from above
1948 0 : return 1.0 + (gnu90 - 1.0) * std::sin(tiltr); // eq. 53
1949 1 : } else if (Tilt >= 60.0) {
1950 0 : Real64 g = 0.5 * std::pow(1.0 + std::pow(Ra / 3160.0, 20.6), -0.1); // eq. 47
1951 0 : Real64 gnu601a = 1.0 + pow_7(0.0936 * std::pow(Ra, 0.314) / (1.0 + g)); // eq. 45
1952 0 : Real64 gnu601 = std::pow(gnu601a, 0.142857);
1953 :
1954 : // For any aspect ratio
1955 0 : Real64 gnu602 = (0.104 + 0.175 / AspRat) * std::pow(Ra, 0.283); // eq. 46
1956 0 : Real64 gnu60 = max(gnu601, gnu602);
1957 :
1958 : // linear interpolation for layers inclined at angles between 60 and 90 deg
1959 0 : return ((90.0 - Tilt) * gnu60 + (Tilt - 60.0) * gnu90) / 30.0;
1960 : } else { // eq. 42
1961 1 : Real64 cra = Ra * std::cos(tiltr);
1962 1 : Real64 a = 1.0 - 1708.0 / cra;
1963 1 : Real64 b = std::pow(cra / 5830.0, 0.33333) - 1.0;
1964 1 : Real64 gnua = (std::abs(a) + a) / 2.0;
1965 1 : Real64 gnub = (std::abs(b) + b) / 2.0;
1966 1 : Real64 ang = 1708.0 * std::pow(std::sin(1.8 * tiltr), 1.6);
1967 1 : return 1.0 + 1.44 * gnua * (1.0 - ang / cra) + gnub;
1968 : }
1969 : }
1970 :
1971 : } // namespace TranspiredCollector
1972 :
1973 : } // namespace EnergyPlus
|