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