Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/AirTerminalUnit.hh>
57 : #include <EnergyPlus/Autosizing/Base.hh>
58 : #include <EnergyPlus/BranchNodeConnections.hh>
59 : #include <EnergyPlus/CurveManager.hh>
60 : #include <EnergyPlus/Data/EnergyPlusData.hh>
61 : #include <EnergyPlus/DataContaminantBalance.hh>
62 : #include <EnergyPlus/DataDefineEquip.hh>
63 : #include <EnergyPlus/DataEnvironment.hh>
64 : #include <EnergyPlus/DataHVACGlobals.hh>
65 : #include <EnergyPlus/DataIPShortCuts.hh>
66 : #include <EnergyPlus/DataLoopNode.hh>
67 : #include <EnergyPlus/DataSizing.hh>
68 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
69 : #include <EnergyPlus/DataZoneEquipment.hh>
70 : #include <EnergyPlus/FluidProperties.hh>
71 : #include <EnergyPlus/General.hh>
72 : #include <EnergyPlus/GeneralRoutines.hh>
73 : #include <EnergyPlus/HVACFourPipeBeam.hh>
74 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
75 : #include <EnergyPlus/NodeInputManager.hh>
76 : #include <EnergyPlus/OutputProcessor.hh>
77 : #include <EnergyPlus/OutputReportPredefined.hh>
78 : #include <EnergyPlus/Plant/DataPlant.hh>
79 : #include <EnergyPlus/PlantUtilities.hh>
80 : #include <EnergyPlus/Psychrometrics.hh>
81 : #include <EnergyPlus/ScheduleManager.hh>
82 : #include <EnergyPlus/UtilityRoutines.hh>
83 :
84 : namespace EnergyPlus {
85 :
86 : namespace FourPipeBeam {
87 :
88 : // HVACFourPipeBeam::HVACFourPipeBeam(){}
89 : ///// Note use of shared_ptr here is not a good pattern, not to be replicated without further discussion.
90 30 : std::shared_ptr<AirTerminalUnit> HVACFourPipeBeam::fourPipeBeamFactory(EnergyPlusData &state, std::string objectName)
91 : {
92 :
93 : using BranchNodeConnections::TestCompSet;
94 : using DataLoopNode::ObjectIsNotParent;
95 : using DataLoopNode::ObjectIsParent;
96 : using NodeInputManager::GetOnlySingleNode;
97 : using namespace DataSizing;
98 : using Curve::GetCurveIndex;
99 : using ScheduleManager::GetScheduleIndex;
100 : static constexpr std::string_view routineName("FourPipeBeamFactory "); // include trailing blank space
101 :
102 : int beamIndex; // loop index
103 :
104 : // certain object in the input file
105 30 : bool errFlag = false;
106 30 : bool ErrorsFound(false); // Set to true if errors in input, fatal at end of routine
107 30 : bool found = false;
108 : bool airNodeFound;
109 : int aDUIndex;
110 :
111 : ///// Note use of shared_ptr here is not a good pattern, not to be replicated without further discussion.
112 30 : std::shared_ptr<HVACFourPipeBeam> thisBeam(new HVACFourPipeBeam());
113 30 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
114 : // find the number of cooled beam units
115 30 : cCurrentModuleObject = "AirTerminal:SingleDuct:ConstantVolume:FourPipeBeam";
116 :
117 : // find beam index from name
118 30 : beamIndex = state.dataInputProcessing->inputProcessor->getObjectItemNum(state, cCurrentModuleObject, objectName);
119 30 : if (beamIndex > 0) {
120 : int IOStatus;
121 30 : int NumAlphas = 16;
122 30 : int NumNumbers = 11;
123 60 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
124 : cCurrentModuleObject,
125 : beamIndex,
126 30 : state.dataIPShortCut->cAlphaArgs,
127 : NumAlphas,
128 30 : state.dataIPShortCut->rNumericArgs,
129 : NumNumbers,
130 : IOStatus,
131 30 : state.dataIPShortCut->lNumericFieldBlanks,
132 30 : state.dataIPShortCut->lAlphaFieldBlanks,
133 30 : state.dataIPShortCut->cAlphaFieldNames,
134 30 : state.dataIPShortCut->cNumericFieldNames);
135 30 : found = true;
136 : } else {
137 0 : ErrorsFound = true;
138 : }
139 :
140 30 : errFlag = false;
141 30 : GlobalNames::VerifyUniqueADUName(state, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1), errFlag, cCurrentModuleObject + " Name");
142 30 : if (errFlag) {
143 0 : ErrorsFound = true;
144 : }
145 30 : thisBeam->name = state.dataIPShortCut->cAlphaArgs(1);
146 30 : thisBeam->unitType = cCurrentModuleObject;
147 :
148 30 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
149 0 : thisBeam->airAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
150 : } else {
151 30 : thisBeam->airAvailSchedNum = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2)); // convert schedule name to pointer
152 30 : if (thisBeam->airAvailSchedNum == 0) {
153 0 : ShowSevereError(state,
154 0 : format("{}{}: invalid {} entered ={} for {}={}",
155 : routineName,
156 : cCurrentModuleObject,
157 0 : state.dataIPShortCut->cAlphaFieldNames(2),
158 0 : state.dataIPShortCut->cAlphaArgs(2),
159 0 : state.dataIPShortCut->cAlphaFieldNames(1),
160 0 : state.dataIPShortCut->cAlphaArgs(1)));
161 0 : ErrorsFound = true;
162 : }
163 : }
164 30 : if (state.dataIPShortCut->lAlphaFieldBlanks(3)) {
165 0 : thisBeam->coolingAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
166 : } else {
167 30 : thisBeam->coolingAvailSchedNum = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(3)); // convert schedule name to index
168 30 : if (thisBeam->coolingAvailSchedNum == 0) {
169 0 : ShowSevereError(state,
170 0 : format("{}{}: invalid {} entered ={} for {}={}",
171 : routineName,
172 : cCurrentModuleObject,
173 0 : state.dataIPShortCut->cAlphaFieldNames(3),
174 0 : state.dataIPShortCut->cAlphaArgs(3),
175 0 : state.dataIPShortCut->cAlphaFieldNames(1),
176 0 : state.dataIPShortCut->cAlphaArgs(1)));
177 0 : ErrorsFound = true;
178 : }
179 : }
180 30 : if (state.dataIPShortCut->lAlphaFieldBlanks(4)) {
181 0 : thisBeam->heatingAvailSchedNum = ScheduleManager::ScheduleAlwaysOn;
182 : } else {
183 30 : thisBeam->heatingAvailSchedNum = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(4)); // convert schedule name to index
184 30 : if (thisBeam->heatingAvailSchedNum == 0) {
185 0 : ShowSevereError(state,
186 0 : format("{}{}: invalid {} entered ={} for {}={}",
187 : routineName,
188 : cCurrentModuleObject,
189 0 : state.dataIPShortCut->cAlphaFieldNames(4),
190 0 : state.dataIPShortCut->cAlphaArgs(4),
191 0 : state.dataIPShortCut->cAlphaFieldNames(1),
192 0 : state.dataIPShortCut->cAlphaArgs(1)));
193 0 : ErrorsFound = true;
194 : }
195 : }
196 :
197 30 : thisBeam->airInNodeNum = GetOnlySingleNode(state,
198 30 : state.dataIPShortCut->cAlphaArgs(5),
199 : ErrorsFound,
200 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeFourPipeBeam,
201 30 : state.dataIPShortCut->cAlphaArgs(1),
202 : DataLoopNode::NodeFluidType::Air,
203 : DataLoopNode::ConnectionType::Inlet,
204 : NodeInputManager::CompFluidStream::Primary,
205 : ObjectIsNotParent,
206 30 : state.dataIPShortCut->cAlphaFieldNames(5));
207 30 : thisBeam->airOutNodeNum = GetOnlySingleNode(state,
208 30 : state.dataIPShortCut->cAlphaArgs(6),
209 : ErrorsFound,
210 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeFourPipeBeam,
211 30 : state.dataIPShortCut->cAlphaArgs(1),
212 : DataLoopNode::NodeFluidType::Air,
213 : DataLoopNode::ConnectionType::Outlet,
214 : NodeInputManager::CompFluidStream::Primary,
215 : ObjectIsNotParent,
216 30 : state.dataIPShortCut->cAlphaFieldNames(6));
217 30 : if (state.dataIPShortCut->lAlphaFieldBlanks(7) && state.dataIPShortCut->lAlphaFieldBlanks(8)) { // no chilled water nodes, no beam cooling
218 0 : thisBeam->beamCoolingPresent = false;
219 30 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(7) &&
220 0 : !state.dataIPShortCut->lAlphaFieldBlanks(8)) { // outlet node but no inlet node for chilled water
221 0 : thisBeam->beamCoolingPresent = false;
222 0 : ShowWarningError(state,
223 0 : format("{}{}: missing {} for {}={}, simulation continues with no beam cooling",
224 : routineName,
225 : cCurrentModuleObject,
226 0 : state.dataIPShortCut->cAlphaFieldNames(7),
227 0 : state.dataIPShortCut->cAlphaFieldNames(1),
228 0 : state.dataIPShortCut->cAlphaArgs(1)));
229 60 : } else if (!state.dataIPShortCut->lAlphaFieldBlanks(7) &&
230 30 : state.dataIPShortCut->lAlphaFieldBlanks(8)) { // inlet node but no outlet node for chilled water
231 0 : thisBeam->beamCoolingPresent = false;
232 0 : ShowWarningError(state,
233 0 : format("{}{}: missing {} for {}={}, simulation continues with no beam cooling",
234 : routineName,
235 : cCurrentModuleObject,
236 0 : state.dataIPShortCut->cAlphaFieldNames(8),
237 0 : state.dataIPShortCut->cAlphaFieldNames(1),
238 0 : state.dataIPShortCut->cAlphaArgs(1)));
239 : } else {
240 30 : thisBeam->beamCoolingPresent = true;
241 30 : thisBeam->cWInNodeNum = GetOnlySingleNode(state,
242 30 : state.dataIPShortCut->cAlphaArgs(7),
243 : ErrorsFound,
244 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeFourPipeBeam,
245 30 : state.dataIPShortCut->cAlphaArgs(1),
246 : DataLoopNode::NodeFluidType::Water,
247 : DataLoopNode::ConnectionType::Inlet,
248 : NodeInputManager::CompFluidStream::Secondary,
249 : ObjectIsParent,
250 30 : state.dataIPShortCut->cAlphaFieldNames(7));
251 30 : thisBeam->cWOutNodeNum = GetOnlySingleNode(state,
252 30 : state.dataIPShortCut->cAlphaArgs(8),
253 : ErrorsFound,
254 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeFourPipeBeam,
255 30 : state.dataIPShortCut->cAlphaArgs(1),
256 : DataLoopNode::NodeFluidType::Water,
257 : DataLoopNode::ConnectionType::Outlet,
258 : NodeInputManager::CompFluidStream::Secondary,
259 : ObjectIsParent,
260 30 : state.dataIPShortCut->cAlphaFieldNames(8));
261 : }
262 30 : if (state.dataIPShortCut->lAlphaFieldBlanks(9) && state.dataIPShortCut->lAlphaFieldBlanks(10)) { // no hot water nodes, no beam heating
263 0 : thisBeam->beamHeatingPresent = false;
264 30 : } else if (state.dataIPShortCut->lAlphaFieldBlanks(9) &&
265 0 : !state.dataIPShortCut->lAlphaFieldBlanks(10)) { // outlet node but no inlet node for hot water
266 0 : thisBeam->beamHeatingPresent = false;
267 0 : ShowWarningError(state,
268 0 : format("{}{}: missing {} for {}={}, simulation continues with no beam heating",
269 : routineName,
270 : cCurrentModuleObject,
271 0 : state.dataIPShortCut->cAlphaFieldNames(9),
272 0 : state.dataIPShortCut->cAlphaFieldNames(1),
273 0 : state.dataIPShortCut->cAlphaArgs(1)));
274 60 : } else if (!state.dataIPShortCut->lAlphaFieldBlanks(9) &&
275 30 : state.dataIPShortCut->lAlphaFieldBlanks(10)) { // inlet node but no outlet node for hot water
276 0 : thisBeam->beamHeatingPresent = false;
277 0 : ShowWarningError(state,
278 0 : format("{}{}: missing {} for {}={}, simulation continues with no beam heating",
279 : routineName,
280 : cCurrentModuleObject,
281 0 : state.dataIPShortCut->cAlphaFieldNames(10),
282 0 : state.dataIPShortCut->cAlphaFieldNames(1),
283 0 : state.dataIPShortCut->cAlphaArgs(1)));
284 : } else {
285 30 : thisBeam->beamHeatingPresent = true;
286 30 : thisBeam->hWInNodeNum = GetOnlySingleNode(state,
287 30 : state.dataIPShortCut->cAlphaArgs(9),
288 : ErrorsFound,
289 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeFourPipeBeam,
290 30 : state.dataIPShortCut->cAlphaArgs(1),
291 : DataLoopNode::NodeFluidType::Water,
292 : DataLoopNode::ConnectionType::Inlet,
293 : NodeInputManager::CompFluidStream::Secondary,
294 : ObjectIsParent,
295 30 : state.dataIPShortCut->cAlphaFieldNames(9));
296 30 : thisBeam->hWOutNodeNum = GetOnlySingleNode(state,
297 30 : state.dataIPShortCut->cAlphaArgs(10),
298 : ErrorsFound,
299 : DataLoopNode::ConnectionObjectType::AirTerminalSingleDuctConstantVolumeFourPipeBeam,
300 30 : state.dataIPShortCut->cAlphaArgs(1),
301 : DataLoopNode::NodeFluidType::Water,
302 : DataLoopNode::ConnectionType::Outlet,
303 : NodeInputManager::CompFluidStream::Secondary,
304 : ObjectIsParent,
305 30 : state.dataIPShortCut->cAlphaFieldNames(10));
306 : }
307 30 : thisBeam->vDotDesignPrimAir = state.dataIPShortCut->rNumericArgs(1);
308 30 : if (thisBeam->vDotDesignPrimAir == AutoSize) {
309 30 : thisBeam->vDotDesignPrimAirWasAutosized = true;
310 : }
311 30 : thisBeam->vDotDesignCW = state.dataIPShortCut->rNumericArgs(2);
312 30 : if (thisBeam->vDotDesignCW == AutoSize && thisBeam->beamCoolingPresent) {
313 30 : thisBeam->vDotDesignCWWasAutosized = true;
314 : }
315 30 : thisBeam->vDotDesignHW = state.dataIPShortCut->rNumericArgs(3);
316 30 : if (thisBeam->vDotDesignHW == AutoSize && thisBeam->beamHeatingPresent) {
317 30 : thisBeam->vDotDesignHWWasAutosized = true;
318 : }
319 30 : thisBeam->totBeamLength = state.dataIPShortCut->rNumericArgs(4);
320 30 : if (thisBeam->totBeamLength == AutoSize) {
321 30 : thisBeam->totBeamLengthWasAutosized = true;
322 : }
323 30 : thisBeam->vDotNormRatedPrimAir = state.dataIPShortCut->rNumericArgs(5);
324 30 : thisBeam->qDotNormRatedCooling = state.dataIPShortCut->rNumericArgs(6);
325 30 : thisBeam->deltaTempRatedCooling = state.dataIPShortCut->rNumericArgs(7);
326 30 : thisBeam->vDotNormRatedCW = state.dataIPShortCut->rNumericArgs(8);
327 :
328 30 : thisBeam->modCoolingQdotDeltaTFuncNum = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(11));
329 30 : if (thisBeam->modCoolingQdotDeltaTFuncNum == 0 && thisBeam->beamCoolingPresent) {
330 0 : ShowSevereError(state, format("{}{}=\"{}\"", routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
331 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(11), state.dataIPShortCut->cAlphaArgs(11)));
332 0 : ErrorsFound = true;
333 : }
334 30 : thisBeam->modCoolingQdotAirFlowFuncNum = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(12));
335 30 : if (thisBeam->modCoolingQdotAirFlowFuncNum == 0 && thisBeam->beamCoolingPresent) {
336 0 : ShowSevereError(state, format("{}{}=\"{}\"", routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
337 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(12), state.dataIPShortCut->cAlphaArgs(12)));
338 0 : ErrorsFound = true;
339 : }
340 30 : thisBeam->modCoolingQdotCWFlowFuncNum = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(13));
341 30 : if (thisBeam->modCoolingQdotCWFlowFuncNum == 0 && thisBeam->beamCoolingPresent) {
342 0 : ShowSevereError(state, format("{}{}=\"{}\"", routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
343 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(13), state.dataIPShortCut->cAlphaArgs(13)));
344 0 : ErrorsFound = true;
345 : }
346 30 : thisBeam->qDotNormRatedHeating = state.dataIPShortCut->rNumericArgs(9);
347 30 : thisBeam->deltaTempRatedHeating = state.dataIPShortCut->rNumericArgs(10);
348 30 : thisBeam->vDotNormRatedHW = state.dataIPShortCut->rNumericArgs(11);
349 30 : thisBeam->modHeatingQdotDeltaTFuncNum = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(14));
350 30 : if (thisBeam->modHeatingQdotDeltaTFuncNum == 0 && thisBeam->beamHeatingPresent) {
351 0 : ShowSevereError(state, format("{}{}=\"{}\"", routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
352 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(14), state.dataIPShortCut->cAlphaArgs(14)));
353 0 : ErrorsFound = true;
354 : }
355 30 : thisBeam->modHeatingQdotAirFlowFuncNum = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(15));
356 30 : if (thisBeam->modHeatingQdotAirFlowFuncNum == 0 && thisBeam->beamHeatingPresent) {
357 0 : ShowSevereError(state, format("{}{}=\"{}\"", routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
358 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(15), state.dataIPShortCut->cAlphaArgs(15)));
359 0 : ErrorsFound = true;
360 : }
361 30 : thisBeam->modHeatingQdotHWFlowFuncNum = GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(16));
362 30 : if (thisBeam->modHeatingQdotHWFlowFuncNum == 0 && thisBeam->beamHeatingPresent) {
363 0 : ShowSevereError(state, format("{}{}=\"{}\"", routineName, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
364 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(16), state.dataIPShortCut->cAlphaArgs(16)));
365 0 : ErrorsFound = true;
366 : }
367 : // Register component set data
368 60 : TestCompSet(state,
369 : cCurrentModuleObject,
370 30 : thisBeam->name,
371 30 : state.dataLoopNodes->NodeID(thisBeam->airInNodeNum),
372 30 : state.dataLoopNodes->NodeID(thisBeam->airOutNodeNum),
373 : "Air Nodes");
374 30 : if (thisBeam->beamCoolingPresent) {
375 60 : TestCompSet(state,
376 : cCurrentModuleObject,
377 30 : thisBeam->name,
378 30 : state.dataLoopNodes->NodeID(thisBeam->cWInNodeNum),
379 30 : state.dataLoopNodes->NodeID(thisBeam->cWOutNodeNum),
380 : "Chilled Water Nodes");
381 : }
382 30 : if (thisBeam->beamHeatingPresent) {
383 60 : TestCompSet(state,
384 : cCurrentModuleObject,
385 30 : thisBeam->name,
386 30 : state.dataLoopNodes->NodeID(thisBeam->hWInNodeNum),
387 30 : state.dataLoopNodes->NodeID(thisBeam->hWOutNodeNum),
388 : "Hot Water Nodes");
389 : }
390 :
391 : // Setup the Cooled Beam reporting variables
392 30 : if (thisBeam->beamCoolingPresent) {
393 60 : SetupOutputVariable(state,
394 : "Zone Air Terminal Beam Sensible Cooling Energy",
395 : Constant::Units::J,
396 30 : thisBeam->beamCoolingEnergy,
397 : OutputProcessor::TimeStepType::System,
398 : OutputProcessor::StoreType::Sum,
399 30 : thisBeam->name,
400 : Constant::eResource::EnergyTransfer,
401 : OutputProcessor::Group::HVAC,
402 : OutputProcessor::EndUseCat::CoolingCoils);
403 60 : SetupOutputVariable(state,
404 : "Zone Air Terminal Beam Sensible Cooling Rate",
405 : Constant::Units::W,
406 30 : thisBeam->beamCoolingRate,
407 : OutputProcessor::TimeStepType::System,
408 : OutputProcessor::StoreType::Average,
409 30 : thisBeam->name);
410 : }
411 30 : if (thisBeam->beamHeatingPresent) {
412 60 : SetupOutputVariable(state,
413 : "Zone Air Terminal Beam Sensible Heating Energy",
414 : Constant::Units::J,
415 30 : thisBeam->beamHeatingEnergy,
416 : OutputProcessor::TimeStepType::System,
417 : OutputProcessor::StoreType::Sum,
418 30 : thisBeam->name,
419 : Constant::eResource::EnergyTransfer,
420 : OutputProcessor::Group::HVAC,
421 : OutputProcessor::EndUseCat::HeatingCoils);
422 60 : SetupOutputVariable(state,
423 : "Zone Air Terminal Beam Sensible Heating Rate",
424 : Constant::Units::W,
425 30 : thisBeam->beamHeatingRate,
426 : OutputProcessor::TimeStepType::System,
427 : OutputProcessor::StoreType::Average,
428 30 : thisBeam->name);
429 : }
430 60 : SetupOutputVariable(state,
431 : "Zone Air Terminal Primary Air Sensible Cooling Energy",
432 : Constant::Units::J,
433 30 : thisBeam->supAirCoolingEnergy,
434 : OutputProcessor::TimeStepType::System,
435 : OutputProcessor::StoreType::Sum,
436 30 : thisBeam->name);
437 60 : SetupOutputVariable(state,
438 : "Zone Air Terminal Primary Air Sensible Cooling Rate",
439 : Constant::Units::W,
440 30 : thisBeam->supAirCoolingRate,
441 : OutputProcessor::TimeStepType::System,
442 : OutputProcessor::StoreType::Average,
443 30 : thisBeam->name);
444 60 : SetupOutputVariable(state,
445 : "Zone Air Terminal Primary Air Sensible Heating Energy",
446 : Constant::Units::J,
447 30 : thisBeam->supAirHeatingEnergy,
448 : OutputProcessor::TimeStepType::System,
449 : OutputProcessor::StoreType::Sum,
450 30 : thisBeam->name);
451 60 : SetupOutputVariable(state,
452 : "Zone Air Terminal Primary Air Sensible Heating Rate",
453 : Constant::Units::W,
454 30 : thisBeam->supAirHeatingRate,
455 : OutputProcessor::TimeStepType::System,
456 : OutputProcessor::StoreType::Average,
457 30 : thisBeam->name);
458 60 : SetupOutputVariable(state,
459 : "Zone Air Terminal Primary Air Flow Rate",
460 : Constant::Units::m3_s,
461 30 : thisBeam->primAirFlow,
462 : OutputProcessor::TimeStepType::System,
463 : OutputProcessor::StoreType::Average,
464 30 : thisBeam->name);
465 :
466 60 : SetupOutputVariable(state,
467 : "Zone Air Terminal Outdoor Air Volume Flow Rate",
468 : Constant::Units::m3_s,
469 30 : thisBeam->OutdoorAirFlowRate,
470 : OutputProcessor::TimeStepType::System,
471 : OutputProcessor::StoreType::Average,
472 30 : thisBeam->name);
473 :
474 30 : airNodeFound = false;
475 510 : for (aDUIndex = 1; aDUIndex <= (int)state.dataDefineEquipment->AirDistUnit.size(); ++aDUIndex) {
476 480 : if (thisBeam->airOutNodeNum == state.dataDefineEquipment->AirDistUnit(aDUIndex).OutletNodeNum) {
477 30 : thisBeam->aDUNum = aDUIndex;
478 30 : state.dataDefineEquipment->AirDistUnit(aDUIndex).InletNodeNum = thisBeam->airInNodeNum;
479 : }
480 : }
481 : // assumes if there isn't one assigned, it's an error
482 30 : if (thisBeam->aDUNum == 0) {
483 0 : ShowSevereError(state,
484 0 : format("{}No matching Air Distribution Unit, for Unit = [{},{}].", routineName, cCurrentModuleObject, thisBeam->name));
485 0 : ShowContinueError(state, format("...should have outlet node={}", state.dataLoopNodes->NodeID(thisBeam->airOutNodeNum)));
486 0 : ErrorsFound = true;
487 : } else {
488 :
489 : // Fill the Zone Equipment data with the supply air inlet node number of this unit.
490 600 : for (int ctrlZone = 1; ctrlZone <= state.dataGlobal->NumOfZones; ++ctrlZone) {
491 570 : if (!state.dataZoneEquip->ZoneEquipConfig(ctrlZone).IsControlled) continue;
492 930 : for (int supAirIn = 1; supAirIn <= state.dataZoneEquip->ZoneEquipConfig(ctrlZone).NumInletNodes; ++supAirIn) {
493 480 : if (thisBeam->airOutNodeNum == state.dataZoneEquip->ZoneEquipConfig(ctrlZone).InletNode(supAirIn)) {
494 30 : thisBeam->zoneIndex = ctrlZone;
495 30 : thisBeam->zoneNodeIndex = state.dataZoneEquip->ZoneEquipConfig(ctrlZone).ZoneNode;
496 30 : thisBeam->ctrlZoneInNodeIndex = supAirIn;
497 30 : state.dataZoneEquip->ZoneEquipConfig(ctrlZone).AirDistUnitCool(supAirIn).InNode = thisBeam->airInNodeNum;
498 30 : state.dataZoneEquip->ZoneEquipConfig(ctrlZone).AirDistUnitCool(supAirIn).OutNode = thisBeam->airOutNodeNum;
499 30 : state.dataDefineEquipment->AirDistUnit(thisBeam->aDUNum).TermUnitSizingNum =
500 30 : state.dataZoneEquip->ZoneEquipConfig(ctrlZone).AirDistUnitCool(supAirIn).TermUnitSizingIndex;
501 30 : thisBeam->termUnitSizingNum = state.dataDefineEquipment->AirDistUnit(thisBeam->aDUNum).TermUnitSizingNum;
502 30 : state.dataDefineEquipment->AirDistUnit(thisBeam->aDUNum).ZoneEqNum = ctrlZone;
503 30 : if (thisBeam->beamHeatingPresent) {
504 30 : state.dataZoneEquip->ZoneEquipConfig(ctrlZone).AirDistUnitHeat(supAirIn).InNode = thisBeam->airInNodeNum;
505 30 : state.dataZoneEquip->ZoneEquipConfig(ctrlZone).AirDistUnitHeat(supAirIn).OutNode = thisBeam->airOutNodeNum;
506 : }
507 30 : airNodeFound = true;
508 30 : break;
509 : }
510 : }
511 : }
512 : }
513 30 : if (!airNodeFound) {
514 0 : ShowSevereError(state, format("The outlet air node from the {} = {}", cCurrentModuleObject, thisBeam->name));
515 0 : ShowContinueError(state, format("did not have a matching Zone Equipment Inlet Node, Node ={}", state.dataIPShortCut->cAlphaArgs(5)));
516 0 : ErrorsFound = true;
517 : }
518 :
519 30 : if (found && !ErrorsFound) {
520 30 : state.dataFourPipeBeam->FourPipeBeams.push_back(thisBeam);
521 30 : return thisBeam;
522 : } else {
523 0 : ShowFatalError(state, format("{}Errors found in getting input. Preceding conditions cause termination.", routineName));
524 0 : return nullptr;
525 : }
526 30 : }
527 :
528 120 : int HVACFourPipeBeam::getAirLoopNum()
529 : {
530 120 : return airLoopNum;
531 : }
532 :
533 0 : int HVACFourPipeBeam::getZoneIndex()
534 : {
535 0 : return zoneIndex;
536 : }
537 :
538 330 : Real64 HVACFourPipeBeam::getPrimAirDesignVolFlow()
539 : {
540 330 : return vDotDesignPrimAir;
541 : }
542 :
543 30 : int HVACFourPipeBeam::getTermUnitSizingIndex()
544 : {
545 30 : return termUnitSizingNum;
546 : }
547 :
548 428235 : void HVACFourPipeBeam::simulate(EnergyPlusData &state,
549 : bool const FirstHVACIteration, // TRUE if first HVAC iteration in time step
550 : Real64 &NonAirSysOutput // convective cooling by the beam system [W]
551 : )
552 : {
553 :
554 : // initialize the unit
555 428235 : this->init(state, FirstHVACIteration);
556 :
557 : // control and simulate the beam
558 428235 : if (!this->mySizeFlag) {
559 428205 : this->control(state, FirstHVACIteration, NonAirSysOutput);
560 :
561 : // Update the current unit's outlet nodes.
562 428205 : this->update(state);
563 :
564 : // Fill the report variables.
565 428205 : this->report(state);
566 : }
567 428235 : }
568 :
569 428235 : void HVACFourPipeBeam::init(EnergyPlusData &state,
570 : bool const FirstHVACIteration // TRUE if first air loop solution this HVAC step
571 : )
572 : {
573 :
574 : // Using
575 : using DataZoneEquipment::CheckZoneEquipmentList;
576 : using PlantUtilities::InitComponentNodes;
577 : using PlantUtilities::ScanPlantLoopsForObject;
578 : using PlantUtilities::SetComponentFlowRate;
579 : using ScheduleManager::GetCurrentScheduleValue;
580 :
581 : static constexpr std::string_view routineName("HVACFourPipeBeam::init");
582 :
583 428235 : if (this->plantLoopScanFlag && allocated(state.dataPlnt->PlantLoop)) {
584 30 : bool errFlag = false;
585 30 : if (this->beamCoolingPresent) {
586 90 : ScanPlantLoopsForObject(state,
587 : this->name,
588 : DataPlant::PlantEquipmentType::FourPipeBeamAirTerminal,
589 30 : this->cWplantLoc,
590 : errFlag,
591 : _,
592 : _,
593 : _,
594 30 : this->cWInNodeNum,
595 : _);
596 30 : if (errFlag) {
597 0 : ShowFatalError(state, format("{} Program terminated for previous conditions.", routineName));
598 : }
599 : }
600 30 : if (this->beamHeatingPresent) {
601 90 : ScanPlantLoopsForObject(state,
602 : this->name,
603 : DataPlant::PlantEquipmentType::FourPipeBeamAirTerminal,
604 30 : this->hWplantLoc,
605 : errFlag,
606 : _,
607 : _,
608 : _,
609 30 : this->hWInNodeNum,
610 : _);
611 30 : if (errFlag) {
612 0 : ShowFatalError(state, format("{} Program terminated for previous conditions.", routineName));
613 : }
614 : }
615 30 : this->plantLoopScanFlag = false;
616 : }
617 :
618 428235 : if (!this->zoneEquipmentListChecked && state.dataZoneEquip->ZoneEquipInputsFilled) {
619 : // Check to see if there is a Air Distribution Unit on the Zone Equipment List
620 30 : if (this->aDUNum != 0) {
621 30 : if (!CheckZoneEquipmentList(state, "ZONEHVAC:AIRDISTRIBUTIONUNIT", state.dataDefineEquipment->AirDistUnit(this->aDUNum).Name)) {
622 0 : ShowSevereError(state,
623 0 : format("{}: ADU=[Air Distribution Unit,{}] is not on any ZoneHVAC:EquipmentList.",
624 : routineName,
625 0 : state.dataDefineEquipment->AirDistUnit(this->aDUNum).Name));
626 0 : ShowContinueError(state, format("...Unit=[{},{}] will not be simulated.", this->unitType, this->name));
627 : }
628 30 : this->zoneEquipmentListChecked = true;
629 : }
630 : }
631 :
632 428235 : if (!state.dataGlobal->SysSizingCalc && this->mySizeFlag && !this->plantLoopScanFlag) {
633 : // if ( SysSizingCalc && this->mySizeFlag && ! this->plantLoopScanFlag ) {
634 30 : this->airLoopNum = state.dataZoneEquip->ZoneEquipConfig(this->zoneIndex).InletNodeAirLoopNum(this->ctrlZoneInNodeIndex);
635 30 : state.dataDefineEquipment->AirDistUnit(this->aDUNum).AirLoopNum = this->airLoopNum;
636 30 : this->set_size(state); // calculate autosize values (in any) and convert volume flow rates to mass flow rates
637 30 : if (this->beamCoolingPresent) { // initialize chilled water design mass flow rate in plant routines
638 30 : InitComponentNodes(state, 0.0, this->mDotDesignCW, this->cWInNodeNum, this->cWOutNodeNum);
639 : }
640 30 : if (this->beamHeatingPresent) { // initialize hot water design mass flow rate in plant routines
641 30 : InitComponentNodes(state, 0.0, this->mDotDesignHW, this->hWInNodeNum, this->hWOutNodeNum);
642 : }
643 30 : this->mySizeFlag = false;
644 : }
645 :
646 : // Do the Begin Environment initializations
647 428235 : if (state.dataGlobal->BeginEnvrnFlag && this->myEnvrnFlag) {
648 :
649 255 : state.dataLoopNodes->Node(this->airInNodeNum).MassFlowRateMax = this->mDotDesignPrimAir;
650 255 : state.dataLoopNodes->Node(this->airOutNodeNum).MassFlowRateMax = this->mDotDesignPrimAir;
651 255 : state.dataLoopNodes->Node(this->airInNodeNum).MassFlowRateMin = 0.0;
652 255 : state.dataLoopNodes->Node(this->airOutNodeNum).MassFlowRateMin = 0.0;
653 :
654 255 : if (this->beamCoolingPresent) { // initialize chilled water design mass flow rate in plant routines
655 255 : InitComponentNodes(state, 0.0, this->mDotDesignCW, this->cWInNodeNum, this->cWOutNodeNum);
656 : }
657 255 : if (this->beamHeatingPresent) { // initialize hot water design mass flow rate in plant routines
658 255 : InitComponentNodes(state, 0.0, this->mDotDesignHW, this->hWInNodeNum, this->hWOutNodeNum);
659 : }
660 :
661 255 : if (this->airLoopNum == 0) { // fill air loop index
662 0 : if (this->zoneIndex > 0 && this->ctrlZoneInNodeIndex > 0) {
663 0 : this->airLoopNum = state.dataZoneEquip->ZoneEquipConfig(this->zoneIndex).InletNodeAirLoopNum(this->ctrlZoneInNodeIndex);
664 : }
665 : }
666 :
667 255 : this->myEnvrnFlag = false;
668 : } // end one time inits
669 :
670 428235 : if (!state.dataGlobal->BeginEnvrnFlag) {
671 424740 : this->myEnvrnFlag = true;
672 : }
673 :
674 : // Do the start of HVAC time step initializations
675 428235 : if (FirstHVACIteration) {
676 : // check availability schedules and set flags
677 163125 : if (GetCurrentScheduleValue(state, this->airAvailSchedNum) > 0.0) {
678 104295 : this->airAvailable = true;
679 : } else {
680 58830 : this->airAvailable = false;
681 : }
682 163125 : if (this->airAvailable && beamCoolingPresent && (GetCurrentScheduleValue(state, this->coolingAvailSchedNum) > 0.0)) {
683 104295 : this->coolingAvailable = true;
684 : } else {
685 58830 : this->coolingAvailable = false;
686 : }
687 163125 : if (this->airAvailable && beamHeatingPresent && (GetCurrentScheduleValue(state, this->heatingAvailSchedNum) > 0.0)) {
688 104295 : this->heatingAvailable = true;
689 : } else {
690 58830 : this->heatingAvailable = false;
691 : }
692 : // check for upstream zero flow. If nonzero and air available, set primary flow to max
693 163125 : if (this->airAvailable && state.dataLoopNodes->Node(this->airInNodeNum).MassFlowRate > 0.0) {
694 80365 : state.dataLoopNodes->Node(this->airInNodeNum).MassFlowRate = this->mDotDesignPrimAir;
695 : } else {
696 82760 : state.dataLoopNodes->Node(this->airInNodeNum).MassFlowRate = 0.0;
697 : }
698 : // reset the max and min avail flows
699 163125 : if (this->airAvailable && state.dataLoopNodes->Node(this->airInNodeNum).MassFlowRateMaxAvail > 0.0) {
700 80365 : state.dataLoopNodes->Node(this->airInNodeNum).MassFlowRateMaxAvail = this->mDotDesignPrimAir;
701 80365 : state.dataLoopNodes->Node(this->airInNodeNum).MassFlowRateMinAvail = this->mDotDesignPrimAir;
702 : } else {
703 82760 : state.dataLoopNodes->Node(this->airInNodeNum).MassFlowRateMaxAvail = 0.0;
704 82760 : state.dataLoopNodes->Node(this->airInNodeNum).MassFlowRateMinAvail = 0.0;
705 : }
706 : }
707 :
708 : // do these initializations every time step
709 428235 : if (beamCoolingPresent) {
710 428235 : this->cWTempIn = state.dataLoopNodes->Node(this->cWInNodeNum).Temp;
711 428235 : this->cWTempOut = this->cWTempIn;
712 : }
713 428235 : if (beamHeatingPresent) {
714 428235 : this->hWTempIn = state.dataLoopNodes->Node(this->hWInNodeNum).Temp;
715 428235 : this->hWTempOut = this->hWTempIn;
716 : }
717 428235 : this->mDotSystemAir = state.dataLoopNodes->Node(this->airInNodeNum).MassFlowRateMaxAvail;
718 428235 : state.dataLoopNodes->Node(this->airInNodeNum).MassFlowRate = this->mDotSystemAir;
719 428235 : this->tDBZoneAirTemp = state.dataLoopNodes->Node(this->zoneNodeIndex).Temp;
720 428235 : this->tDBSystemAir = state.dataLoopNodes->Node(this->airInNodeNum).Temp;
721 428235 : this->cpZoneAir = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(this->zoneNodeIndex).HumRat);
722 428235 : this->cpSystemAir = Psychrometrics::PsyCpAirFnW(state.dataLoopNodes->Node(this->airInNodeNum).HumRat);
723 428235 : this->qDotBeamCooling = 0.0;
724 428235 : this->qDotBeamHeating = 0.0;
725 428235 : this->supAirCoolingRate = 0.0;
726 428235 : this->supAirHeatingRate = 0.0;
727 428235 : this->beamCoolingRate = 0.0;
728 428235 : this->beamHeatingRate = 0.0;
729 428235 : this->primAirFlow = 0.0;
730 :
731 428235 : } // init
732 :
733 30 : void HVACFourPipeBeam::set_size(EnergyPlusData &state)
734 : {
735 :
736 : // Using
737 : using namespace DataSizing;
738 : using FluidProperties::GetDensityGlycol;
739 : using FluidProperties::GetSpecificHeatGlycol;
740 : using PlantUtilities::MyPlantSizingIndex;
741 : using PlantUtilities::RegisterPlantCompDesignFlow;
742 : using Psychrometrics::PsyCpAirFnW;
743 : using namespace std::placeholders;
744 :
745 : static constexpr std::string_view routineName("HVACFourPipeBeam::set_size ");
746 :
747 30 : bool ErrorsFound = false;
748 : Real64 rho; // local fluid density
749 : bool noHardSizeAnchorAvailable; // aid for complex logic surrounding mix of hard size and autosizes
750 30 : Real64 cpAir = 0.0;
751 30 : Real64 ErrTolerance = 0.001;
752 :
753 30 : Real64 mDotAirSolutionHeating = 0.0;
754 30 : Real64 mDotAirSolutionCooling = 0.0;
755 30 : Real64 originalTermUnitSizeMaxVDot = 0.0;
756 30 : Real64 originalTermUnitSizeCoolVDot = 0.0;
757 30 : Real64 originalTermUnitSizeHeatVDot = 0.0;
758 :
759 : // convert rated primary flow rate to mass flow rate using standard pressure and dry air at 20.0
760 30 : this->mDotNormRatedPrimAir = this->vDotNormRatedPrimAir * state.dataEnvrn->rhoAirSTP;
761 :
762 30 : noHardSizeAnchorAvailable = false;
763 :
764 30 : if (state.dataSize->CurTermUnitSizingNum > 0) {
765 30 : originalTermUnitSizeMaxVDot = std::max(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlow,
766 30 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow);
767 30 : originalTermUnitSizeCoolVDot = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolVolFlow;
768 30 : originalTermUnitSizeHeatVDot = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatVolFlow;
769 : }
770 :
771 30 : if (this->totBeamLengthWasAutosized && this->vDotDesignPrimAirWasAutosized && this->vDotDesignCWWasAutosized &&
772 30 : this->vDotDesignHWWasAutosized) {
773 30 : noHardSizeAnchorAvailable = true;
774 0 : } else if (this->totBeamLengthWasAutosized && this->vDotDesignPrimAirWasAutosized && this->vDotDesignCWWasAutosized && !beamHeatingPresent) {
775 0 : noHardSizeAnchorAvailable = true;
776 0 : } else if (this->totBeamLengthWasAutosized && this->vDotDesignPrimAirWasAutosized && !this->beamCoolingPresent &&
777 0 : this->vDotDesignHWWasAutosized) {
778 0 : noHardSizeAnchorAvailable = true;
779 0 : } else if (!this->totBeamLengthWasAutosized) { // the simplest case is where length is not autosized
780 : // use the normalized rated values (likely defaulted ) with length to calculate any that are autosized
781 0 : if (this->vDotDesignPrimAirWasAutosized) {
782 0 : this->vDotDesignPrimAir = this->vDotNormRatedPrimAir * this->totBeamLength;
783 : }
784 0 : if (this->vDotDesignCWWasAutosized) {
785 0 : this->vDotDesignCW = this->vDotNormRatedCW * this->totBeamLength;
786 : }
787 0 : if (vDotDesignHWWasAutosized) {
788 0 : this->vDotDesignHW = this->vDotNormRatedHW * this->totBeamLength;
789 : }
790 : } else { // need to find beam length
791 : // the next simplest case is if the supply air rate is given
792 0 : if (!this->vDotDesignPrimAirWasAutosized) { //
793 : // find length from air flow rate and then proceed
794 0 : this->totBeamLength = this->vDotDesignPrimAir / this->vDotNormRatedPrimAir;
795 0 : if (this->vDotDesignCWWasAutosized) {
796 0 : this->vDotDesignCW = this->vDotNormRatedCW * this->totBeamLength;
797 : }
798 0 : if (vDotDesignHWWasAutosized) {
799 0 : this->vDotDesignHW = this->vDotNormRatedHW * this->totBeamLength;
800 : }
801 : } else { // both air and length are autosized
802 0 : if (this->beamCoolingPresent && !this->vDotDesignCWWasAutosized) { // we have a chilled water flow rate to use
803 0 : this->totBeamLength = this->vDotDesignCW / this->vDotNormRatedCW;
804 0 : this->vDotDesignPrimAir = this->vDotNormRatedPrimAir * this->totBeamLength;
805 0 : if (vDotDesignHWWasAutosized) {
806 0 : this->vDotDesignHW = this->vDotNormRatedHW * this->totBeamLength;
807 : }
808 0 : } else if (this->beamHeatingPresent && !this->vDotDesignHWWasAutosized) { // we have a hot water flow rate to use
809 0 : this->totBeamLength = this->vDotDesignHW / this->vDotNormRatedHW;
810 0 : this->vDotDesignPrimAir = this->vDotNormRatedPrimAir * this->totBeamLength;
811 0 : if (this->vDotDesignCWWasAutosized) { // don't think it can come here but...
812 0 : this->vDotDesignCW = this->vDotNormRatedCW * this->totBeamLength;
813 : }
814 : } else {
815 : // should not come here, developer exception
816 : }
817 : } // no air flow rate
818 : } // no beam length
819 :
820 60 : if (noHardSizeAnchorAvailable && (state.dataSize->CurZoneEqNum > 0) &&
821 30 : (state.dataSize->CurTermUnitSizingNum > 0)) { // need to use central sizing results to calculate
822 :
823 : // set up for solver
824 :
825 30 : CheckZoneSizing(state, this->unitType, this->name);
826 : // minimum flow rate is from air flow rate on the terminal unit final zone size ( typically ventilation minimum and may be too low)
827 30 : Real64 minFlow(0.0);
828 30 : Real64 maxFlowCool(0.0);
829 30 : minFlow = std::min(state.dataEnvrn->StdRhoAir * originalTermUnitSizeMaxVDot,
830 30 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).MinOA * state.dataEnvrn->StdRhoAir);
831 30 : minFlow = std::max(0.0, minFlow);
832 : // max flow is as if the air supply was sufficient to provide all the conditioning
833 :
834 30 : if (beamCoolingPresent) {
835 30 : cpAir = PsyCpAirFnW(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolCoilInHumRatTU);
836 :
837 30 : if ((state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtCoolPeak -
838 30 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolCoilInTempTU) >
839 : 2.0) { // avoid div by zero and blow up
840 30 : maxFlowCool = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolLoad /
841 30 : (cpAir * (state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtCoolPeak -
842 30 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolCoilInTempTU));
843 : } else {
844 0 : maxFlowCool = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolLoad / (cpAir * 2.0);
845 : }
846 30 : if (minFlow * 3.0 >= maxFlowCool) {
847 0 : minFlow = maxFlowCool / 3.0; // make sure min is significantly lower than max.
848 : }
849 :
850 30 : int pltSizCoolNum = MyPlantSizingIndex(state, "four pipe beam unit", this->name, this->cWInNodeNum, this->cWOutNodeNum, ErrorsFound);
851 30 : if (pltSizCoolNum == 0) {
852 0 : ShowSevereError(state, "Autosizing of water flow requires a cooling loop Sizing:Plant object");
853 0 : ShowContinueError(state, format("Occurs in {} Object={}", this->unitType, this->name));
854 0 : ErrorsFound = true;
855 : } else {
856 30 : this->cWTempIn = state.dataSize->PlantSizData(pltSizCoolNum).ExitTemp;
857 : }
858 30 : this->mDotHW = 0.0;
859 30 : this->tDBZoneAirTemp = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtCoolPeak;
860 30 : this->tDBSystemAir = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolCoilInTempTU;
861 30 : this->cpZoneAir = PsyCpAirFnW(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneHumRatAtCoolPeak);
862 30 : this->cpSystemAir = PsyCpAirFnW(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolCoilInHumRatTU);
863 30 : this->qDotZoneReq = -1.0 * state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolLoad;
864 30 : this->qDotZoneToCoolSetPt = -1.0 * state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesCoolLoad;
865 30 : this->airAvailable = true;
866 30 : this->coolingAvailable = true;
867 30 : this->heatingAvailable = false;
868 1800 : auto f = [&state, this](Real64 const airFlow) {
869 : static constexpr std::string_view routineName("Real64 HVACFourPipeBeam::residualSizing ");
870 90 : this->mDotSystemAir = airFlow;
871 90 : this->vDotDesignPrimAir = this->mDotSystemAir / state.dataEnvrn->StdRhoAir;
872 90 : this->totBeamLength = this->vDotDesignPrimAir / this->vDotNormRatedPrimAir;
873 90 : if (this->vDotDesignCWWasAutosized) {
874 90 : this->vDotDesignCW = this->vDotNormRatedCW * this->totBeamLength;
875 90 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
876 90 : state.dataPlnt->PlantLoop(this->cWplantLoc.loopNum).FluidName,
877 : Constant::CWInitConvTemp,
878 90 : state.dataPlnt->PlantLoop(this->cWplantLoc.loopNum).FluidIndex,
879 : routineName);
880 90 : this->mDotNormRatedCW = this->vDotNormRatedCW * rho;
881 90 : this->mDotCW = this->vDotDesignCW * rho;
882 90 : if (this->beamCoolingPresent) {
883 90 : PlantUtilities::InitComponentNodes(state, 0.0, this->mDotCW, this->cWInNodeNum, this->cWOutNodeNum);
884 : }
885 : }
886 90 : if (vDotDesignHWWasAutosized) {
887 90 : this->vDotDesignHW = this->vDotNormRatedHW * this->totBeamLength;
888 90 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
889 90 : state.dataPlnt->PlantLoop(this->hWplantLoc.loopNum).FluidName,
890 : Constant::HWInitConvTemp,
891 90 : state.dataPlnt->PlantLoop(this->hWplantLoc.loopNum).FluidIndex,
892 : routineName);
893 90 : this->mDotNormRatedHW = this->vDotNormRatedHW * rho;
894 90 : this->mDotHW = this->vDotDesignHW * rho;
895 90 : if (this->beamHeatingPresent) {
896 90 : PlantUtilities::InitComponentNodes(state, 0.0, this->mDotHW, this->hWInNodeNum, this->hWOutNodeNum);
897 : }
898 : }
899 90 : this->calc(state);
900 90 : if (this->qDotZoneReq != 0.0) {
901 90 : return ((this->qDotZoneReq - this->qDotTotalDelivered) / this->qDotZoneReq);
902 : } else {
903 0 : return 1.0;
904 : }
905 30 : };
906 30 : int SolFlag = 0;
907 30 : General::SolveRoot(state, ErrTolerance, 50, SolFlag, mDotAirSolutionCooling, f, minFlow, maxFlowCool);
908 30 : if (SolFlag == -1) {
909 0 : ShowWarningError(state, format("Cooling load sizing search failed in four pipe beam unit called {}", this->name));
910 0 : ShowContinueError(state, " Iteration limit exceeded in calculating size for design cooling load");
911 30 : } else if (SolFlag == -2) {
912 0 : ShowWarningError(state, format("Cooling load sizing search failed in four pipe beam unit called {}", this->name));
913 0 : ShowContinueError(state, " Bad size limits");
914 : }
915 : }
916 :
917 30 : if (beamHeatingPresent) {
918 30 : cpAir = PsyCpAirFnW(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInHumRatTU);
919 30 : Real64 maxFlowHeat = 0.0;
920 30 : if ((state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInTempTU -
921 30 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtHeatPeak) >
922 : 2.0) { // avoid div by zero and blow up
923 0 : maxFlowHeat = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatLoad /
924 0 : (cpAir * (state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInTempTU -
925 0 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtHeatPeak));
926 : } else {
927 30 : maxFlowHeat = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatLoad / (cpAir * 2.0);
928 : }
929 :
930 30 : int pltSizHeatNum = MyPlantSizingIndex(state, "four pipe beam unit", this->name, this->hWInNodeNum, this->hWOutNodeNum, ErrorsFound);
931 30 : if (pltSizHeatNum == 0) {
932 0 : ShowSevereError(state, "Autosizing of water flow requires a heating loop Sizing:Plant object");
933 0 : ShowContinueError(state, format("Occurs in {} Object={}", this->unitType, this->name));
934 0 : ErrorsFound = true;
935 : } else {
936 30 : this->hWTempIn = state.dataSize->PlantSizData(pltSizHeatNum).ExitTemp;
937 : }
938 30 : this->mDotCW = 0.0;
939 30 : this->tDBZoneAirTemp = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneTempAtHeatPeak;
940 30 : this->tDBSystemAir = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInTempTU;
941 30 : this->cpZoneAir = PsyCpAirFnW(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).ZoneHumRatAtHeatPeak);
942 30 : this->cpSystemAir = PsyCpAirFnW(state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatCoilInHumRatTU);
943 30 : this->qDotZoneReq = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatLoad;
944 30 : this->qDotZoneToHeatSetPt = state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).DesHeatLoad;
945 30 : this->airAvailable = true;
946 30 : this->heatingAvailable = true;
947 30 : this->coolingAvailable = false;
948 1800 : auto f = [&state, this](Real64 const airFlow) {
949 : static constexpr std::string_view routineName("Real64 HVACFourPipeBeam::residualSizing ");
950 90 : this->mDotSystemAir = airFlow;
951 90 : this->vDotDesignPrimAir = this->mDotSystemAir / state.dataEnvrn->StdRhoAir;
952 90 : this->totBeamLength = this->vDotDesignPrimAir / this->vDotNormRatedPrimAir;
953 90 : if (this->vDotDesignCWWasAutosized) {
954 90 : this->vDotDesignCW = this->vDotNormRatedCW * this->totBeamLength;
955 90 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
956 90 : state.dataPlnt->PlantLoop(this->cWplantLoc.loopNum).FluidName,
957 : Constant::CWInitConvTemp,
958 90 : state.dataPlnt->PlantLoop(this->cWplantLoc.loopNum).FluidIndex,
959 : routineName);
960 90 : this->mDotNormRatedCW = this->vDotNormRatedCW * rho;
961 90 : this->mDotCW = this->vDotDesignCW * rho;
962 90 : if (this->beamCoolingPresent) {
963 90 : PlantUtilities::InitComponentNodes(state, 0.0, this->mDotCW, this->cWInNodeNum, this->cWOutNodeNum);
964 : }
965 : }
966 90 : if (vDotDesignHWWasAutosized) {
967 90 : this->vDotDesignHW = this->vDotNormRatedHW * this->totBeamLength;
968 90 : Real64 const rho = FluidProperties::GetDensityGlycol(state,
969 90 : state.dataPlnt->PlantLoop(this->hWplantLoc.loopNum).FluidName,
970 : Constant::HWInitConvTemp,
971 90 : state.dataPlnt->PlantLoop(this->hWplantLoc.loopNum).FluidIndex,
972 : routineName);
973 90 : this->mDotNormRatedHW = this->vDotNormRatedHW * rho;
974 90 : this->mDotHW = this->vDotDesignHW * rho;
975 90 : if (this->beamHeatingPresent) {
976 90 : PlantUtilities::InitComponentNodes(state, 0.0, this->mDotHW, this->hWInNodeNum, this->hWOutNodeNum);
977 : }
978 : }
979 90 : this->calc(state);
980 90 : if (this->qDotZoneReq != 0.0) {
981 90 : return ((this->qDotZoneReq - this->qDotTotalDelivered) / this->qDotZoneReq);
982 : } else {
983 0 : return 1.0;
984 : }
985 30 : };
986 30 : int SolFlag = 0;
987 30 : General::SolveRoot(state, ErrTolerance, 50, SolFlag, mDotAirSolutionHeating, f, 0.0, maxFlowHeat);
988 30 : if (SolFlag == -1) {
989 0 : ShowWarningError(state, format("Heating load sizing search failed in four pipe beam unit called {}", this->name));
990 0 : ShowContinueError(state, " Iteration limit exceeded in calculating size for design heating load");
991 30 : } else if (SolFlag == -2) {
992 0 : ShowWarningError(state, format("Heating load sizing search failed in four pipe beam unit called {}", this->name));
993 0 : ShowContinueError(state, " Bad size limits");
994 : }
995 : }
996 :
997 : // take the larger of heating and cooling
998 30 : this->mDotDesignPrimAir = std::max(mDotAirSolutionHeating, mDotAirSolutionCooling);
999 : // make sure this is higher than the zone OA requirement
1000 30 : this->mDotDesignPrimAir =
1001 60 : std::max(this->mDotDesignPrimAir,
1002 30 : state.dataSize->TermUnitFinalZoneSizing(state.dataSize->CurTermUnitSizingNum).MinOA * state.dataEnvrn->StdRhoAir);
1003 30 : this->vDotDesignPrimAir = this->mDotDesignPrimAir / state.dataEnvrn->StdRhoAir;
1004 30 : this->totBeamLength = this->vDotDesignPrimAir / this->vDotNormRatedPrimAir;
1005 30 : if (this->vDotDesignCWWasAutosized) {
1006 30 : this->vDotDesignCW = this->vDotNormRatedCW * this->totBeamLength;
1007 : }
1008 30 : if (vDotDesignHWWasAutosized) {
1009 30 : this->vDotDesignHW = this->vDotNormRatedHW * this->totBeamLength;
1010 : }
1011 : }
1012 : // fill in mass flow rate versions of working variables (regardless of autosizing )
1013 30 : this->mDotDesignPrimAir = this->vDotDesignPrimAir * state.dataEnvrn->StdRhoAir;
1014 :
1015 30 : if ((originalTermUnitSizeMaxVDot > 0.0) && (originalTermUnitSizeMaxVDot != this->vDotDesignPrimAir) && (state.dataSize->CurZoneEqNum > 0)) {
1016 30 : if ((state.dataSize->SysSizingRunDone) && (this->airLoopNum > 0)) {
1017 : // perturb system size to handle change in system size calculated without knowing about 4 pipe beam
1018 : // Note that this approach is not necessarily appropriate for coincident system design option
1019 : // and it might be moved to make such adjustments in SizingManager::ManageSystemSizingAdjustments()
1020 30 : state.dataSize->FinalSysSizing(this->airLoopNum).DesMainVolFlow += (this->vDotDesignPrimAir - originalTermUnitSizeMaxVDot);
1021 30 : state.dataSize->FinalSysSizing(this->airLoopNum).DesCoolVolFlow += (this->vDotDesignPrimAir - originalTermUnitSizeCoolVDot);
1022 30 : state.dataSize->FinalSysSizing(this->airLoopNum).DesHeatVolFlow += (this->vDotDesignPrimAir - originalTermUnitSizeHeatVDot);
1023 30 : state.dataSize->FinalSysSizing(this->airLoopNum).MassFlowAtCoolPeak +=
1024 30 : (this->vDotDesignPrimAir - originalTermUnitSizeCoolVDot) * state.dataEnvrn->StdRhoAir;
1025 :
1026 60 : BaseSizer::reportSizerOutput(state,
1027 : this->unitType,
1028 : this->name,
1029 : "AirLoopHVAC Design Supply Air Flow Rate Adjustment [m3/s]",
1030 30 : (this->vDotDesignPrimAir - originalTermUnitSizeMaxVDot));
1031 : } else {
1032 0 : ShowSevereError(state, "Four pipe beam requires system sizing. Turn on system sizing.");
1033 0 : ShowFatalError(state, "Program terminating due to previous errors");
1034 : }
1035 : }
1036 :
1037 30 : if (this->beamCoolingPresent) {
1038 30 : rho = FluidProperties::GetDensityGlycol(state,
1039 30 : state.dataPlnt->PlantLoop(this->cWplantLoc.loopNum).FluidName,
1040 : Constant::CWInitConvTemp,
1041 30 : state.dataPlnt->PlantLoop(this->cWplantLoc.loopNum).FluidIndex,
1042 : routineName);
1043 30 : this->mDotNormRatedCW = this->vDotNormRatedCW * rho;
1044 30 : this->mDotDesignCW = this->vDotDesignCW * rho;
1045 30 : PlantUtilities::InitComponentNodes(state, 0.0, this->mDotDesignCW, this->cWInNodeNum, this->cWOutNodeNum);
1046 : }
1047 30 : if (this->beamHeatingPresent) {
1048 30 : rho = FluidProperties::GetDensityGlycol(state,
1049 30 : state.dataPlnt->PlantLoop(this->hWplantLoc.loopNum).FluidName,
1050 : Constant::HWInitConvTemp,
1051 30 : state.dataPlnt->PlantLoop(this->hWplantLoc.loopNum).FluidIndex,
1052 : routineName);
1053 30 : this->mDotNormRatedHW = this->vDotNormRatedHW * rho;
1054 30 : this->mDotDesignHW = this->vDotDesignHW * rho;
1055 30 : PlantUtilities::InitComponentNodes(state, 0.0, this->mDotDesignHW, this->hWInNodeNum, this->hWOutNodeNum);
1056 : }
1057 :
1058 : // report final sizes if autosized
1059 30 : if (this->vDotDesignPrimAirWasAutosized) {
1060 30 : BaseSizer::reportSizerOutput(state, this->unitType, this->name, "Supply Air Flow Rate [m3/s]", this->vDotDesignPrimAir);
1061 : }
1062 30 : if (this->vDotDesignCWWasAutosized) {
1063 30 : BaseSizer::reportSizerOutput(state, this->unitType, this->name, "Maximum Total Chilled Water Flow Rate [m3/s]", this->vDotDesignCW);
1064 : }
1065 30 : if (this->vDotDesignHWWasAutosized) {
1066 30 : BaseSizer::reportSizerOutput(state, this->unitType, this->name, "Maximum Total Hot Water Flow Rate [m3/s]", this->vDotDesignHW);
1067 : }
1068 30 : if (this->totBeamLengthWasAutosized) {
1069 30 : BaseSizer::reportSizerOutput(state, this->unitType, this->name, "Zone Total Beam Length [m]", this->totBeamLength);
1070 : }
1071 : // save the design water volume flow rate for use by the water loop sizing algorithms
1072 30 : if (this->vDotDesignCW > 0.0 && this->beamCoolingPresent) {
1073 30 : RegisterPlantCompDesignFlow(state, this->cWInNodeNum, this->vDotDesignCW);
1074 : }
1075 30 : if (this->vDotDesignHW > 0.0 && this->beamHeatingPresent) {
1076 30 : RegisterPlantCompDesignFlow(state, this->hWInNodeNum, this->vDotDesignHW);
1077 : }
1078 30 : if (ErrorsFound) {
1079 0 : ShowFatalError(state, "Preceding four pipe beam sizing errors cause program termination");
1080 : }
1081 :
1082 30 : } // set_size
1083 :
1084 428205 : void HVACFourPipeBeam::control(EnergyPlusData &state,
1085 : [[maybe_unused]] bool const FirstHVACIteration, // TRUE if 1st HVAC simulation of system timestep
1086 : Real64 &NonAirSysOutput // convective cooling by the beam system [W]
1087 : )
1088 : {
1089 :
1090 : // Using/Aliasing
1091 : using namespace DataZoneEnergyDemands;
1092 : using PlantUtilities::SetComponentFlowRate;
1093 : using namespace std::placeholders;
1094 :
1095 : int SolFlag;
1096 : Real64 ErrTolerance;
1097 :
1098 428205 : NonAirSysOutput = 0.0; // initialize
1099 :
1100 428205 : if (this->mDotSystemAir < HVAC::VerySmallMassFlow ||
1101 260850 : (!this->airAvailable && !this->coolingAvailable && !this->heatingAvailable)) { // unit is off
1102 167355 : this->mDotHW = 0.0;
1103 167355 : if (this->beamHeatingPresent) {
1104 167355 : SetComponentFlowRate(state, this->mDotHW, this->hWInNodeNum, this->hWOutNodeNum, this->hWplantLoc);
1105 : }
1106 167355 : this->hWTempOut = this->hWTempIn;
1107 : // assume if there is still flow that unit has an internal bypass and convector does not still heat
1108 167355 : this->mDotCW = 0.0;
1109 167355 : this->cWTempOut = this->cWTempIn;
1110 167355 : if (this->beamCoolingPresent) {
1111 167355 : SetComponentFlowRate(state, this->mDotCW, this->cWInNodeNum, this->cWOutNodeNum, this->cWplantLoc);
1112 : }
1113 : // assume if there is still flow that unit has an internal bypass and convector does not still cool
1114 : // don't even need to run calc
1115 167355 : return;
1116 : }
1117 :
1118 260850 : if (this->airAvailable && this->mDotSystemAir > HVAC::VerySmallMassFlow && !this->coolingAvailable && !this->heatingAvailable) {
1119 0 : this->mDotHW = 0.0;
1120 0 : if (this->beamHeatingPresent) {
1121 0 : SetComponentFlowRate(state, this->mDotHW, this->hWInNodeNum, this->hWOutNodeNum, this->hWplantLoc);
1122 : }
1123 : // assume if there is still flow that unit has an internal bypass and convector does not still heat
1124 0 : this->hWTempOut = this->hWTempIn;
1125 0 : this->mDotCW = 0.0;
1126 0 : if (this->beamCoolingPresent) {
1127 0 : SetComponentFlowRate(state, this->mDotCW, this->cWInNodeNum, this->cWOutNodeNum, this->cWplantLoc);
1128 : }
1129 : // assume if there is still flow that unit has an internal bypass and convector does not still cool
1130 0 : this->cWTempOut = this->cWTempIn;
1131 0 : this->calc(state);
1132 :
1133 0 : return;
1134 : }
1135 :
1136 : // get zone loads
1137 260850 : this->qDotZoneReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(this->zoneIndex).RemainingOutputRequired;
1138 260850 : this->qDotZoneToHeatSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(this->zoneIndex).RemainingOutputReqToHeatSP;
1139 260850 : this->qDotZoneToCoolSetPt = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(this->zoneIndex).RemainingOutputReqToCoolSP;
1140 :
1141 : // decide if beam is in heating or cooling
1142 :
1143 260850 : this->qDotSystemAir = this->mDotSystemAir * ((this->cpSystemAir * this->tDBSystemAir) - (this->cpZoneAir * this->tDBZoneAirTemp));
1144 :
1145 260850 : this->qDotBeamReq = this->qDotZoneReq - this->qDotSystemAir;
1146 :
1147 260850 : if (this->qDotBeamReq < -HVAC::SmallLoad && this->coolingAvailable) { // beam cooling needed
1148 : // first calc with max chilled water flow
1149 86893 : this->mDotHW = 0.0;
1150 86893 : if (this->beamHeatingPresent) {
1151 86893 : SetComponentFlowRate(state, this->mDotHW, this->hWInNodeNum, this->hWOutNodeNum, this->hWplantLoc);
1152 : }
1153 86893 : this->hWTempOut = this->hWTempIn;
1154 86893 : this->mDotCW = this->mDotDesignCW;
1155 86893 : this->calc(state);
1156 86893 : if (this->qDotBeamCooling < (qDotBeamReq - HVAC::SmallLoad)) {
1157 : // can overcool, modulate chilled water flow rate to meet load
1158 79392 : this->qDotBeamCoolingMax = this->qDotBeamCooling;
1159 79392 : ErrTolerance = 0.01;
1160 1422576 : auto f = [&state, this](Real64 const cWFlow) {
1161 474192 : this->mDotHW = 0.0;
1162 474192 : this->mDotCW = cWFlow;
1163 474192 : this->calc(state);
1164 474192 : if (this->qDotBeamCoolingMax != 0.0) {
1165 474192 : return (((this->qDotZoneToCoolSetPt - this->qDotSystemAir) - this->qDotBeamCooling) / this->qDotBeamCoolingMax);
1166 : } else {
1167 0 : return 1.0;
1168 : }
1169 79392 : };
1170 79392 : General::SolveRoot(state, ErrTolerance, 50, SolFlag, this->mDotCW, f, 0.0, this->mDotDesignCW);
1171 79392 : if (SolFlag == -1) {
1172 : // ShowWarningError( "Cold water control failed in four pipe beam unit called " + this->name );
1173 : // ShowContinueError(state, " Iteration limit exceeded in calculating cold water mass flow rate" );
1174 79148 : } else if (SolFlag == -2) {
1175 : // ShowWarningError( "Cold water control failed in four pipe beam unit called " + this->name );
1176 : // ShowContinueError(state, " Bad cold water flow limits" );
1177 : }
1178 79392 : this->calc(state);
1179 79392 : NonAirSysOutput = this->qDotBeamCooling;
1180 79392 : return;
1181 : } else { // can run flat out without overcooling, which we just did
1182 7501 : NonAirSysOutput = this->qDotBeamCooling;
1183 7501 : return;
1184 : }
1185 :
1186 173957 : } else if (qDotBeamReq > HVAC::SmallLoad && this->heatingAvailable) { // beam heating needed
1187 : // first calc with max hot water flow
1188 173951 : this->mDotCW = 0.0;
1189 173951 : if (this->beamCoolingPresent) {
1190 173951 : SetComponentFlowRate(state, this->mDotCW, this->cWInNodeNum, this->cWOutNodeNum, this->cWplantLoc);
1191 : }
1192 173951 : this->cWTempOut = this->cWTempIn;
1193 173951 : this->mDotHW = this->mDotDesignHW;
1194 173951 : this->calc(state);
1195 173951 : if (this->qDotBeamHeating > (qDotBeamReq + HVAC::SmallLoad)) {
1196 92037 : this->qDotBeamHeatingMax = this->qDotBeamHeating;
1197 : // can overheat, modulate hot water flow to meet load
1198 92037 : ErrTolerance = 0.01;
1199 1090017 : auto f = [&state, this](Real64 const hWFlow) {
1200 363339 : this->mDotHW = hWFlow;
1201 363339 : this->mDotCW = 0.0;
1202 363339 : this->calc(state);
1203 363339 : if (this->qDotBeamHeatingMax != 0.0) {
1204 363339 : return (((this->qDotZoneToHeatSetPt - this->qDotSystemAir) - this->qDotBeamHeating) / this->qDotBeamHeatingMax);
1205 : } else {
1206 0 : return 1.0;
1207 : }
1208 92037 : };
1209 92037 : General::SolveRoot(state, ErrTolerance, 50, SolFlag, this->mDotHW, f, 0.0, this->mDotDesignHW);
1210 92037 : if (SolFlag == -1) {
1211 : // ShowWarningError( "Hot water control failed in four pipe beam unit called " + this->name );
1212 : // ShowContinueError(state, " Iteration limit exceeded in calculating hot water mass flow rate" );
1213 91981 : } else if (SolFlag == -2) {
1214 : // ShowWarningError( "Hot water control failed in four pipe beam called " + this->name );
1215 : // ShowContinueError(state, " Bad hot water flow limits" );
1216 : }
1217 92037 : this->calc(state);
1218 92037 : NonAirSysOutput = this->qDotBeamHeating;
1219 92037 : return;
1220 :
1221 : } else { // can run flat out without overheating, which we just did
1222 81914 : NonAirSysOutput = this->qDotBeamHeating;
1223 81914 : return;
1224 : }
1225 :
1226 : } else {
1227 6 : this->mDotHW = 0.0;
1228 6 : if (this->beamHeatingPresent) {
1229 6 : SetComponentFlowRate(state, this->mDotHW, this->hWInNodeNum, this->hWOutNodeNum, this->hWplantLoc);
1230 : }
1231 6 : this->hWTempOut = this->hWTempIn;
1232 : // assume if there is still flow that unit has an internal bypass and convector does not still heat
1233 6 : this->mDotCW = 0.0;
1234 6 : this->cWTempOut = this->cWTempIn;
1235 6 : if (this->beamCoolingPresent) {
1236 6 : SetComponentFlowRate(state, this->mDotCW, this->cWInNodeNum, this->cWOutNodeNum, this->cWplantLoc);
1237 : }
1238 : // assume if there is still flow that unit has an internal bypass and convector does not still cool
1239 : // don't even need to run calc
1240 6 : return;
1241 : }
1242 : }
1243 :
1244 1269984 : void HVACFourPipeBeam::calc(EnergyPlusData &state)
1245 : {
1246 :
1247 : // Using/Aliasing
1248 : using FluidProperties::GetDensityGlycol;
1249 : using FluidProperties::GetSpecificHeatGlycol;
1250 : using PlantUtilities::SetComponentFlowRate;
1251 :
1252 : // Locals
1253 : // SUBROUTINE ARGUMENT DEFINITIONS:
1254 :
1255 : // SUBROUTINE PARAMETER DEFINITIONS:
1256 : static constexpr std::string_view routineName("HVACFourPipeBeam::calc ");
1257 :
1258 : // INTERFACE BLOCK SPECIFICATIONS
1259 : // na
1260 :
1261 : // DERIVED TYPE DEFINITIONS
1262 : // na
1263 :
1264 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1265 : Real64 fModCoolCWMdot; // Cooling capacity modification factor function of chilled water flow rate
1266 : Real64 fModCoolDeltaT; // Cooling capacity modification factor function of air-water temperature difference
1267 : Real64 fModCoolAirMdot; // Cooling capacity modification factor function of primary air flow rate
1268 : Real64 fModHeatHWMdot; // Heating capacity modification factor function of hot water flow rate
1269 : Real64 fModHeatDeltaT; // Heating capacity modification factor function of water - air temperature difference
1270 : Real64 fModHeatAirMdot; // Heating capacity modification factor function of primary air flow rate
1271 : Real64 cp; // local fluid specific heat
1272 :
1273 1269984 : this->qDotBeamHeating = 0.0;
1274 1269984 : this->qDotBeamCooling = 0.0;
1275 1269984 : this->qDotSystemAir = this->mDotSystemAir * ((this->cpSystemAir * this->tDBSystemAir) - (this->cpZoneAir * this->tDBZoneAirTemp));
1276 :
1277 1269984 : if (this->coolingAvailable && this->mDotCW > HVAC::VerySmallMassFlow) {
1278 : // test chilled water flow against plant, it might not all be available
1279 561163 : SetComponentFlowRate(state, this->mDotCW, this->cWInNodeNum, this->cWOutNodeNum, this->cWplantLoc);
1280 : fModCoolCWMdot =
1281 561163 : Curve::CurveValue(state, this->modCoolingQdotCWFlowFuncNum, ((this->mDotCW / this->totBeamLength) / this->mDotNormRatedCW));
1282 : fModCoolDeltaT =
1283 561163 : Curve::CurveValue(state, this->modCoolingQdotDeltaTFuncNum, ((this->tDBZoneAirTemp - this->cWTempIn) / this->deltaTempRatedCooling));
1284 1122326 : fModCoolAirMdot = Curve::CurveValue(
1285 561163 : state, this->modCoolingQdotAirFlowFuncNum, ((this->mDotSystemAir / this->totBeamLength) / this->mDotNormRatedPrimAir));
1286 561163 : this->qDotBeamCooling = -1.0 * this->qDotNormRatedCooling * fModCoolDeltaT * fModCoolAirMdot * fModCoolCWMdot * this->totBeamLength;
1287 561163 : cp = GetSpecificHeatGlycol(state,
1288 561163 : state.dataPlnt->PlantLoop(this->cWplantLoc.loopNum).FluidName,
1289 : this->cWTempIn,
1290 561163 : state.dataPlnt->PlantLoop(this->cWplantLoc.loopNum).FluidIndex,
1291 : routineName);
1292 561163 : if (this->mDotCW > 0.0) {
1293 561140 : this->cWTempOut = this->cWTempIn - (this->qDotBeamCooling / (this->mDotCW * cp));
1294 : } else {
1295 23 : this->cWTempOut = this->cWTempIn;
1296 : }
1297 : // check if non physical temperature rise, can't be warmer than air
1298 561163 : if (this->cWTempOut > (std::max(this->tDBSystemAir, this->tDBZoneAirTemp) - 1.0)) {
1299 : // throw recurring warning as this indicates a problem in beam model input
1300 0 : ShowRecurringWarningErrorAtEnd(state,
1301 0 : std::string{routineName} + " four pipe beam name " + this->name +
1302 : ", chilled water outlet temperature is too warm. Capacity was limited. check beam capacity input ",
1303 0 : this->cWTempOutErrorCount,
1304 0 : this->cWTempOut,
1305 0 : this->cWTempOut);
1306 : // restrict it within 1.0 C of warmest air and recalculate cooling
1307 0 : this->cWTempOut = (std::max(this->tDBSystemAir, this->tDBZoneAirTemp) - 1.0);
1308 0 : this->qDotBeamCooling = this->mDotCW * cp * (this->cWTempIn - this->cWTempOut);
1309 : }
1310 : } else {
1311 708821 : this->mDotCW = 0.0;
1312 708821 : if (this->beamCoolingPresent) {
1313 708821 : SetComponentFlowRate(state, this->mDotCW, this->cWInNodeNum, this->cWOutNodeNum, this->cWplantLoc);
1314 : }
1315 708821 : this->cWTempOut = this->cWTempIn;
1316 708821 : this->qDotBeamCooling = 0.0;
1317 : }
1318 1269984 : if (this->heatingAvailable && this->mDotHW > HVAC::VerySmallMassFlow) {
1319 : // test hot water flow against plant, it might not all be available
1320 474735 : SetComponentFlowRate(state, this->mDotHW, this->hWInNodeNum, this->hWOutNodeNum, this->hWplantLoc);
1321 : fModHeatHWMdot =
1322 474735 : Curve::CurveValue(state, this->modHeatingQdotHWFlowFuncNum, ((this->mDotHW / this->totBeamLength) / this->mDotNormRatedHW));
1323 : fModHeatDeltaT =
1324 474735 : Curve::CurveValue(state, this->modHeatingQdotDeltaTFuncNum, ((this->hWTempIn - this->tDBZoneAirTemp) / this->deltaTempRatedHeating));
1325 949470 : fModHeatAirMdot = Curve::CurveValue(
1326 474735 : state, this->modHeatingQdotAirFlowFuncNum, ((this->mDotSystemAir / this->totBeamLength) / this->mDotNormRatedPrimAir));
1327 474735 : this->qDotBeamHeating = this->qDotNormRatedHeating * fModHeatDeltaT * fModHeatAirMdot * fModHeatHWMdot * this->totBeamLength;
1328 474735 : cp = GetSpecificHeatGlycol(state,
1329 474735 : state.dataPlnt->PlantLoop(this->hWplantLoc.loopNum).FluidName,
1330 : this->hWTempIn,
1331 474735 : state.dataPlnt->PlantLoop(this->hWplantLoc.loopNum).FluidIndex,
1332 : routineName);
1333 474735 : if (this->mDotHW > 0.0) {
1334 474553 : this->hWTempOut = this->hWTempIn - (this->qDotBeamHeating / (this->mDotHW * cp));
1335 : } else {
1336 182 : this->hWTempOut = this->hWTempIn;
1337 : }
1338 : // check if non physical temperature drop, can't be cooler than air
1339 474735 : if (this->hWTempOut < (std::min(this->tDBSystemAir, this->tDBZoneAirTemp) + 1.0)) {
1340 : // throw recurring warning as this indicates a problem in beam model input
1341 0 : ShowRecurringWarningErrorAtEnd(state,
1342 0 : std::string{routineName} + " four pipe beam name " + this->name +
1343 : ", hot water outlet temperature is too cool. Capacity was limited. check beam capacity input ",
1344 0 : this->hWTempOutErrorCount,
1345 0 : this->hWTempOut,
1346 0 : this->hWTempOut);
1347 : // restrict it within 1.0 C of warmest air and recalculate cooling
1348 0 : this->hWTempOut = (std::min(this->tDBSystemAir, this->tDBZoneAirTemp) + 1.0);
1349 0 : this->qDotBeamHeating = this->mDotHW * cp * (this->hWTempIn - this->hWTempOut);
1350 : }
1351 : } else {
1352 795249 : this->mDotHW = 0.0;
1353 795249 : if (this->beamHeatingPresent) {
1354 795249 : SetComponentFlowRate(state, this->mDotHW, this->hWInNodeNum, this->hWOutNodeNum, this->hWplantLoc);
1355 : }
1356 795249 : this->hWTempOut = this->hWTempIn;
1357 795249 : this->qDotBeamHeating = 0.0;
1358 : }
1359 :
1360 1269984 : this->qDotTotalDelivered = this->qDotSystemAir + this->qDotBeamCooling + this->qDotBeamHeating;
1361 1269984 : }
1362 :
1363 428205 : void HVACFourPipeBeam::update(EnergyPlusData &state) const // update node date elsewhere in EnergyPlus, does not change state of this
1364 : {
1365 428205 : auto &Node(state.dataLoopNodes->Node);
1366 :
1367 : using PlantUtilities::SafeCopyPlantNode;
1368 :
1369 : // Set the outlet air nodes of the unit; note that all quantities are unchanged from inlet to outlet
1370 428205 : Node(this->airOutNodeNum).MassFlowRate = Node(this->airInNodeNum).MassFlowRate;
1371 428205 : Node(this->airOutNodeNum).Temp = Node(this->airInNodeNum).Temp;
1372 428205 : Node(this->airOutNodeNum).HumRat = Node(this->airInNodeNum).HumRat;
1373 428205 : Node(this->airOutNodeNum).Enthalpy = Node(this->airInNodeNum).Enthalpy;
1374 428205 : Node(this->airOutNodeNum).Quality = Node(this->airInNodeNum).Quality;
1375 428205 : Node(this->airOutNodeNum).Press = Node(this->airInNodeNum).Press;
1376 428205 : Node(this->airOutNodeNum).MassFlowRateMin = Node(this->airInNodeNum).MassFlowRateMin;
1377 428205 : Node(this->airOutNodeNum).MassFlowRateMax = Node(this->airInNodeNum).MassFlowRateMax;
1378 428205 : Node(this->airOutNodeNum).MassFlowRateMinAvail = Node(this->airInNodeNum).MassFlowRateMinAvail;
1379 428205 : Node(this->airOutNodeNum).MassFlowRateMaxAvail = Node(this->airInNodeNum).MassFlowRateMaxAvail;
1380 :
1381 428205 : if (state.dataContaminantBalance->Contaminant.CO2Simulation) {
1382 0 : Node(this->airOutNodeNum).CO2 = Node(this->airInNodeNum).CO2;
1383 : }
1384 :
1385 428205 : if (state.dataContaminantBalance->Contaminant.GenericContamSimulation) {
1386 0 : Node(this->airOutNodeNum).GenContam = Node(this->airInNodeNum).GenContam;
1387 : }
1388 :
1389 : // Set the outlet water nodes for the unit
1390 :
1391 428205 : if (this->beamCoolingPresent) {
1392 428205 : SafeCopyPlantNode(state, this->cWInNodeNum, this->cWOutNodeNum);
1393 428205 : Node(this->cWOutNodeNum).Temp = this->cWTempOut;
1394 : }
1395 428205 : if (this->beamHeatingPresent) {
1396 428205 : SafeCopyPlantNode(state, this->hWInNodeNum, this->hWOutNodeNum);
1397 428205 : Node(this->hWOutNodeNum).Temp = this->hWTempOut;
1398 : }
1399 428205 : }
1400 :
1401 428205 : void HVACFourPipeBeam::report(EnergyPlusData &state) // fill out local output variables for reporting
1402 : {
1403 :
1404 : Real64 ReportingConstant;
1405 :
1406 428205 : ReportingConstant = state.dataHVACGlobal->TimeStepSysSec;
1407 :
1408 428205 : if (this->beamCoolingPresent) {
1409 428205 : this->beamCoolingRate = std::abs(this->qDotBeamCooling); // report var has positive sign convention
1410 428205 : this->beamCoolingEnergy = this->beamCoolingRate * ReportingConstant;
1411 : }
1412 428205 : if (this->beamHeatingPresent) {
1413 428205 : this->beamHeatingRate = this->qDotBeamHeating;
1414 428205 : this->beamHeatingEnergy = this->beamHeatingRate * ReportingConstant;
1415 : }
1416 428205 : if (qDotSystemAir <= 0.0) { // cooling
1417 421217 : this->supAirCoolingRate = std::abs(this->qDotSystemAir);
1418 421217 : this->supAirHeatingRate = 0.0;
1419 : } else {
1420 6988 : this->supAirHeatingRate = this->qDotSystemAir;
1421 6988 : this->supAirCoolingRate = 0.0;
1422 : }
1423 428205 : this->supAirCoolingEnergy = this->supAirCoolingRate * ReportingConstant;
1424 428205 : this->supAirHeatingEnergy = this->supAirHeatingRate * ReportingConstant;
1425 :
1426 428205 : this->primAirFlow = this->mDotSystemAir / state.dataEnvrn->StdRhoAir;
1427 :
1428 428205 : this->CalcOutdoorAirVolumeFlowRate(state);
1429 428205 : }
1430 :
1431 428205 : void HVACFourPipeBeam::CalcOutdoorAirVolumeFlowRate(EnergyPlusData &state)
1432 : {
1433 : // calculates zone outdoor air volume flow rate using the supply air flow rate and OA fraction
1434 428205 : if (this->airLoopNum > 0) {
1435 428205 : this->OutdoorAirFlowRate = (state.dataLoopNodes->Node(this->airOutNodeNum).MassFlowRate / state.dataEnvrn->StdRhoAir) *
1436 428205 : state.dataAirLoop->AirLoopFlow(this->airLoopNum).OAFrac;
1437 : } else {
1438 0 : this->OutdoorAirFlowRate = 0.0;
1439 : }
1440 428205 : }
1441 :
1442 30 : void HVACFourPipeBeam::reportTerminalUnit(EnergyPlusData &state)
1443 : {
1444 : // populate the predefined equipment summary report related to air terminals
1445 30 : auto &orp = state.dataOutRptPredefined;
1446 30 : auto &adu = state.dataDefineEquipment->AirDistUnit(this->aDUNum);
1447 30 : if (!state.dataSize->TermUnitFinalZoneSizing.empty()) {
1448 30 : auto &sizing = state.dataSize->TermUnitFinalZoneSizing(adu.TermUnitSizingNum);
1449 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinFlow, adu.Name, sizing.DesCoolVolFlowMin);
1450 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinOutdoorFlow, adu.Name, sizing.MinOA);
1451 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSupCoolingSP, adu.Name, sizing.CoolDesTemp);
1452 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSupHeatingSP, adu.Name, sizing.HeatDesTemp);
1453 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermHeatingCap, adu.Name, sizing.DesHeatLoad);
1454 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermCoolingCap, adu.Name, sizing.DesCoolLoad);
1455 : }
1456 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermTypeInp, adu.Name, "AirTerminal:SingleDuct:ConstantVolume:FourPipeBeam");
1457 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermPrimFlow, adu.Name, this->vDotNormRatedPrimAir);
1458 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermSecdFlow, adu.Name, "n/a");
1459 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinFlowSch, adu.Name, "n/a");
1460 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMaxFlowReh, adu.Name, "n/a");
1461 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermMinOAflowSch, adu.Name, "n/a");
1462 30 : if (this->beamHeatingPresent) {
1463 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermHeatCoilType, adu.Name, "Included");
1464 : } else {
1465 0 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermHeatCoilType, adu.Name, "None");
1466 : }
1467 :
1468 30 : if (this->beamCoolingPresent) {
1469 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermCoolCoilType, adu.Name, "Included");
1470 : } else {
1471 0 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermCoolCoilType, adu.Name, "None");
1472 : }
1473 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermFanType, adu.Name, "n/a");
1474 30 : OutputReportPredefined::PreDefTableEntry(state, orp->pdchAirTermFanName, adu.Name, "n/a");
1475 30 : }
1476 :
1477 : } // namespace FourPipeBeam
1478 :
1479 : } // namespace EnergyPlus
|