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/Autosizing/HeatingCapacitySizing.hh>
57 : #include <EnergyPlus/BaseboardRadiator.hh>
58 : #include <EnergyPlus/BranchNodeConnections.hh>
59 : #include <EnergyPlus/Data/EnergyPlusData.hh>
60 : #include <EnergyPlus/DataHVACGlobals.hh>
61 : #include <EnergyPlus/DataHeatBalance.hh>
62 : #include <EnergyPlus/DataIPShortCuts.hh>
63 : #include <EnergyPlus/DataLoopNode.hh>
64 : #include <EnergyPlus/DataPrecisionGlobals.hh>
65 : #include <EnergyPlus/DataSizing.hh>
66 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
67 : #include <EnergyPlus/DataZoneEquipment.hh>
68 : #include <EnergyPlus/FluidProperties.hh>
69 : #include <EnergyPlus/General.hh>
70 : #include <EnergyPlus/GeneralRoutines.hh>
71 : #include <EnergyPlus/GlobalNames.hh>
72 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
73 : #include <EnergyPlus/NodeInputManager.hh>
74 : #include <EnergyPlus/OutputProcessor.hh>
75 : #include <EnergyPlus/Plant/DataPlant.hh>
76 : #include <EnergyPlus/PlantUtilities.hh>
77 : #include <EnergyPlus/Psychrometrics.hh>
78 : #include <EnergyPlus/ScheduleManager.hh>
79 : #include <EnergyPlus/UtilityRoutines.hh>
80 :
81 : namespace EnergyPlus {
82 : namespace BaseboardRadiator {
83 :
84 : // Module containing the routines dealing with the BASEBOARD HEATER
85 : // component(s).
86 :
87 : // MODULE INFORMATION:
88 : // AUTHOR Russ Taylor
89 : // DATE WRITTEN Jan 1998
90 : // MODIFIED Fred Buhl, October 1999
91 : // RE-ENGINEERED na
92 :
93 : // Using/Aliasing
94 : using DataHVACGlobals::SmallLoad;
95 :
96 : // Use statements for access to subroutines in other modules
97 : using namespace ScheduleManager;
98 : using FluidProperties::GetDensityGlycol;
99 : using FluidProperties::GetSpecificHeatGlycol;
100 : using Psychrometrics::PsyCpAirFnW;
101 : using Psychrometrics::PsyRhoAirFnPbTdbW;
102 :
103 771 : static std::string const cCMO_BBRadiator_Water("ZoneHVAC:Baseboard:Convective:Water");
104 :
105 170169 : void SimBaseboard(EnergyPlusData &state,
106 : std::string const &EquipName,
107 : int const ControlledZoneNum,
108 : bool const FirstHVACIteration,
109 : Real64 &PowerMet,
110 : int &CompIndex)
111 : {
112 :
113 : // SUBROUTINE INFORMATION:
114 : // AUTHOR Russ Taylor
115 : // DATE WRITTEN Nov 1997
116 :
117 : // PURPOSE OF THIS SUBROUTINE:
118 : // This subroutine simulates the Baseboard Radiators.
119 :
120 170169 : if (state.dataBaseboardRadiator->getInputFlag) {
121 9 : GetBaseboardInput(state);
122 9 : state.dataBaseboardRadiator->getInputFlag = false;
123 : }
124 :
125 : // Find the correct Baseboard Equipment
126 170169 : if (CompIndex == 0) {
127 30 : int BaseboardNum = UtilityRoutines::FindItemInList(EquipName, state.dataBaseboardRadiator->baseboards, &BaseboardParams::EquipID);
128 30 : if (BaseboardNum == 0) {
129 0 : ShowFatalError(state, "SimBaseboard: Unit not found=" + EquipName);
130 : }
131 30 : CompIndex = BaseboardNum;
132 : }
133 170169 : assert(CompIndex <= (int)state.dataBaseboardRadiator->baseboards.size());
134 170169 : auto &thisBaseboard = state.dataBaseboardRadiator->baseboards(CompIndex);
135 170169 : if (thisBaseboard.CheckEquipName) {
136 30 : if (EquipName != thisBaseboard.EquipID) {
137 0 : ShowFatalError(state,
138 0 : format("SimBaseboard: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
139 : CompIndex,
140 : EquipName,
141 0 : thisBaseboard.EquipID));
142 : }
143 30 : thisBaseboard.CheckEquipName = false;
144 : }
145 :
146 170169 : thisBaseboard.InitBaseboard(state, CompIndex);
147 :
148 170169 : Real64 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
149 170169 : Real64 MaxWaterFlow = 0.0;
150 170169 : Real64 MinWaterFlow = 0.0;
151 170169 : Real64 DummyMdot = 0.0;
152 :
153 170169 : if ((QZnReq < SmallLoad) || (thisBaseboard.WaterInletTemp <= thisBaseboard.AirInletTemp)) {
154 : // IF (Baseboard(BaseboardNum)%WaterInletTemp <= Baseboard(BaseboardNum)%AirInletTemp) THEN
155 : // The baseboard cannot provide cooling. Thus, if the zone required load is negative or the water inlet
156 : // temperature is lower than the zone air temperature, then we need to shut down the baseboard unit
157 :
158 105913 : thisBaseboard.WaterOutletTemp = thisBaseboard.WaterInletTemp;
159 105913 : thisBaseboard.AirOutletTemp = thisBaseboard.AirInletTemp;
160 105913 : thisBaseboard.Power = 0.0;
161 105913 : thisBaseboard.WaterMassFlowRate = 0.0;
162 : // init hot water flow rate to zero
163 105913 : DummyMdot = 0.0;
164 105913 : PlantUtilities::SetActuatedBranchFlowRate(state, DummyMdot, thisBaseboard.WaterInletNode, thisBaseboard.plantLoc, false);
165 :
166 : } else {
167 : // init hot water flow rate to zero
168 64256 : DummyMdot = 0.0;
169 64256 : PlantUtilities::SetActuatedBranchFlowRate(state, DummyMdot, thisBaseboard.WaterInletNode, thisBaseboard.plantLoc, true);
170 :
171 : // On the first HVAC iteration the system values are given to the controller, but after that
172 : // the demand limits are in place and there needs to be feedback to the Zone Equipment
173 64256 : if (FirstHVACIteration) {
174 32140 : MaxWaterFlow = thisBaseboard.WaterMassFlowRateMax;
175 32140 : MinWaterFlow = 0.0;
176 : } else {
177 32116 : MaxWaterFlow = state.dataLoopNodes->Node(thisBaseboard.WaterInletNode).MassFlowRateMaxAvail;
178 32116 : MinWaterFlow = state.dataLoopNodes->Node(thisBaseboard.WaterInletNode).MassFlowRateMinAvail;
179 : }
180 :
181 64256 : ControlCompOutput(state,
182 : thisBaseboard.EquipID,
183 : cCMO_BBRadiator_Water,
184 : CompIndex,
185 : FirstHVACIteration,
186 : QZnReq,
187 : thisBaseboard.WaterInletNode,
188 : MaxWaterFlow,
189 : MinWaterFlow,
190 : thisBaseboard.Offset,
191 : thisBaseboard.ControlCompTypeNum,
192 : thisBaseboard.CompErrIndex,
193 : _,
194 : _,
195 : _,
196 : _,
197 : _,
198 : thisBaseboard.plantLoc);
199 :
200 64256 : PowerMet = thisBaseboard.Power;
201 : }
202 :
203 170169 : UpdateBaseboard(state, CompIndex);
204 170169 : thisBaseboard.Energy = thisBaseboard.Power * state.dataHVACGlobal->TimeStepSys * DataGlobalConstants::SecInHour;
205 170169 : }
206 :
207 9 : void GetBaseboardInput(EnergyPlusData &state)
208 : {
209 :
210 : // SUBROUTINE INFORMATION:
211 : // AUTHOR Russ Taylor
212 : // DATE WRITTEN Nov 1997
213 :
214 : // PURPOSE OF THIS SUBROUTINE:
215 : // This subroutine gets the input for the Baseboard units.
216 :
217 : // METHODOLOGY EMPLOYED:
218 : // Standard input processor calls.
219 :
220 : // Using/Aliasing
221 : using BranchNodeConnections::TestCompSet;
222 : using NodeInputManager::GetOnlySingleNode;
223 : using namespace DataLoopNode;
224 : using GlobalNames::VerifyUniqueBaseboardName;
225 : using namespace DataSizing;
226 :
227 : // SUBROUTINE PARAMETER DEFINITIONS:
228 : static constexpr std::string_view RoutineName("GetBaseboardInput: "); // include trailing blank space
229 9 : int constexpr iHeatCAPMAlphaNum(5); // get input index to water baseboard Radiator system heating capacity sizing method
230 9 : int constexpr iHeatDesignCapacityNumericNum(1); // get input index to water baseboard Radiator system electric heating capacity
231 9 : int constexpr iHeatCapacityPerFloorAreaNumericNum(
232 : 2); // get input index to water baseboard Radiator system electric heating capacity per floor area sizing
233 9 : int constexpr iHeatFracOfAutosizedCapacityNumericNum(
234 : 3); // get input index to water baseboard Radiator system electric heating capacity sizing as fraction of autozized heating capacity
235 :
236 9 : bool ErrorsFound(false); // If errors detected in input
237 9 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
238 :
239 9 : cCurrentModuleObject = cCMO_BBRadiator_Water;
240 :
241 9 : int NumConvHWBaseboards = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
242 :
243 : // Calculate total number of baseboard units
244 :
245 9 : state.dataBaseboardRadiator->baseboards.allocate(NumConvHWBaseboards);
246 :
247 9 : if (NumConvHWBaseboards > 0) { // Get the data for cooling schemes
248 39 : for (int ConvHWBaseboardNum = 1; ConvHWBaseboardNum <= NumConvHWBaseboards; ++ConvHWBaseboardNum) {
249 30 : int NumAlphas = 0;
250 30 : int NumNums = 0;
251 30 : int IOStat = 0;
252 :
253 210 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
254 : cCurrentModuleObject,
255 : ConvHWBaseboardNum,
256 30 : state.dataIPShortCut->cAlphaArgs,
257 : NumAlphas,
258 30 : state.dataIPShortCut->rNumericArgs,
259 : NumNums,
260 : IOStat,
261 30 : state.dataIPShortCut->lNumericFieldBlanks,
262 30 : state.dataIPShortCut->lAlphaFieldBlanks,
263 30 : state.dataIPShortCut->cAlphaFieldNames,
264 30 : state.dataIPShortCut->cNumericFieldNames);
265 :
266 30 : auto &thisBaseboard = state.dataBaseboardRadiator->baseboards(ConvHWBaseboardNum);
267 30 : thisBaseboard.FieldNames.allocate(NumNums);
268 30 : thisBaseboard.FieldNames = "";
269 30 : thisBaseboard.FieldNames = state.dataIPShortCut->cNumericFieldNames;
270 :
271 30 : if (UtilityRoutines::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound)) {
272 0 : continue;
273 : }
274 :
275 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
276 30 : VerifyUniqueBaseboardName(
277 60 : state, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1), ErrorsFound, cCurrentModuleObject + " Name");
278 :
279 30 : thisBaseboard.EquipID = state.dataIPShortCut->cAlphaArgs(1); // name of this baseboard
280 30 : thisBaseboard.EquipType = DataPlant::PlantEquipmentType::Baseboard_Conv_Water;
281 30 : thisBaseboard.Schedule = state.dataIPShortCut->cAlphaArgs(2);
282 30 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
283 0 : thisBaseboard.SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
284 : } else {
285 30 : thisBaseboard.SchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
286 30 : if (thisBaseboard.SchedPtr == 0) {
287 0 : ShowSevereError(state,
288 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(2) +
289 0 : " entered =" + state.dataIPShortCut->cAlphaArgs(2) + " for " + state.dataIPShortCut->cAlphaFieldNames(1) +
290 0 : '=' + state.dataIPShortCut->cAlphaArgs(1));
291 0 : ErrorsFound = true;
292 : }
293 : }
294 : // get inlet node number
295 30 : thisBaseboard.WaterInletNode = GetOnlySingleNode(state,
296 30 : state.dataIPShortCut->cAlphaArgs(3),
297 : ErrorsFound,
298 : DataLoopNode::ConnectionObjectType::ZoneHVACBaseboardConvectiveWater,
299 30 : state.dataIPShortCut->cAlphaArgs(1),
300 : DataLoopNode::NodeFluidType::Water,
301 : DataLoopNode::ConnectionType::Inlet,
302 : NodeInputManager::CompFluidStream::Primary,
303 30 : ObjectIsNotParent);
304 : // get outlet node number
305 30 : thisBaseboard.WaterOutletNode = GetOnlySingleNode(state,
306 30 : state.dataIPShortCut->cAlphaArgs(4),
307 : ErrorsFound,
308 : DataLoopNode::ConnectionObjectType::ZoneHVACBaseboardConvectiveWater,
309 30 : state.dataIPShortCut->cAlphaArgs(1),
310 : DataLoopNode::NodeFluidType::Water,
311 : DataLoopNode::ConnectionType::Outlet,
312 : NodeInputManager::CompFluidStream::Primary,
313 30 : ObjectIsNotParent);
314 :
315 60 : TestCompSet(state,
316 : cCMO_BBRadiator_Water,
317 30 : state.dataIPShortCut->cAlphaArgs(1),
318 30 : state.dataIPShortCut->cAlphaArgs(3),
319 30 : state.dataIPShortCut->cAlphaArgs(4),
320 : "Hot Water Nodes");
321 :
322 : // Determine steam baseboard radiator system heating design capacity sizing method
323 30 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "HeatingDesignCapacity")) {
324 30 : thisBaseboard.HeatingCapMethod = HeatingDesignCapacity;
325 30 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatDesignCapacityNumericNum)) {
326 30 : thisBaseboard.ScaledHeatingCapacity = state.dataIPShortCut->rNumericArgs(iHeatDesignCapacityNumericNum);
327 30 : if (thisBaseboard.ScaledHeatingCapacity < 0.0 && thisBaseboard.ScaledHeatingCapacity != AutoSize) {
328 0 : ShowSevereError(state, cCMO_BBRadiator_Water + " = " + thisBaseboard.EquipID);
329 0 : ShowContinueError(state,
330 0 : format("Illegal {} = {:.7T}",
331 0 : state.dataIPShortCut->cNumericFieldNames(iHeatDesignCapacityNumericNum),
332 0 : state.dataIPShortCut->rNumericArgs(iHeatDesignCapacityNumericNum)));
333 0 : ErrorsFound = true;
334 : }
335 : } else {
336 0 : ShowSevereError(state, cCMO_BBRadiator_Water + " = " + thisBaseboard.EquipID);
337 0 : ShowContinueError(state,
338 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
339 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
340 0 : ShowContinueError(state,
341 0 : "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(iHeatDesignCapacityNumericNum));
342 0 : ErrorsFound = true;
343 : }
344 0 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "CapacityPerFloorArea")) {
345 0 : thisBaseboard.HeatingCapMethod = CapacityPerFloorArea;
346 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatCapacityPerFloorAreaNumericNum)) {
347 0 : thisBaseboard.ScaledHeatingCapacity = state.dataIPShortCut->rNumericArgs(iHeatCapacityPerFloorAreaNumericNum);
348 0 : if (thisBaseboard.ScaledHeatingCapacity <= 0.0) {
349 0 : ShowSevereError(state, cCMO_BBRadiator_Water + " = " + thisBaseboard.EquipID);
350 0 : ShowContinueError(state,
351 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
352 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
353 0 : ShowContinueError(state,
354 0 : format("Illegal {} = {:.7T}",
355 0 : state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum),
356 0 : state.dataIPShortCut->rNumericArgs(iHeatCapacityPerFloorAreaNumericNum)));
357 0 : ErrorsFound = true;
358 0 : } else if (thisBaseboard.ScaledHeatingCapacity == AutoSize) {
359 0 : ShowSevereError(state, cCMO_BBRadiator_Water + " = " + thisBaseboard.EquipID);
360 0 : ShowContinueError(state,
361 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
362 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
363 0 : ShowContinueError(
364 0 : state, "Illegal " + state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum) + " = Autosize");
365 0 : ErrorsFound = true;
366 : }
367 : } else {
368 0 : ShowSevereError(state, cCMO_BBRadiator_Water + " = " + thisBaseboard.EquipID);
369 0 : ShowContinueError(state,
370 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
371 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
372 0 : ShowContinueError(
373 0 : state, "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum));
374 0 : ErrorsFound = true;
375 : }
376 0 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "FractionOfAutosizedHeatingCapacity")) {
377 0 : thisBaseboard.HeatingCapMethod = FractionOfAutosizedHeatingCapacity;
378 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatFracOfAutosizedCapacityNumericNum)) {
379 0 : thisBaseboard.ScaledHeatingCapacity = state.dataIPShortCut->rNumericArgs(iHeatFracOfAutosizedCapacityNumericNum);
380 0 : if (thisBaseboard.ScaledHeatingCapacity < 0.0) {
381 0 : ShowSevereError(state, cCMO_BBRadiator_Water + " = " + thisBaseboard.EquipID);
382 0 : ShowContinueError(state,
383 0 : format("Illegal {} = {:.7T}",
384 0 : state.dataIPShortCut->cNumericFieldNames(iHeatFracOfAutosizedCapacityNumericNum),
385 0 : state.dataIPShortCut->rNumericArgs(iHeatFracOfAutosizedCapacityNumericNum)));
386 0 : ErrorsFound = true;
387 : }
388 : } else {
389 0 : ShowSevereError(state, cCMO_BBRadiator_Water + " = " + thisBaseboard.EquipID);
390 0 : ShowContinueError(state,
391 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
392 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
393 0 : ShowContinueError(
394 0 : state, "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(iHeatFracOfAutosizedCapacityNumericNum));
395 0 : ErrorsFound = true;
396 : }
397 : } else {
398 0 : ShowSevereError(state, cCMO_BBRadiator_Water + " = " + thisBaseboard.EquipID);
399 0 : ShowContinueError(state,
400 0 : "Illegal " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
401 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
402 0 : ErrorsFound = true;
403 : }
404 :
405 30 : thisBaseboard.UA = state.dataIPShortCut->rNumericArgs(4);
406 30 : thisBaseboard.WaterVolFlowRateMax = state.dataIPShortCut->rNumericArgs(5);
407 30 : thisBaseboard.Offset = state.dataIPShortCut->rNumericArgs(6);
408 : // Set default convergence tolerance
409 30 : if (thisBaseboard.Offset <= 0.0) {
410 5 : thisBaseboard.Offset = 0.001;
411 : }
412 :
413 30 : thisBaseboard.ZonePtr =
414 30 : DataZoneEquipment::GetZoneEquipControlledZoneNum(state, DataZoneEquipment::ZoneEquip::BBWaterConvective, thisBaseboard.EquipID);
415 : }
416 :
417 9 : if (ErrorsFound) {
418 0 : ShowFatalError(state, std::string{RoutineName} + "Errors found in getting input. Preceding condition(s) cause termination.");
419 : }
420 : }
421 :
422 39 : for (int BaseboardNum = 1; BaseboardNum <= NumConvHWBaseboards; ++BaseboardNum) {
423 :
424 : // Setup Report variables for the unit
425 : // CurrentModuleObject='ZoneHVAC:Baseboard:Convective:Water'
426 30 : auto &thisBaseboard = state.dataBaseboardRadiator->baseboards(BaseboardNum);
427 60 : SetupOutputVariable(state,
428 : "Baseboard Total Heating Energy",
429 : OutputProcessor::Unit::J,
430 : thisBaseboard.Energy,
431 : OutputProcessor::SOVTimeStepType::System,
432 : OutputProcessor::SOVStoreType::Summed,
433 : thisBaseboard.EquipID,
434 : _,
435 : "ENERGYTRANSFER",
436 : "BASEBOARD",
437 : _,
438 30 : "System");
439 :
440 60 : SetupOutputVariable(state,
441 : "Baseboard Hot Water Energy",
442 : OutputProcessor::Unit::J,
443 : thisBaseboard.Energy,
444 : OutputProcessor::SOVTimeStepType::System,
445 : OutputProcessor::SOVStoreType::Summed,
446 : thisBaseboard.EquipID,
447 : _,
448 : "PLANTLOOPHEATINGDEMAND",
449 : "BASEBOARD",
450 : _,
451 30 : "System");
452 :
453 60 : SetupOutputVariable(state,
454 : "Baseboard Total Heating Rate",
455 : OutputProcessor::Unit::W,
456 : thisBaseboard.Power,
457 : OutputProcessor::SOVTimeStepType::System,
458 : OutputProcessor::SOVStoreType::Average,
459 30 : thisBaseboard.EquipID);
460 :
461 60 : SetupOutputVariable(state,
462 : "Baseboard Hot Water Mass Flow Rate",
463 : OutputProcessor::Unit::kg_s,
464 : thisBaseboard.WaterMassFlowRate,
465 : OutputProcessor::SOVTimeStepType::System,
466 : OutputProcessor::SOVStoreType::Average,
467 30 : thisBaseboard.EquipID);
468 :
469 60 : SetupOutputVariable(state,
470 : "Baseboard Air Mass Flow Rate",
471 : OutputProcessor::Unit::kg_s,
472 : thisBaseboard.AirMassFlowRate,
473 : OutputProcessor::SOVTimeStepType::System,
474 : OutputProcessor::SOVStoreType::Average,
475 30 : thisBaseboard.EquipID);
476 :
477 60 : SetupOutputVariable(state,
478 : "Baseboard Air Inlet Temperature",
479 : OutputProcessor::Unit::C,
480 : thisBaseboard.AirInletTemp,
481 : OutputProcessor::SOVTimeStepType::System,
482 : OutputProcessor::SOVStoreType::Average,
483 30 : thisBaseboard.EquipID);
484 :
485 60 : SetupOutputVariable(state,
486 : "Baseboard Air Outlet Temperature",
487 : OutputProcessor::Unit::C,
488 : thisBaseboard.AirOutletTemp,
489 : OutputProcessor::SOVTimeStepType::System,
490 : OutputProcessor::SOVStoreType::Average,
491 30 : thisBaseboard.EquipID);
492 :
493 60 : SetupOutputVariable(state,
494 : "Baseboard Water Inlet Temperature",
495 : OutputProcessor::Unit::C,
496 : thisBaseboard.WaterInletTemp,
497 : OutputProcessor::SOVTimeStepType::System,
498 : OutputProcessor::SOVStoreType::Average,
499 30 : thisBaseboard.EquipID);
500 :
501 60 : SetupOutputVariable(state,
502 : "Baseboard Water Outlet Temperature",
503 : OutputProcessor::Unit::C,
504 : thisBaseboard.WaterOutletTemp,
505 : OutputProcessor::SOVTimeStepType::System,
506 : OutputProcessor::SOVStoreType::Average,
507 30 : thisBaseboard.EquipID);
508 : }
509 9 : }
510 :
511 170169 : void BaseboardParams::InitBaseboard(EnergyPlusData &state, int baseboardNum)
512 : {
513 :
514 : // SUBROUTINE INFORMATION:
515 : // AUTHOR Russ Taylor
516 : // DATE WRITTEN Nov 1997
517 :
518 : // PURPOSE OF THIS SUBROUTINE:
519 : // This subroutine initializes the Baseboard units during simulation.
520 :
521 : static constexpr std::string_view RoutineName("BaseboardRadiator:InitBaseboard");
522 :
523 170169 : if (this->SetLoopIndexFlag && allocated(state.dataPlnt->PlantLoop)) {
524 30 : bool errFlag = false;
525 30 : PlantUtilities::ScanPlantLoopsForObject(state, this->EquipID, this->EquipType, this->plantLoc, errFlag, _, _, _, _, _);
526 30 : if (errFlag) {
527 0 : ShowFatalError(state, "InitBaseboard: Program terminated for previous conditions.");
528 : }
529 30 : this->SetLoopIndexFlag = false;
530 : }
531 :
532 170169 : if (!state.dataGlobal->SysSizingCalc && this->MySizeFlag && !this->SetLoopIndexFlag) {
533 : // for each coil, do the sizing once.
534 30 : this->SizeBaseboard(state, baseboardNum);
535 :
536 30 : this->MySizeFlag = false;
537 : }
538 :
539 : // Do the Begin Environment initializations
540 170169 : if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag && !this->SetLoopIndexFlag) {
541 232 : int WaterInletNode = this->WaterInletNode;
542 464 : Real64 rho = GetDensityGlycol(state,
543 232 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
544 : DataGlobalConstants::HWInitConvTemp,
545 232 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
546 232 : RoutineName);
547 232 : this->WaterMassFlowRateMax = rho * this->WaterVolFlowRateMax;
548 232 : PlantUtilities::InitComponentNodes(state, 0.0, this->WaterMassFlowRateMax, this->WaterInletNode, this->WaterOutletNode);
549 232 : state.dataLoopNodes->Node(WaterInletNode).Temp = DataGlobalConstants::HWInitConvTemp;
550 696 : Real64 Cp = GetSpecificHeatGlycol(state,
551 232 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
552 232 : state.dataLoopNodes->Node(WaterInletNode).Temp,
553 232 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
554 232 : RoutineName);
555 232 : state.dataLoopNodes->Node(WaterInletNode).Enthalpy = Cp * state.dataLoopNodes->Node(WaterInletNode).Temp;
556 232 : state.dataLoopNodes->Node(WaterInletNode).Quality = 0.0;
557 232 : state.dataLoopNodes->Node(WaterInletNode).Press = 0.0;
558 232 : state.dataLoopNodes->Node(WaterInletNode).HumRat = 0.0;
559 : // pick a mass flow rate that depends on the max water mass flow rate. CR 8842 changed to factor of 2.0
560 232 : if (this->AirMassFlowRate <= 0.0) {
561 31 : this->AirMassFlowRate = 2.0 * this->WaterMassFlowRateMax;
562 : }
563 232 : this->MyEnvrnFlag = false;
564 : }
565 :
566 170169 : if (!state.dataGlobal->BeginEnvrnFlag) {
567 168862 : this->MyEnvrnFlag = true;
568 : }
569 :
570 : // Do the every time step initializations
571 170169 : int WaterInletNode = this->WaterInletNode;
572 170169 : int ZoneNode = state.dataZoneEquip->ZoneEquipConfig(this->ZonePtr).ZoneNode;
573 170169 : this->WaterMassFlowRate = state.dataLoopNodes->Node(WaterInletNode).MassFlowRate;
574 170169 : this->WaterInletTemp = state.dataLoopNodes->Node(WaterInletNode).Temp;
575 170169 : this->WaterInletEnthalpy = state.dataLoopNodes->Node(WaterInletNode).Enthalpy;
576 170169 : this->AirInletTemp = state.dataLoopNodes->Node(ZoneNode).Temp;
577 170169 : this->AirInletHumRat = state.dataLoopNodes->Node(ZoneNode).HumRat;
578 170169 : }
579 :
580 30 : void BaseboardParams::SizeBaseboard(EnergyPlusData &state, int baseboardNum)
581 : {
582 :
583 : // SUBROUTINE INFORMATION:
584 : // AUTHOR Fred Buhl
585 : // DATE WRITTEN February 2002
586 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
587 : // July 2014, B.Nigusse, added scalable sizing
588 : // RE-ENGINEERED na
589 :
590 : // PURPOSE OF THIS SUBROUTINE:
591 : // This subroutine is for sizing hot water baseboard components for which flow rates and UAs have not been
592 : // specified in the input.
593 :
594 : // METHODOLOGY EMPLOYED:
595 : // Obtains flow rates from the zone sizing arrays and plant sizing data. UAs are
596 : // calculated by numerically inverting the baseboard calculation routine.
597 :
598 : // Using/Aliasing
599 : using namespace DataSizing;
600 : using DataHVACGlobals::HeatingCapacitySizing;
601 :
602 : using PlantUtilities::RegisterPlantCompDesignFlow;
603 :
604 : // SUBROUTINE PARAMETER DEFINITIONS:
605 30 : Real64 constexpr Acc(0.0001); // Accuracy of result
606 30 : int constexpr MaxIte(500); // Maximum number of iterations
607 30 : static std::string const RoutineName(cCMO_BBRadiator_Water + ":SizeBaseboard");
608 :
609 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
610 : int WaterInletNode;
611 30 : int PltSizHeatNum(0); // index of plant sizing object for 1st heating loop
612 30 : Real64 DesCoilLoad(0.0);
613 : int SolFla; // Flag of solver
614 : Real64 UA0; // lower bound for UA
615 : Real64 UA1; // upper bound for UA
616 : Real64 UA;
617 30 : bool ErrorsFound(false); // If errors detected in input
618 : Real64 rho; // local fluid density
619 : Real64 Cp; // local fluid specific heat
620 30 : bool FlowAutoSize(false); // Indicator to autosizing water volume flow
621 30 : bool UAAutoSize(false); // Indicator to autosizing UA
622 30 : Real64 WaterVolFlowRateMaxDes(0.0); // Design water volume flow for reproting
623 30 : Real64 WaterVolFlowRateMaxUser(0.0); // User hard-sized volume flow for reporting
624 30 : Real64 UADes(0.0); // Design UA value for reproting
625 30 : Real64 UAUser(0.0); // User hard-sized value for reporting
626 60 : std::string CompName; // component name
627 60 : std::string CompType; // component type
628 60 : std::string SizingString; // input field sizing description (e.g., Nominal Capacity)
629 : Real64 TempSize; // autosized value of coil input field
630 30 : int FieldNum = 1; // IDD numeric field number where input field description is found
631 : int SizingMethod; // Integer representation of sizing method name (HeatingCapacitySizing)
632 : bool PrintFlag; // TRUE when sizing information is reported in the eio file
633 30 : int CapSizingMethod(0); // capacity sizing methods (HeatingDesignCapacity, CapacityPerFloorArea, and FractionOfAutosizedHeatingCapacity )
634 :
635 30 : auto &ZoneEqSizing(state.dataSize->ZoneEqSizing);
636 30 : auto &CurZoneEqNum(state.dataSize->CurZoneEqNum);
637 30 : auto &FinalZoneSizing(state.dataSize->FinalZoneSizing);
638 30 : auto &DataScalableCapSizingON(state.dataSize->DataScalableCapSizingON);
639 :
640 : // find the appropriate heating Plant Sizing object
641 30 : PltSizHeatNum = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).PlantSizNum;
642 :
643 30 : if (PltSizHeatNum > 0) {
644 :
645 23 : DataScalableCapSizingON = false;
646 :
647 23 : if (CurZoneEqNum > 0) {
648 :
649 23 : if (this->WaterVolFlowRateMax == AutoSize) {
650 23 : FlowAutoSize = true;
651 : }
652 23 : if (!FlowAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation should continue
653 0 : if (this->WaterVolFlowRateMax > 0.0) {
654 0 : BaseSizer::reportSizerOutput(
655 0 : state, cCMO_BBRadiator_Water, this->EquipID, "User-Specified Maximum Water Flow Rate [m3/s]", this->WaterVolFlowRateMax);
656 : }
657 : } else {
658 23 : CheckZoneSizing(state, cCMO_BBRadiator_Water, this->EquipID);
659 23 : CompType = cCMO_BBRadiator_Water;
660 23 : CompName = this->EquipID;
661 23 : state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
662 23 : state.dataSize->DataZoneNumber = this->ZonePtr;
663 23 : SizingMethod = HeatingCapacitySizing;
664 23 : FieldNum = 1;
665 23 : PrintFlag = false;
666 23 : SizingString = this->FieldNames(FieldNum) + " [W]";
667 23 : CapSizingMethod = this->HeatingCapMethod;
668 23 : ZoneEqSizing(CurZoneEqNum).SizingMethod(SizingMethod) = CapSizingMethod;
669 23 : if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
670 : CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
671 :
672 23 : if (CapSizingMethod == HeatingDesignCapacity) {
673 23 : if (this->ScaledHeatingCapacity == AutoSize) {
674 23 : CheckZoneSizing(state, CompType, CompName);
675 23 : ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = FinalZoneSizing(CurZoneEqNum).NonAirSysDesHeatLoad;
676 : } else {
677 0 : ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = this->ScaledHeatingCapacity;
678 : }
679 23 : ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
680 23 : TempSize = ZoneEqSizing(CurZoneEqNum).DesHeatingLoad;
681 0 : } else if (CapSizingMethod == CapacityPerFloorArea) {
682 0 : ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
683 0 : ZoneEqSizing(CurZoneEqNum).DesHeatingLoad =
684 0 : this->ScaledHeatingCapacity * state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
685 0 : TempSize = ZoneEqSizing(CurZoneEqNum).DesHeatingLoad;
686 0 : DataScalableCapSizingON = true;
687 0 : } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
688 0 : CheckZoneSizing(state, CompType, CompName);
689 0 : ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
690 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = this->ScaledHeatingCapacity;
691 0 : ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = FinalZoneSizing(CurZoneEqNum).NonAirSysDesHeatLoad;
692 0 : TempSize = AutoSize;
693 0 : DataScalableCapSizingON = true;
694 : } else {
695 0 : TempSize = this->ScaledHeatingCapacity;
696 : }
697 23 : bool errorsFound = false;
698 46 : HeatingCapacitySizer sizerHeatingCapacity;
699 23 : sizerHeatingCapacity.overrideSizingString(SizingString);
700 23 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
701 23 : DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
702 46 : DataScalableCapSizingON = false;
703 : } else {
704 0 : DesCoilLoad = 0.0;
705 : }
706 :
707 23 : if (DesCoilLoad >= SmallLoad) {
708 69 : Cp = GetSpecificHeatGlycol(state,
709 23 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
710 : DataGlobalConstants::HWInitConvTemp,
711 23 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
712 : RoutineName);
713 69 : rho = GetDensityGlycol(state,
714 23 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
715 : DataGlobalConstants::HWInitConvTemp,
716 23 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
717 : RoutineName);
718 23 : WaterVolFlowRateMaxDes = DesCoilLoad / (state.dataSize->PlantSizData(PltSizHeatNum).DeltaT * Cp * rho);
719 : } else {
720 0 : WaterVolFlowRateMaxDes = 0.0;
721 : }
722 :
723 23 : if (FlowAutoSize) {
724 23 : this->WaterVolFlowRateMax = WaterVolFlowRateMaxDes;
725 46 : BaseSizer::reportSizerOutput(
726 23 : state, cCMO_BBRadiator_Water, this->EquipID, "Design Size Maximum Water Flow Rate [m3/s]", WaterVolFlowRateMaxDes);
727 : } else { // hard-sized with sizing data
728 0 : if (this->WaterVolFlowRateMax > 0.0 && WaterVolFlowRateMaxDes > 0.0) {
729 0 : WaterVolFlowRateMaxUser = this->WaterVolFlowRateMax;
730 0 : BaseSizer::reportSizerOutput(state,
731 : cCMO_BBRadiator_Water,
732 : this->EquipID,
733 : "Design Size Maximum Water Flow Rate [m3/s]",
734 : WaterVolFlowRateMaxDes,
735 : "User-Specified Maximum Water Flow Rate [m3/s]",
736 0 : WaterVolFlowRateMaxUser);
737 : // Report a warning to note difference between the two
738 0 : if (state.dataGlobal->DisplayExtraWarnings) {
739 0 : if ((std::abs(WaterVolFlowRateMaxDes - WaterVolFlowRateMaxUser) / WaterVolFlowRateMaxUser) >
740 0 : state.dataSize->AutoVsHardSizingThreshold) {
741 0 : ShowMessage(state,
742 0 : "SizeBaseboard: Potential issue with equipment sizing for ZoneHVAC:Baseboard:Convective:Water=\"" +
743 0 : this->EquipID + "\".");
744 0 : ShowContinueError(state,
745 0 : format("User-Specified Maximum Water Flow Rate of {:.5R} [m3/s]", WaterVolFlowRateMaxUser));
746 0 : ShowContinueError(
747 0 : state, format("differs from Design Size Maximum Water Flow Rate of {:.5R} [m3/s]", WaterVolFlowRateMaxDes));
748 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
749 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
750 : }
751 : }
752 : }
753 : }
754 : }
755 :
756 : // UA sizing
757 : // Set hard-sized values to the local variable to correct a false indication aftet SolFla function calculation
758 23 : if (this->UA == AutoSize) {
759 23 : UAAutoSize = true;
760 : } else {
761 0 : UAUser = this->UA;
762 : }
763 23 : if (!UAAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation should continue
764 0 : if (this->UA > 0.0) {
765 0 : BaseSizer::reportSizerOutput(
766 0 : state, cCMO_BBRadiator_Water, this->EquipID, "User-Specified U-Factor Times Area Value [W/K]", this->UA);
767 : }
768 : } else {
769 23 : this->WaterInletTemp = state.dataSize->PlantSizData(PltSizHeatNum).ExitTemp;
770 23 : this->AirInletTemp = FinalZoneSizing(CurZoneEqNum).ZoneTempAtHeatPeak;
771 23 : this->AirInletHumRat = FinalZoneSizing(CurZoneEqNum).ZoneHumRatAtHeatPeak;
772 23 : WaterInletNode = this->WaterInletNode;
773 69 : rho = GetDensityGlycol(state,
774 23 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
775 : DataGlobalConstants::HWInitConvTemp,
776 23 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
777 : RoutineName);
778 23 : state.dataLoopNodes->Node(WaterInletNode).MassFlowRate = rho * this->WaterVolFlowRateMax;
779 :
780 23 : CompType = cCMO_BBRadiator_Water;
781 23 : CompName = this->EquipID;
782 23 : state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
783 23 : state.dataSize->DataZoneNumber = this->ZonePtr;
784 23 : SizingMethod = HeatingCapacitySizing;
785 23 : FieldNum = 1;
786 23 : PrintFlag = false;
787 23 : SizingString = this->FieldNames(FieldNum) + " [W]";
788 23 : CapSizingMethod = this->HeatingCapMethod;
789 23 : ZoneEqSizing(CurZoneEqNum).SizingMethod(SizingMethod) = CapSizingMethod;
790 23 : if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
791 : CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
792 23 : if (CapSizingMethod == HeatingDesignCapacity) {
793 23 : if (this->ScaledHeatingCapacity == AutoSize) {
794 23 : CheckZoneSizing(state, CompType, CompName);
795 23 : ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = FinalZoneSizing(CurZoneEqNum).NonAirSysDesHeatLoad;
796 : } else {
797 0 : ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = this->ScaledHeatingCapacity;
798 : }
799 23 : ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
800 23 : TempSize = ZoneEqSizing(CurZoneEqNum).DesHeatingLoad;
801 0 : } else if (CapSizingMethod == CapacityPerFloorArea) {
802 0 : ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
803 0 : ZoneEqSizing(CurZoneEqNum).DesHeatingLoad =
804 0 : this->ScaledHeatingCapacity * state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
805 0 : TempSize = ZoneEqSizing(CurZoneEqNum).DesHeatingLoad;
806 0 : DataScalableCapSizingON = true;
807 0 : } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
808 0 : CheckZoneSizing(state, CompType, CompName);
809 0 : ZoneEqSizing(CurZoneEqNum).HeatingCapacity = true;
810 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = this->ScaledHeatingCapacity;
811 0 : ZoneEqSizing(CurZoneEqNum).DesHeatingLoad = FinalZoneSizing(CurZoneEqNum).NonAirSysDesHeatLoad;
812 0 : TempSize = AutoSize;
813 0 : DataScalableCapSizingON = true;
814 : } else {
815 0 : TempSize = this->ScaledHeatingCapacity;
816 : }
817 23 : bool errorsFound = false;
818 46 : HeatingCapacitySizer sizerHeatingCapacity;
819 23 : sizerHeatingCapacity.overrideSizingString(SizingString);
820 23 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
821 23 : DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
822 46 : DataScalableCapSizingON = false;
823 : } else {
824 0 : DesCoilLoad = 0.0; // FinalZoneSizing(CurZoneEqNum).NonAirSysDesHeatLoad;
825 : }
826 23 : if (DesCoilLoad >= SmallLoad) {
827 : // pick an air mass flow rate that is twice the water mass flow rate (CR8842)
828 23 : this->DesAirMassFlowRate = 2.0 * rho * this->WaterVolFlowRateMax;
829 : // set the lower and upper limits on the UA
830 23 : UA0 = 0.001 * DesCoilLoad;
831 23 : UA1 = DesCoilLoad;
832 :
833 : // before iterating on a design UA check output at lower UA bound
834 23 : this->UA = UA0;
835 23 : Real64 LoadMet = 0.0;
836 23 : SimHWConvective(state, baseboardNum, LoadMet);
837 23 : if (LoadMet < DesCoilLoad) { // baseboard output should be below design load
838 : // now check output at max UA (where UA = design load)
839 23 : this->UA = UA1;
840 23 : SimHWConvective(state, baseboardNum, LoadMet);
841 :
842 23 : if (LoadMet > DesCoilLoad) { // if the load met is greater than design load, OK to iterate on UA
843 : // Invert the baseboard model: given the design inlet conditions and the design load, find the design UA.
844 2093 : auto f = [&state, baseboardNum, DesCoilLoad](Real64 UA) {
845 897 : state.dataBaseboardRadiator->baseboards(baseboardNum).UA = UA;
846 299 : int localBaseBoardNum = baseboardNum;
847 299 : Real64 LoadMet = 0.0;
848 299 : SimHWConvective(state, localBaseBoardNum, LoadMet);
849 598 : return (DesCoilLoad - LoadMet) / DesCoilLoad;
850 23 : };
851 23 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1);
852 : // if the numerical inversion failed, issue error messages.
853 23 : if (SolFla == -1) {
854 0 : ShowSevereError(state,
855 0 : "SizeBaseboard: Autosizing of HW baseboard UA failed for " + cCMO_BBRadiator_Water + "=\"" +
856 0 : this->EquipID + "\"");
857 0 : ShowContinueError(state, "Iteration limit exceeded in calculating coil UA");
858 0 : if (UAAutoSize) {
859 0 : ErrorsFound = true;
860 : } else {
861 0 : ShowContinueError(
862 : state, "Could not calculate design value for comparison to user value, and the simulation continues");
863 0 : UA = 0.0;
864 : }
865 23 : } else if (SolFla == -2) {
866 0 : ShowSevereError(state,
867 0 : "SizeBaseboard: Autosizing of HW baseboard UA failed for " + cCMO_BBRadiator_Water + "=\"" +
868 0 : this->EquipID + "\"");
869 0 : ShowContinueError(state, "Bad starting values for UA");
870 0 : if (UAAutoSize) {
871 0 : ErrorsFound = true;
872 : } else {
873 0 : ShowContinueError(
874 : state, "Could not calculate design value for comparison to user value, and the simulation continues");
875 0 : UA = 0.0;
876 : }
877 : }
878 23 : UADes = UA; // baseboard->baseboards(BaseboardNum)%UA = UA
879 : } else { // baseboard design load is greater than output at UA = design load so set UA = design load
880 0 : UADes = UA1;
881 0 : if (UAAutoSize) {
882 0 : ShowWarningError(state,
883 0 : "SizeBaseboard: Autosizing of HW baseboard UA failed for " + cCMO_BBRadiator_Water + "=\"" +
884 0 : this->EquipID + "\"");
885 0 : ShowContinueError(
886 0 : state, "Design UA set equal to design coil load for " + cCMO_BBRadiator_Water + "=\"" + this->EquipID + "\"");
887 0 : ShowContinueError(state, format("Design coil load used during sizing = {:.5R} W.", DesCoilLoad));
888 0 : ShowContinueError(state, format("Inlet water temperature used during sizing = {:.5R} C.", this->WaterInletTemp));
889 : }
890 : }
891 : } else { // baseboard design load is less than output at UA = 0.001 * design load so set UA to minimum value
892 0 : UADes = UA0;
893 0 : if (UAAutoSize) {
894 0 : ShowWarningError(state,
895 0 : "SizeBaseboard: Autosizing of HW baseboard UA failed for " + cCMO_BBRadiator_Water + "=\"" +
896 0 : this->EquipID + "\"");
897 0 : ShowContinueError(state,
898 0 : "Design UA set equal to 0.001 * design coil load for " + cCMO_BBRadiator_Water + "=\"" +
899 0 : this->EquipID + "\"");
900 0 : ShowContinueError(state, format("Design coil load used during sizing = {:.5R} W.", DesCoilLoad));
901 0 : ShowContinueError(state, format("Inlet water temperature used during sizing = {:.5R} C.", this->WaterInletTemp));
902 : }
903 : }
904 :
905 : } else {
906 0 : UADes = 0.0;
907 : }
908 :
909 23 : if (UAAutoSize) {
910 23 : this->UA = UADes;
911 46 : BaseSizer::reportSizerOutput(
912 23 : state, cCMO_BBRadiator_Water, this->EquipID, "Design Size U-Factor Times Area Value [W/K]", UADes);
913 : } else { // Hard-sized with sizing data
914 0 : this->UA = UAUser; // need to put this back as HWBaseboardUAResidual will have reset it, CR9377
915 0 : if (UAUser > 0.0 && UADes > 0.0) {
916 0 : BaseSizer::reportSizerOutput(state,
917 : cCMO_BBRadiator_Water,
918 : this->EquipID,
919 : "Design Size U-Factor Times Area Value [W/K]",
920 : UADes,
921 : "User-Specified U-Factor Times Area Value [W/K]",
922 0 : UAUser);
923 : // Report difference between design size and hard-sized values
924 0 : if (state.dataGlobal->DisplayExtraWarnings) {
925 0 : if ((std::abs(UADes - UAUser) / UAUser) > state.dataSize->AutoVsHardSizingThreshold) {
926 0 : ShowMessage(state,
927 0 : "SizeBaseboard: Potential issue with equipment sizing for ZoneHVAC:Baseboard:Convective:Water=\"" +
928 0 : this->EquipID + "\".");
929 0 : ShowContinueError(state, format("User-Specified U-Factor Times Area Value of {:.2R} [W/K]", UAUser));
930 0 : ShowContinueError(state, format("differs from Design Size U-Factor Times Area Value of {:.2R} [W/K]", UADes));
931 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
932 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
933 : }
934 : }
935 : }
936 : }
937 : }
938 : }
939 : } else {
940 : // if there is no heating Sizing:Plant object and autosizng was requested, issue an error message
941 7 : if (FlowAutoSize || UAAutoSize) {
942 0 : ShowSevereError(state, "SizeBaseboard: " + cCMO_BBRadiator_Water + "=\"" + this->EquipID + "\"");
943 0 : ShowContinueError(state, "...Autosizing of hot water baseboard requires a heating loop Sizing:Plant object");
944 0 : ErrorsFound = true;
945 : }
946 : }
947 :
948 : // save the design water flow rate for use by the water loop sizing algorithms
949 30 : RegisterPlantCompDesignFlow(state, this->WaterInletNode, this->WaterVolFlowRateMax);
950 :
951 30 : if (ErrorsFound) {
952 0 : ShowFatalError(state, "SizeBaseboard: Preceding sizing errors cause program termination");
953 : }
954 30 : }
955 :
956 729576 : void SimHWConvective(EnergyPlusData &state, int &BaseboardNum, Real64 &LoadMet)
957 : {
958 : // SUBROUTINE INFORMATION:
959 : // AUTHOR Russ Taylor
960 : // DATE WRITTEN Nov 1997
961 : // MODIFIED May 2000 Fred Buhl
962 : // RE-ENGINEERED na
963 :
964 : // PURPOSE OF THIS SUBROUTINE: This subroutine calculates the heat exchange rate
965 : // in a pure convective baseboard heater. The heater is assumed to be crossflow
966 : // with both fluids unmixed. The air flow is buoyancy driven and a constant air
967 : // flow velocity of 0.5m/s is assumed. The solution is by the effectiveness-NTU
968 : // method found in Icropera and DeWitt, Fundamentals of Heat and Mass Transfer,
969 : // Chapter 11.4, p. 523, eq. 11.33
970 :
971 : // REFERENCES:
972 : // Icropera and DeWitt, Fundamentals of Heat and Mass Transfer,
973 : // Chapter 11.4, p. 523, eq. 11.33
974 :
975 : // Using/Aliasing
976 : using namespace DataSizing;
977 : using DataHVACGlobals::SmallLoad;
978 : using PlantUtilities::SetActuatedBranchFlowRate;
979 :
980 : // SUBROUTINE PARAMETER DEFINITIONS:
981 729576 : static std::string const RoutineName(cCMO_BBRadiator_Water + ":SimHWConvective");
982 :
983 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
984 : int ZoneNum;
985 : Real64 WaterInletTemp;
986 : Real64 AirInletTemp;
987 : Real64 CpAir;
988 : Real64 CpWater;
989 : Real64 AirMassFlowRate;
990 : Real64 WaterMassFlowRate;
991 : Real64 CapacitanceAir;
992 : Real64 CapacitanceWater;
993 : Real64 CapacitanceMax;
994 : Real64 CapacitanceMin;
995 : Real64 CapacityRatio;
996 : Real64 NTU;
997 : Real64 Effectiveness;
998 : Real64 WaterOutletTemp;
999 : Real64 AirOutletTemp;
1000 : Real64 AA;
1001 : Real64 BB;
1002 : Real64 CC;
1003 : Real64 QZnReq;
1004 :
1005 729576 : auto &baseboard = state.dataBaseboardRadiator;
1006 :
1007 729576 : ZoneNum = baseboard->baseboards(BaseboardNum).ZonePtr;
1008 729576 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP;
1009 729576 : if (baseboard->baseboards(BaseboardNum).MySizeFlag)
1010 345 : QZnReq = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad; // If in sizing, assign design condition
1011 :
1012 729576 : WaterInletTemp = baseboard->baseboards(BaseboardNum).WaterInletTemp;
1013 729576 : AirInletTemp = baseboard->baseboards(BaseboardNum).AirInletTemp;
1014 :
1015 2188728 : CpWater = GetSpecificHeatGlycol(state,
1016 729576 : state.dataPlnt->PlantLoop(baseboard->baseboards(BaseboardNum).plantLoc.loopNum).FluidName,
1017 : WaterInletTemp,
1018 729576 : state.dataPlnt->PlantLoop(baseboard->baseboards(BaseboardNum).plantLoc.loopNum).FluidIndex,
1019 : RoutineName);
1020 729576 : CpAir = PsyCpAirFnW(baseboard->baseboards(BaseboardNum).AirInletHumRat);
1021 :
1022 729576 : if (baseboard->baseboards(BaseboardNum).DesAirMassFlowRate > 0.0) { // If UA is autosized, assign design condition
1023 512059 : AirMassFlowRate = baseboard->baseboards(BaseboardNum).DesAirMassFlowRate;
1024 : } else {
1025 217517 : AirMassFlowRate = baseboard->baseboards(BaseboardNum).AirMassFlowRate;
1026 : // pick a mass flow rate that depends on the max water mass flow rate. CR 8842 changed to factor of 2.0
1027 217517 : if (AirMassFlowRate <= 0.0) AirMassFlowRate = 2.0 * baseboard->baseboards(BaseboardNum).WaterMassFlowRateMax;
1028 : }
1029 :
1030 729576 : WaterMassFlowRate = state.dataLoopNodes->Node(baseboard->baseboards(BaseboardNum).WaterInletNode).MassFlowRate;
1031 729576 : CapacitanceAir = CpAir * AirMassFlowRate;
1032 :
1033 2185029 : if (QZnReq > SmallLoad && (!state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum) || baseboard->baseboards(BaseboardNum).MySizeFlag) &&
1034 2181330 : (GetCurrentScheduleValue(state, baseboard->baseboards(BaseboardNum).SchedPtr) > 0 || baseboard->baseboards(BaseboardNum).MySizeFlag) &&
1035 725877 : (WaterMassFlowRate > 0.0)) {
1036 662823 : CapacitanceWater = CpWater * WaterMassFlowRate;
1037 662823 : CapacitanceMax = max(CapacitanceAir, CapacitanceWater);
1038 662823 : CapacitanceMin = min(CapacitanceAir, CapacitanceWater);
1039 662823 : CapacityRatio = CapacitanceMin / CapacitanceMax;
1040 662823 : NTU = baseboard->baseboards(BaseboardNum).UA / CapacitanceMin;
1041 : // The effectiveness is given by the following formula:
1042 : // Effectiveness = 1. - EXP((1./CapacityRatio)*(NTU)**0.22*(EXP(-CapacityRatio*(NTU)**0.78)-1.))
1043 : // To prevent possible underflows (numbers smaller than the computer can handle) we must break
1044 : // the calculation up into steps and check the size of the exponential arguments.
1045 662823 : AA = -CapacityRatio * std::pow(NTU, 0.78);
1046 662823 : if (AA < DataPrecisionGlobals::EXP_LowerLimit) {
1047 0 : BB = 0.0;
1048 : } else {
1049 662823 : BB = std::exp(AA);
1050 : }
1051 662823 : CC = (1.0 / CapacityRatio) * std::pow(NTU, 0.22) * (BB - 1.0);
1052 662823 : if (CC < DataPrecisionGlobals::EXP_LowerLimit) {
1053 17293 : Effectiveness = 1.0;
1054 : } else {
1055 645530 : Effectiveness = 1.0 - std::exp(CC);
1056 : }
1057 662823 : AirOutletTemp = AirInletTemp + Effectiveness * CapacitanceMin * (WaterInletTemp - AirInletTemp) / CapacitanceAir;
1058 662823 : WaterOutletTemp = WaterInletTemp - CapacitanceAir * (AirOutletTemp - AirInletTemp) / CapacitanceWater;
1059 662823 : LoadMet = CapacitanceWater * (WaterInletTemp - WaterOutletTemp);
1060 662823 : baseboard->baseboards(BaseboardNum).WaterOutletEnthalpy =
1061 662823 : baseboard->baseboards(BaseboardNum).WaterInletEnthalpy - LoadMet / WaterMassFlowRate;
1062 : } else {
1063 66753 : AirOutletTemp = AirInletTemp;
1064 66753 : WaterOutletTemp = WaterInletTemp;
1065 66753 : LoadMet = 0.0;
1066 66753 : baseboard->baseboards(BaseboardNum).WaterOutletEnthalpy = baseboard->baseboards(BaseboardNum).WaterInletEnthalpy;
1067 66753 : WaterMassFlowRate = 0.0;
1068 :
1069 133506 : SetActuatedBranchFlowRate(
1070 133506 : state, WaterMassFlowRate, baseboard->baseboards(BaseboardNum).WaterInletNode, baseboard->baseboards(BaseboardNum).plantLoc, false);
1071 66753 : AirMassFlowRate = 0.0;
1072 : }
1073 :
1074 729576 : baseboard->baseboards(BaseboardNum).WaterOutletTemp = WaterOutletTemp;
1075 729576 : baseboard->baseboards(BaseboardNum).AirOutletTemp = AirOutletTemp;
1076 729576 : baseboard->baseboards(BaseboardNum).Power = LoadMet;
1077 729576 : baseboard->baseboards(BaseboardNum).WaterMassFlowRate = WaterMassFlowRate;
1078 729576 : baseboard->baseboards(BaseboardNum).AirMassFlowRate = AirMassFlowRate;
1079 729576 : }
1080 :
1081 170169 : void UpdateBaseboard(EnergyPlusData &state, int &BaseboardNum)
1082 : {
1083 :
1084 : // SUBROUTINE INFORMATION:
1085 : // AUTHOR Russ Taylor
1086 : // DATE WRITTEN Nov 1997
1087 : // MODIFIED na
1088 : // RE-ENGINEERED na
1089 :
1090 : // Using/Aliasing
1091 : using PlantUtilities::SafeCopyPlantNode;
1092 :
1093 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1094 : int WaterInletNode;
1095 : int WaterOutletNode;
1096 :
1097 170169 : auto &baseboard = state.dataBaseboardRadiator;
1098 :
1099 170169 : WaterInletNode = baseboard->baseboards(BaseboardNum).WaterInletNode;
1100 170169 : WaterOutletNode = baseboard->baseboards(BaseboardNum).WaterOutletNode;
1101 :
1102 170169 : SafeCopyPlantNode(state, WaterInletNode, WaterOutletNode);
1103 : // Set the outlet air nodes of the Baseboard
1104 : // Set the outlet water nodes for the Coil
1105 170169 : state.dataLoopNodes->Node(WaterOutletNode).Temp = baseboard->baseboards(BaseboardNum).WaterOutletTemp;
1106 170169 : state.dataLoopNodes->Node(WaterOutletNode).Enthalpy = baseboard->baseboards(BaseboardNum).WaterOutletEnthalpy;
1107 170169 : }
1108 :
1109 : } // namespace BaseboardRadiator
1110 :
1111 2313 : } // namespace EnergyPlus
|