Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/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 HVAC::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 : static std::string const cCMO_BBRadiator_Water("ZoneHVAC:Baseboard:Convective:Water");
104 :
105 161893 : 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 161893 : if (state.dataBaseboardRadiator->getInputFlag) {
121 9 : GetBaseboardInput(state);
122 9 : state.dataBaseboardRadiator->getInputFlag = false;
123 : }
124 :
125 : // Find the correct Baseboard Equipment
126 161893 : if (CompIndex == 0) {
127 30 : int BaseboardNum = Util::FindItemInList(EquipName, state.dataBaseboardRadiator->baseboards, &BaseboardParams::EquipID);
128 30 : if (BaseboardNum == 0) {
129 0 : ShowFatalError(state, format("SimBaseboard: Unit not found={}", EquipName));
130 : }
131 30 : CompIndex = BaseboardNum;
132 : }
133 161893 : assert(CompIndex <= (int)state.dataBaseboardRadiator->baseboards.size());
134 161893 : auto &thisBaseboard = state.dataBaseboardRadiator->baseboards(CompIndex);
135 161893 : 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 161893 : thisBaseboard.InitBaseboard(state, CompIndex);
147 :
148 161893 : Real64 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ControlledZoneNum).RemainingOutputReqToHeatSP;
149 161893 : Real64 MaxWaterFlow = 0.0;
150 161893 : Real64 MinWaterFlow = 0.0;
151 161893 : Real64 DummyMdot = 0.0;
152 :
153 161893 : 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 97653 : thisBaseboard.WaterOutletTemp = thisBaseboard.WaterInletTemp;
159 97653 : thisBaseboard.AirOutletTemp = thisBaseboard.AirInletTemp;
160 97653 : thisBaseboard.Power = 0.0;
161 97653 : thisBaseboard.WaterMassFlowRate = 0.0;
162 : // init hot water flow rate to zero
163 97653 : DummyMdot = 0.0;
164 97653 : PlantUtilities::SetActuatedBranchFlowRate(state, DummyMdot, thisBaseboard.WaterInletNode, thisBaseboard.plantLoc, false);
165 :
166 : } else {
167 : // init hot water flow rate to zero
168 64240 : DummyMdot = 0.0;
169 64240 : 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 64240 : if (FirstHVACIteration) {
174 32132 : MaxWaterFlow = thisBaseboard.WaterMassFlowRateMax;
175 32132 : MinWaterFlow = 0.0;
176 : } else {
177 32108 : MaxWaterFlow = state.dataLoopNodes->Node(thisBaseboard.WaterInletNode).MassFlowRateMaxAvail;
178 32108 : MinWaterFlow = state.dataLoopNodes->Node(thisBaseboard.WaterInletNode).MassFlowRateMinAvail;
179 : }
180 :
181 192720 : ControlCompOutput(state,
182 64240 : thisBaseboard.EquipID,
183 : cCMO_BBRadiator_Water,
184 : CompIndex,
185 : FirstHVACIteration,
186 : QZnReq,
187 : thisBaseboard.WaterInletNode,
188 : MaxWaterFlow,
189 : MinWaterFlow,
190 : thisBaseboard.Offset,
191 64240 : thisBaseboard.ControlCompTypeNum,
192 64240 : thisBaseboard.CompErrIndex,
193 : _,
194 : _,
195 : _,
196 : _,
197 : _,
198 64240 : thisBaseboard.plantLoc);
199 :
200 64240 : PowerMet = thisBaseboard.Power;
201 : }
202 :
203 161893 : UpdateBaseboard(state, CompIndex);
204 161893 : thisBaseboard.Energy = thisBaseboard.Power * state.dataHVACGlobal->TimeStepSysSec;
205 161893 : }
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 = 2; // index to baseboard Radiator system electric heating capacity per floor area sizing
232 9 : int constexpr iHeatFracOfAutosizedCapacityNumericNum = 3; // index to baseboard heating capacity fraction of autosized heating capacity
233 :
234 9 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
235 :
236 9 : cCurrentModuleObject = cCMO_BBRadiator_Water;
237 :
238 9 : int NumConvHWBaseboards = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
239 :
240 : // Calculate total number of baseboard units
241 :
242 9 : state.dataBaseboardRadiator->baseboards.allocate(NumConvHWBaseboards);
243 :
244 9 : if (NumConvHWBaseboards > 0) { // Get the data for cooling schemes
245 9 : bool ErrorsFound(false); // If errors detected in input
246 39 : for (int ConvHWBaseboardNum = 1; ConvHWBaseboardNum <= NumConvHWBaseboards; ++ConvHWBaseboardNum) {
247 30 : int NumAlphas = 0;
248 30 : int NumNums = 0;
249 30 : int IOStat = 0;
250 :
251 60 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
252 : cCurrentModuleObject,
253 : ConvHWBaseboardNum,
254 30 : state.dataIPShortCut->cAlphaArgs,
255 : NumAlphas,
256 30 : state.dataIPShortCut->rNumericArgs,
257 : NumNums,
258 : IOStat,
259 30 : state.dataIPShortCut->lNumericFieldBlanks,
260 30 : state.dataIPShortCut->lAlphaFieldBlanks,
261 30 : state.dataIPShortCut->cAlphaFieldNames,
262 30 : state.dataIPShortCut->cNumericFieldNames);
263 :
264 30 : auto &thisBaseboard = state.dataBaseboardRadiator->baseboards(ConvHWBaseboardNum);
265 30 : thisBaseboard.FieldNames.allocate(NumNums);
266 30 : thisBaseboard.FieldNames = state.dataIPShortCut->cNumericFieldNames;
267 :
268 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
269 30 : VerifyUniqueBaseboardName(
270 60 : state, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1), ErrorsFound, cCurrentModuleObject + " Name");
271 :
272 30 : thisBaseboard.EquipID = state.dataIPShortCut->cAlphaArgs(1); // name of this baseboard
273 30 : thisBaseboard.EquipType = DataPlant::PlantEquipmentType::Baseboard_Conv_Water;
274 30 : thisBaseboard.Schedule = state.dataIPShortCut->cAlphaArgs(2);
275 30 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
276 0 : thisBaseboard.SchedPtr = ScheduleManager::ScheduleAlwaysOn;
277 : } else {
278 30 : thisBaseboard.SchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
279 30 : if (thisBaseboard.SchedPtr == 0) {
280 0 : ShowSevereError(state,
281 0 : format("{}{}: invalid {} entered ={} for {}={}",
282 : RoutineName,
283 : cCurrentModuleObject,
284 0 : state.dataIPShortCut->cAlphaFieldNames(2),
285 0 : state.dataIPShortCut->cAlphaArgs(2),
286 0 : state.dataIPShortCut->cAlphaFieldNames(1),
287 0 : state.dataIPShortCut->cAlphaArgs(1)));
288 0 : ErrorsFound = true;
289 : }
290 : }
291 : // get inlet node number
292 30 : thisBaseboard.WaterInletNode = GetOnlySingleNode(state,
293 30 : state.dataIPShortCut->cAlphaArgs(3),
294 : ErrorsFound,
295 : DataLoopNode::ConnectionObjectType::ZoneHVACBaseboardConvectiveWater,
296 30 : state.dataIPShortCut->cAlphaArgs(1),
297 : DataLoopNode::NodeFluidType::Water,
298 : DataLoopNode::ConnectionType::Inlet,
299 : NodeInputManager::CompFluidStream::Primary,
300 : ObjectIsNotParent);
301 : // get outlet node number
302 30 : thisBaseboard.WaterOutletNode = GetOnlySingleNode(state,
303 30 : state.dataIPShortCut->cAlphaArgs(4),
304 : ErrorsFound,
305 : DataLoopNode::ConnectionObjectType::ZoneHVACBaseboardConvectiveWater,
306 30 : state.dataIPShortCut->cAlphaArgs(1),
307 : DataLoopNode::NodeFluidType::Water,
308 : DataLoopNode::ConnectionType::Outlet,
309 : NodeInputManager::CompFluidStream::Primary,
310 : ObjectIsNotParent);
311 :
312 60 : TestCompSet(state,
313 : cCMO_BBRadiator_Water,
314 30 : state.dataIPShortCut->cAlphaArgs(1),
315 30 : state.dataIPShortCut->cAlphaArgs(3),
316 30 : state.dataIPShortCut->cAlphaArgs(4),
317 : "Hot Water Nodes");
318 :
319 : // Determine steam baseboard radiator system heating design capacity sizing method
320 30 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "HeatingDesignCapacity")) {
321 30 : thisBaseboard.HeatingCapMethod = HeatingDesignCapacity;
322 30 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatDesignCapacityNumericNum)) {
323 30 : thisBaseboard.ScaledHeatingCapacity = state.dataIPShortCut->rNumericArgs(iHeatDesignCapacityNumericNum);
324 30 : if (thisBaseboard.ScaledHeatingCapacity < 0.0 && thisBaseboard.ScaledHeatingCapacity != AutoSize) {
325 0 : ShowSevereError(state, format("{} = {}", cCMO_BBRadiator_Water, thisBaseboard.EquipID));
326 0 : ShowContinueError(state,
327 0 : format("Illegal {} = {:.7T}",
328 0 : state.dataIPShortCut->cNumericFieldNames(iHeatDesignCapacityNumericNum),
329 0 : state.dataIPShortCut->rNumericArgs(iHeatDesignCapacityNumericNum)));
330 0 : ErrorsFound = true;
331 : }
332 : } else {
333 0 : ShowSevereError(state, format("{} = {}", cCMO_BBRadiator_Water, thisBaseboard.EquipID));
334 0 : ShowContinueError(state,
335 0 : format("Input for {} = {}",
336 0 : state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum),
337 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum)));
338 0 : ShowContinueError(
339 0 : state, format("Blank field not allowed for {}", state.dataIPShortCut->cNumericFieldNames(iHeatDesignCapacityNumericNum)));
340 0 : ErrorsFound = true;
341 : }
342 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "CapacityPerFloorArea")) {
343 0 : thisBaseboard.HeatingCapMethod = CapacityPerFloorArea;
344 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatCapacityPerFloorAreaNumericNum)) {
345 0 : thisBaseboard.ScaledHeatingCapacity = state.dataIPShortCut->rNumericArgs(iHeatCapacityPerFloorAreaNumericNum);
346 0 : if (thisBaseboard.ScaledHeatingCapacity <= 0.0) {
347 0 : ShowSevereError(state, format("{} = {}", cCMO_BBRadiator_Water, thisBaseboard.EquipID));
348 0 : ShowContinueError(state,
349 0 : format("Input for {} = {}",
350 0 : state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum),
351 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum)));
352 0 : ShowContinueError(state,
353 0 : format("Illegal {} = {:.7T}",
354 0 : state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum),
355 0 : state.dataIPShortCut->rNumericArgs(iHeatCapacityPerFloorAreaNumericNum)));
356 0 : ErrorsFound = true;
357 0 : } else if (thisBaseboard.ScaledHeatingCapacity == AutoSize) {
358 0 : ShowSevereError(state, format("{} = {}", cCMO_BBRadiator_Water, thisBaseboard.EquipID));
359 0 : ShowContinueError(state,
360 0 : format("Input for {} = {}",
361 0 : state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum),
362 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum)));
363 0 : ShowContinueError(
364 : state,
365 0 : format("Illegal {} = Autosize", state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum)));
366 0 : ErrorsFound = true;
367 : }
368 : } else {
369 0 : ShowSevereError(state, format("{} = {}", cCMO_BBRadiator_Water, thisBaseboard.EquipID));
370 0 : ShowContinueError(state,
371 0 : format("Input for {} = {}",
372 0 : state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum),
373 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum)));
374 0 : ShowContinueError(
375 : state,
376 0 : format("Blank field not allowed for {}", state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum)));
377 0 : ErrorsFound = true;
378 : }
379 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "FractionOfAutosizedHeatingCapacity")) {
380 0 : thisBaseboard.HeatingCapMethod = FractionOfAutosizedHeatingCapacity;
381 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatFracOfAutosizedCapacityNumericNum)) {
382 0 : thisBaseboard.ScaledHeatingCapacity = state.dataIPShortCut->rNumericArgs(iHeatFracOfAutosizedCapacityNumericNum);
383 0 : if (thisBaseboard.ScaledHeatingCapacity < 0.0) {
384 0 : ShowSevereError(state, format("{} = {}", cCMO_BBRadiator_Water, thisBaseboard.EquipID));
385 0 : ShowContinueError(state,
386 0 : format("Illegal {} = {:.7T}",
387 0 : state.dataIPShortCut->cNumericFieldNames(iHeatFracOfAutosizedCapacityNumericNum),
388 0 : state.dataIPShortCut->rNumericArgs(iHeatFracOfAutosizedCapacityNumericNum)));
389 0 : ErrorsFound = true;
390 : }
391 : } else {
392 0 : ShowSevereError(state, format("{} = {}", cCMO_BBRadiator_Water, thisBaseboard.EquipID));
393 0 : ShowContinueError(state,
394 0 : format("Input for {} = {}",
395 0 : state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum),
396 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum)));
397 0 : ShowContinueError(state,
398 0 : format("Blank field not allowed for {}",
399 0 : state.dataIPShortCut->cNumericFieldNames(iHeatFracOfAutosizedCapacityNumericNum)));
400 0 : ErrorsFound = true;
401 : }
402 : } else {
403 0 : ShowSevereError(state, format("{} = {}", cCMO_BBRadiator_Water, thisBaseboard.EquipID));
404 0 : ShowContinueError(state,
405 0 : format("Illegal {} = {}",
406 0 : state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum),
407 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum)));
408 0 : ErrorsFound = true;
409 : }
410 :
411 30 : thisBaseboard.UA = state.dataIPShortCut->rNumericArgs(4);
412 30 : thisBaseboard.WaterVolFlowRateMax = state.dataIPShortCut->rNumericArgs(5);
413 30 : thisBaseboard.Offset = state.dataIPShortCut->rNumericArgs(6);
414 : // Set default convergence tolerance
415 30 : if (thisBaseboard.Offset <= 0.0) {
416 0 : thisBaseboard.Offset = 0.001;
417 : }
418 :
419 30 : thisBaseboard.ZonePtr = DataZoneEquipment::GetZoneEquipControlledZoneNum(
420 30 : state, DataZoneEquipment::ZoneEquipType::BaseboardConvectiveWater, thisBaseboard.EquipID);
421 : }
422 :
423 9 : if (ErrorsFound) {
424 0 : ShowFatalError(state, format("{}Errors found in getting input. Preceding condition(s) cause termination.", RoutineName));
425 : }
426 : }
427 :
428 39 : for (int BaseboardNum = 1; BaseboardNum <= NumConvHWBaseboards; ++BaseboardNum) {
429 :
430 : // Setup Report variables for the unit
431 : // CurrentModuleObject='ZoneHVAC:Baseboard:Convective:Water'
432 30 : auto &thisBaseboard = state.dataBaseboardRadiator->baseboards(BaseboardNum);
433 60 : SetupOutputVariable(state,
434 : "Baseboard Total Heating Energy",
435 : Constant::Units::J,
436 30 : thisBaseboard.Energy,
437 : OutputProcessor::TimeStepType::System,
438 : OutputProcessor::StoreType::Sum,
439 30 : thisBaseboard.EquipID,
440 : Constant::eResource::EnergyTransfer,
441 : OutputProcessor::Group::HVAC,
442 : OutputProcessor::EndUseCat::Baseboard);
443 :
444 60 : SetupOutputVariable(state,
445 : "Baseboard Hot Water Energy",
446 : Constant::Units::J,
447 30 : thisBaseboard.Energy,
448 : OutputProcessor::TimeStepType::System,
449 : OutputProcessor::StoreType::Sum,
450 30 : thisBaseboard.EquipID,
451 : Constant::eResource::PlantLoopHeatingDemand,
452 : OutputProcessor::Group::HVAC,
453 : OutputProcessor::EndUseCat::Baseboard);
454 :
455 60 : SetupOutputVariable(state,
456 : "Baseboard Total Heating Rate",
457 : Constant::Units::W,
458 30 : thisBaseboard.Power,
459 : OutputProcessor::TimeStepType::System,
460 : OutputProcessor::StoreType::Average,
461 30 : thisBaseboard.EquipID);
462 :
463 60 : SetupOutputVariable(state,
464 : "Baseboard Hot Water Mass Flow Rate",
465 : Constant::Units::kg_s,
466 30 : thisBaseboard.WaterMassFlowRate,
467 : OutputProcessor::TimeStepType::System,
468 : OutputProcessor::StoreType::Average,
469 30 : thisBaseboard.EquipID);
470 :
471 60 : SetupOutputVariable(state,
472 : "Baseboard Air Mass Flow Rate",
473 : Constant::Units::kg_s,
474 30 : thisBaseboard.AirMassFlowRate,
475 : OutputProcessor::TimeStepType::System,
476 : OutputProcessor::StoreType::Average,
477 30 : thisBaseboard.EquipID);
478 :
479 60 : SetupOutputVariable(state,
480 : "Baseboard Air Inlet Temperature",
481 : Constant::Units::C,
482 30 : thisBaseboard.AirInletTemp,
483 : OutputProcessor::TimeStepType::System,
484 : OutputProcessor::StoreType::Average,
485 30 : thisBaseboard.EquipID);
486 :
487 60 : SetupOutputVariable(state,
488 : "Baseboard Air Outlet Temperature",
489 : Constant::Units::C,
490 30 : thisBaseboard.AirOutletTemp,
491 : OutputProcessor::TimeStepType::System,
492 : OutputProcessor::StoreType::Average,
493 30 : thisBaseboard.EquipID);
494 :
495 60 : SetupOutputVariable(state,
496 : "Baseboard Water Inlet Temperature",
497 : Constant::Units::C,
498 30 : thisBaseboard.WaterInletTemp,
499 : OutputProcessor::TimeStepType::System,
500 : OutputProcessor::StoreType::Average,
501 30 : thisBaseboard.EquipID);
502 :
503 60 : SetupOutputVariable(state,
504 : "Baseboard Water Outlet Temperature",
505 : Constant::Units::C,
506 30 : thisBaseboard.WaterOutletTemp,
507 : OutputProcessor::TimeStepType::System,
508 : OutputProcessor::StoreType::Average,
509 30 : thisBaseboard.EquipID);
510 : }
511 9 : }
512 :
513 161893 : void BaseboardParams::InitBaseboard(EnergyPlusData &state, int baseboardNum)
514 : {
515 :
516 : // SUBROUTINE INFORMATION:
517 : // AUTHOR Russ Taylor
518 : // DATE WRITTEN Nov 1997
519 :
520 : // PURPOSE OF THIS SUBROUTINE:
521 : // This subroutine initializes the Baseboard units during simulation.
522 :
523 : static constexpr std::string_view RoutineName = "BaseboardRadiator:InitBaseboard";
524 :
525 161893 : if (this->SetLoopIndexFlag && allocated(state.dataPlnt->PlantLoop)) {
526 30 : bool errFlag = false;
527 30 : PlantUtilities::ScanPlantLoopsForObject(state, this->EquipID, this->EquipType, this->plantLoc, errFlag, _, _, _, _, _);
528 30 : if (errFlag) {
529 0 : ShowFatalError(state, "InitBaseboard: Program terminated for previous conditions.");
530 : }
531 30 : this->SetLoopIndexFlag = false;
532 : }
533 :
534 161893 : if (!state.dataGlobal->SysSizingCalc && this->MySizeFlag && !this->SetLoopIndexFlag) {
535 : // for each coil, do the sizing once.
536 30 : this->SizeBaseboard(state, baseboardNum);
537 :
538 30 : this->MySizeFlag = false;
539 : }
540 :
541 : // Do the Begin Environment initializations
542 161893 : if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag && !this->SetLoopIndexFlag) {
543 232 : int WaterInletNode = this->WaterInletNode;
544 232 : Real64 rho = GetDensityGlycol(state,
545 232 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
546 : Constant::HWInitConvTemp,
547 232 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
548 : RoutineName);
549 232 : this->WaterMassFlowRateMax = rho * this->WaterVolFlowRateMax;
550 232 : PlantUtilities::InitComponentNodes(state, 0.0, this->WaterMassFlowRateMax, this->WaterInletNode, this->WaterOutletNode);
551 232 : state.dataLoopNodes->Node(WaterInletNode).Temp = Constant::HWInitConvTemp;
552 232 : Real64 Cp = GetSpecificHeatGlycol(state,
553 232 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
554 232 : state.dataLoopNodes->Node(WaterInletNode).Temp,
555 232 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
556 : RoutineName);
557 232 : state.dataLoopNodes->Node(WaterInletNode).Enthalpy = Cp * state.dataLoopNodes->Node(WaterInletNode).Temp;
558 232 : state.dataLoopNodes->Node(WaterInletNode).Quality = 0.0;
559 232 : state.dataLoopNodes->Node(WaterInletNode).Press = 0.0;
560 232 : state.dataLoopNodes->Node(WaterInletNode).HumRat = 0.0;
561 : // pick a mass flow rate that depends on the max water mass flow rate. CR 8842 changed to factor of 2.0
562 232 : if (this->AirMassFlowRate <= 0.0) {
563 31 : this->AirMassFlowRate = 2.0 * this->WaterMassFlowRateMax;
564 : }
565 232 : this->MyEnvrnFlag = false;
566 : }
567 :
568 161893 : if (!state.dataGlobal->BeginEnvrnFlag) {
569 160586 : this->MyEnvrnFlag = true;
570 : }
571 :
572 : // Do the every time step initializations
573 161893 : int WaterInletNode = this->WaterInletNode;
574 161893 : int ZoneNode = state.dataZoneEquip->ZoneEquipConfig(this->ZonePtr).ZoneNode;
575 161893 : this->WaterMassFlowRate = state.dataLoopNodes->Node(WaterInletNode).MassFlowRate;
576 161893 : this->WaterInletTemp = state.dataLoopNodes->Node(WaterInletNode).Temp;
577 161893 : this->WaterInletEnthalpy = state.dataLoopNodes->Node(WaterInletNode).Enthalpy;
578 161893 : this->AirInletTemp = state.dataLoopNodes->Node(ZoneNode).Temp;
579 161893 : this->AirInletHumRat = state.dataLoopNodes->Node(ZoneNode).HumRat;
580 161893 : }
581 :
582 30 : void BaseboardParams::SizeBaseboard(EnergyPlusData &state, int baseboardNum)
583 : {
584 :
585 : // SUBROUTINE INFORMATION:
586 : // AUTHOR Fred Buhl
587 : // DATE WRITTEN February 2002
588 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
589 : // July 2014, B.Nigusse, added scalable sizing
590 :
591 : // PURPOSE OF THIS SUBROUTINE:
592 : // This subroutine is for sizing hot water baseboard components for which flow rates and UAs have not been
593 : // specified in the input.
594 :
595 : // METHODOLOGY EMPLOYED:
596 : // Obtains flow rates from the zone sizing arrays and plant sizing data. UAs are
597 : // calculated by numerically inverting the baseboard calculation routine.
598 :
599 : // SUBROUTINE PARAMETER DEFINITIONS:
600 30 : Real64 constexpr Acc = 0.0001; // Accuracy of result
601 30 : int constexpr MaxIte = 500; // Maximum number of iterations
602 30 : static std::string const RoutineName = cCMO_BBRadiator_Water + ":SizeBaseboard";
603 :
604 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
605 30 : Real64 DesCoilLoad(0.0);
606 : Real64 UA0; // lower bound for UA
607 : Real64 UA1; // upper bound for UA
608 : Real64 UA;
609 30 : bool ErrorsFound(false); // If errors detected in input
610 : Real64 rho; // local fluid density
611 : Real64 Cp; // local fluid specific heat
612 30 : Real64 WaterVolFlowRateMaxDes(0.0); // Design water volume flow for reproting
613 30 : Real64 WaterVolFlowRateMaxUser(0.0); // User hard-sized volume flow for reporting
614 30 : Real64 UADes(0.0); // Design UA value for reproting
615 30 : Real64 UAUser(0.0); // User hard-sized value for reporting
616 : Real64 TempSize; // autosized value of coil input field
617 :
618 : // find the appropriate heating Plant Sizing object
619 30 : int PltSizHeatNum = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).PlantSizNum;
620 :
621 30 : if (PltSizHeatNum > 0) {
622 :
623 23 : state.dataSize->DataScalableCapSizingON = false;
624 :
625 23 : if (state.dataSize->CurZoneEqNum > 0) {
626 23 : auto &zoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
627 23 : auto const &finalZoneSizing = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum);
628 23 : bool FlowAutoSize = false; // Indicator to autosizing water volume flow
629 :
630 23 : if (this->WaterVolFlowRateMax == DataSizing::AutoSize) {
631 23 : FlowAutoSize = true;
632 : }
633 23 : if (!FlowAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation should continue
634 0 : if (this->WaterVolFlowRateMax > 0.0) {
635 0 : BaseSizer::reportSizerOutput(
636 : state, cCMO_BBRadiator_Water, this->EquipID, "User-Specified Maximum Water Flow Rate [m3/s]", this->WaterVolFlowRateMax);
637 : }
638 : } else {
639 23 : CheckZoneSizing(state, cCMO_BBRadiator_Water, this->EquipID);
640 23 : std::string_view const CompType = cCMO_BBRadiator_Water;
641 23 : std::string_view const CompName = this->EquipID;
642 23 : state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
643 23 : state.dataSize->DataZoneNumber = this->ZonePtr;
644 23 : int SizingMethod = HVAC::HeatingCapacitySizing;
645 23 : int FieldNum = 1;
646 23 : std::string const SizingString = format("{} [W]", this->FieldNames(FieldNum));
647 23 : int CapSizingMethod = this->HeatingCapMethod;
648 23 : zoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
649 23 : if (CapSizingMethod == DataSizing::HeatingDesignCapacity || CapSizingMethod == DataSizing::CapacityPerFloorArea ||
650 : CapSizingMethod == DataSizing::FractionOfAutosizedHeatingCapacity) {
651 :
652 23 : if (CapSizingMethod == DataSizing::HeatingDesignCapacity) {
653 23 : if (this->ScaledHeatingCapacity == DataSizing::AutoSize) {
654 23 : CheckZoneSizing(state, CompType, CompName);
655 23 : zoneEqSizing.DesHeatingLoad = finalZoneSizing.NonAirSysDesHeatLoad;
656 : } else {
657 0 : zoneEqSizing.DesHeatingLoad = this->ScaledHeatingCapacity;
658 : }
659 23 : zoneEqSizing.HeatingCapacity = true;
660 23 : TempSize = zoneEqSizing.DesHeatingLoad;
661 0 : } else if (CapSizingMethod == DataSizing::CapacityPerFloorArea) {
662 0 : zoneEqSizing.HeatingCapacity = true;
663 0 : zoneEqSizing.DesHeatingLoad =
664 0 : this->ScaledHeatingCapacity * state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
665 0 : TempSize = zoneEqSizing.DesHeatingLoad;
666 0 : state.dataSize->DataScalableCapSizingON = true;
667 0 : } else if (CapSizingMethod == DataSizing::FractionOfAutosizedHeatingCapacity) {
668 0 : CheckZoneSizing(state, CompType, CompName);
669 0 : zoneEqSizing.HeatingCapacity = true;
670 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = this->ScaledHeatingCapacity;
671 0 : zoneEqSizing.DesHeatingLoad = finalZoneSizing.NonAirSysDesHeatLoad;
672 0 : TempSize = DataSizing::AutoSize;
673 0 : state.dataSize->DataScalableCapSizingON = true;
674 : } else {
675 0 : TempSize = this->ScaledHeatingCapacity;
676 : }
677 23 : bool PrintFlag = false; // TRUE when sizing information is reported in the eio file
678 23 : bool errorsFound = false;
679 23 : HeatingCapacitySizer sizerHeatingCapacity;
680 23 : sizerHeatingCapacity.overrideSizingString(SizingString);
681 23 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
682 23 : DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
683 23 : state.dataSize->DataScalableCapSizingON = false;
684 23 : } else {
685 0 : DesCoilLoad = 0.0;
686 : }
687 :
688 23 : if (DesCoilLoad >= SmallLoad) {
689 46 : Cp = GetSpecificHeatGlycol(state,
690 23 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
691 : Constant::HWInitConvTemp,
692 23 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
693 : RoutineName);
694 46 : rho = GetDensityGlycol(state,
695 23 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
696 : Constant::HWInitConvTemp,
697 23 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
698 : RoutineName);
699 23 : WaterVolFlowRateMaxDes = DesCoilLoad / (state.dataSize->PlantSizData(PltSizHeatNum).DeltaT * Cp * rho);
700 : } else {
701 0 : WaterVolFlowRateMaxDes = 0.0;
702 : }
703 :
704 23 : if (FlowAutoSize) {
705 23 : this->WaterVolFlowRateMax = WaterVolFlowRateMaxDes;
706 23 : BaseSizer::reportSizerOutput(
707 : state, cCMO_BBRadiator_Water, this->EquipID, "Design Size Maximum Water Flow Rate [m3/s]", WaterVolFlowRateMaxDes);
708 : } else { // hard-sized with sizing data
709 0 : if (this->WaterVolFlowRateMax > 0.0 && WaterVolFlowRateMaxDes > 0.0) {
710 0 : WaterVolFlowRateMaxUser = this->WaterVolFlowRateMax;
711 0 : BaseSizer::reportSizerOutput(state,
712 : cCMO_BBRadiator_Water,
713 : this->EquipID,
714 : "Design Size Maximum Water Flow Rate [m3/s]",
715 : WaterVolFlowRateMaxDes,
716 : "User-Specified Maximum Water Flow Rate [m3/s]",
717 : WaterVolFlowRateMaxUser);
718 : // Report a warning to note difference between the two
719 0 : if (state.dataGlobal->DisplayExtraWarnings) {
720 0 : if ((std::abs(WaterVolFlowRateMaxDes - WaterVolFlowRateMaxUser) / WaterVolFlowRateMaxUser) >
721 0 : state.dataSize->AutoVsHardSizingThreshold) {
722 0 : ShowMessage(
723 : state,
724 0 : format("SizeBaseboard: Potential issue with equipment sizing for ZoneHVAC:Baseboard:Convective:Water=\"{}\".",
725 0 : this->EquipID));
726 0 : ShowContinueError(state,
727 0 : format("User-Specified Maximum Water Flow Rate of {:.5R} [m3/s]", WaterVolFlowRateMaxUser));
728 0 : ShowContinueError(
729 0 : state, format("differs from Design Size Maximum Water Flow Rate of {:.5R} [m3/s]", WaterVolFlowRateMaxDes));
730 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
731 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
732 : }
733 : }
734 : }
735 : }
736 23 : }
737 :
738 : // UA sizing
739 23 : bool UAAutoSize = false; // Indicator to autosizing UA
740 : // Set hard-sized values to the local variable to correct a false indication aftet SolFla function calculation
741 23 : if (this->UA == DataSizing::AutoSize) {
742 23 : UAAutoSize = true;
743 : } else {
744 0 : UAUser = this->UA;
745 : }
746 23 : if (!UAAutoSize && !state.dataSize->ZoneSizingRunDone) { // Simulation should continue
747 0 : if (this->UA > 0.0) {
748 0 : BaseSizer::reportSizerOutput(
749 : state, cCMO_BBRadiator_Water, this->EquipID, "User-Specified U-Factor Times Area Value [W/K]", this->UA);
750 : }
751 : } else {
752 23 : this->WaterInletTemp = state.dataSize->PlantSizData(PltSizHeatNum).ExitTemp;
753 23 : this->AirInletTemp = finalZoneSizing.ZoneTempAtHeatPeak;
754 23 : this->AirInletHumRat = finalZoneSizing.ZoneHumRatAtHeatPeak;
755 46 : rho = GetDensityGlycol(state,
756 23 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidName,
757 : Constant::HWInitConvTemp,
758 23 : state.dataPlnt->PlantLoop(this->plantLoc.loopNum).FluidIndex,
759 : RoutineName);
760 23 : state.dataLoopNodes->Node(this->WaterInletNode).MassFlowRate = rho * this->WaterVolFlowRateMax;
761 :
762 23 : std::string_view const CompType = cCMO_BBRadiator_Water;
763 23 : std::string_view const CompName = this->EquipID;
764 23 : state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
765 23 : state.dataSize->DataZoneNumber = this->ZonePtr;
766 23 : int SizingMethod = HVAC::HeatingCapacitySizing;
767 23 : int FieldNum = 1;
768 23 : std::string const SizingString = format("{} [W]", this->FieldNames(FieldNum));
769 23 : int CapSizingMethod = this->HeatingCapMethod;
770 23 : zoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
771 23 : if (CapSizingMethod == DataSizing::HeatingDesignCapacity || CapSizingMethod == DataSizing::CapacityPerFloorArea ||
772 : CapSizingMethod == DataSizing::FractionOfAutosizedHeatingCapacity) {
773 23 : if (CapSizingMethod == DataSizing::HeatingDesignCapacity) {
774 23 : if (this->ScaledHeatingCapacity == DataSizing::AutoSize) {
775 23 : CheckZoneSizing(state, CompType, CompName);
776 23 : zoneEqSizing.DesHeatingLoad = finalZoneSizing.NonAirSysDesHeatLoad;
777 : } else {
778 0 : zoneEqSizing.DesHeatingLoad = this->ScaledHeatingCapacity;
779 : }
780 23 : zoneEqSizing.HeatingCapacity = true;
781 23 : TempSize = zoneEqSizing.DesHeatingLoad;
782 0 : } else if (CapSizingMethod == DataSizing::CapacityPerFloorArea) {
783 0 : zoneEqSizing.HeatingCapacity = true;
784 0 : zoneEqSizing.DesHeatingLoad =
785 0 : this->ScaledHeatingCapacity * state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
786 0 : TempSize = zoneEqSizing.DesHeatingLoad;
787 0 : state.dataSize->DataScalableCapSizingON = true;
788 0 : } else if (CapSizingMethod == DataSizing::FractionOfAutosizedHeatingCapacity) {
789 0 : CheckZoneSizing(state, CompType, CompName);
790 0 : zoneEqSizing.HeatingCapacity = true;
791 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = this->ScaledHeatingCapacity;
792 0 : zoneEqSizing.DesHeatingLoad = finalZoneSizing.NonAirSysDesHeatLoad;
793 0 : TempSize = DataSizing::AutoSize;
794 0 : state.dataSize->DataScalableCapSizingON = true;
795 : } else {
796 0 : TempSize = this->ScaledHeatingCapacity;
797 : }
798 23 : bool PrintFlag = false;
799 23 : bool errorsFound = false;
800 23 : HeatingCapacitySizer sizerHeatingCapacity;
801 23 : sizerHeatingCapacity.overrideSizingString(SizingString);
802 23 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
803 23 : DesCoilLoad = sizerHeatingCapacity.size(state, TempSize, errorsFound);
804 23 : state.dataSize->DataScalableCapSizingON = false;
805 23 : } else {
806 0 : DesCoilLoad = 0.0; // FinalZoneSizing(CurZoneEqNum).NonAirSysDesHeatLoad;
807 : }
808 23 : if (DesCoilLoad >= SmallLoad) {
809 : // pick an air mass flow rate that is twice the water mass flow rate (CR8842)
810 23 : this->DesAirMassFlowRate = 2.0 * rho * this->WaterVolFlowRateMax;
811 : // set the lower and upper limits on the UA
812 23 : UA0 = 0.001 * DesCoilLoad;
813 23 : UA1 = DesCoilLoad;
814 :
815 : // before iterating on a design UA check output at lower UA bound
816 23 : this->UA = UA0;
817 23 : Real64 LoadMet = 0.0;
818 23 : SimHWConvective(state, baseboardNum, LoadMet);
819 23 : if (LoadMet < DesCoilLoad) { // baseboard output should be below design load
820 : // now check output at max UA (where UA = design load)
821 23 : this->UA = UA1;
822 23 : SimHWConvective(state, baseboardNum, LoadMet);
823 :
824 23 : if (LoadMet > DesCoilLoad) { // if the load met is greater than design load, OK to iterate on UA
825 : // Invert the baseboard model: given the design inlet conditions and the design load, find the design UA.
826 1196 : auto f = [&state, baseboardNum, DesCoilLoad](Real64 UA) {
827 299 : state.dataBaseboardRadiator->baseboards(baseboardNum).UA = UA;
828 299 : int localBaseBoardNum = baseboardNum;
829 299 : Real64 LoadMet = 0.0;
830 299 : SimHWConvective(state, localBaseBoardNum, LoadMet);
831 299 : return (DesCoilLoad - LoadMet) / DesCoilLoad;
832 23 : };
833 23 : int SolFla = 0;
834 23 : General::SolveRoot(state, Acc, MaxIte, SolFla, UA, f, UA0, UA1);
835 : // if the numerical inversion failed, issue error messages.
836 23 : if (SolFla == -1) {
837 0 : ShowSevereError(state,
838 0 : format("SizeBaseboard: Autosizing of HW baseboard UA failed for {}=\"{}\"",
839 : cCMO_BBRadiator_Water,
840 0 : this->EquipID));
841 0 : ShowContinueError(state, "Iteration limit exceeded in calculating coil UA");
842 0 : if (UAAutoSize) {
843 0 : ErrorsFound = true;
844 : } else {
845 0 : ShowContinueError(
846 : state, "Could not calculate design value for comparison to user value, and the simulation continues");
847 0 : UA = 0.0;
848 : }
849 23 : } else if (SolFla == -2) {
850 0 : ShowSevereError(state,
851 0 : format("SizeBaseboard: Autosizing of HW baseboard UA failed for {}=\"{}\"",
852 : cCMO_BBRadiator_Water,
853 0 : this->EquipID));
854 0 : ShowContinueError(state, "Bad starting values for UA");
855 0 : if (UAAutoSize) {
856 0 : ErrorsFound = true;
857 : } else {
858 0 : ShowContinueError(
859 : state, "Could not calculate design value for comparison to user value, and the simulation continues");
860 0 : UA = 0.0;
861 : }
862 : }
863 23 : UADes = UA; // baseboard->baseboards(BaseboardNum)%UA = UA
864 : } else { // baseboard design load is greater than output at UA = design load so set UA = design load
865 0 : UADes = UA1;
866 0 : if (UAAutoSize) {
867 0 : ShowWarningError(state,
868 0 : format("SizeBaseboard: Autosizing of HW baseboard UA failed for {}=\"{}\"",
869 : cCMO_BBRadiator_Water,
870 0 : this->EquipID));
871 0 : ShowContinueError(
872 0 : state, format("Design UA set equal to design coil load for {}=\"{}\"", cCMO_BBRadiator_Water, this->EquipID));
873 0 : ShowContinueError(state, format("Design coil load used during sizing = {:.5R} W.", DesCoilLoad));
874 0 : ShowContinueError(state, format("Inlet water temperature used during sizing = {:.5R} C.", this->WaterInletTemp));
875 : }
876 : }
877 : } else { // baseboard design load is less than output at UA = 0.001 * design load so set UA to minimum value
878 0 : UADes = UA0;
879 0 : if (UAAutoSize) {
880 0 : ShowWarningError(state,
881 0 : format("SizeBaseboard: Autosizing of HW baseboard UA failed for {}=\"{}\"",
882 : cCMO_BBRadiator_Water,
883 0 : this->EquipID));
884 0 : ShowContinueError(
885 : state,
886 0 : format("Design UA set equal to 0.001 * 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 :
892 : } else {
893 0 : UADes = 0.0;
894 : }
895 :
896 23 : if (UAAutoSize) {
897 23 : this->UA = UADes;
898 23 : BaseSizer::reportSizerOutput(
899 : state, cCMO_BBRadiator_Water, this->EquipID, "Design Size U-Factor Times Area Value [W/K]", UADes);
900 : } else { // Hard-sized with sizing data
901 0 : this->UA = UAUser; // need to put this back as HWBaseboardUAResidual will have reset it, CR9377
902 0 : if (UAUser > 0.0 && UADes > 0.0) {
903 0 : BaseSizer::reportSizerOutput(state,
904 : cCMO_BBRadiator_Water,
905 : this->EquipID,
906 : "Design Size U-Factor Times Area Value [W/K]",
907 : UADes,
908 : "User-Specified U-Factor Times Area Value [W/K]",
909 : UAUser);
910 : // Report difference between design size and hard-sized values
911 0 : if (state.dataGlobal->DisplayExtraWarnings) {
912 0 : if ((std::abs(UADes - UAUser) / UAUser) > state.dataSize->AutoVsHardSizingThreshold) {
913 0 : ShowMessage(
914 : state,
915 0 : format("SizeBaseboard: Potential issue with equipment sizing for ZoneHVAC:Baseboard:Convective:Water=\"{}\".",
916 0 : this->EquipID));
917 0 : ShowContinueError(state, format("User-Specified U-Factor Times Area Value of {:.2R} [W/K]", UAUser));
918 0 : ShowContinueError(state, format("differs from Design Size U-Factor Times Area Value of {:.2R} [W/K]", UADes));
919 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
920 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
921 : }
922 : }
923 : }
924 : }
925 23 : }
926 : }
927 : } else {
928 : // if there is no heating Sizing:Plant object and autosizng was requested, issue an error message
929 7 : if (this->WaterVolFlowRateMax == DataSizing::AutoSize || this->UA == DataSizing::AutoSize) {
930 0 : ShowSevereError(state, format("SizeBaseboard: {}=\"{}\"", cCMO_BBRadiator_Water, this->EquipID));
931 0 : ShowContinueError(state, "...Autosizing of hot water baseboard requires a heating loop Sizing:Plant object");
932 0 : ErrorsFound = true;
933 : }
934 : }
935 :
936 : // save the design water flow rate for use by the water loop sizing algorithms
937 30 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->WaterInletNode, this->WaterVolFlowRateMax);
938 :
939 30 : if (ErrorsFound) {
940 0 : ShowFatalError(state, "SizeBaseboard: Preceding sizing errors cause program termination");
941 : }
942 30 : }
943 :
944 729041 : void SimHWConvective(EnergyPlusData &state, int &BaseboardNum, Real64 &LoadMet)
945 : {
946 : // SUBROUTINE INFORMATION:
947 : // AUTHOR Russ Taylor
948 : // DATE WRITTEN Nov 1997
949 : // MODIFIED May 2000 Fred Buhl
950 : // RE-ENGINEERED na
951 :
952 : // PURPOSE OF THIS SUBROUTINE: This subroutine calculates the heat exchange rate
953 : // in a pure convective baseboard heater. The heater is assumed to be crossflow
954 : // with both fluids unmixed. The air flow is buoyancy driven and a constant air
955 : // flow velocity of 0.5m/s is assumed. The solution is by the effectiveness-NTU
956 : // method found in Icropera and DeWitt, Fundamentals of Heat and Mass Transfer,
957 : // Chapter 11.4, p. 523, eq. 11.33
958 :
959 : // REFERENCES:
960 : // Icropera and DeWitt, Fundamentals of Heat and Mass Transfer,
961 : // Chapter 11.4, p. 523, eq. 11.33
962 :
963 : // Using/Aliasing
964 : using namespace DataSizing;
965 : using HVAC::SmallLoad;
966 : using PlantUtilities::SetActuatedBranchFlowRate;
967 :
968 : // SUBROUTINE PARAMETER DEFINITIONS:
969 729041 : static std::string const RoutineName(cCMO_BBRadiator_Water + ":SimHWConvective");
970 :
971 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
972 : int ZoneNum;
973 : Real64 WaterInletTemp;
974 : Real64 AirInletTemp;
975 : Real64 CpAir;
976 : Real64 CpWater;
977 : Real64 AirMassFlowRate;
978 : Real64 WaterMassFlowRate;
979 : Real64 CapacitanceAir;
980 : Real64 CapacitanceWater;
981 : Real64 CapacitanceMax;
982 : Real64 CapacitanceMin;
983 : Real64 CapacityRatio;
984 : Real64 NTU;
985 : Real64 Effectiveness;
986 : Real64 WaterOutletTemp;
987 : Real64 AirOutletTemp;
988 : Real64 AA;
989 : Real64 BB;
990 : Real64 CC;
991 : Real64 QZnReq;
992 :
993 729041 : auto &baseboard = state.dataBaseboardRadiator;
994 :
995 729041 : ZoneNum = baseboard->baseboards(BaseboardNum).ZonePtr;
996 729041 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP;
997 729041 : if (baseboard->baseboards(BaseboardNum).MySizeFlag)
998 345 : QZnReq = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad; // If in sizing, assign design condition
999 :
1000 729041 : WaterInletTemp = baseboard->baseboards(BaseboardNum).WaterInletTemp;
1001 729041 : AirInletTemp = baseboard->baseboards(BaseboardNum).AirInletTemp;
1002 :
1003 1458082 : CpWater = GetSpecificHeatGlycol(state,
1004 729041 : state.dataPlnt->PlantLoop(baseboard->baseboards(BaseboardNum).plantLoc.loopNum).FluidName,
1005 : WaterInletTemp,
1006 729041 : state.dataPlnt->PlantLoop(baseboard->baseboards(BaseboardNum).plantLoc.loopNum).FluidIndex,
1007 : RoutineName);
1008 729041 : CpAir = PsyCpAirFnW(baseboard->baseboards(BaseboardNum).AirInletHumRat);
1009 :
1010 729041 : if (baseboard->baseboards(BaseboardNum).DesAirMassFlowRate > 0.0) { // If UA is autosized, assign design condition
1011 511379 : AirMassFlowRate = baseboard->baseboards(BaseboardNum).DesAirMassFlowRate;
1012 : } else {
1013 217662 : AirMassFlowRate = baseboard->baseboards(BaseboardNum).AirMassFlowRate;
1014 : // pick a mass flow rate that depends on the max water mass flow rate. CR 8842 changed to factor of 2.0
1015 217662 : if (AirMassFlowRate <= 0.0) AirMassFlowRate = 2.0 * baseboard->baseboards(BaseboardNum).WaterMassFlowRateMax;
1016 : }
1017 :
1018 729041 : WaterMassFlowRate = state.dataLoopNodes->Node(baseboard->baseboards(BaseboardNum).WaterInletNode).MassFlowRate;
1019 729041 : CapacitanceAir = CpAir * AirMassFlowRate;
1020 :
1021 729041 : if (QZnReq > SmallLoad && (!state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum) || baseboard->baseboards(BaseboardNum).MySizeFlag) &&
1022 2183424 : (GetCurrentScheduleValue(state, baseboard->baseboards(BaseboardNum).SchedPtr) > 0 || baseboard->baseboards(BaseboardNum).MySizeFlag) &&
1023 725342 : (WaterMassFlowRate > 0.0)) {
1024 662304 : CapacitanceWater = CpWater * WaterMassFlowRate;
1025 662304 : CapacitanceMax = max(CapacitanceAir, CapacitanceWater);
1026 662304 : CapacitanceMin = min(CapacitanceAir, CapacitanceWater);
1027 662304 : CapacityRatio = CapacitanceMin / CapacitanceMax;
1028 662304 : NTU = baseboard->baseboards(BaseboardNum).UA / CapacitanceMin;
1029 : // The effectiveness is given by the following formula:
1030 : // Effectiveness = 1. - EXP((1./CapacityRatio)*(NTU)**0.22*(EXP(-CapacityRatio*(NTU)**0.78)-1.))
1031 : // To prevent possible underflows (numbers smaller than the computer can handle) we must break
1032 : // the calculation up into steps and check the size of the exponential arguments.
1033 662304 : AA = -CapacityRatio * std::pow(NTU, 0.78);
1034 662304 : if (AA < DataPrecisionGlobals::EXP_LowerLimit) {
1035 0 : BB = 0.0;
1036 : } else {
1037 662304 : BB = std::exp(AA);
1038 : }
1039 662304 : CC = (1.0 / CapacityRatio) * std::pow(NTU, 0.22) * (BB - 1.0);
1040 662304 : if (CC < DataPrecisionGlobals::EXP_LowerLimit) {
1041 17101 : Effectiveness = 1.0;
1042 : } else {
1043 645203 : Effectiveness = 1.0 - std::exp(CC);
1044 : }
1045 662304 : AirOutletTemp = AirInletTemp + Effectiveness * CapacitanceMin * (WaterInletTemp - AirInletTemp) / CapacitanceAir;
1046 662304 : WaterOutletTemp = WaterInletTemp - CapacitanceAir * (AirOutletTemp - AirInletTemp) / CapacitanceWater;
1047 662304 : LoadMet = CapacitanceWater * (WaterInletTemp - WaterOutletTemp);
1048 662304 : baseboard->baseboards(BaseboardNum).WaterOutletEnthalpy =
1049 662304 : baseboard->baseboards(BaseboardNum).WaterInletEnthalpy - LoadMet / WaterMassFlowRate;
1050 : } else {
1051 66737 : AirOutletTemp = AirInletTemp;
1052 66737 : WaterOutletTemp = WaterInletTemp;
1053 66737 : LoadMet = 0.0;
1054 66737 : baseboard->baseboards(BaseboardNum).WaterOutletEnthalpy = baseboard->baseboards(BaseboardNum).WaterInletEnthalpy;
1055 66737 : WaterMassFlowRate = 0.0;
1056 :
1057 66737 : SetActuatedBranchFlowRate(
1058 66737 : state, WaterMassFlowRate, baseboard->baseboards(BaseboardNum).WaterInletNode, baseboard->baseboards(BaseboardNum).plantLoc, false);
1059 66737 : AirMassFlowRate = 0.0;
1060 : }
1061 :
1062 729041 : baseboard->baseboards(BaseboardNum).WaterOutletTemp = WaterOutletTemp;
1063 729041 : baseboard->baseboards(BaseboardNum).AirOutletTemp = AirOutletTemp;
1064 729041 : baseboard->baseboards(BaseboardNum).Power = LoadMet;
1065 729041 : baseboard->baseboards(BaseboardNum).WaterMassFlowRate = WaterMassFlowRate;
1066 729041 : baseboard->baseboards(BaseboardNum).AirMassFlowRate = AirMassFlowRate;
1067 729041 : }
1068 :
1069 161893 : void UpdateBaseboard(EnergyPlusData &state, int &BaseboardNum)
1070 : {
1071 :
1072 : // SUBROUTINE INFORMATION:
1073 : // AUTHOR Russ Taylor
1074 : // DATE WRITTEN Nov 1997
1075 : // MODIFIED na
1076 : // RE-ENGINEERED na
1077 :
1078 : // Using/Aliasing
1079 : using PlantUtilities::SafeCopyPlantNode;
1080 :
1081 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1082 : int WaterInletNode;
1083 : int WaterOutletNode;
1084 :
1085 161893 : auto &baseboard = state.dataBaseboardRadiator;
1086 :
1087 161893 : WaterInletNode = baseboard->baseboards(BaseboardNum).WaterInletNode;
1088 161893 : WaterOutletNode = baseboard->baseboards(BaseboardNum).WaterOutletNode;
1089 :
1090 161893 : SafeCopyPlantNode(state, WaterInletNode, WaterOutletNode);
1091 : // Set the outlet air nodes of the Baseboard
1092 : // Set the outlet water nodes for the Coil
1093 161893 : state.dataLoopNodes->Node(WaterOutletNode).Temp = baseboard->baseboards(BaseboardNum).WaterOutletTemp;
1094 161893 : state.dataLoopNodes->Node(WaterOutletNode).Enthalpy = baseboard->baseboards(BaseboardNum).WaterOutletEnthalpy;
1095 161893 : }
1096 :
1097 : } // namespace BaseboardRadiator
1098 :
1099 : } // namespace EnergyPlus
|