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