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