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 <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/Autosizing/Base.hh>
57 : #include <EnergyPlus/BranchNodeConnections.hh>
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataContaminantBalance.hh>
60 : #include <EnergyPlus/DataDefineEquip.hh>
61 : #include <EnergyPlus/DataEnvironment.hh>
62 : #include <EnergyPlus/DataHVACGlobals.hh>
63 : #include <EnergyPlus/DataLoopNode.hh>
64 : #include <EnergyPlus/DataSizing.hh>
65 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
66 : #include <EnergyPlus/DataZoneEquipment.hh>
67 : #include <EnergyPlus/FluidProperties.hh>
68 : #include <EnergyPlus/General.hh>
69 : #include <EnergyPlus/GeneralRoutines.hh>
70 : #include <EnergyPlus/HVACCooledBeam.hh>
71 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
72 : #include <EnergyPlus/NodeInputManager.hh>
73 : #include <EnergyPlus/OutputProcessor.hh>
74 : #include <EnergyPlus/OutputReportPredefined.hh>
75 : #include <EnergyPlus/Plant/DataPlant.hh>
76 : #include <EnergyPlus/PlantUtilities.hh>
77 : #include <EnergyPlus/Psychrometrics.hh>
78 : #include <EnergyPlus/ScheduleManager.hh>
79 : #include <EnergyPlus/UtilityRoutines.hh>
80 : #include <EnergyPlus/WaterCoils.hh>
81 :
82 : namespace EnergyPlus {
83 :
84 : namespace HVACCooledBeam {
85 :
86 : // Module containing routines dealing with cooled beam units
87 :
88 : // MODULE INFORMATION:
89 : // AUTHOR Fred Buhl
90 : // DATE WRITTEN February 2, 2008
91 : // MODIFIED na
92 : // RE-ENGINEERED na
93 :
94 : // PURPOSE OF THIS MODULE:
95 : // To encapsulate the data and algorithms needed to simulate cooled beam units
96 :
97 : // METHODOLOGY EMPLOYED:
98 : // Cooled beam units are treated as terminal units. There is a fixed amount of supply air delivered
99 : // either directly through a diffuser or through the cooled beam units. Thermodynamically the
100 : // situation is similar to 4 pipe induction terminal units. The detailed methodology follows the
101 : // method in DOE-2.1E.
102 :
103 : // Using/Aliasing
104 : using namespace DataLoopNode;
105 : using HVAC::SmallAirVolFlow;
106 : using HVAC::SmallLoad;
107 : using HVAC::SmallMassFlow;
108 : using HVAC::SmallWaterVolFlow;
109 : using Psychrometrics::PsyCpAirFnW;
110 : using Psychrometrics::PsyHFnTdbW;
111 : using Psychrometrics::PsyRhoAirFnPbTdbW;
112 :
113 0 : void SimCoolBeam(EnergyPlusData &state,
114 : std::string_view CompName, // name of the cooled beam unit
115 : bool const FirstHVACIteration, // TRUE if first HVAC iteration in time step
116 : int const ZoneNum, // index of zone served by the unit
117 : int const ZoneNodeNum, // zone node number of zone served by the unit
118 : int &CompIndex, // which cooled beam unit in data structure
119 : Real64 &NonAirSysOutput // convective cooling by the beam system [W]
120 : )
121 : {
122 :
123 : // SUBROUTINE INFORMATION:
124 : // AUTHOR Fred Buhl
125 : // DATE WRITTEN Feb 3, 2009
126 : // MODIFIED na
127 : // RE-ENGINEERED na
128 :
129 : // PURPOSE OF THIS SUBROUTINE:
130 : // Manages the simulation of a cooled beam unit.
131 : // Called from SimZoneAirLoopEquipment in module ZoneAirLoopEquipmentManager.
132 :
133 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
134 : int CBNum; // index of cooled beam unit being simulated
135 :
136 : // First time SimIndUnit is called, get the input for all the cooled beam units
137 0 : if (state.dataHVACCooledBeam->GetInputFlag) {
138 0 : GetCoolBeams(state);
139 0 : state.dataHVACCooledBeam->GetInputFlag = false;
140 : }
141 :
142 : // Get the unit index
143 0 : if (CompIndex == 0) {
144 0 : CBNum = Util::FindItemInList(CompName, state.dataHVACCooledBeam->CoolBeam);
145 0 : if (CBNum == 0) {
146 0 : ShowFatalError(state, format("SimCoolBeam: Cool Beam Unit not found={}", CompName));
147 : }
148 0 : CompIndex = CBNum;
149 : } else {
150 0 : CBNum = CompIndex;
151 0 : if (CBNum > state.dataHVACCooledBeam->NumCB || CBNum < 1) {
152 0 : ShowFatalError(state,
153 0 : format("SimCoolBeam: Invalid CompIndex passed={}, Number of Cool Beam Units={}, System name={}",
154 : CompIndex,
155 0 : state.dataHVACCooledBeam->NumCB,
156 : CompName));
157 : }
158 0 : if (state.dataHVACCooledBeam->CheckEquipName(CBNum)) {
159 0 : if (CompName != state.dataHVACCooledBeam->CoolBeam(CBNum).Name) {
160 0 : ShowFatalError(state,
161 0 : format("SimCoolBeam: Invalid CompIndex passed={}, Cool Beam Unit name={}, stored Cool Beam Unit for that index={}",
162 : CompIndex,
163 : CompName,
164 0 : state.dataHVACCooledBeam->CoolBeam(CBNum).Name));
165 : }
166 0 : state.dataHVACCooledBeam->CheckEquipName(CBNum) = false;
167 : }
168 : }
169 0 : if (CBNum == 0) {
170 0 : ShowFatalError(state, format("Cool Beam Unit not found = {}", CompName));
171 : }
172 :
173 0 : state.dataSize->CurTermUnitSizingNum =
174 0 : state.dataDefineEquipment->AirDistUnit(state.dataHVACCooledBeam->CoolBeam(CBNum).ADUNum).TermUnitSizingNum;
175 : // initialize the unit
176 0 : InitCoolBeam(state, CBNum, FirstHVACIteration);
177 :
178 0 : ControlCoolBeam(state, CBNum, ZoneNum, ZoneNodeNum, FirstHVACIteration, NonAirSysOutput);
179 :
180 : // Update the current unit's outlet nodes. No update needed
181 0 : UpdateCoolBeam(state, CBNum);
182 :
183 : // Fill the report variables. There are no report variables
184 0 : ReportCoolBeam(state, CBNum);
185 0 : }
186 :
187 0 : void GetCoolBeams(EnergyPlusData &state)
188 : {
189 :
190 : // SUBROUTINE INFORMATION:
191 : // AUTHOR Fred Buhl
192 : // DATE WRITTEN Feb 3, 2009
193 : // MODIFIED na
194 : // RE-ENGINEERED na
195 :
196 : // PURPOSE OF THIS SUBROUTINE:
197 : // Obtains input data for cool beam units and stores it in the
198 : // cool beam unit data structures
199 :
200 : // METHODOLOGY EMPLOYED:
201 : // Uses "Get" routines to read in data.
202 :
203 : // Using/Aliasing
204 : using BranchNodeConnections::TestCompSet;
205 : using NodeInputManager::GetOnlySingleNode;
206 : using namespace DataSizing;
207 : using WaterCoils::GetCoilWaterInletNode;
208 :
209 : // SUBROUTINE PARAMETER DEFINITIONS:
210 : static constexpr std::string_view RoutineName("GetCoolBeams "); // include trailing blank space
211 : static constexpr std::string_view routineName = "GetCoolBeams";
212 :
213 : int CBIndex; // loop index
214 0 : std::string CurrentModuleObject; // for ease in getting objects
215 0 : Array1D_string Alphas; // Alpha input items for object
216 0 : Array1D_string cAlphaFields; // Alpha field names
217 0 : Array1D_string cNumericFields; // Numeric field names
218 0 : Array1D<Real64> Numbers; // Numeric input items for object
219 0 : Array1D_bool lAlphaBlanks; // Logical array, alpha field input BLANK = .TRUE.
220 0 : Array1D_bool lNumericBlanks; // Logical array, numeric field input BLANK = .TRUE.
221 0 : int NumAlphas(0); // Number of Alphas for each GetObjectItem call
222 0 : int NumNumbers(0); // Number of Numbers for each GetObjectItem call
223 0 : int TotalArgs(0); // Total number of alpha and numeric arguments (max) for a
224 : // certain object in the input file
225 : int IOStatus; // Used in GetObjectItem
226 0 : bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
227 : int CtrlZone; // controlled zome do loop index
228 : int SupAirIn; // controlled zone supply air inlet index
229 : bool AirNodeFound;
230 : int ADUNum;
231 :
232 0 : auto &CoolBeam = state.dataHVACCooledBeam->CoolBeam;
233 0 : auto &CheckEquipName = state.dataHVACCooledBeam->CheckEquipName;
234 :
235 : // find the number of cooled beam units
236 0 : CurrentModuleObject = "AirTerminal:SingleDuct:ConstantVolume:CooledBeam";
237 : // Update Num in state and make local convenience copy
238 0 : int NumCB = state.dataHVACCooledBeam->NumCB = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
239 : // allocate the data structures
240 0 : CoolBeam.allocate(NumCB);
241 0 : CheckEquipName.dimension(NumCB, true);
242 :
243 0 : state.dataInputProcessing->inputProcessor->getObjectDefMaxArgs(state, CurrentModuleObject, TotalArgs, NumAlphas, NumNumbers);
244 0 : NumAlphas = 7;
245 0 : NumNumbers = 16;
246 0 : TotalArgs = 23;
247 :
248 0 : Alphas.allocate(NumAlphas);
249 0 : cAlphaFields.allocate(NumAlphas);
250 0 : cNumericFields.allocate(NumNumbers);
251 0 : Numbers.dimension(NumNumbers, 0.0);
252 0 : lAlphaBlanks.dimension(NumAlphas, true);
253 0 : lNumericBlanks.dimension(NumNumbers, true);
254 :
255 : // loop over cooled beam units; get and load the input data
256 0 : for (CBIndex = 1; CBIndex <= NumCB; ++CBIndex) {
257 :
258 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
259 : CurrentModuleObject,
260 : CBIndex,
261 : Alphas,
262 : NumAlphas,
263 : Numbers,
264 : NumNumbers,
265 : IOStatus,
266 : lNumericBlanks,
267 : lAlphaBlanks,
268 : cAlphaFields,
269 : cNumericFields);
270 :
271 0 : ErrorObjectHeader eoh{routineName, CurrentModuleObject, Alphas(1)};
272 0 : int CBNum = CBIndex;
273 :
274 0 : CoolBeam(CBNum).Name = Alphas(1);
275 0 : CoolBeam(CBNum).UnitType = CurrentModuleObject;
276 0 : CoolBeam(CBNum).UnitType_Num = 1;
277 0 : CoolBeam(CBNum).CBTypeString = Alphas(3);
278 0 : if (Util::SameString(CoolBeam(CBNum).CBTypeString, "Passive")) {
279 0 : CoolBeam(CBNum).CBType = CooledBeamType::Passive;
280 0 : } else if (Util::SameString(CoolBeam(CBNum).CBTypeString, "Active")) {
281 0 : CoolBeam(CBNum).CBType = CooledBeamType::Active;
282 : } else {
283 0 : ShowSevereError(state, format("Illegal {} = {}.", cAlphaFields(3), CoolBeam(CBNum).CBTypeString));
284 0 : ShowContinueError(state, format("Occurs in {} = {}", CurrentModuleObject, CoolBeam(CBNum).Name));
285 0 : ErrorsFound = true;
286 : }
287 :
288 0 : if (lAlphaBlanks(2)) {
289 0 : CoolBeam(CBNum).availSched = Sched::GetScheduleAlwaysOn(state);
290 0 : } else if ((CoolBeam(CBNum).availSched = Sched::GetSchedule(state, Alphas(2))) == nullptr) { // convert schedule name to pointer
291 0 : ShowSevereItemNotFound(state, eoh, cAlphaFields(2), Alphas(2));
292 0 : ErrorsFound = true;
293 : }
294 0 : CoolBeam(CBNum).AirInNode = GetOnlySingleNode(state,
295 0 : Alphas(4),
296 : ErrorsFound,
297 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeCooledBeam,
298 0 : Alphas(1),
299 : DataLoopNode::NodeFluidType::Air,
300 : DataLoopNode::ConnectionType::Inlet,
301 : NodeInputManager::CompFluidStream::Primary,
302 : ObjectIsNotParent,
303 0 : cAlphaFields(4));
304 0 : CoolBeam(CBNum).AirOutNode = GetOnlySingleNode(state,
305 0 : Alphas(5),
306 : ErrorsFound,
307 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeCooledBeam,
308 0 : Alphas(1),
309 : DataLoopNode::NodeFluidType::Air,
310 : DataLoopNode::ConnectionType::Outlet,
311 : NodeInputManager::CompFluidStream::Primary,
312 : ObjectIsNotParent,
313 0 : cAlphaFields(5));
314 0 : CoolBeam(CBNum).CWInNode = GetOnlySingleNode(state,
315 0 : Alphas(6),
316 : ErrorsFound,
317 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeCooledBeam,
318 0 : Alphas(1),
319 : DataLoopNode::NodeFluidType::Water,
320 : DataLoopNode::ConnectionType::Inlet,
321 : NodeInputManager::CompFluidStream::Secondary,
322 : ObjectIsNotParent,
323 0 : cAlphaFields(6));
324 0 : CoolBeam(CBNum).CWOutNode = GetOnlySingleNode(state,
325 0 : Alphas(7),
326 : ErrorsFound,
327 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeCooledBeam,
328 0 : Alphas(1),
329 : DataLoopNode::NodeFluidType::Water,
330 : DataLoopNode::ConnectionType::Outlet,
331 : NodeInputManager::CompFluidStream::Secondary,
332 : ObjectIsNotParent,
333 0 : cAlphaFields(7));
334 0 : CoolBeam(CBNum).MaxAirVolFlow = Numbers(1);
335 0 : CoolBeam(CBNum).MaxCoolWaterVolFlow = Numbers(2);
336 0 : CoolBeam(CBNum).NumBeams = Numbers(3);
337 0 : CoolBeam(CBNum).BeamLength = Numbers(4);
338 0 : CoolBeam(CBNum).DesInletWaterTemp = Numbers(5);
339 0 : CoolBeam(CBNum).DesOutletWaterTemp = Numbers(6);
340 0 : CoolBeam(CBNum).CoilArea = Numbers(7);
341 0 : CoolBeam(CBNum).a = Numbers(8);
342 0 : CoolBeam(CBNum).n1 = Numbers(9);
343 0 : CoolBeam(CBNum).n2 = Numbers(10);
344 0 : CoolBeam(CBNum).n3 = Numbers(11);
345 0 : CoolBeam(CBNum).a0 = Numbers(12);
346 0 : CoolBeam(CBNum).K1 = Numbers(13);
347 0 : CoolBeam(CBNum).n = Numbers(14);
348 0 : CoolBeam(CBNum).Kin = Numbers(15);
349 0 : CoolBeam(CBNum).InDiam = Numbers(16);
350 :
351 : // Register component set data
352 0 : TestCompSet(state,
353 : CurrentModuleObject,
354 0 : CoolBeam(CBNum).Name,
355 0 : state.dataLoopNodes->NodeID(CoolBeam(CBNum).AirInNode),
356 0 : state.dataLoopNodes->NodeID(CoolBeam(CBNum).AirOutNode),
357 : "Air Nodes");
358 0 : TestCompSet(state,
359 : CurrentModuleObject,
360 0 : CoolBeam(CBNum).Name,
361 0 : state.dataLoopNodes->NodeID(CoolBeam(CBNum).CWInNode),
362 0 : state.dataLoopNodes->NodeID(CoolBeam(CBNum).CWOutNode),
363 : "Water Nodes");
364 :
365 : // Setup the Cooled Beam reporting variables
366 : // CurrentModuleObject = "AirTerminal:SingleDuct:ConstantVolume:CooledBeam"
367 0 : SetupOutputVariable(state,
368 : "Zone Air Terminal Beam Sensible Cooling Energy",
369 : Constant::Units::J,
370 0 : CoolBeam(CBNum).BeamCoolingEnergy,
371 : OutputProcessor::TimeStepType::System,
372 : OutputProcessor::StoreType::Sum,
373 0 : CoolBeam(CBNum).Name,
374 : Constant::eResource::EnergyTransfer,
375 : OutputProcessor::Group::HVAC,
376 : OutputProcessor::EndUseCat::CoolingCoils);
377 0 : SetupOutputVariable(state,
378 : "Zone Air Terminal Beam Chilled Water Energy",
379 : Constant::Units::J,
380 0 : CoolBeam(CBNum).BeamCoolingEnergy,
381 : OutputProcessor::TimeStepType::System,
382 : OutputProcessor::StoreType::Sum,
383 0 : CoolBeam(CBNum).Name,
384 : Constant::eResource::PlantLoopCoolingDemand,
385 : OutputProcessor::Group::HVAC,
386 : OutputProcessor::EndUseCat::CoolingCoils);
387 0 : SetupOutputVariable(state,
388 : "Zone Air Terminal Beam Sensible Cooling Rate",
389 : Constant::Units::W,
390 0 : CoolBeam(CBNum).BeamCoolingRate,
391 : OutputProcessor::TimeStepType::System,
392 : OutputProcessor::StoreType::Average,
393 0 : CoolBeam(CBNum).Name);
394 0 : SetupOutputVariable(state,
395 : "Zone Air Terminal Supply Air Sensible Cooling Energy",
396 : Constant::Units::J,
397 0 : CoolBeam(CBNum).SupAirCoolingEnergy,
398 : OutputProcessor::TimeStepType::System,
399 : OutputProcessor::StoreType::Sum,
400 0 : CoolBeam(CBNum).Name);
401 0 : SetupOutputVariable(state,
402 : "Zone Air Terminal Supply Air Sensible Cooling Rate",
403 : Constant::Units::W,
404 0 : CoolBeam(CBNum).SupAirCoolingRate,
405 : OutputProcessor::TimeStepType::System,
406 : OutputProcessor::StoreType::Average,
407 0 : CoolBeam(CBNum).Name);
408 0 : SetupOutputVariable(state,
409 : "Zone Air Terminal Supply Air Sensible Heating Energy",
410 : Constant::Units::J,
411 0 : CoolBeam(CBNum).SupAirHeatingEnergy,
412 : OutputProcessor::TimeStepType::System,
413 : OutputProcessor::StoreType::Sum,
414 0 : CoolBeam(CBNum).Name);
415 0 : SetupOutputVariable(state,
416 : "Zone Air Terminal Supply Air Sensible Heating Rate",
417 : Constant::Units::W,
418 0 : CoolBeam(CBNum).SupAirHeatingRate,
419 : OutputProcessor::TimeStepType::System,
420 : OutputProcessor::StoreType::Average,
421 0 : CoolBeam(CBNum).Name);
422 :
423 0 : SetupOutputVariable(state,
424 : "Zone Air Terminal Outdoor Air Volume Flow Rate",
425 : Constant::Units::m3_s,
426 0 : CoolBeam(CBNum).OutdoorAirFlowRate,
427 : OutputProcessor::TimeStepType::System,
428 : OutputProcessor::StoreType::Average,
429 0 : CoolBeam(CBNum).Name);
430 :
431 0 : for (ADUNum = 1; ADUNum <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++ADUNum) {
432 0 : if (CoolBeam(CBNum).AirOutNode == state.dataDefineEquipment->AirDistUnit(ADUNum).OutletNodeNum) {
433 0 : CoolBeam(CBNum).ADUNum = ADUNum;
434 0 : state.dataDefineEquipment->AirDistUnit(ADUNum).InletNodeNum = CoolBeam(CBNum).AirInNode;
435 : }
436 : }
437 : // one assumes if there isn't one assigned, it's an error?
438 0 : if (CoolBeam(CBNum).ADUNum == 0) {
439 0 : ShowSevereError(
440 : state,
441 0 : format("{}No matching Air Distribution Unit, for Unit = [{},{}].", RoutineName, CurrentModuleObject, CoolBeam(CBNum).Name));
442 0 : ShowContinueError(state, format("...should have outlet node={}", state.dataLoopNodes->NodeID(CoolBeam(CBNum).AirOutNode)));
443 0 : ErrorsFound = true;
444 : } else {
445 :
446 : // Fill the Zone Equipment data with the supply air inlet node number of this unit.
447 0 : AirNodeFound = false;
448 0 : for (CtrlZone = 1; CtrlZone <= state.dataGlobal->NumOfZones; ++CtrlZone) {
449 0 : if (!state.dataZoneEquip->ZoneEquipConfig(CtrlZone).IsControlled) continue;
450 0 : for (SupAirIn = 1; SupAirIn <= state.dataZoneEquip->ZoneEquipConfig(CtrlZone).NumInletNodes; ++SupAirIn) {
451 0 : if (CoolBeam(CBNum).AirOutNode == state.dataZoneEquip->ZoneEquipConfig(CtrlZone).InletNode(SupAirIn)) {
452 0 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).InNode = CoolBeam(CBNum).AirInNode;
453 0 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).OutNode = CoolBeam(CBNum).AirOutNode;
454 0 : state.dataDefineEquipment->AirDistUnit(CoolBeam(CBNum).ADUNum).TermUnitSizingNum =
455 0 : state.dataZoneEquip->ZoneEquipConfig(CtrlZone).AirDistUnitCool(SupAirIn).TermUnitSizingIndex;
456 0 : state.dataDefineEquipment->AirDistUnit(CoolBeam(CBNum).ADUNum).ZoneEqNum = CtrlZone;
457 0 : CoolBeam(CBNum).CtrlZoneNum = CtrlZone;
458 0 : CoolBeam(CBNum).ctrlZoneInNodeIndex = SupAirIn;
459 0 : AirNodeFound = true;
460 0 : break;
461 : }
462 : }
463 : }
464 : }
465 0 : if (!AirNodeFound) {
466 0 : ShowSevereError(state, format("The outlet air node from the {} = {}", CurrentModuleObject, CoolBeam(CBNum).Name));
467 0 : ShowContinueError(state, format("did not have a matching Zone Equipment Inlet Node, Node ={}", Alphas(5)));
468 0 : ErrorsFound = true;
469 : }
470 : }
471 :
472 0 : Alphas.deallocate();
473 0 : cAlphaFields.deallocate();
474 0 : cNumericFields.deallocate();
475 0 : Numbers.deallocate();
476 0 : lAlphaBlanks.deallocate();
477 0 : lNumericBlanks.deallocate();
478 :
479 0 : if (ErrorsFound) {
480 0 : ShowFatalError(state, format("{}Errors found in getting input. Preceding conditions cause termination.", RoutineName));
481 : }
482 0 : }
483 :
484 0 : void InitCoolBeam(EnergyPlusData &state,
485 : int const CBNum, // number of the current cooled beam unit being simulated
486 : bool const FirstHVACIteration // TRUE if first air loop solution this HVAC step
487 : )
488 : {
489 :
490 : // SUBROUTINE INFORMATION:
491 : // AUTHOR Fred Buhl
492 : // DATE WRITTEN February 6, 2009
493 : // MODIFIED na
494 : // RE-ENGINEERED na
495 :
496 : // PURPOSE OF THIS SUBROUTINE:
497 : // This subroutine is for initialization of the cooled beam units
498 :
499 : // METHODOLOGY EMPLOYED:
500 : // Uses the status flags to trigger initializations.
501 :
502 : // Using/Aliasing
503 : using DataZoneEquipment::CheckZoneEquipmentList;
504 : using PlantUtilities::InitComponentNodes;
505 : using PlantUtilities::ScanPlantLoopsForObject;
506 : using PlantUtilities::SetComponentFlowRate;
507 :
508 : // SUBROUTINE PARAMETER DEFINITIONS:
509 : static constexpr std::string_view RoutineName("InitCoolBeam");
510 :
511 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
512 : int InAirNode; // supply air inlet node number
513 : int OutAirNode; // unit air outlet node
514 : int InWaterNode; // unit inlet chilled water node
515 : int OutWaterNode; // unit outlet chilled water node
516 : Real64 RhoAir; // air density at outside pressure and standard temperature and humidity
517 : Real64 rho; // local fluid density
518 :
519 0 : auto &coolBeam = state.dataHVACCooledBeam->CoolBeam(CBNum);
520 0 : auto &ZoneEquipmentListChecked = state.dataHVACCooledBeam->ZoneEquipmentListChecked;
521 0 : int NumCB = state.dataHVACCooledBeam->NumCB;
522 :
523 0 : if (coolBeam.PlantLoopScanFlag && allocated(state.dataPlnt->PlantLoop)) {
524 0 : bool errFlag = false;
525 0 : ScanPlantLoopsForObject(
526 0 : state, coolBeam.Name, DataPlant::PlantEquipmentType::CooledBeamAirTerminal, coolBeam.CWPlantLoc, errFlag, _, _, _, _, _);
527 0 : if (errFlag) {
528 0 : ShowFatalError(state, "InitCoolBeam: Program terminated for previous conditions.");
529 : }
530 0 : coolBeam.PlantLoopScanFlag = false;
531 : }
532 :
533 0 : if (!ZoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
534 0 : std::string CurrentModuleObject = "AirTerminal:SingleDuct:ConstantVolume:CooledBeam";
535 0 : ZoneEquipmentListChecked = true;
536 : // Check to see if there is a Air Distribution Unit on the Zone Equipment List
537 0 : for (int Loop = 1; Loop <= NumCB; ++Loop) {
538 0 : if (coolBeam.ADUNum == 0) continue;
539 0 : if (CheckZoneEquipmentList(state, "ZONEHVAC:AIRDISTRIBUTIONUNIT", state.dataDefineEquipment->AirDistUnit(coolBeam.ADUNum).Name))
540 0 : continue;
541 0 : ShowSevereError(state,
542 0 : format("InitCoolBeam: ADU=[Air Distribution Unit,{}] is not on any ZoneHVAC:EquipmentList.",
543 0 : state.dataDefineEquipment->AirDistUnit(coolBeam.ADUNum).Name));
544 0 : ShowContinueError(state, format("...Unit=[{},{}] will not be simulated.", CurrentModuleObject, coolBeam.Name));
545 : }
546 0 : }
547 :
548 0 : if (!state.dataGlobal->SysSizingCalc && coolBeam.MySizeFlag && !coolBeam.PlantLoopScanFlag) {
549 :
550 0 : SizeCoolBeam(state, CBNum);
551 :
552 0 : InWaterNode = coolBeam.CWInNode;
553 0 : OutWaterNode = coolBeam.CWOutNode;
554 0 : rho = state.dataPlnt->PlantLoop(coolBeam.CWPlantLoc.loopNum).glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
555 0 : coolBeam.MaxCoolWaterMassFlow = rho * coolBeam.MaxCoolWaterVolFlow;
556 0 : InitComponentNodes(state, 0.0, coolBeam.MaxCoolWaterMassFlow, InWaterNode, OutWaterNode);
557 0 : coolBeam.MySizeFlag = false;
558 : }
559 :
560 : // Do the Begin Environment initializations
561 0 : if (state.dataGlobal->BeginEnvrnFlag && coolBeam.MyEnvrnFlag) {
562 0 : RhoAir = state.dataEnvrn->StdRhoAir;
563 0 : InAirNode = coolBeam.AirInNode;
564 0 : OutAirNode = coolBeam.AirOutNode;
565 : // set the mass flow rates from the input volume flow rates
566 0 : coolBeam.MaxAirMassFlow = RhoAir * coolBeam.MaxAirVolFlow;
567 0 : state.dataLoopNodes->Node(InAirNode).MassFlowRateMax = coolBeam.MaxAirMassFlow;
568 0 : state.dataLoopNodes->Node(OutAirNode).MassFlowRateMax = coolBeam.MaxAirMassFlow;
569 0 : state.dataLoopNodes->Node(InAirNode).MassFlowRateMin = 0.0;
570 0 : state.dataLoopNodes->Node(OutAirNode).MassFlowRateMin = 0.0;
571 :
572 0 : InWaterNode = coolBeam.CWInNode;
573 0 : OutWaterNode = coolBeam.CWOutNode;
574 0 : InitComponentNodes(state, 0.0, coolBeam.MaxCoolWaterMassFlow, InWaterNode, OutWaterNode);
575 :
576 0 : if (coolBeam.AirLoopNum == 0) { // fill air loop index
577 0 : if (coolBeam.CtrlZoneNum > 0 && coolBeam.ctrlZoneInNodeIndex > 0) {
578 0 : coolBeam.AirLoopNum =
579 0 : state.dataZoneEquip->ZoneEquipConfig(coolBeam.CtrlZoneNum).InletNodeAirLoopNum(coolBeam.ctrlZoneInNodeIndex);
580 0 : state.dataDefineEquipment->AirDistUnit(coolBeam.ADUNum).AirLoopNum = coolBeam.AirLoopNum;
581 : }
582 : }
583 :
584 0 : coolBeam.MyEnvrnFlag = false;
585 : } // end one time inits
586 :
587 0 : if (!state.dataGlobal->BeginEnvrnFlag) {
588 0 : coolBeam.MyEnvrnFlag = true;
589 : }
590 :
591 0 : InAirNode = coolBeam.AirInNode;
592 0 : OutAirNode = coolBeam.AirOutNode;
593 :
594 : // Do the start of HVAC time step initializations
595 0 : if (FirstHVACIteration) {
596 : // check for upstream zero flow. If nonzero and schedule ON, set primary flow to max
597 0 : if (coolBeam.availSched->getCurrentVal() > 0.0 && state.dataLoopNodes->Node(InAirNode).MassFlowRate > 0.0) {
598 0 : state.dataLoopNodes->Node(InAirNode).MassFlowRate = coolBeam.MaxAirMassFlow;
599 : } else {
600 0 : state.dataLoopNodes->Node(InAirNode).MassFlowRate = 0.0;
601 : }
602 : // reset the max and min avail flows
603 0 : if (coolBeam.availSched->getCurrentVal() > 0.0 && state.dataLoopNodes->Node(InAirNode).MassFlowRateMaxAvail > 0.0) {
604 0 : state.dataLoopNodes->Node(InAirNode).MassFlowRateMaxAvail = coolBeam.MaxAirMassFlow;
605 0 : state.dataLoopNodes->Node(InAirNode).MassFlowRateMinAvail = coolBeam.MaxAirMassFlow;
606 : } else {
607 0 : state.dataLoopNodes->Node(InAirNode).MassFlowRateMaxAvail = 0.0;
608 0 : state.dataLoopNodes->Node(InAirNode).MassFlowRateMinAvail = 0.0;
609 : }
610 : }
611 :
612 : // do these initializations every time step
613 0 : InWaterNode = coolBeam.CWInNode;
614 0 : coolBeam.TWIn = state.dataLoopNodes->Node(InWaterNode).Temp;
615 0 : coolBeam.SupAirCoolingRate = 0.0;
616 0 : coolBeam.SupAirHeatingRate = 0.0;
617 0 : }
618 :
619 0 : void SizeCoolBeam(EnergyPlusData &state, int const CBNum)
620 : {
621 :
622 : // SUBROUTINE INFORMATION:
623 : // AUTHOR Fred Buhl
624 : // DATE WRITTEN February 10, 2009
625 : // MODIFIED na
626 : // RE-ENGINEERED na
627 :
628 : // PURPOSE OF THIS SUBROUTINE:
629 : // This subroutine is for sizing cooled beam units for which flow rates have not been
630 : // specified in the input
631 :
632 : // METHODOLOGY EMPLOYED:
633 : // Accesses zone sizing array for air flow rates and zone and plant sizing arrays to
634 : // calculate coil water flow rates.
635 :
636 : // Using/Aliasing
637 : using namespace DataSizing;
638 : using PlantUtilities::MyPlantSizingIndex;
639 : using PlantUtilities::RegisterPlantCompDesignFlow;
640 :
641 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
642 : static constexpr std::string_view RoutineName("SizeCoolBeam");
643 0 : int PltSizCoolNum(0); // index of plant sizing object for the cooling loop
644 0 : int NumBeams(0); // number of beams in the zone
645 0 : Real64 DesCoilLoad(0.0); // total cooling capacity of the beams in the zone [W]
646 0 : Real64 DesLoadPerBeam(0.0); // cooling capacity per individual beam [W]
647 0 : Real64 DesAirVolFlow(0.0); // design total supply air flow rate [m3/s]
648 0 : Real64 DesAirFlowPerBeam(0.0); // design supply air volumetric flow per beam [m3/s]
649 0 : Real64 RhoAir(0.0);
650 0 : Real64 CpAir(0.0);
651 0 : Real64 WaterVel(0.0); // design water velocity in beam
652 0 : Real64 IndAirFlowPerBeamL(0.0); // induced volumetric air flow rate per beam length [m3/s-m]
653 0 : Real64 DT(0.0); // air - water delta T [C]
654 0 : Real64 LengthX(0.0); // test value for beam length [m]
655 0 : Real64 Length(0.0); // beam length [m]
656 0 : Real64 ConvFlow(0.0); // convective and induced air mass flow rate across beam per beam plan area [kg/s-m2]
657 0 : Real64 K(0.0); // coil (beam) heat transfer coefficient [W/m2-K]
658 0 : Real64 WaterVolFlowPerBeam(0.0); // Cooling water volumetric flow per beam [m3]
659 : bool ErrorsFound;
660 : Real64 rho; // local fluid density
661 : Real64 Cp; // local fluid specific heat
662 :
663 0 : PltSizCoolNum = 0;
664 0 : DesAirVolFlow = 0.0;
665 0 : CpAir = 0.0;
666 0 : RhoAir = state.dataEnvrn->StdRhoAir;
667 0 : ErrorsFound = false;
668 :
669 0 : auto &coolBeam = state.dataHVACCooledBeam->CoolBeam(CBNum);
670 :
671 : // find the appropriate Plant Sizing object
672 0 : if (coolBeam.MaxAirVolFlow == AutoSize || coolBeam.BeamLength == AutoSize) {
673 0 : PltSizCoolNum = MyPlantSizingIndex(state, "cooled beam unit", coolBeam.Name, coolBeam.CWInNode, coolBeam.CWOutNode, ErrorsFound);
674 : }
675 :
676 0 : if (coolBeam.Kin == Constant::AutoCalculate) {
677 0 : if (coolBeam.CBType == CooledBeamType::Passive) {
678 0 : coolBeam.Kin = 0.0;
679 : } else {
680 0 : coolBeam.Kin = 2.0;
681 : }
682 0 : BaseSizer::reportSizerOutput(state, coolBeam.UnitType, coolBeam.Name, "Coefficient of Induction Kin", coolBeam.Kin);
683 : }
684 :
685 0 : if (coolBeam.MaxAirVolFlow == AutoSize) {
686 :
687 0 : if (state.dataSize->CurTermUnitSizingNum > 0) {
688 :
689 0 : CheckZoneSizing(state, coolBeam.UnitType, coolBeam.Name);
690 0 : coolBeam.MaxAirVolFlow = max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlow,
691 0 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow);
692 0 : if (coolBeam.MaxAirVolFlow < SmallAirVolFlow) {
693 0 : coolBeam.MaxAirVolFlow = 0.0;
694 : }
695 0 : BaseSizer::reportSizerOutput(state, coolBeam.UnitType, coolBeam.Name, "Supply Air Flow Rate [m3/s]", coolBeam.MaxAirVolFlow);
696 : }
697 : }
698 :
699 0 : if (coolBeam.MaxCoolWaterVolFlow == AutoSize) {
700 :
701 0 : if ((state.dataSize->CurZoneEqNum > 0) && (state.dataSize->CurTermUnitSizingNum > 0)) {
702 :
703 0 : CheckZoneSizing(state, coolBeam.UnitType, coolBeam.Name);
704 :
705 0 : if (PltSizCoolNum > 0) {
706 :
707 0 : if (state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolMassFlow >= SmallAirVolFlow) {
708 0 : DesAirVolFlow = coolBeam.MaxAirVolFlow;
709 0 : CpAir = PsyCpAirFnW(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).CoolDesHumRat);
710 : // the design cooling coil load is the zone load minus whatever the central system does. Note that
711 : // DesCoolCoilInTempTU is really the primary air inlet temperature for the unit.
712 0 : if (state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtCoolPeak > 0.0) {
713 0 : DesCoilLoad = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).NonAirSysDesCoolLoad -
714 0 : CpAir * RhoAir * DesAirVolFlow *
715 0 : (state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtCoolPeak -
716 0 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolCoilInTempTU);
717 : } else {
718 0 : DesCoilLoad = CpAir * RhoAir * DesAirVolFlow *
719 0 : (state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolCoilInTempTU -
720 0 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneSizThermSetPtHi);
721 : }
722 :
723 0 : rho = state.dataPlnt->PlantLoop(coolBeam.CWPlantLoc.loopNum).glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
724 :
725 0 : Cp = state.dataPlnt->PlantLoop(coolBeam.CWPlantLoc.loopNum)
726 0 : .glycol->getSpecificHeat(state, Constant::CWInitConvTemp, RoutineName);
727 :
728 0 : coolBeam.MaxCoolWaterVolFlow = DesCoilLoad / ((coolBeam.DesOutletWaterTemp - coolBeam.DesInletWaterTemp) * Cp * rho);
729 0 : coolBeam.MaxCoolWaterVolFlow = max(coolBeam.MaxCoolWaterVolFlow, 0.0);
730 0 : if (coolBeam.MaxCoolWaterVolFlow < SmallWaterVolFlow) {
731 0 : coolBeam.MaxCoolWaterVolFlow = 0.0;
732 : }
733 : } else {
734 0 : coolBeam.MaxCoolWaterVolFlow = 0.0;
735 : }
736 :
737 0 : BaseSizer::reportSizerOutput(
738 : state, coolBeam.UnitType, coolBeam.Name, "Maximum Total Chilled Water Flow Rate [m3/s]", coolBeam.MaxCoolWaterVolFlow);
739 : } else {
740 0 : ShowSevereError(state, "Autosizing of water flow requires a cooling loop Sizing:Plant object");
741 0 : ShowContinueError(state, format("Occurs in{} Object={}", coolBeam.UnitType, coolBeam.Name));
742 0 : ErrorsFound = true;
743 : }
744 : }
745 : }
746 :
747 0 : if (coolBeam.NumBeams == AutoSize) {
748 0 : rho = state.dataPlnt->PlantLoop(coolBeam.CWPlantLoc.loopNum).glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
749 :
750 0 : NumBeams = int(coolBeam.MaxCoolWaterVolFlow * rho / NomMassFlowPerBeam) + 1;
751 0 : coolBeam.NumBeams = double(NumBeams);
752 0 : BaseSizer::reportSizerOutput(state, coolBeam.UnitType, coolBeam.Name, "Number of Beams", coolBeam.NumBeams);
753 : }
754 :
755 0 : if (coolBeam.BeamLength == AutoSize) {
756 :
757 0 : if (state.dataSize->CurTermUnitSizingNum > 0) {
758 :
759 0 : CheckZoneSizing(state, coolBeam.UnitType, coolBeam.Name);
760 :
761 0 : if (PltSizCoolNum > 0) {
762 0 : rho = state.dataPlnt->PlantLoop(coolBeam.CWPlantLoc.loopNum).glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
763 :
764 0 : Cp = state.dataPlnt->PlantLoop(coolBeam.CWPlantLoc.loopNum).glycol->getSpecificHeat(state, Constant::CWInitConvTemp, RoutineName);
765 0 : DesCoilLoad = coolBeam.MaxCoolWaterVolFlow * (coolBeam.DesOutletWaterTemp - coolBeam.DesInletWaterTemp) * Cp * rho;
766 0 : if (DesCoilLoad > 0.0) {
767 0 : DesLoadPerBeam = DesCoilLoad / NumBeams;
768 0 : DesAirFlowPerBeam = coolBeam.MaxAirVolFlow / NumBeams;
769 0 : WaterVolFlowPerBeam = coolBeam.MaxCoolWaterVolFlow / NumBeams;
770 0 : WaterVel = WaterVolFlowPerBeam / (Constant::Pi * pow_2(coolBeam.InDiam) / 4.0);
771 0 : if (state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtCoolPeak > 0.0) {
772 0 : DT = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtCoolPeak -
773 0 : 0.5 * (coolBeam.DesInletWaterTemp + coolBeam.DesOutletWaterTemp);
774 0 : if (DT <= 0.0) {
775 0 : DT = 7.8;
776 : }
777 : } else {
778 0 : DT = 7.8;
779 : }
780 0 : LengthX = 1.0;
781 0 : for (int Iter = 1; Iter <= 100; ++Iter) {
782 0 : IndAirFlowPerBeamL = coolBeam.K1 * std::pow(DT, coolBeam.n) + coolBeam.Kin * DesAirFlowPerBeam / LengthX;
783 0 : ConvFlow = (IndAirFlowPerBeamL / coolBeam.a0) * RhoAir;
784 0 : if (WaterVel > MinWaterVel) {
785 0 : K = coolBeam.a * std::pow(DT, coolBeam.n1) * std::pow(ConvFlow, coolBeam.n2) * std::pow(WaterVel, coolBeam.n3);
786 : } else {
787 0 : K = coolBeam.a * std::pow(DT, coolBeam.n1) * std::pow(ConvFlow, coolBeam.n2) * std::pow(MinWaterVel, coolBeam.n3) *
788 0 : (WaterVel / MinWaterVel);
789 : }
790 0 : Length = DesLoadPerBeam / (K * coolBeam.CoilArea * DT);
791 0 : if (coolBeam.Kin <= 0.0) break;
792 : // Check for convergence
793 0 : if (std::abs(Length - LengthX) > 0.01) {
794 : // New guess for length
795 0 : LengthX += 0.5 * (Length - LengthX);
796 : } else {
797 0 : break; // convergence achieved
798 : }
799 : }
800 : } else {
801 0 : Length = 0.0;
802 : }
803 0 : coolBeam.BeamLength = Length;
804 0 : coolBeam.BeamLength = max(coolBeam.BeamLength, 1.0);
805 0 : BaseSizer::reportSizerOutput(state, coolBeam.UnitType, coolBeam.Name, "Beam Length [m]", coolBeam.BeamLength);
806 : } else {
807 0 : ShowSevereError(state, "Autosizing of cooled beam length requires a cooling loop Sizing:Plant object");
808 0 : ShowContinueError(state, format("Occurs in{} Object={}", coolBeam.UnitType, coolBeam.Name));
809 0 : ErrorsFound = true;
810 : }
811 : }
812 : }
813 :
814 : // save the design water volumetric flow rate for use by the water loop sizing algorithms
815 0 : if (coolBeam.MaxCoolWaterVolFlow > 0.0) {
816 0 : RegisterPlantCompDesignFlow(state, coolBeam.CWInNode, coolBeam.MaxCoolWaterVolFlow);
817 : }
818 :
819 0 : if (ErrorsFound) {
820 0 : ShowFatalError(state, "Preceding cooled beam sizing errors cause program termination");
821 : }
822 0 : }
823 :
824 0 : void ControlCoolBeam(EnergyPlusData &state,
825 : int const CBNum, // number of the current unit being simulated
826 : int const ZoneNum, // number of zone being served
827 : int const ZoneNodeNum, // zone node number
828 : [[maybe_unused]] bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
829 : Real64 &NonAirSysOutput // convective cooling by the beam system [W]
830 : )
831 : {
832 :
833 : // SUBROUTINE INFORMATION:
834 : // AUTHOR Fred Buhl
835 : // DATE WRITTEN Feb 12, 2009
836 : // MODIFIED na
837 : // RE-ENGINEERED na
838 :
839 : // PURPOSE OF THIS SUBROUTINE:
840 : // Simulate a cooled beam unit;
841 :
842 : // METHODOLOGY EMPLOYED:
843 : // (1) From the zone load and the Supply air inlet conditions calculate the beam load
844 : // (2) If there is a beam load, vary the water flow rate to match the beam load
845 :
846 : // REFERENCES:
847 : // na
848 :
849 : // Using/Aliasing
850 : using namespace DataZoneEnergyDemands;
851 : using PlantUtilities::SetComponentFlowRate;
852 :
853 : // Locals
854 : // SUBROUTINE ARGUMENT DEFINITIONS:
855 :
856 : // SUBROUTINE PARAMETER DEFINITIONS:
857 : // na
858 :
859 : // INTERFACE BLOCK SPECIFICATIONS:
860 : // na
861 :
862 : // DERIVED TYPE DEFINITIONS:
863 : // na
864 :
865 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
866 : Real64 QZnReq; // heating or cooling needed by zone [Watts]
867 : Real64 QToHeatSetPt; // [W] remaining load to heating setpoint
868 : Real64 QToCoolSetPt; // [W] remaining load to cooling setpoint
869 0 : Real64 QMin(0.0); // cooled beam output at minimum water flow [W]
870 0 : Real64 QMax(0.0); // cooled beam output at maximum water flow [W]
871 0 : Real64 QSup(0.0); // heating or cooling by supply air [W]
872 0 : Real64 PowerMet(0.0); // power supplied
873 0 : Real64 CWFlow(0.0); // cold water flow [kg/s]
874 0 : Real64 AirMassFlow(0.0); // air mass flow rate for the cooled beam system [kg/s]
875 0 : Real64 MaxColdWaterFlow(0.0); // max water mass flow rate for the cooled beam system [kg/s]
876 0 : Real64 MinColdWaterFlow(0.0); // min water mass flow rate for the cooled beam system [kg/s]
877 0 : Real64 CpAirZn(0.0); // specific heat of air at zone conditions [J/kg-C]
878 0 : Real64 CpAirSys(0.0); // specific heat of air at supply air conditions [J/kg-C]
879 0 : Real64 TWOut(0.0); // outlet water tamperature [C]
880 : int ControlNode; // the water inlet node
881 : int InAirNode; // the air inlet node
882 : bool UnitOn; // TRUE if unit is on
883 : Real64 ErrTolerance;
884 0 : auto &coolBeam = state.dataHVACCooledBeam->CoolBeam(CBNum);
885 :
886 0 : UnitOn = true;
887 0 : PowerMet = 0.0;
888 0 : InAirNode = coolBeam.AirInNode;
889 0 : ControlNode = coolBeam.CWInNode;
890 0 : AirMassFlow = state.dataLoopNodes->Node(InAirNode).MassFlowRateMaxAvail;
891 0 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputRequired;
892 0 : QToHeatSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP;
893 0 : QToCoolSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToCoolSP;
894 0 : CpAirZn = PsyCpAirFnW(state.dataLoopNodes->Node(ZoneNodeNum).HumRat);
895 0 : CpAirSys = PsyCpAirFnW(state.dataLoopNodes->Node(InAirNode).HumRat);
896 0 : MaxColdWaterFlow = coolBeam.MaxCoolWaterMassFlow;
897 0 : SetComponentFlowRate(state, MaxColdWaterFlow, coolBeam.CWInNode, coolBeam.CWOutNode, coolBeam.CWPlantLoc);
898 0 : MinColdWaterFlow = 0.0;
899 0 : SetComponentFlowRate(state, MinColdWaterFlow, coolBeam.CWInNode, coolBeam.CWOutNode, coolBeam.CWPlantLoc);
900 :
901 0 : if (coolBeam.availSched->getCurrentVal() <= 0.0) UnitOn = false;
902 0 : if (MaxColdWaterFlow <= SmallMassFlow) UnitOn = false;
903 :
904 : // Set the unit's air inlet nodes mass flow rates
905 0 : state.dataLoopNodes->Node(InAirNode).MassFlowRate = AirMassFlow;
906 : // set the air volumetric flow rate per beam
907 0 : coolBeam.BeamFlow = state.dataLoopNodes->Node(InAirNode).MassFlowRate / (state.dataEnvrn->StdRhoAir * coolBeam.NumBeams);
908 : // fire the unit at min water flow
909 0 : CalcCoolBeam(state, CBNum, ZoneNodeNum, MinColdWaterFlow, QMin, TWOut);
910 : // cooling by supply air
911 0 : QSup = AirMassFlow * (CpAirSys * state.dataLoopNodes->Node(InAirNode).Temp - CpAirZn * state.dataLoopNodes->Node(ZoneNodeNum).Temp);
912 : // load on the beams is QToCoolSetPt-QSup
913 0 : if (UnitOn) {
914 0 : if ((QToCoolSetPt - QSup) < -SmallLoad) {
915 : // There is a cooling demand on the cooled beam system.
916 : // First, see if the system can meet the load
917 0 : CalcCoolBeam(state, CBNum, ZoneNodeNum, MaxColdWaterFlow, QMax, TWOut);
918 0 : if ((QMax < QToCoolSetPt - QSup - SmallLoad) && (QMax != QMin)) {
919 : // The cooled beam system can meet the demand.
920 : // Set up the iterative calculation of chilled water flow rate
921 0 : ErrTolerance = 0.01;
922 0 : auto f = [&state, CBNum, ZoneNodeNum, QToCoolSetPt, QSup, QMin, QMax](Real64 const CWFlow) {
923 0 : Real64 const par3 = QToCoolSetPt - QSup;
924 0 : Real64 UnitOutput(0.0);
925 0 : Real64 TWOut(0.0);
926 0 : CalcCoolBeam(state, CBNum, ZoneNodeNum, CWFlow, UnitOutput, TWOut);
927 0 : return (par3 - UnitOutput) / (QMax - QMin);
928 0 : };
929 0 : int SolFlag = 0;
930 0 : General::SolveRoot(state, ErrTolerance, 50, SolFlag, CWFlow, f, MinColdWaterFlow, MaxColdWaterFlow);
931 0 : if (SolFlag == -1) {
932 0 : ShowWarningError(state, format("Cold water control failed in cooled beam unit {}", coolBeam.Name));
933 0 : ShowContinueError(state, " Iteration limit exceeded in calculating cold water mass flow rate");
934 0 : } else if (SolFlag == -2) {
935 0 : ShowWarningError(state, format("Cold water control failed in cooled beam unit {}", coolBeam.Name));
936 0 : ShowContinueError(state, " Bad cold water flow limits");
937 : }
938 0 : } else {
939 : // unit maxed out
940 0 : CWFlow = MaxColdWaterFlow;
941 : }
942 : } else {
943 : // unit has no load
944 0 : CWFlow = MinColdWaterFlow;
945 : }
946 : } else {
947 : // unit Off
948 0 : CWFlow = MinColdWaterFlow;
949 : }
950 : // Get the cooling output at the chosen water flow rate
951 0 : CalcCoolBeam(state, CBNum, ZoneNodeNum, CWFlow, PowerMet, TWOut);
952 0 : coolBeam.BeamCoolingRate = -PowerMet;
953 0 : if (QSup < 0.0) {
954 0 : coolBeam.SupAirCoolingRate = std::abs(QSup);
955 : } else {
956 0 : coolBeam.SupAirHeatingRate = QSup;
957 : }
958 0 : coolBeam.CoolWaterMassFlow = state.dataLoopNodes->Node(ControlNode).MassFlowRate;
959 0 : coolBeam.TWOut = TWOut;
960 0 : coolBeam.EnthWaterOut = state.dataLoopNodes->Node(ControlNode).Enthalpy + coolBeam.BeamCoolingRate;
961 : // Node(ControlNode)%MassFlowRate = CWFlow
962 0 : NonAirSysOutput = PowerMet;
963 0 : }
964 :
965 0 : void CalcCoolBeam(EnergyPlusData &state,
966 : int const CBNum, // Unit index
967 : int const ZoneNode, // zone node number
968 : Real64 const CWFlow, // cold water flow [kg/s]
969 : Real64 &LoadMet, // load met by unit [W]
970 : Real64 &TWOut // chilled water outlet temperature [C]
971 : )
972 : {
973 :
974 : // SUBROUTINE INFORMATION:
975 : // AUTHOR Fred Buhl
976 : // DATE WRITTEN Feb 2009
977 : // MODIFIED na
978 : // RE-ENGINEERED na
979 :
980 : // PURPOSE OF THIS SUBROUTINE:
981 : // Simulate a cooled beam given the chilled water flow rate
982 :
983 : // METHODOLOGY EMPLOYED:
984 : // Uses the cooled beam equations; iteratively varies water outlet temperature
985 : // until air-side and water-side cooling outputs match.
986 :
987 : // REFERENCES:
988 : // na
989 :
990 : // Using/Aliasing
991 : using PlantUtilities::SetComponentFlowRate;
992 :
993 : // Locals
994 : // SUBROUTINE ARGUMENT DEFINITIONS:
995 :
996 : // SUBROUTINE PARAMETER DEFINITIONS:
997 : static constexpr std::string_view RoutineName("CalcCoolBeam");
998 :
999 : // INTERFACE BLOCK SPECIFICATIONS
1000 : // na
1001 :
1002 : // DERIVED TYPE DEFINITIONS
1003 : // na
1004 :
1005 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1006 0 : int Iter(0); // TWOut iteration index
1007 0 : Real64 TWIn(0.0); // Inlet water temperature [C]
1008 0 : Real64 ZTemp(0.0); // zone air temperature [C]
1009 0 : Real64 WaterCoolPower(0.0); // cooling power from water side [W]
1010 0 : Real64 DT(0.0); // approximate air - water delta T [C]
1011 0 : Real64 IndFlow(0.0); // induced air flow rate per beam length [m3/s-m]
1012 0 : Real64 CoilFlow(0.0); // mass air flow rate of air passing through "coil" [kg/m2-s]
1013 0 : Real64 WaterVel(0.0); // water velocity [m/s]
1014 0 : Real64 K(0.0); // coil heat transfer coefficient [W/m2-K]
1015 0 : Real64 AirCoolPower(0.0); // cooling power from the air side [W]
1016 : Real64 Diff; // difference between water side cooling power and air side cooling power [W]
1017 0 : Real64 CWFlowPerBeam(0.0); // water mass flow rate per beam
1018 0 : Real64 Coeff(0.0); // iteration parameter
1019 0 : Real64 Delta(0.0);
1020 0 : Real64 mdot(0.0);
1021 : Real64 Cp; // local fluid specific heat
1022 : Real64 rho; // local fluid density
1023 :
1024 : // test CWFlow against plant
1025 0 : mdot = CWFlow;
1026 0 : auto const &coolBeam = state.dataHVACCooledBeam->CoolBeam(CBNum);
1027 :
1028 0 : SetComponentFlowRate(state, mdot, coolBeam.CWInNode, coolBeam.CWOutNode, coolBeam.CWPlantLoc);
1029 :
1030 0 : CWFlowPerBeam = mdot / coolBeam.NumBeams;
1031 0 : TWIn = coolBeam.TWIn;
1032 :
1033 0 : Cp = state.dataPlnt->PlantLoop(coolBeam.CWPlantLoc.loopNum).glycol->getSpecificHeat(state, TWIn, RoutineName);
1034 :
1035 0 : rho = state.dataPlnt->PlantLoop(coolBeam.CWPlantLoc.loopNum).glycol->getDensity(state, TWIn, RoutineName);
1036 :
1037 0 : TWOut = TWIn + 2.0;
1038 0 : ZTemp = state.dataLoopNodes->Node(ZoneNode).Temp;
1039 0 : if (mdot <= 0.0 || TWIn <= 0.0) {
1040 0 : LoadMet = 0.0;
1041 0 : TWOut = TWIn;
1042 0 : return;
1043 : }
1044 0 : for (Iter = 1; Iter <= 200; ++Iter) {
1045 0 : if (Iter > 50 && Iter < 100) {
1046 0 : Coeff = 0.1 * Coeff2;
1047 0 : } else if (Iter > 100) {
1048 0 : Coeff = 0.01 * Coeff2;
1049 : } else {
1050 0 : Coeff = Coeff2;
1051 : }
1052 :
1053 0 : WaterCoolPower = CWFlowPerBeam * Cp * (TWOut - TWIn);
1054 0 : DT = max(ZTemp - 0.5 * (TWIn + TWOut), 0.0);
1055 0 : IndFlow = coolBeam.K1 * std::pow(DT, coolBeam.n) + coolBeam.Kin * coolBeam.BeamFlow / coolBeam.BeamLength;
1056 0 : CoilFlow = (IndFlow / coolBeam.a0) * state.dataEnvrn->StdRhoAir;
1057 0 : WaterVel = CWFlowPerBeam / (rho * Constant::Pi * pow_2(coolBeam.InDiam) / 4.0);
1058 0 : if (WaterVel > MinWaterVel) {
1059 0 : K = coolBeam.a * std::pow(DT, coolBeam.n1) * std::pow(CoilFlow, coolBeam.n2) * std::pow(WaterVel, coolBeam.n3);
1060 : } else {
1061 0 : K = coolBeam.a * std::pow(DT, coolBeam.n1) * std::pow(CoilFlow, coolBeam.n2) * std::pow(MinWaterVel, coolBeam.n3) *
1062 0 : (WaterVel / MinWaterVel);
1063 : }
1064 0 : AirCoolPower = K * coolBeam.CoilArea * DT * coolBeam.BeamLength;
1065 0 : Diff = WaterCoolPower - AirCoolPower;
1066 0 : Delta = TWOut * (std::abs(Diff) / Coeff);
1067 0 : if (std::abs(Diff) > 0.1) {
1068 0 : if (Diff < 0.0) {
1069 0 : TWOut += Delta; // increase TWout
1070 0 : if (TWOut > ZTemp) { // check that water outlet temperature is less than zone temperature
1071 0 : WaterCoolPower = 0.0;
1072 0 : TWOut = ZTemp;
1073 0 : break;
1074 : }
1075 : } else {
1076 0 : TWOut -= Delta; // Decrease TWout
1077 0 : if (TWOut < TWIn) {
1078 0 : TWOut = TWIn;
1079 : }
1080 : }
1081 : } else {
1082 : // water and air side outputs have converged
1083 0 : break;
1084 : }
1085 : }
1086 0 : LoadMet = -WaterCoolPower * coolBeam.NumBeams;
1087 : }
1088 :
1089 0 : void UpdateCoolBeam(EnergyPlusData &state, int const CBNum)
1090 : {
1091 :
1092 : // SUBROUTINE INFORMATION:
1093 : // AUTHOR Fred Buhl
1094 : // DATE WRITTEN Feb 2009
1095 : // MODIFIED na
1096 : // RE-ENGINEERED na
1097 :
1098 : // PURPOSE OF THIS SUBROUTINE:
1099 : // This subroutine updates the cooled beam unit outlet nodes
1100 :
1101 : // METHODOLOGY EMPLOYED:
1102 : // Data is moved from the cooled beam unit data structure to the unit outlet nodes.
1103 :
1104 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1105 0 : auto &coolBeam = state.dataHVACCooledBeam->CoolBeam(CBNum);
1106 0 : auto const &airInletNode = state.dataLoopNodes->Node(coolBeam.AirInNode);
1107 0 : auto &airOutletNode = state.dataLoopNodes->Node(coolBeam.AirOutNode);
1108 :
1109 : // Set the outlet air nodes of the unit; note that all quantities are unchanged
1110 0 : airOutletNode.MassFlowRate = airInletNode.MassFlowRate;
1111 0 : airOutletNode.Temp = airInletNode.Temp;
1112 0 : airOutletNode.HumRat = airInletNode.HumRat;
1113 0 : airOutletNode.Enthalpy = airInletNode.Enthalpy;
1114 :
1115 : // Set the outlet water nodes for the unit
1116 0 : PlantUtilities::SafeCopyPlantNode(state, coolBeam.CWInNode, coolBeam.CWOutNode);
1117 :
1118 0 : state.dataLoopNodes->Node(coolBeam.CWOutNode).Temp = coolBeam.TWOut;
1119 0 : state.dataLoopNodes->Node(coolBeam.CWOutNode).Enthalpy = coolBeam.EnthWaterOut;
1120 :
1121 : // Set the air outlet nodes for properties that just pass through & not used
1122 0 : airOutletNode.Quality = airInletNode.Quality;
1123 0 : airOutletNode.Press = airInletNode.Press;
1124 0 : airOutletNode.MassFlowRateMin = airInletNode.MassFlowRateMin;
1125 0 : airOutletNode.MassFlowRateMax = airInletNode.MassFlowRateMax;
1126 0 : airOutletNode.MassFlowRateMinAvail = airInletNode.MassFlowRateMinAvail;
1127 0 : airOutletNode.MassFlowRateMaxAvail = airInletNode.MassFlowRateMaxAvail;
1128 :
1129 0 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1130 0 : airOutletNode.CO2 = airInletNode.CO2;
1131 : }
1132 :
1133 0 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1134 0 : airOutletNode.GenContam = airInletNode.GenContam;
1135 : }
1136 0 : }
1137 :
1138 0 : void ReportCoolBeam(EnergyPlusData &state, int const CBNum)
1139 : {
1140 :
1141 : // SUBROUTINE INFORMATION:
1142 : // AUTHOR Fred Buhl
1143 : // DATE WRITTEN Feb 2009
1144 : // MODIFIED na
1145 : // RE-ENGINEERED na
1146 :
1147 : // PURPOSE OF THIS SUBROUTINE:
1148 : // This subroutine updates the report variable for the cooled beam units
1149 :
1150 : // METHODOLOGY EMPLOYED:
1151 : // NA
1152 :
1153 : // REFERENCES:
1154 : // na
1155 :
1156 : // USE STATEMENTS:
1157 :
1158 : // Locals
1159 : // SUBROUTINE ARGUMENT DEFINITIONS:
1160 :
1161 : // SUBROUTINE PARAMETER DEFINITIONS:
1162 : // na
1163 :
1164 : // INTERFACE BLOCK SPECIFICATIONS
1165 : // na
1166 :
1167 : // DERIVED TYPE DEFINITIONS
1168 : // na
1169 :
1170 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1171 :
1172 : Real64 ReportingConstant;
1173 0 : auto &coolBeam = state.dataHVACCooledBeam->CoolBeam(CBNum);
1174 :
1175 0 : ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
1176 : // report the WaterCoil energy from this component
1177 0 : coolBeam.BeamCoolingEnergy = coolBeam.BeamCoolingRate * ReportingConstant;
1178 0 : coolBeam.SupAirCoolingEnergy = coolBeam.SupAirCoolingRate * ReportingConstant;
1179 0 : coolBeam.SupAirHeatingEnergy = coolBeam.SupAirHeatingRate * ReportingConstant;
1180 :
1181 : // set zone OA volume flow rate report variable
1182 0 : coolBeam.CalcOutdoorAirVolumeFlowRate(state);
1183 0 : }
1184 :
1185 0 : void CoolBeamData::CalcOutdoorAirVolumeFlowRate(EnergyPlusData &state)
1186 : {
1187 : // calculates zone outdoor air volume flow rate using the supply air flow rate and OA fraction
1188 0 : if (this->AirLoopNum > 0) {
1189 0 : this->OutdoorAirFlowRate = (state.dataLoopNodes->Node(this->AirOutNode).MassFlowRate / state.dataEnvrn->StdRhoAir) *
1190 0 : state.dataAirLoop->AirLoopFlow(this->AirLoopNum).OAFrac;
1191 : } else {
1192 0 : this->OutdoorAirFlowRate = 0.0;
1193 : }
1194 0 : }
1195 :
1196 1 : void CoolBeamData::reportTerminalUnit(EnergyPlusData &state)
1197 : {
1198 : // populate the predefined equipment summary report related to air terminals
1199 1 : auto &orp = state.dataOutRptPredefined;
1200 1 : auto &adu = state.dataDefineEquipment->AirDistUnit(this->ADUNum);
1201 1 : if (!state.dataSize->TermUnitFinalZoneSizing.empty()) {
1202 1 : auto &sizing = state.dataSize->TermUnitFinalZoneSizing(adu.TermUnitSizingNum);
1203 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinFlow, adu.Name, sizing.DesCoolVolFlowMin);
1204 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinOutdoorFlow, adu.Name, sizing.MinOA);
1205 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSupCoolingSP, adu.Name, sizing.CoolDesTemp);
1206 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSupHeatingSP, adu.Name, sizing.HeatDesTemp);
1207 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermHeatingCap, adu.Name, sizing.DesHeatLoad);
1208 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermCoolingCap, adu.Name, sizing.DesCoolLoad);
1209 : }
1210 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermTypeInp, adu.Name, this->UnitType);
1211 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermPrimFlow, adu.Name, this->MaxAirVolFlow);
1212 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSecdFlow, adu.Name, "n/a");
1213 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinFlowSch, adu.Name, "n/a");
1214 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMaxFlowReh, adu.Name, "n/a");
1215 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinOAflowSch, adu.Name, "n/a");
1216 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermHeatCoilType, adu.Name, "n/a");
1217 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermCoolCoilType, adu.Name, this->CBTypeString);
1218 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermFanType, adu.Name, "n/a");
1219 1 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermFanName, adu.Name, "n/a");
1220 1 : }
1221 :
1222 : } // namespace HVACCooledBeam
1223 :
1224 : } // namespace EnergyPlus
|