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