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 : // ObjexxFCL Headers
49 : #include <ObjexxFCL/Array.functions.hh>
50 :
51 : // EnergyPlus Headers
52 : #include <EnergyPlus/Autosizing/HeatingCapacitySizing.hh>
53 : #include <EnergyPlus/Data/EnergyPlusData.hh>
54 : #include <EnergyPlus/DataHVACGlobals.hh>
55 : #include <EnergyPlus/DataHeatBalFanSys.hh>
56 : #include <EnergyPlus/DataHeatBalSurface.hh>
57 : #include <EnergyPlus/DataHeatBalance.hh>
58 : #include <EnergyPlus/DataIPShortCuts.hh>
59 : #include <EnergyPlus/DataLoopNode.hh>
60 : #include <EnergyPlus/DataSizing.hh>
61 : #include <EnergyPlus/DataSurfaces.hh>
62 : #include <EnergyPlus/DataZoneEnergyDemands.hh>
63 : #include <EnergyPlus/DataZoneEquipment.hh>
64 : #include <EnergyPlus/ElectricBaseboardRadiator.hh>
65 : #include <EnergyPlus/GeneralRoutines.hh>
66 : #include <EnergyPlus/GlobalNames.hh>
67 : #include <EnergyPlus/HeatBalanceIntRadExchange.hh>
68 : #include <EnergyPlus/HeatBalanceSurfaceManager.hh>
69 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
70 : #include <EnergyPlus/OutputProcessor.hh>
71 : #include <EnergyPlus/Psychrometrics.hh>
72 : #include <EnergyPlus/ScheduleManager.hh>
73 : #include <EnergyPlus/UtilityRoutines.hh>
74 :
75 : namespace EnergyPlus {
76 :
77 : namespace ElectricBaseboardRadiator {
78 :
79 : // Module ElectricBaseboardRadiator -- (ref: Object: ZoneHVAC:Baseboard:RadiantConvective:Electric)
80 :
81 : // MODULE INFORMATION:
82 : // AUTHOR Daeho Kang
83 : // DATE WRITTEN Feb 2010
84 :
85 : // PURPOSE OF THIS MODULE:
86 : // This module is to calculate the actual convective heat addition that an electrical baseboard heater
87 : // deliveres to a space.
88 :
89 : // METHODOLOGY EMPLOYED:
90 : // Based on the convective-only electric baseboard module (Object: ZoneHVAC:Baseboard:Convective:Electric)
91 : // written by Richard Liesen in Nov 2001, this new electric baseboard module is to add the existing calculation
92 : // algorithm of radiant heat transfer in the high temperature radiant system module.
93 :
94 : // REFERENCES:
95 : // HighTempRadiantSystem module (ZoneHVAC:HighTemperatureRadiant)
96 : // Convective electric baseboard module (ZoneHVAC:Baseboard:Convective:Electric)
97 :
98 9900 : void SimElecBaseboard(EnergyPlusData &state,
99 : std::string const &EquipName,
100 : int const ControlledZoneNum,
101 : bool const FirstHVACIteration,
102 : Real64 &PowerMet,
103 : int &CompIndex)
104 : {
105 :
106 : // SUBROUTINE INFORMATION:
107 : // AUTHOR Richard Liesen
108 : // DATE WRITTEN Nov 2001
109 : // MODIFIED Feb 2010 Daeho Kang for radiant component
110 :
111 : // PURPOSE OF THIS SUBROUTINE:
112 : // This subroutine simulates the Electric Baseboard units.
113 :
114 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
115 : int BaseboardNum; // Index of unit in baseboard array
116 9900 : int NumElecBaseboards = state.dataElectBaseboardRad->NumElecBaseboards;
117 :
118 9900 : if (state.dataElectBaseboardRad->GetInputFlag) {
119 1 : GetElectricBaseboardInput(state);
120 1 : state.dataElectBaseboardRad->GetInputFlag = false;
121 : }
122 :
123 : // Find the correct Baseboard Equipment
124 9900 : if (CompIndex == 0) {
125 2 : BaseboardNum = Util::FindItemInList(EquipName, state.dataElectBaseboardRad->ElecBaseboard, &ElecBaseboardParams::EquipName);
126 2 : if (BaseboardNum == 0) {
127 0 : ShowFatalError(state, "SimElectricBaseboard: Unit not found=" + EquipName);
128 : }
129 2 : CompIndex = BaseboardNum;
130 : } else {
131 9898 : BaseboardNum = CompIndex;
132 9898 : if (BaseboardNum > NumElecBaseboards || BaseboardNum < 1) {
133 0 : ShowFatalError(state,
134 0 : format("SimElectricBaseboard: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
135 : BaseboardNum,
136 : NumElecBaseboards,
137 : EquipName));
138 : }
139 9898 : if (state.dataElectBaseboardRad->ElecBaseboard(BaseboardNum).CheckEquipName) {
140 2 : if (EquipName != state.dataElectBaseboardRad->ElecBaseboard(BaseboardNum).EquipName) {
141 0 : ShowFatalError(state,
142 0 : format("SimElectricBaseboard: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
143 : BaseboardNum,
144 : EquipName,
145 0 : state.dataElectBaseboardRad->ElecBaseboard(BaseboardNum).EquipName));
146 : }
147 2 : state.dataElectBaseboardRad->ElecBaseboard(BaseboardNum).CheckEquipName = false;
148 : }
149 : }
150 :
151 9900 : InitElectricBaseboard(state, BaseboardNum, ControlledZoneNum, FirstHVACIteration);
152 9900 : CalcElectricBaseboard(state, BaseboardNum, ControlledZoneNum);
153 :
154 9900 : PowerMet = state.dataElectBaseboardRad->ElecBaseboard(BaseboardNum).TotPower;
155 :
156 9900 : UpdateElectricBaseboard(state, BaseboardNum);
157 9900 : ReportElectricBaseboard(state, BaseboardNum);
158 9900 : }
159 :
160 1 : void GetElectricBaseboardInput(EnergyPlusData &state)
161 : {
162 :
163 : // SUBROUTINE INFORMATION:
164 : // AUTHOR Richard Liesen
165 : // DATE WRITTEN Nov 2001
166 : // MODIFIED Feb 2010 Daeho Kang for radiant component
167 :
168 : // PURPOSE OF THIS SUBROUTINE:
169 : // This subroutine gets the input for the Baseboard units.
170 :
171 : // SUBROUTINE PARAMETER DEFINITIONS:
172 : static constexpr std::string_view RoutineName("GetElectricBaseboardInput: "); // include trailing blank space
173 1 : Real64 constexpr MaxFraction(1.0); // Maximum limit of fractional values
174 1 : Real64 constexpr MinFraction(0.0); // Minimum limit of fractional values
175 : // INTEGER,PARAMETER :: MaxDistribSurfaces = 20 ! Maximum number of surfaces that a baseboard heater can radiate to
176 1 : int constexpr MinDistribSurfaces(1); // Minimum number of surfaces that a baseboard heater can radiate to
177 1 : int constexpr iHeatCAPMAlphaNum(3); // get input index to HW baseboard heating capacity sizing method
178 1 : int constexpr iHeatDesignCapacityNumericNum(1); // get input index to HW baseboard heating capacity
179 1 : int constexpr iHeatCapacityPerFloorAreaNumericNum(2); // get input index to HW baseboard heating capacity per floor area sizing
180 1 : int constexpr iHeatFracOfAutosizedCapacityNumericNum(
181 : 3); // get input index to HW baseboard heating capacity sizing as fraction of autosized heating capacity
182 :
183 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
184 : int NumAlphas;
185 : int NumNumbers;
186 : int IOStat;
187 1 : bool ErrorsFound(false); // If errors detected in input
188 1 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
189 :
190 1 : cCurrentModuleObject = state.dataElectBaseboardRad->cCMO_BBRadiator_Electric;
191 :
192 : // Update Num in state and make local convenience copy
193 2 : int NumElecBaseboards = state.dataElectBaseboardRad->NumElecBaseboards =
194 1 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
195 :
196 : // object is extensible, no max args needed as IPShortCuts being used
197 1 : auto &ElecBaseboardNumericFields = state.dataElectBaseboardRad->ElecBaseboardNumericFields;
198 :
199 1 : state.dataElectBaseboardRad->ElecBaseboard.allocate(NumElecBaseboards);
200 1 : ElecBaseboardNumericFields.allocate(NumElecBaseboards);
201 :
202 3 : for (int BaseboardNum = 1; BaseboardNum <= NumElecBaseboards; ++BaseboardNum) {
203 2 : auto &elecBaseboard = state.dataElectBaseboardRad->ElecBaseboard(BaseboardNum);
204 :
205 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
206 : cCurrentModuleObject,
207 : BaseboardNum,
208 2 : state.dataIPShortCut->cAlphaArgs,
209 : NumAlphas,
210 2 : state.dataIPShortCut->rNumericArgs,
211 : NumNumbers,
212 : IOStat,
213 2 : state.dataIPShortCut->lNumericFieldBlanks,
214 2 : state.dataIPShortCut->lAlphaFieldBlanks,
215 2 : state.dataIPShortCut->cAlphaFieldNames,
216 2 : state.dataIPShortCut->cNumericFieldNames);
217 :
218 2 : ElecBaseboardNumericFields(BaseboardNum).FieldNames.allocate(NumNumbers);
219 2 : ElecBaseboardNumericFields(BaseboardNum).FieldNames = "";
220 2 : ElecBaseboardNumericFields(BaseboardNum).FieldNames = state.dataIPShortCut->cNumericFieldNames;
221 :
222 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
223 2 : GlobalNames::VerifyUniqueBaseboardName(
224 4 : state, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1), ErrorsFound, cCurrentModuleObject + " Name");
225 :
226 2 : elecBaseboard.EquipName = state.dataIPShortCut->cAlphaArgs(1); // name of this baseboard
227 2 : elecBaseboard.Schedule = state.dataIPShortCut->cAlphaArgs(2);
228 2 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
229 0 : elecBaseboard.SchedPtr = ScheduleManager::ScheduleAlwaysOn;
230 : } else {
231 2 : elecBaseboard.SchedPtr = ScheduleManager::GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
232 2 : if (elecBaseboard.SchedPtr == 0) {
233 0 : ShowSevereError(state,
234 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(2) +
235 0 : " entered =" + state.dataIPShortCut->cAlphaArgs(2) + " for " + state.dataIPShortCut->cAlphaFieldNames(1) +
236 0 : '=' + state.dataIPShortCut->cAlphaArgs(1));
237 0 : ErrorsFound = true;
238 : }
239 : }
240 :
241 : // Determine HW radiant baseboard heating design capacity sizing method
242 2 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "HeatingDesignCapacity")) {
243 2 : elecBaseboard.HeatingCapMethod = DataSizing::HeatingDesignCapacity;
244 :
245 2 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatDesignCapacityNumericNum)) {
246 2 : elecBaseboard.ScaledHeatingCapacity = state.dataIPShortCut->rNumericArgs(iHeatDesignCapacityNumericNum);
247 2 : if (elecBaseboard.ScaledHeatingCapacity < 0.0 && elecBaseboard.ScaledHeatingCapacity != DataSizing::AutoSize) {
248 0 : ShowSevereError(state, cCurrentModuleObject + " = " + elecBaseboard.EquipName);
249 0 : ShowContinueError(state,
250 0 : format("Illegal {} = {:.7T}",
251 0 : state.dataIPShortCut->cNumericFieldNames(iHeatDesignCapacityNumericNum),
252 0 : state.dataIPShortCut->rNumericArgs(iHeatDesignCapacityNumericNum)));
253 0 : ErrorsFound = true;
254 : }
255 : } else {
256 0 : ShowSevereError(state, cCurrentModuleObject + " = " + elecBaseboard.EquipName);
257 0 : ShowContinueError(state,
258 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
259 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
260 0 : ShowContinueError(state,
261 0 : "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(iHeatDesignCapacityNumericNum));
262 0 : ErrorsFound = true;
263 : }
264 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "CapacityPerFloorArea")) {
265 0 : elecBaseboard.HeatingCapMethod = DataSizing::CapacityPerFloorArea;
266 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatCapacityPerFloorAreaNumericNum)) {
267 0 : elecBaseboard.ScaledHeatingCapacity = state.dataIPShortCut->rNumericArgs(iHeatCapacityPerFloorAreaNumericNum);
268 0 : if (elecBaseboard.ScaledHeatingCapacity <= 0.0) {
269 0 : ShowSevereError(state, cCurrentModuleObject + " = " + elecBaseboard.EquipName);
270 0 : ShowContinueError(state,
271 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
272 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
273 0 : ShowContinueError(state,
274 0 : format("Illegal {} = {:.7T}",
275 0 : state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum),
276 0 : state.dataIPShortCut->rNumericArgs(iHeatCapacityPerFloorAreaNumericNum)));
277 0 : ErrorsFound = true;
278 0 : } else if (elecBaseboard.ScaledHeatingCapacity == DataSizing::AutoSize) {
279 0 : ShowSevereError(state, cCurrentModuleObject + " = " + elecBaseboard.EquipName);
280 0 : ShowContinueError(state,
281 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
282 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
283 0 : ShowContinueError(state,
284 0 : "Illegal " + state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum) + " = Autosize");
285 0 : ErrorsFound = true;
286 : }
287 : } else {
288 0 : ShowSevereError(state, cCurrentModuleObject + " = " + elecBaseboard.EquipName);
289 0 : ShowContinueError(state,
290 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
291 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
292 0 : ShowContinueError(state,
293 0 : "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum));
294 0 : ErrorsFound = true;
295 : }
296 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "FractionOfAutosizedHeatingCapacity")) {
297 0 : elecBaseboard.HeatingCapMethod = DataSizing::FractionOfAutosizedHeatingCapacity;
298 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatFracOfAutosizedCapacityNumericNum)) {
299 0 : elecBaseboard.ScaledHeatingCapacity = state.dataIPShortCut->rNumericArgs(iHeatFracOfAutosizedCapacityNumericNum);
300 0 : if (elecBaseboard.ScaledHeatingCapacity < 0.0) {
301 0 : ShowSevereError(state, cCurrentModuleObject + " = " + elecBaseboard.EquipName);
302 0 : ShowContinueError(state,
303 0 : format("Illegal {} = {:.7T}",
304 0 : state.dataIPShortCut->cNumericFieldNames(iHeatFracOfAutosizedCapacityNumericNum),
305 0 : state.dataIPShortCut->rNumericArgs(iHeatFracOfAutosizedCapacityNumericNum)));
306 0 : ErrorsFound = true;
307 : }
308 : } else {
309 0 : ShowSevereError(state, cCurrentModuleObject + " = " + elecBaseboard.EquipName);
310 0 : ShowContinueError(state,
311 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
312 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
313 0 : ShowContinueError(
314 0 : state, "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(iHeatFracOfAutosizedCapacityNumericNum));
315 0 : ErrorsFound = true;
316 : }
317 : } else {
318 0 : ShowSevereError(state, cCurrentModuleObject + " = " + elecBaseboard.EquipName);
319 0 : ShowContinueError(state,
320 0 : "Illegal " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
321 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
322 0 : ErrorsFound = true;
323 : }
324 :
325 2 : elecBaseboard.BaseboardEfficiency = state.dataIPShortCut->rNumericArgs(4);
326 2 : elecBaseboard.FracRadiant = state.dataIPShortCut->rNumericArgs(5);
327 2 : if (elecBaseboard.FracRadiant < MinFraction) {
328 0 : ShowWarningError(state,
329 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
330 0 : state.dataIPShortCut->cNumericFieldNames(5) + " was lower than the allowable minimum.");
331 0 : ShowContinueError(state, format("...reset to minimum value=[{:.2R}].", MinFraction));
332 0 : elecBaseboard.FracRadiant = MinFraction;
333 : }
334 2 : if (elecBaseboard.FracRadiant > MaxFraction) {
335 0 : ShowWarningError(state,
336 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
337 0 : state.dataIPShortCut->cNumericFieldNames(5) + " was higher than the allowable maximum.");
338 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MaxFraction));
339 0 : elecBaseboard.FracRadiant = MaxFraction;
340 : }
341 :
342 : // Remaining fraction is added to the zone as convective heat transfer
343 2 : if (elecBaseboard.FracRadiant > MaxFraction) {
344 0 : ShowWarningError(state,
345 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
346 : "\", Fraction Radiant was higher than the allowable maximum.");
347 0 : elecBaseboard.FracRadiant = MaxFraction;
348 0 : elecBaseboard.FracConvect = 0.0;
349 : } else {
350 2 : elecBaseboard.FracConvect = 1.0 - elecBaseboard.FracRadiant;
351 : }
352 :
353 2 : elecBaseboard.FracDistribPerson = state.dataIPShortCut->rNumericArgs(6);
354 2 : if (elecBaseboard.FracDistribPerson < MinFraction) {
355 0 : ShowWarningError(state,
356 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
357 0 : state.dataIPShortCut->cNumericFieldNames(6) + " was lower than the allowable minimum.");
358 0 : ShowContinueError(state, format("...reset to minimum value=[{:.2R}].", MinFraction));
359 0 : elecBaseboard.FracDistribPerson = MinFraction;
360 : }
361 2 : if (elecBaseboard.FracDistribPerson > MaxFraction) {
362 0 : ShowWarningError(state,
363 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
364 0 : state.dataIPShortCut->cNumericFieldNames(6) + " was higher than the allowable maximum.");
365 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MaxFraction));
366 0 : elecBaseboard.FracDistribPerson = MaxFraction;
367 : }
368 :
369 2 : elecBaseboard.TotSurfToDistrib = NumNumbers - 6;
370 :
371 2 : if ((elecBaseboard.TotSurfToDistrib < MinDistribSurfaces) && (elecBaseboard.FracRadiant > MinFraction)) {
372 0 : ShowSevereError(state,
373 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
374 : "\", the number of surface/radiant fraction groups entered was less than the allowable minimum.");
375 0 : ShowContinueError(state, format("...the minimum that must be entered=[{}].", MinDistribSurfaces));
376 0 : ErrorsFound = true;
377 0 : elecBaseboard.TotSurfToDistrib = 0; // error
378 : }
379 :
380 2 : elecBaseboard.SurfaceName.allocate(elecBaseboard.TotSurfToDistrib);
381 2 : elecBaseboard.SurfaceName = "";
382 2 : elecBaseboard.SurfacePtr.allocate(elecBaseboard.TotSurfToDistrib);
383 2 : elecBaseboard.SurfacePtr = 0;
384 2 : elecBaseboard.FracDistribToSurf.allocate(elecBaseboard.TotSurfToDistrib);
385 2 : elecBaseboard.FracDistribToSurf = 0.0;
386 :
387 2 : elecBaseboard.ZonePtr =
388 2 : DataZoneEquipment::GetZoneEquipControlledZoneNum(state, DataZoneEquipment::ZoneEquipType::BaseboardElectric, elecBaseboard.EquipName);
389 :
390 2 : Real64 AllFracsSummed = elecBaseboard.FracDistribPerson;
391 12 : for (int SurfNum = 1; SurfNum <= elecBaseboard.TotSurfToDistrib; ++SurfNum) {
392 10 : elecBaseboard.SurfaceName(SurfNum) = state.dataIPShortCut->cAlphaArgs(SurfNum + 3);
393 10 : elecBaseboard.SurfacePtr(SurfNum) = HeatBalanceIntRadExchange::GetRadiantSystemSurface(
394 10 : state, cCurrentModuleObject, elecBaseboard.EquipName, elecBaseboard.ZonePtr, elecBaseboard.SurfaceName(SurfNum), ErrorsFound);
395 10 : elecBaseboard.FracDistribToSurf(SurfNum) = state.dataIPShortCut->rNumericArgs(SurfNum + 6);
396 10 : if (elecBaseboard.FracDistribToSurf(SurfNum) > MaxFraction) {
397 0 : ShowWarningError(state,
398 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
399 0 : state.dataIPShortCut->cNumericFieldNames(SurfNum + 6) + "was greater than the allowable maximum.");
400 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MaxFraction));
401 0 : elecBaseboard.TotSurfToDistrib = MaxFraction;
402 : }
403 10 : if (elecBaseboard.FracDistribToSurf(SurfNum) < MinFraction) {
404 0 : ShowWarningError(state,
405 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
406 0 : state.dataIPShortCut->cNumericFieldNames(SurfNum + 6) + "was less than the allowable minimum.");
407 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MinFraction));
408 0 : elecBaseboard.TotSurfToDistrib = MinFraction;
409 : }
410 10 : if (elecBaseboard.SurfacePtr(SurfNum) != 0) {
411 10 : state.dataSurface->surfIntConv(elecBaseboard.SurfacePtr(SurfNum)).getsRadiantHeat = true;
412 10 : state.dataSurface->allGetsRadiantHeatSurfaceList.emplace_back(elecBaseboard.SurfacePtr(SurfNum));
413 : }
414 :
415 10 : AllFracsSummed += elecBaseboard.FracDistribToSurf(SurfNum);
416 : } // Surfaces
417 :
418 2 : if (AllFracsSummed > (MaxFraction + 0.01)) {
419 0 : ShowSevereError(state,
420 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
421 : "\", Summed radiant fractions for people + surface groups > 1.0");
422 0 : ErrorsFound = true;
423 : }
424 2 : if ((AllFracsSummed < (MaxFraction - 0.01)) &&
425 0 : (elecBaseboard.FracRadiant > MinFraction)) { // User didn't distribute all of the | radiation warn that some will be lost
426 0 : ShowWarningError(state,
427 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
428 : "\", Summed radiant fractions for people + surface groups < 1.0");
429 0 : ShowContinueError(state, "The rest of the radiant energy delivered by the baseboard heater will be lost");
430 : }
431 : }
432 :
433 1 : if (ErrorsFound) {
434 0 : ShowFatalError(state, std::string{RoutineName} + cCurrentModuleObject + "Errors found getting input. Program terminates.");
435 : }
436 :
437 3 : for (auto &elecBaseboard : state.dataElectBaseboardRad->ElecBaseboard) {
438 : // Setup Report variables for the Electric Baseboards
439 : // CurrentModuleObject='ZoneHVAC:Baseboard:RadiantConvective:Electric'
440 4 : SetupOutputVariable(state,
441 : "Baseboard Total Heating Rate",
442 : Constant::Units::W,
443 2 : elecBaseboard.TotPower,
444 : OutputProcessor::TimeStepType::System,
445 : OutputProcessor::StoreType::Average,
446 2 : elecBaseboard.EquipName);
447 :
448 4 : SetupOutputVariable(state,
449 : "Baseboard Convective Heating Rate",
450 : Constant::Units::W,
451 2 : elecBaseboard.ConvPower,
452 : OutputProcessor::TimeStepType::System,
453 : OutputProcessor::StoreType::Average,
454 2 : elecBaseboard.EquipName);
455 4 : SetupOutputVariable(state,
456 : "Baseboard Radiant Heating Rate",
457 : Constant::Units::W,
458 2 : elecBaseboard.RadPower,
459 : OutputProcessor::TimeStepType::System,
460 : OutputProcessor::StoreType::Average,
461 2 : elecBaseboard.EquipName);
462 :
463 4 : SetupOutputVariable(state,
464 : "Baseboard Electricity Energy",
465 : Constant::Units::J,
466 2 : elecBaseboard.ElecUseLoad,
467 : OutputProcessor::TimeStepType::System,
468 : OutputProcessor::StoreType::Sum,
469 2 : elecBaseboard.EquipName,
470 : Constant::eResource::Electricity,
471 : OutputProcessor::Group::HVAC,
472 : OutputProcessor::EndUseCat::Heating);
473 4 : SetupOutputVariable(state,
474 : "Baseboard Electricity Rate",
475 : Constant::Units::W,
476 2 : elecBaseboard.ElecUseRate,
477 : OutputProcessor::TimeStepType::System,
478 : OutputProcessor::StoreType::Average,
479 2 : elecBaseboard.EquipName);
480 4 : SetupOutputVariable(state,
481 : "Baseboard Total Heating Energy",
482 : Constant::Units::J,
483 2 : elecBaseboard.TotEnergy,
484 : OutputProcessor::TimeStepType::System,
485 : OutputProcessor::StoreType::Sum,
486 2 : elecBaseboard.EquipName,
487 : Constant::eResource::EnergyTransfer,
488 : OutputProcessor::Group::HVAC,
489 : OutputProcessor::EndUseCat::Baseboard);
490 :
491 4 : SetupOutputVariable(state,
492 : "Baseboard Convective Heating Energy",
493 : Constant::Units::J,
494 2 : elecBaseboard.ConvEnergy,
495 : OutputProcessor::TimeStepType::System,
496 : OutputProcessor::StoreType::Sum,
497 2 : elecBaseboard.EquipName);
498 4 : SetupOutputVariable(state,
499 : "Baseboard Radiant Heating Energy",
500 : Constant::Units::J,
501 2 : elecBaseboard.RadEnergy,
502 : OutputProcessor::TimeStepType::System,
503 : OutputProcessor::StoreType::Sum,
504 2 : elecBaseboard.EquipName);
505 : }
506 1 : }
507 :
508 9900 : void InitElectricBaseboard(EnergyPlusData &state, int const BaseboardNum, int const ControlledZoneNum, bool const FirstHVACIteration)
509 : {
510 :
511 : // SUBROUTINE INFORMATION:
512 : // AUTHOR Richard Liesen
513 : // DATE WRITTEN Nov 2001
514 : // MODIFIED Feb 2010 Daeho Kang for radiant component
515 :
516 : // PURPOSE OF THIS SUBROUTINE:
517 : // This subroutine initializes the Baseboard units during simulation.
518 :
519 9900 : auto &elecBaseboard = state.dataElectBaseboardRad->ElecBaseboard(BaseboardNum);
520 :
521 9900 : if (!state.dataGlobal->SysSizingCalc && elecBaseboard.MySizeFlag) {
522 : // for each coil, do the sizing once.
523 2 : SizeElectricBaseboard(state, BaseboardNum);
524 2 : elecBaseboard.MySizeFlag = false;
525 : }
526 :
527 : // Do the Begin Environment initializations
528 9900 : if (state.dataGlobal->BeginEnvrnFlag && elecBaseboard.MyEnvrnFlag) {
529 : // Initialize
530 12 : elecBaseboard.ZeroBBSourceSumHATsurf = 0.0;
531 12 : elecBaseboard.QBBElecRadSource = 0.0;
532 12 : elecBaseboard.QBBElecRadSrcAvg = 0.0;
533 12 : elecBaseboard.LastQBBElecRadSrc = 0.0;
534 12 : elecBaseboard.LastSysTimeElapsed = 0.0;
535 12 : elecBaseboard.LastTimeStepSys = 0.0;
536 :
537 12 : elecBaseboard.MyEnvrnFlag = false;
538 : }
539 :
540 9900 : if (!state.dataGlobal->BeginEnvrnFlag) {
541 9838 : elecBaseboard.MyEnvrnFlag = true;
542 : }
543 :
544 9900 : if (state.dataGlobal->BeginTimeStepFlag && FirstHVACIteration) {
545 4054 : elecBaseboard.ZeroBBSourceSumHATsurf = state.dataHeatBal->Zone(ControlledZoneNum).sumHATsurf(state);
546 4054 : elecBaseboard.QBBElecRadSrcAvg = 0.0;
547 4054 : elecBaseboard.LastQBBElecRadSrc = 0.0;
548 4054 : elecBaseboard.LastSysTimeElapsed = 0.0;
549 4054 : elecBaseboard.LastTimeStepSys = 0.0;
550 : }
551 :
552 : // Do the every time step initializations
553 9900 : int ZoneNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
554 9900 : elecBaseboard.AirInletTemp = state.dataLoopNodes->Node(ZoneNode).Temp;
555 9900 : elecBaseboard.AirInletHumRat = state.dataLoopNodes->Node(ZoneNode).HumRat;
556 :
557 : // Set the reporting variables to zero at each timestep.
558 9900 : elecBaseboard.TotPower = 0.0;
559 9900 : elecBaseboard.Power = 0.0;
560 9900 : elecBaseboard.ConvPower = 0.0;
561 9900 : elecBaseboard.RadPower = 0.0;
562 9900 : elecBaseboard.TotEnergy = 0.0;
563 9900 : elecBaseboard.Energy = 0.0;
564 9900 : elecBaseboard.ConvEnergy = 0.0;
565 9900 : elecBaseboard.RadEnergy = 0.0;
566 9900 : elecBaseboard.ElecUseLoad = 0.0;
567 9900 : elecBaseboard.ElecUseRate = 0.0;
568 9900 : }
569 :
570 2 : void SizeElectricBaseboard(EnergyPlusData &state, int const BaseboardNum)
571 : {
572 :
573 : // SUBROUTINE INFORMATION:
574 : // AUTHOR Fred Buhl
575 : // DATE WRITTEN February 2002
576 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
577 : // July 2014, B. Nigusse, added scalable sizing
578 :
579 : // PURPOSE OF THIS SUBROUTINE:
580 : // This subroutine is for sizing electric baseboard components for which nominal capacities have not been
581 : // specified in the input.
582 :
583 : // METHODOLOGY EMPLOYED:
584 : // Obtains flow rates from the zone sizing arrays and plant sizing data. UAs are
585 : // calculated by numerically inverting the baseboard calculation routine.
586 :
587 : // SUBROUTINE PARAMETER DEFINITIONS:
588 : static constexpr std::string_view RoutineName("SizeElectricBaseboard");
589 :
590 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
591 : Real64 TempSize; // autosized value of coil input field
592 :
593 2 : if (state.dataSize->CurZoneEqNum > 0) {
594 2 : auto &zoneEqSizing = state.dataSize->ZoneEqSizing(state.dataSize->CurZoneEqNum);
595 2 : auto &elecBaseboard = state.dataElectBaseboardRad->ElecBaseboard(BaseboardNum);
596 2 : state.dataSize->DataScalableCapSizingON = false;
597 :
598 2 : std::string_view const CompType = state.dataElectBaseboardRad->cCMO_BBRadiator_Electric;
599 2 : std::string_view const CompName = elecBaseboard.EquipName;
600 2 : state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
601 2 : state.dataSize->DataZoneNumber = elecBaseboard.ZonePtr;
602 2 : int SizingMethod = HVAC::HeatingCapacitySizing; // Integer representation of sizing method name (e.g., CoolingAirflowSizing)
603 2 : int FieldNum = 1; // IDD numeric field number where input field description is found
604 : std::string const SizingString =
605 2 : format("{} [W]", state.dataElectBaseboardRad->ElecBaseboardNumericFields(BaseboardNum).FieldNames(FieldNum));
606 : // capacity sizing methods (e.g., HeatingDesignCapacity, CapacityPerFloorArea, FractionOfAutosizedCoolingCapacity)
607 2 : int CapSizingMethod = elecBaseboard.HeatingCapMethod;
608 2 : zoneEqSizing.SizingMethod(SizingMethod) = CapSizingMethod;
609 2 : if (CapSizingMethod == DataSizing::HeatingDesignCapacity || CapSizingMethod == DataSizing::CapacityPerFloorArea ||
610 : CapSizingMethod == DataSizing::FractionOfAutosizedHeatingCapacity) {
611 2 : bool PrintFlag = true; // TRUE when sizing information is reported in the eio file
612 2 : if (CapSizingMethod == DataSizing::HeatingDesignCapacity) {
613 2 : if (elecBaseboard.ScaledHeatingCapacity == DataSizing::AutoSize) {
614 2 : CheckZoneSizing(state, CompType, CompName);
615 2 : zoneEqSizing.DesHeatingLoad = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad;
616 : } else {
617 0 : zoneEqSizing.DesHeatingLoad = elecBaseboard.ScaledHeatingCapacity;
618 : }
619 2 : zoneEqSizing.HeatingCapacity = true;
620 2 : TempSize = elecBaseboard.ScaledHeatingCapacity;
621 0 : } else if (CapSizingMethod == DataSizing::CapacityPerFloorArea) {
622 0 : if (state.dataSize->ZoneSizingRunDone) {
623 0 : zoneEqSizing.HeatingCapacity = true;
624 0 : zoneEqSizing.DesHeatingLoad = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad;
625 : }
626 0 : TempSize = elecBaseboard.ScaledHeatingCapacity * state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
627 0 : state.dataSize->DataScalableCapSizingON = true;
628 0 : } else if (CapSizingMethod == DataSizing::FractionOfAutosizedHeatingCapacity) {
629 0 : CheckZoneSizing(state, CompType, CompName);
630 0 : zoneEqSizing.HeatingCapacity = true;
631 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = elecBaseboard.ScaledHeatingCapacity;
632 0 : zoneEqSizing.DesHeatingLoad = state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad;
633 0 : Real64 FracOfAutoSzCap = DataSizing::AutoSize;
634 0 : bool ErrorsFound = false;
635 0 : HeatingCapacitySizer sizerHeatingCapacity;
636 0 : sizerHeatingCapacity.overrideSizingString(SizingString);
637 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
638 0 : FracOfAutoSzCap = sizerHeatingCapacity.size(state, FracOfAutoSzCap, ErrorsFound);
639 0 : TempSize = FracOfAutoSzCap;
640 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
641 0 : state.dataSize->DataScalableCapSizingON = true;
642 0 : } else {
643 0 : TempSize = elecBaseboard.ScaledHeatingCapacity;
644 : }
645 2 : bool errorsFound = false;
646 2 : HeatingCapacitySizer sizerHeatingCapacity;
647 2 : sizerHeatingCapacity.overrideSizingString(SizingString);
648 2 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
649 2 : elecBaseboard.NominalCapacity = sizerHeatingCapacity.size(state, TempSize, errorsFound);
650 2 : state.dataSize->DataScalableCapSizingON = false;
651 2 : }
652 2 : }
653 2 : }
654 :
655 9900 : void CalcElectricBaseboard(EnergyPlusData &state, int const BaseboardNum, [[maybe_unused]] int const ControlledZoneNum)
656 : {
657 : // SUBROUTINE INFORMATION:
658 : // AUTHOR Richard Liesen
659 : // DATE WRITTEN Nov 2001
660 : // MODIFIED Feb 2010 Daeho Kang for radiant component
661 : // Sep 2011 LKL/BG - resimulate only zones needing it for Radiant systems
662 :
663 : // PURPOSE OF THIS SUBROUTINE:
664 : // This subroutine calculates the heat exchange rate in a Electric baseboard heater.
665 : // It includes radiant heat transfer to people and surfaces in a space, and the actual convective
666 : // system impact of a electric baseboard heater is determined after the radiant heat distribution.
667 :
668 : // METHODOLOGY EMPLOYED:
669 : // This is primarily modified from Convective Electric Baseboard. An existing algorithm of radiant
670 : // heat transfer calculation in the High Temperature Radiant System module is implemented.
671 :
672 : // SUBROUTINE PARAMETER DEFINITIONS:
673 9900 : Real64 constexpr SimpConvAirFlowSpeed(0.5); // m/s
674 :
675 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
676 : Real64 QBBCap;
677 : Real64 RadHeat;
678 : Real64 LoadMet;
679 9900 : auto &elecBaseboard = state.dataElectBaseboardRad->ElecBaseboard(BaseboardNum);
680 :
681 9900 : int ZoneNum = elecBaseboard.ZonePtr;
682 9900 : Real64 QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP;
683 9900 : Real64 AirInletTemp = elecBaseboard.AirInletTemp;
684 9900 : Real64 AirOutletTemp = AirInletTemp;
685 9900 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(elecBaseboard.AirInletHumRat);
686 9900 : Real64 AirMassFlowRate = SimpConvAirFlowSpeed;
687 9900 : Real64 CapacitanceAir = CpAir * AirMassFlowRate;
688 :
689 : // Currently only the efficiency is used to calculate the electric consumption. There could be some
690 : // thermal loss that could be accounted for with this efficiency input.
691 9900 : Real64 Effic = elecBaseboard.BaseboardEfficiency;
692 :
693 14562 : if (QZnReq > HVAC::SmallLoad && !state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum) &&
694 4662 : ScheduleManager::GetCurrentScheduleValue(state, elecBaseboard.SchedPtr) > 0.0) {
695 :
696 : // If the load exceeds the capacity than the capacity is set to the BB limit.
697 4662 : if (QZnReq > elecBaseboard.NominalCapacity) {
698 1108 : QBBCap = elecBaseboard.NominalCapacity;
699 : } else {
700 3554 : QBBCap = QZnReq;
701 : }
702 4662 : RadHeat = QBBCap * elecBaseboard.FracRadiant;
703 4662 : elecBaseboard.QBBElecRadSource = RadHeat;
704 :
705 4662 : if (elecBaseboard.FracRadiant > 0.0) { // User defines radiant heat addition
706 : // Now, distribute the radiant energy of all systems to the appropriate surfaces, to people, and the air
707 4662 : DistributeBBElecRadGains(state);
708 : // Now "simulate" the system by recalculating the heat balances
709 4662 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
710 4662 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
711 : // Here an assumption is made regarding radiant heat transfer to people.
712 : // While the radiant heat transfer to people array will be used by the thermal comfort
713 : // routines, the energy transfer to people would get lost from the perspective
714 : // of the heat balance. So, to avoid this net loss of energy which clearly
715 : // gets added to the zones, we must account for it somehow. This assumption
716 : // that all energy radiated to people is converted to convective energy is
717 : // not very precise, but at least it conserves energy. The system impact to heat balance
718 : // should include this.
719 4662 : LoadMet = (state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state) - elecBaseboard.ZeroBBSourceSumHATsurf) +
720 4662 : (QBBCap * elecBaseboard.FracConvect) + (RadHeat * elecBaseboard.FracDistribPerson);
721 :
722 4662 : if (LoadMet < 0.0) {
723 : // This basically means that SumHATsurf is LESS than ZeroBBSourceSumHATsurf which
724 : // should not happen unless something unusual is happening like a fast change
725 : // in temperature or some sort of change in internal load. This is not a problem
726 : // normally, but when LoadMet goes negative the choice is to either zero out
727 : // the baseboard or give it another shot at getting an accurate reading on
728 : // what is happening in the zone. If it is still predicting a negative heating
729 : // load, then zero everything out.
730 : // First, turn off the baseboard:
731 0 : elecBaseboard.QBBElecRadSource = 0.0;
732 0 : DistributeBBElecRadGains(state);
733 0 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
734 0 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
735 0 : Real64 TempZeroBBSourceSumHATsurf = state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state);
736 : // Now, turn it back on:
737 0 : elecBaseboard.QBBElecRadSource = RadHeat;
738 0 : DistributeBBElecRadGains(state);
739 0 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
740 0 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
741 : // Recalculate LoadMet with new ZeroBBSource... term and see if it is positive now. If not, shut it down.
742 0 : LoadMet = (state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state) - TempZeroBBSourceSumHATsurf) +
743 0 : (QBBCap * elecBaseboard.FracConvect) + (RadHeat * elecBaseboard.FracDistribPerson);
744 0 : if (LoadMet < 0.0) {
745 : // LoadMet is still less than zero so shut everything down
746 0 : UpdateElectricBaseboardOff(
747 0 : LoadMet, QBBCap, RadHeat, elecBaseboard.QBBElecRadSource, elecBaseboard.ElecUseRate, AirOutletTemp, AirInletTemp);
748 : } else {
749 : // Corrected LoadMet is now positive so use this and move forward with system operating
750 0 : UpdateElectricBaseboardOn(AirOutletTemp, elecBaseboard.ElecUseRate, AirInletTemp, QBBCap, CapacitanceAir, Effic);
751 : }
752 : } else {
753 :
754 4662 : UpdateElectricBaseboardOn(AirOutletTemp, elecBaseboard.ElecUseRate, AirInletTemp, QBBCap, CapacitanceAir, Effic);
755 : }
756 :
757 : } else { // zero radiant fraction, no need of recalculation of heat balances
758 :
759 0 : LoadMet = QBBCap;
760 0 : UpdateElectricBaseboardOn(AirOutletTemp, elecBaseboard.ElecUseRate, AirInletTemp, QBBCap, CapacitanceAir, Effic);
761 : }
762 :
763 : } else { // If there is an off condition the BB does nothing.
764 :
765 5238 : UpdateElectricBaseboardOff(
766 5238 : LoadMet, QBBCap, RadHeat, elecBaseboard.QBBElecRadSource, elecBaseboard.ElecUseRate, AirOutletTemp, AirInletTemp);
767 : }
768 :
769 : // Assign calculated ones
770 9900 : elecBaseboard.AirOutletTemp = AirOutletTemp;
771 9900 : elecBaseboard.Power = QBBCap;
772 9900 : elecBaseboard.TotPower = LoadMet;
773 9900 : elecBaseboard.RadPower = RadHeat;
774 9900 : elecBaseboard.ConvPower = QBBCap - RadHeat;
775 9900 : }
776 :
777 5238 : void UpdateElectricBaseboardOff(Real64 &LoadMet,
778 : Real64 &QBBCap,
779 : Real64 &RadHeat,
780 : Real64 &QBBElecRadSrc,
781 : Real64 &ElecUseRate,
782 : Real64 &AirOutletTemp,
783 : Real64 const AirInletTemp)
784 : {
785 :
786 : // SUBROUTINE INFORMATION:
787 : // AUTHOR Rick Strand
788 : // DATE WRITTEN August 2017
789 :
790 : // PURPOSE OF THIS SUBROUTINE: Zero out appropriate system variables when it is off
791 :
792 5238 : QBBCap = 0.0;
793 5238 : LoadMet = 0.0;
794 5238 : RadHeat = 0.0;
795 5238 : AirOutletTemp = AirInletTemp;
796 5238 : QBBElecRadSrc = 0.0;
797 5238 : ElecUseRate = 0.0;
798 5238 : }
799 :
800 4662 : void UpdateElectricBaseboardOn(
801 : Real64 &AirOutletTemp, Real64 &ElecUseRate, Real64 const AirInletTemp, Real64 const QBBCap, Real64 const CapacitanceAir, Real64 const Effic)
802 : {
803 :
804 : // SUBROUTINE INFORMATION:
805 : // AUTHOR Rick Strand
806 : // DATE WRITTEN August 2017
807 :
808 : // PURPOSE OF THIS SUBROUTINE: System is on, so calculate some of the result variables
809 :
810 4662 : AirOutletTemp = AirInletTemp + QBBCap / CapacitanceAir;
811 : // This could be utilized somehow or even reported so the data structures are left in place
812 : // The Baseboard electric Load is calculated using the efficiency
813 4662 : ElecUseRate = QBBCap / Effic;
814 4662 : }
815 :
816 9900 : void UpdateElectricBaseboard(EnergyPlusData &state, int const BaseboardNum)
817 : {
818 :
819 : // SUBROUTINE INFORMATION:
820 : // AUTHOR Russ Taylor
821 : // Rick Strand
822 : // DATE WRITTEN Nov 1997
823 : // February 2001
824 : // MODIFIED Feb 2010 Daeho Kang for radiant component
825 :
826 : // Using/Aliasing
827 9900 : Real64 SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
828 9900 : Real64 TimeStepSys = state.dataHVACGlobal->TimeStepSys;
829 9900 : auto &elecBaseboard = state.dataElectBaseboardRad->ElecBaseboard(BaseboardNum);
830 :
831 : // First, update the running average if necessary...
832 9900 : if (elecBaseboard.LastSysTimeElapsed == SysTimeElapsed) {
833 9444 : elecBaseboard.QBBElecRadSrcAvg -= elecBaseboard.LastQBBElecRadSrc * elecBaseboard.LastTimeStepSys / state.dataGlobal->TimeStepZone;
834 : }
835 : // Update the running average and the "last" values with the current values of the appropriate variables
836 9900 : elecBaseboard.QBBElecRadSrcAvg += elecBaseboard.QBBElecRadSource * TimeStepSys / state.dataGlobal->TimeStepZone;
837 :
838 9900 : elecBaseboard.LastQBBElecRadSrc = elecBaseboard.QBBElecRadSource;
839 9900 : elecBaseboard.LastSysTimeElapsed = SysTimeElapsed;
840 9900 : elecBaseboard.LastTimeStepSys = TimeStepSys;
841 9900 : }
842 :
843 2804482 : void UpdateBBElecRadSourceValAvg(EnergyPlusData &state, bool &ElecBaseboardSysOn) // .TRUE. if the radiant system has run this zone time step
844 : {
845 :
846 : // SUBROUTINE INFORMATION:
847 : // AUTHOR Rick Strand
848 : // DATE WRITTEN February 2001
849 : // MODIFIED Feb 2010 Daeho Kang for baseboard
850 :
851 : // PURPOSE OF THIS SUBROUTINE:
852 : // To transfer the average value of the heat source over the entire
853 : // zone time step back to the heat balance routines so that the heat
854 : // balance algorithms can simulate one last time with the average source
855 : // to maintain some reasonable amount of continuity and energy balance
856 : // in the temperature and flux histories.
857 :
858 : // METHODOLOGY EMPLOYED:
859 : // All of the record keeping for the average term is done in the Update
860 : // routine so the only other thing that this subroutine does is check to
861 : // see if the system was even on. If any average term is non-zero, then
862 : // one or more of the radiant systems was running.
863 :
864 2804482 : ElecBaseboardSysOn = false;
865 :
866 : // If this was never allocated, then there are no radiant systems in this input file (just RETURN)
867 2804482 : if (state.dataElectBaseboardRad->NumElecBaseboards == 0) return;
868 :
869 : // If it was allocated, then we have to check to see if this was running at all...
870 6084 : for (auto &elecBaseboard : state.dataElectBaseboardRad->ElecBaseboard) {
871 4056 : elecBaseboard.QBBElecRadSource = elecBaseboard.QBBElecRadSrcAvg;
872 4056 : if (elecBaseboard.QBBElecRadSrcAvg != 0.0) {
873 2012 : ElecBaseboardSysOn = true;
874 : }
875 : }
876 :
877 : // QBBElecRadSource has been modified so we need to redistribute gains
878 2028 : DistributeBBElecRadGains(state);
879 : }
880 :
881 6690 : void DistributeBBElecRadGains(EnergyPlusData &state)
882 : {
883 :
884 : // SUBROUTINE INFORMATION:
885 : // AUTHOR Rick Strand
886 : // DATE WRITTEN February 2001
887 : // MODIFIED Feb 2010 Daeho Kang for baseboard
888 : // April 2010 Brent Griffith, max limit to protect surface temperature calcs
889 :
890 : // PURPOSE OF THIS SUBROUTINE:
891 : // To distribute the gains from the electric basebaord heater
892 : // as specified in the user input file. This includes distribution
893 : // of long wavelength radiant gains to surfaces and "people."
894 :
895 : // METHODOLOGY EMPLOYED:
896 : // We must cycle through all of the radiant systems because each
897 : // surface could feel the effect of more than one radiant system.
898 : // Note that the energy radiated to people is assumed to affect them
899 : // but them it is assumed to be convected to the air.
900 :
901 : // SUBROUTINE PARAMETER DEFINITIONS:
902 6690 : Real64 constexpr SmallestArea(0.001); // Smallest area in meters squared (to avoid a divide by zero)
903 :
904 : // Initialize arrays
905 20070 : for (auto &elecBaseboard : state.dataElectBaseboardRad->ElecBaseboard) {
906 80280 : for (int radSurfNum = 1; radSurfNum <= elecBaseboard.TotSurfToDistrib; ++radSurfNum) {
907 66900 : int surfNum = elecBaseboard.SurfacePtr(radSurfNum);
908 66900 : state.dataHeatBalFanSys->surfQRadFromHVAC(surfNum).ElecBaseboard = 0.0;
909 : }
910 : }
911 6690 : state.dataHeatBalFanSys->ZoneQElecBaseboardToPerson = 0.0;
912 :
913 20070 : for (auto &elecBaseboard : state.dataElectBaseboardRad->ElecBaseboard) {
914 13380 : if (elecBaseboard.ZonePtr > 0) { // issue 5806 can be zero during first calls to baseboards, will be set after all are modeled
915 13380 : int ZoneNum = elecBaseboard.ZonePtr;
916 13380 : state.dataHeatBalFanSys->ZoneQElecBaseboardToPerson(ZoneNum) += elecBaseboard.QBBElecRadSource * elecBaseboard.FracDistribPerson;
917 :
918 80280 : for (int RadSurfNum = 1; RadSurfNum <= elecBaseboard.TotSurfToDistrib; ++RadSurfNum) {
919 66900 : int SurfNum = elecBaseboard.SurfacePtr(RadSurfNum);
920 66900 : if (state.dataSurface->Surface(SurfNum).Area > SmallestArea) {
921 : Real64 ThisSurfIntensity =
922 66900 : (elecBaseboard.QBBElecRadSource * elecBaseboard.FracDistribToSurf(RadSurfNum) / state.dataSurface->Surface(SurfNum).Area);
923 66900 : state.dataHeatBalFanSys->surfQRadFromHVAC(SurfNum).ElecBaseboard += ThisSurfIntensity;
924 66900 : if (ThisSurfIntensity > DataHeatBalFanSys::MaxRadHeatFlux) {
925 0 : ShowSevereError(state, "DistributeBBElecRadGains: excessive thermal radiation heat flux intensity detected");
926 0 : ShowContinueError(state, "Surface = " + state.dataSurface->Surface(SurfNum).Name);
927 0 : ShowContinueError(state, format("Surface area = {:.3R} [m2]", state.dataSurface->Surface(SurfNum).Area));
928 0 : ShowContinueError(state,
929 0 : "Occurs in " + state.dataElectBaseboardRad->cCMO_BBRadiator_Electric + " = " + elecBaseboard.EquipName);
930 0 : ShowContinueError(state, format("Radiation intensity = {:.2R} [W/m2]", ThisSurfIntensity));
931 0 : ShowContinueError(
932 0 : state, "Assign a larger surface area or more surfaces in " + state.dataElectBaseboardRad->cCMO_BBRadiator_Electric);
933 0 : ShowFatalError(state, "DistributeBBElecRadGains: excessive thermal radiation heat flux intensity detected");
934 : }
935 : } else {
936 0 : ShowSevereError(state, "DistributeBBElecRadGains: surface not large enough to receive thermal radiation heat flux");
937 0 : ShowContinueError(state, "Surface = " + state.dataSurface->Surface(SurfNum).Name);
938 0 : ShowContinueError(state, format("Surface area = {:.3R} [m2]", state.dataSurface->Surface(SurfNum).Area));
939 0 : ShowContinueError(state,
940 0 : "Occurs in " + state.dataElectBaseboardRad->cCMO_BBRadiator_Electric + " = " + elecBaseboard.EquipName);
941 0 : ShowContinueError(
942 0 : state, "Assign a larger surface area or more surfaces in " + state.dataElectBaseboardRad->cCMO_BBRadiator_Electric);
943 0 : ShowFatalError(state, "DistributeBBElecRadGains: surface not large enough to receive thermal radiation heat flux");
944 : }
945 : }
946 : }
947 : }
948 6690 : }
949 :
950 9900 : void ReportElectricBaseboard(EnergyPlusData &state, int const BaseboardNum)
951 : {
952 :
953 : // SUBROUTINE INFORMATION:
954 : // AUTHOR Daeho Kang
955 : // DATE WRITTEN Feb 2010
956 :
957 : // Using/Aliasing
958 9900 : Real64 TimeStepSysSec = state.dataHVACGlobal->TimeStepSysSec;
959 9900 : auto &elecBaseboard = state.dataElectBaseboardRad->ElecBaseboard(BaseboardNum);
960 9900 : elecBaseboard.ElecUseLoad = elecBaseboard.ElecUseRate * TimeStepSysSec;
961 9900 : elecBaseboard.TotEnergy = elecBaseboard.TotPower * TimeStepSysSec;
962 9900 : elecBaseboard.Energy = elecBaseboard.Power * TimeStepSysSec;
963 9900 : elecBaseboard.ConvEnergy = elecBaseboard.ConvPower * TimeStepSysSec;
964 9900 : elecBaseboard.RadEnergy = elecBaseboard.RadPower * TimeStepSysSec;
965 9900 : }
966 :
967 : } // namespace ElectricBaseboardRadiator
968 :
969 : } // namespace EnergyPlus
|