Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // 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 containing the routines dealing with the electric baseboard heater
82 :
83 : // MODULE INFORMATION:
84 : // AUTHOR Daeho Kang
85 : // DATE WRITTEN Feb 2010
86 :
87 : // PURPOSE OF THIS MODULE:
88 : // This module is to calculate the actual convective heat addition that an electrical baseboard heater
89 : // deliveres to a space.
90 :
91 : // METHODOLOGY EMPLOYED:
92 : // Based on the convective-only electric baseboard module (Object: ZoneHVAC:Baseboard:Convective:Electric)
93 : // written by Richard Liesen in Nov 2001, this new electric baseboard module is to add the existing calculation
94 : // algorithm of radiant heat transfer in the high temperature radiant system module.
95 :
96 : // REFERENCES:
97 : // HighTempRadiantSystem module (ZoneHVAC:HighTemperatureRadiant)
98 : // Convective electric baseboard module (ZoneHVAC:Baseboard:Convective:Electric)
99 :
100 9956 : void SimElecBaseboard(EnergyPlusData &state,
101 : std::string const &EquipName,
102 : int const ControlledZoneNum,
103 : bool const FirstHVACIteration,
104 : Real64 &PowerMet,
105 : int &CompIndex)
106 : {
107 :
108 : // SUBROUTINE INFORMATION:
109 : // AUTHOR Richard Liesen
110 : // DATE WRITTEN Nov 2001
111 : // MODIFIED Feb 2010 Daeho Kang for radiant component
112 :
113 : // PURPOSE OF THIS SUBROUTINE:
114 : // This subroutine simulates the Electric Baseboard units.
115 :
116 : // REFERENCES:
117 : // Water baseboard module
118 :
119 : // Using/Aliasing
120 :
121 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
122 : int BaseboardNum; // Index of unit in baseboard array
123 9956 : auto &ElecBaseboard = state.dataElectBaseboardRad->ElecBaseboard;
124 9956 : auto &GetInputFlag = state.dataElectBaseboardRad->GetInputFlag;
125 9956 : auto &NumElecBaseboards = state.dataElectBaseboardRad->NumElecBaseboards;
126 9956 : auto &CheckEquipName = state.dataElectBaseboardRad->CheckEquipName;
127 :
128 9956 : if (GetInputFlag) {
129 1 : GetElectricBaseboardInput(state);
130 1 : GetInputFlag = false;
131 : }
132 :
133 : // Find the correct Baseboard Equipment
134 9956 : if (CompIndex == 0) {
135 2 : BaseboardNum = UtilityRoutines::FindItemInList(EquipName, ElecBaseboard, &ElecBaseboardParams::EquipName);
136 2 : if (BaseboardNum == 0) {
137 0 : ShowFatalError(state, "SimElectricBaseboard: Unit not found=" + EquipName);
138 : }
139 2 : CompIndex = BaseboardNum;
140 : } else {
141 9954 : BaseboardNum = CompIndex;
142 9954 : if (BaseboardNum > NumElecBaseboards || BaseboardNum < 1) {
143 0 : ShowFatalError(state,
144 0 : format("SimElectricBaseboard: Invalid CompIndex passed={}, Number of Units={}, Entered Unit name={}",
145 : BaseboardNum,
146 : NumElecBaseboards,
147 0 : EquipName));
148 : }
149 9954 : if (CheckEquipName(BaseboardNum)) {
150 2 : if (EquipName != ElecBaseboard(BaseboardNum).EquipName) {
151 0 : ShowFatalError(state,
152 0 : format("SimElectricBaseboard: Invalid CompIndex passed={}, Unit name={}, stored Unit Name for that index={}",
153 : BaseboardNum,
154 : EquipName,
155 0 : ElecBaseboard(BaseboardNum).EquipName));
156 : }
157 2 : CheckEquipName(BaseboardNum) = false;
158 : }
159 : }
160 :
161 9956 : InitElectricBaseboard(state, BaseboardNum, ControlledZoneNum, FirstHVACIteration);
162 9956 : CalcElectricBaseboard(state, BaseboardNum, ControlledZoneNum);
163 :
164 9956 : PowerMet = ElecBaseboard(BaseboardNum).TotPower;
165 :
166 9956 : UpdateElectricBaseboard(state, BaseboardNum);
167 9956 : ReportElectricBaseboard(state, BaseboardNum);
168 9956 : }
169 :
170 1 : void GetElectricBaseboardInput(EnergyPlusData &state)
171 : {
172 :
173 : // SUBROUTINE INFORMATION:
174 : // AUTHOR Richard Liesen
175 : // DATE WRITTEN Nov 2001
176 : // MODIFIED Feb 2010 Daeho Kang for radiant component
177 :
178 : // PURPOSE OF THIS SUBROUTINE:
179 : // This subroutine gets the input for the Baseboard units.
180 :
181 : // Using/Aliasing
182 : using DataSizing::AutoSize;
183 : using DataSizing::CapacityPerFloorArea;
184 : using DataSizing::FractionOfAutosizedHeatingCapacity;
185 : using DataSizing::HeatingDesignCapacity;
186 : using GlobalNames::VerifyUniqueBaseboardName;
187 : using ScheduleManager::GetScheduleIndex;
188 :
189 : // SUBROUTINE PARAMETER DEFINITIONS:
190 : static constexpr std::string_view RoutineName("GetElectricBaseboardInput: "); // include trailing blank space
191 1 : Real64 constexpr MaxFraction(1.0); // Maximum limit of fractional values
192 1 : Real64 constexpr MinFraction(0.0); // Minimum limit of fractional values
193 : // INTEGER,PARAMETER :: MaxDistribSurfaces = 20 ! Maximum number of surfaces that a baseboard heater can radiate to
194 1 : int constexpr MinDistribSurfaces(1); // Minimum number of surfaces that a baseboard heater can radiate to
195 1 : int constexpr iHeatCAPMAlphaNum(3); // get input index to HW baseboard heating capacity sizing method
196 1 : int constexpr iHeatDesignCapacityNumericNum(1); // get input index to HW baseboard heating capacity
197 1 : int constexpr iHeatCapacityPerFloorAreaNumericNum(2); // get input index to HW baseboard heating capacity per floor area sizing
198 1 : int constexpr iHeatFracOfAutosizedCapacityNumericNum(
199 : 3); // get input index to HW baseboard heating capacity sizing as fraction of autozized heating capacity
200 :
201 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
202 : Real64 AllFracsSummed; // Sum of the fractions radiant
203 : int BaseboardNum;
204 : int NumAlphas;
205 : int NumNumbers;
206 : int SurfNum; // surface number that radiant heat delivered
207 : int IOStat;
208 1 : bool ErrorsFound(false); // If errors detected in input
209 1 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
210 :
211 1 : cCurrentModuleObject = state.dataElectBaseboardRad->cCMO_BBRadiator_Electric;
212 :
213 1 : state.dataElectBaseboardRad->NumElecBaseboards = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
214 :
215 : // object is extensible, no max args needed as IPShortCuts being used
216 1 : auto &ElecBaseboard = state.dataElectBaseboardRad->ElecBaseboard;
217 1 : auto &CheckEquipName = state.dataElectBaseboardRad->CheckEquipName;
218 1 : auto &ElecBaseboardNumericFields = state.dataElectBaseboardRad->ElecBaseboardNumericFields;
219 1 : auto &NumElecBaseboards = state.dataElectBaseboardRad->NumElecBaseboards;
220 :
221 1 : ElecBaseboard.allocate(NumElecBaseboards);
222 1 : CheckEquipName.allocate(NumElecBaseboards);
223 1 : ElecBaseboardNumericFields.allocate(NumElecBaseboards);
224 1 : CheckEquipName = true;
225 :
226 3 : for (BaseboardNum = 1; BaseboardNum <= NumElecBaseboards; ++BaseboardNum) {
227 :
228 14 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
229 : cCurrentModuleObject,
230 : BaseboardNum,
231 2 : state.dataIPShortCut->cAlphaArgs,
232 : NumAlphas,
233 2 : state.dataIPShortCut->rNumericArgs,
234 : NumNumbers,
235 : IOStat,
236 2 : state.dataIPShortCut->lNumericFieldBlanks,
237 2 : state.dataIPShortCut->lAlphaFieldBlanks,
238 2 : state.dataIPShortCut->cAlphaFieldNames,
239 2 : state.dataIPShortCut->cNumericFieldNames);
240 :
241 2 : ElecBaseboardNumericFields(BaseboardNum).FieldNames.allocate(NumNumbers);
242 2 : ElecBaseboardNumericFields(BaseboardNum).FieldNames = "";
243 2 : ElecBaseboardNumericFields(BaseboardNum).FieldNames = state.dataIPShortCut->cNumericFieldNames;
244 2 : if (UtilityRoutines::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), cCurrentModuleObject, ErrorsFound)) {
245 0 : continue;
246 : }
247 :
248 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
249 2 : VerifyUniqueBaseboardName(state, cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1), ErrorsFound, cCurrentModuleObject + " Name");
250 :
251 2 : ElecBaseboard(BaseboardNum).EquipName = state.dataIPShortCut->cAlphaArgs(1); // name of this baseboard
252 2 : ElecBaseboard(BaseboardNum).Schedule = state.dataIPShortCut->cAlphaArgs(2);
253 2 : if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
254 0 : ElecBaseboard(BaseboardNum).SchedPtr = DataGlobalConstants::ScheduleAlwaysOn;
255 : } else {
256 2 : ElecBaseboard(BaseboardNum).SchedPtr = GetScheduleIndex(state, state.dataIPShortCut->cAlphaArgs(2));
257 2 : if (ElecBaseboard(BaseboardNum).SchedPtr == 0) {
258 0 : ShowSevereError(state,
259 0 : std::string{RoutineName} + cCurrentModuleObject + ": invalid " + state.dataIPShortCut->cAlphaFieldNames(2) +
260 0 : " entered =" + state.dataIPShortCut->cAlphaArgs(2) + " for " + state.dataIPShortCut->cAlphaFieldNames(1) +
261 0 : '=' + state.dataIPShortCut->cAlphaArgs(1));
262 0 : ErrorsFound = true;
263 : }
264 : }
265 :
266 : // Determine HW radiant baseboard heating design capacity sizing method
267 2 : if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "HeatingDesignCapacity")) {
268 2 : ElecBaseboard(BaseboardNum).HeatingCapMethod = HeatingDesignCapacity;
269 :
270 2 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatDesignCapacityNumericNum)) {
271 2 : ElecBaseboard(BaseboardNum).ScaledHeatingCapacity = state.dataIPShortCut->rNumericArgs(iHeatDesignCapacityNumericNum);
272 2 : if (ElecBaseboard(BaseboardNum).ScaledHeatingCapacity < 0.0 && ElecBaseboard(BaseboardNum).ScaledHeatingCapacity != AutoSize) {
273 0 : ShowSevereError(state, cCurrentModuleObject + " = " + ElecBaseboard(BaseboardNum).EquipName);
274 0 : ShowContinueError(state,
275 0 : format("Illegal {} = {:.7T}",
276 0 : state.dataIPShortCut->cNumericFieldNames(iHeatDesignCapacityNumericNum),
277 0 : state.dataIPShortCut->rNumericArgs(iHeatDesignCapacityNumericNum)));
278 0 : ErrorsFound = true;
279 : }
280 : } else {
281 0 : ShowSevereError(state, cCurrentModuleObject + " = " + ElecBaseboard(BaseboardNum).EquipName);
282 0 : ShowContinueError(state,
283 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
284 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
285 0 : ShowContinueError(state,
286 0 : "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(iHeatDesignCapacityNumericNum));
287 0 : ErrorsFound = true;
288 : }
289 0 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "CapacityPerFloorArea")) {
290 0 : ElecBaseboard(BaseboardNum).HeatingCapMethod = CapacityPerFloorArea;
291 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatCapacityPerFloorAreaNumericNum)) {
292 0 : ElecBaseboard(BaseboardNum).ScaledHeatingCapacity = state.dataIPShortCut->rNumericArgs(iHeatCapacityPerFloorAreaNumericNum);
293 0 : if (ElecBaseboard(BaseboardNum).ScaledHeatingCapacity <= 0.0) {
294 0 : ShowSevereError(state, cCurrentModuleObject + " = " + ElecBaseboard(BaseboardNum).EquipName);
295 0 : ShowContinueError(state,
296 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
297 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
298 0 : ShowContinueError(state,
299 0 : format("Illegal {} = {:.7T}",
300 0 : state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum),
301 0 : state.dataIPShortCut->rNumericArgs(iHeatCapacityPerFloorAreaNumericNum)));
302 0 : ErrorsFound = true;
303 0 : } else if (ElecBaseboard(BaseboardNum).ScaledHeatingCapacity == AutoSize) {
304 0 : ShowSevereError(state, cCurrentModuleObject + " = " + ElecBaseboard(BaseboardNum).EquipName);
305 0 : ShowContinueError(state,
306 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
307 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
308 0 : ShowContinueError(state,
309 0 : "Illegal " + state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum) + " = Autosize");
310 0 : ErrorsFound = true;
311 : }
312 : } else {
313 0 : ShowSevereError(state, cCurrentModuleObject + " = " + ElecBaseboard(BaseboardNum).EquipName);
314 0 : ShowContinueError(state,
315 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
316 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
317 0 : ShowContinueError(state,
318 0 : "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(iHeatCapacityPerFloorAreaNumericNum));
319 0 : ErrorsFound = true;
320 : }
321 0 : } else if (UtilityRoutines::SameString(state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum), "FractionOfAutosizedHeatingCapacity")) {
322 0 : ElecBaseboard(BaseboardNum).HeatingCapMethod = FractionOfAutosizedHeatingCapacity;
323 0 : if (!state.dataIPShortCut->lNumericFieldBlanks(iHeatFracOfAutosizedCapacityNumericNum)) {
324 0 : ElecBaseboard(BaseboardNum).ScaledHeatingCapacity = state.dataIPShortCut->rNumericArgs(iHeatFracOfAutosizedCapacityNumericNum);
325 0 : if (ElecBaseboard(BaseboardNum).ScaledHeatingCapacity < 0.0) {
326 0 : ShowSevereError(state, cCurrentModuleObject + " = " + ElecBaseboard(BaseboardNum).EquipName);
327 0 : ShowContinueError(state,
328 0 : format("Illegal {} = {:.7T}",
329 0 : state.dataIPShortCut->cNumericFieldNames(iHeatFracOfAutosizedCapacityNumericNum),
330 0 : state.dataIPShortCut->rNumericArgs(iHeatFracOfAutosizedCapacityNumericNum)));
331 0 : ErrorsFound = true;
332 : }
333 : } else {
334 0 : ShowSevereError(state, cCurrentModuleObject + " = " + ElecBaseboard(BaseboardNum).EquipName);
335 0 : ShowContinueError(state,
336 0 : "Input for " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
337 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
338 0 : ShowContinueError(
339 0 : state, "Blank field not allowed for " + state.dataIPShortCut->cNumericFieldNames(iHeatFracOfAutosizedCapacityNumericNum));
340 0 : ErrorsFound = true;
341 : }
342 : } else {
343 0 : ShowSevereError(state, cCurrentModuleObject + " = " + ElecBaseboard(BaseboardNum).EquipName);
344 0 : ShowContinueError(state,
345 0 : "Illegal " + state.dataIPShortCut->cAlphaFieldNames(iHeatCAPMAlphaNum) + " = " +
346 0 : state.dataIPShortCut->cAlphaArgs(iHeatCAPMAlphaNum));
347 0 : ErrorsFound = true;
348 : }
349 :
350 2 : ElecBaseboard(BaseboardNum).BaseboardEfficiency = state.dataIPShortCut->rNumericArgs(4);
351 2 : ElecBaseboard(BaseboardNum).FracRadiant = state.dataIPShortCut->rNumericArgs(5);
352 2 : if (ElecBaseboard(BaseboardNum).FracRadiant < MinFraction) {
353 0 : ShowWarningError(state,
354 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
355 0 : state.dataIPShortCut->cNumericFieldNames(5) + " was lower than the allowable minimum.");
356 0 : ShowContinueError(state, format("...reset to minimum value=[{:.2R}].", MinFraction));
357 0 : ElecBaseboard(BaseboardNum).FracRadiant = MinFraction;
358 : }
359 2 : if (ElecBaseboard(BaseboardNum).FracRadiant > MaxFraction) {
360 0 : ShowWarningError(state,
361 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
362 0 : state.dataIPShortCut->cNumericFieldNames(5) + " was higher than the allowable maximum.");
363 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MaxFraction));
364 0 : ElecBaseboard(BaseboardNum).FracRadiant = MaxFraction;
365 : }
366 :
367 : // Remaining fraction is added to the zone as convective heat transfer
368 2 : AllFracsSummed = ElecBaseboard(BaseboardNum).FracRadiant;
369 2 : if (AllFracsSummed > MaxFraction) {
370 0 : ShowWarningError(state,
371 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
372 : "\", Fraction Radiant was higher than the allowable maximum.");
373 0 : ElecBaseboard(BaseboardNum).FracRadiant = MaxFraction;
374 0 : ElecBaseboard(BaseboardNum).FracConvect = 0.0;
375 : } else {
376 2 : ElecBaseboard(BaseboardNum).FracConvect = 1.0 - AllFracsSummed;
377 : }
378 :
379 2 : ElecBaseboard(BaseboardNum).FracDistribPerson = state.dataIPShortCut->rNumericArgs(6);
380 2 : if (ElecBaseboard(BaseboardNum).FracDistribPerson < MinFraction) {
381 0 : ShowWarningError(state,
382 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
383 0 : state.dataIPShortCut->cNumericFieldNames(6) + " was lower than the allowable minimum.");
384 0 : ShowContinueError(state, format("...reset to minimum value=[{:.2R}].", MinFraction));
385 0 : ElecBaseboard(BaseboardNum).FracDistribPerson = MinFraction;
386 : }
387 2 : if (ElecBaseboard(BaseboardNum).FracDistribPerson > MaxFraction) {
388 0 : ShowWarningError(state,
389 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
390 0 : state.dataIPShortCut->cNumericFieldNames(6) + " was higher than the allowable maximum.");
391 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MaxFraction));
392 0 : ElecBaseboard(BaseboardNum).FracDistribPerson = MaxFraction;
393 : }
394 :
395 2 : ElecBaseboard(BaseboardNum).TotSurfToDistrib = NumNumbers - 6;
396 : // IF (ElecBaseboard(BaseboardNum)%TotSurfToDistrib > MaxDistribSurfaces) THEN
397 : // CALL ShowWarningError(state, RoutineName//TRIM(cCurrentModuleObject)//'="'//TRIM(state.dataIPShortCut->cAlphaArgs(1))// &
398 : // '", the number of surface/radiant fraction groups entered was higher than the allowable maximum.')
399 : // CALL ShowContinueError(state, '...only the maximum value=['//TRIM(RoundSigDigits(MaxDistribSurfaces))// &
400 : // '] will be processed.')
401 : // ElecBaseboard(BaseboardNum)%TotSurfToDistrib = MaxDistribSurfaces
402 : // END IF
403 2 : if ((ElecBaseboard(BaseboardNum).TotSurfToDistrib < MinDistribSurfaces) && (ElecBaseboard(BaseboardNum).FracRadiant > MinFraction)) {
404 0 : ShowSevereError(state,
405 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
406 : "\", the number of surface/radiant fraction groups entered was less than the allowable minimum.");
407 0 : ShowContinueError(state, format("...the minimum that must be entered=[{}].", MinDistribSurfaces));
408 0 : ErrorsFound = true;
409 0 : ElecBaseboard(BaseboardNum).TotSurfToDistrib = 0; // error
410 : }
411 :
412 2 : ElecBaseboard(BaseboardNum).SurfaceName.allocate(ElecBaseboard(BaseboardNum).TotSurfToDistrib);
413 2 : ElecBaseboard(BaseboardNum).SurfaceName = "";
414 2 : ElecBaseboard(BaseboardNum).SurfacePtr.allocate(ElecBaseboard(BaseboardNum).TotSurfToDistrib);
415 2 : ElecBaseboard(BaseboardNum).SurfacePtr = 0;
416 2 : ElecBaseboard(BaseboardNum).FracDistribToSurf.allocate(ElecBaseboard(BaseboardNum).TotSurfToDistrib);
417 2 : ElecBaseboard(BaseboardNum).FracDistribToSurf = 0.0;
418 :
419 2 : ElecBaseboard(BaseboardNum).ZonePtr = DataZoneEquipment::GetZoneEquipControlledZoneNum(
420 2 : state, DataZoneEquipment::ZoneEquip::BBElectric, ElecBaseboard(BaseboardNum).EquipName);
421 :
422 2 : AllFracsSummed = ElecBaseboard(BaseboardNum).FracDistribPerson;
423 12 : for (SurfNum = 1; SurfNum <= ElecBaseboard(BaseboardNum).TotSurfToDistrib; ++SurfNum) {
424 10 : ElecBaseboard(BaseboardNum).SurfaceName(SurfNum) = state.dataIPShortCut->cAlphaArgs(SurfNum + 3);
425 10 : ElecBaseboard(BaseboardNum).SurfacePtr(SurfNum) =
426 20 : HeatBalanceIntRadExchange::GetRadiantSystemSurface(state,
427 : cCurrentModuleObject,
428 10 : ElecBaseboard(BaseboardNum).EquipName,
429 10 : ElecBaseboard(BaseboardNum).ZonePtr,
430 10 : ElecBaseboard(BaseboardNum).SurfaceName(SurfNum),
431 : ErrorsFound);
432 10 : ElecBaseboard(BaseboardNum).FracDistribToSurf(SurfNum) = state.dataIPShortCut->rNumericArgs(SurfNum + 6);
433 10 : if (ElecBaseboard(BaseboardNum).FracDistribToSurf(SurfNum) > MaxFraction) {
434 0 : ShowWarningError(state,
435 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
436 0 : state.dataIPShortCut->cNumericFieldNames(SurfNum + 6) + "was greater than the allowable maximum.");
437 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MaxFraction));
438 0 : ElecBaseboard(BaseboardNum).TotSurfToDistrib = MaxFraction;
439 : }
440 10 : if (ElecBaseboard(BaseboardNum).FracDistribToSurf(SurfNum) < MinFraction) {
441 0 : ShowWarningError(state,
442 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", " +
443 0 : state.dataIPShortCut->cNumericFieldNames(SurfNum + 6) + "was less than the allowable minimum.");
444 0 : ShowContinueError(state, format("...reset to maximum value=[{:.2R}].", MinFraction));
445 0 : ElecBaseboard(BaseboardNum).TotSurfToDistrib = MinFraction;
446 : }
447 10 : if (ElecBaseboard(BaseboardNum).SurfacePtr(SurfNum) != 0) {
448 10 : state.dataSurface->SurfIntConvSurfGetsRadiantHeat(ElecBaseboard(BaseboardNum).SurfacePtr(SurfNum)) = true;
449 : }
450 :
451 10 : AllFracsSummed += ElecBaseboard(BaseboardNum).FracDistribToSurf(SurfNum);
452 : } // Surfaces
453 :
454 2 : if (AllFracsSummed > (MaxFraction + 0.01)) {
455 0 : ShowSevereError(state,
456 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
457 : "\", Summed radiant fractions for people + surface groups > 1.0");
458 0 : ErrorsFound = true;
459 : }
460 2 : if ((AllFracsSummed < (MaxFraction - 0.01)) &&
461 0 : (ElecBaseboard(BaseboardNum).FracRadiant >
462 : MinFraction)) { // User didn't distribute all of the | radiation warn that some will be lost
463 0 : ShowWarningError(state,
464 0 : std::string{RoutineName} + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) +
465 : "\", Summed radiant fractions for people + surface groups < 1.0");
466 0 : ShowContinueError(state, "The rest of the radiant energy delivered by the baseboard heater will be lost");
467 : }
468 : }
469 :
470 1 : if (ErrorsFound) {
471 0 : ShowFatalError(state, std::string{RoutineName} + cCurrentModuleObject + "Errors found getting input. Program terminates.");
472 : }
473 :
474 3 : for (BaseboardNum = 1; BaseboardNum <= NumElecBaseboards; ++BaseboardNum) {
475 :
476 : // Setup Report variables for the Electric Baseboards
477 : // CurrentModuleObject='ZoneHVAC:Baseboard:RadiantConvective:Electric'
478 8 : SetupOutputVariable(state,
479 : "Baseboard Total Heating Rate",
480 : OutputProcessor::Unit::W,
481 2 : ElecBaseboard(BaseboardNum).TotPower,
482 : OutputProcessor::SOVTimeStepType::System,
483 : OutputProcessor::SOVStoreType::Average,
484 4 : ElecBaseboard(BaseboardNum).EquipName);
485 :
486 8 : SetupOutputVariable(state,
487 : "Baseboard Convective Heating Rate",
488 : OutputProcessor::Unit::W,
489 2 : ElecBaseboard(BaseboardNum).ConvPower,
490 : OutputProcessor::SOVTimeStepType::System,
491 : OutputProcessor::SOVStoreType::Average,
492 4 : ElecBaseboard(BaseboardNum).EquipName);
493 8 : SetupOutputVariable(state,
494 : "Baseboard Radiant Heating Rate",
495 : OutputProcessor::Unit::W,
496 2 : ElecBaseboard(BaseboardNum).RadPower,
497 : OutputProcessor::SOVTimeStepType::System,
498 : OutputProcessor::SOVStoreType::Average,
499 4 : ElecBaseboard(BaseboardNum).EquipName);
500 :
501 8 : SetupOutputVariable(state,
502 : "Baseboard Electricity Energy",
503 : OutputProcessor::Unit::J,
504 2 : ElecBaseboard(BaseboardNum).ElecUseLoad,
505 : OutputProcessor::SOVTimeStepType::System,
506 : OutputProcessor::SOVStoreType::Summed,
507 2 : ElecBaseboard(BaseboardNum).EquipName,
508 : _,
509 : "Electricity",
510 : "HEATING",
511 : _,
512 2 : "System");
513 8 : SetupOutputVariable(state,
514 : "Baseboard Electricity Rate",
515 : OutputProcessor::Unit::W,
516 2 : ElecBaseboard(BaseboardNum).ElecUseRate,
517 : OutputProcessor::SOVTimeStepType::System,
518 : OutputProcessor::SOVStoreType::Average,
519 4 : ElecBaseboard(BaseboardNum).EquipName);
520 8 : SetupOutputVariable(state,
521 : "Baseboard Total Heating Energy",
522 : OutputProcessor::Unit::J,
523 2 : ElecBaseboard(BaseboardNum).TotEnergy,
524 : OutputProcessor::SOVTimeStepType::System,
525 : OutputProcessor::SOVStoreType::Summed,
526 2 : ElecBaseboard(BaseboardNum).EquipName,
527 : _,
528 : "ENERGYTRANSFER",
529 : "BASEBOARD",
530 : _,
531 2 : "System");
532 :
533 8 : SetupOutputVariable(state,
534 : "Baseboard Convective Heating Energy",
535 : OutputProcessor::Unit::J,
536 2 : ElecBaseboard(BaseboardNum).ConvEnergy,
537 : OutputProcessor::SOVTimeStepType::System,
538 : OutputProcessor::SOVStoreType::Summed,
539 4 : ElecBaseboard(BaseboardNum).EquipName);
540 8 : SetupOutputVariable(state,
541 : "Baseboard Radiant Heating Energy",
542 : OutputProcessor::Unit::J,
543 2 : ElecBaseboard(BaseboardNum).RadEnergy,
544 : OutputProcessor::SOVTimeStepType::System,
545 : OutputProcessor::SOVStoreType::Summed,
546 4 : ElecBaseboard(BaseboardNum).EquipName);
547 : }
548 1 : }
549 :
550 9956 : void InitElectricBaseboard(EnergyPlusData &state, int const BaseboardNum, int const ControlledZoneNum, bool const FirstHVACIteration)
551 : {
552 :
553 : // SUBROUTINE INFORMATION:
554 : // AUTHOR Richard Liesen
555 : // DATE WRITTEN Nov 2001
556 : // MODIFIED Feb 2010 Daeho Kang for radiant component
557 :
558 : // PURPOSE OF THIS SUBROUTINE:
559 : // This subroutine initializes the Baseboard units during simulation.
560 :
561 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
562 : int ZoneNode;
563 :
564 9956 : auto &ElecBaseboard = state.dataElectBaseboardRad->ElecBaseboard;
565 9956 : auto &NumElecBaseboards = state.dataElectBaseboardRad->NumElecBaseboards;
566 9956 : auto &MyOneTimeFlag = state.dataElectBaseboardRad->MyOneTimeFlag;
567 9956 : auto &MySizeFlag = state.dataElectBaseboardRad->MySizeFlag;
568 9956 : auto &ZeroSourceSumHATsurf = state.dataElectBaseboardRad->ZeroSourceSumHATsurf;
569 9956 : auto &QBBElecRadSource = state.dataElectBaseboardRad->QBBElecRadSource;
570 9956 : auto &QBBElecRadSrcAvg = state.dataElectBaseboardRad->QBBElecRadSrcAvg;
571 9956 : auto &LastQBBElecRadSrc = state.dataElectBaseboardRad->LastQBBElecRadSrc;
572 9956 : auto &LastSysTimeElapsed = state.dataElectBaseboardRad->LastSysTimeElapsed;
573 9956 : auto &LastTimeStepSys = state.dataElectBaseboardRad->LastTimeStepSys;
574 :
575 : // Do the one time initializations
576 9956 : if (MyOneTimeFlag) {
577 : // initialize the environment and sizing flags
578 1 : state.dataElectBaseboardRad->MyEnvrnFlag.allocate(NumElecBaseboards);
579 1 : MySizeFlag.allocate(NumElecBaseboards);
580 1 : ZeroSourceSumHATsurf.dimension(state.dataGlobal->NumOfZones, 0.0);
581 1 : QBBElecRadSource.dimension(NumElecBaseboards, 0.0);
582 1 : QBBElecRadSrcAvg.dimension(NumElecBaseboards, 0.0);
583 1 : LastQBBElecRadSrc.dimension(NumElecBaseboards, 0.0);
584 1 : LastSysTimeElapsed.dimension(NumElecBaseboards, 0.0);
585 1 : LastTimeStepSys.dimension(NumElecBaseboards, 0.0);
586 1 : state.dataElectBaseboardRad->MyEnvrnFlag = true;
587 1 : MySizeFlag = true;
588 :
589 1 : MyOneTimeFlag = false;
590 : }
591 :
592 9956 : if (!state.dataGlobal->SysSizingCalc && MySizeFlag(BaseboardNum)) {
593 : // for each coil, do the sizing once.
594 2 : SizeElectricBaseboard(state, BaseboardNum);
595 2 : MySizeFlag(BaseboardNum) = false;
596 : }
597 :
598 : // Do the Begin Environment initializations
599 9956 : if (state.dataGlobal->BeginEnvrnFlag && state.dataElectBaseboardRad->MyEnvrnFlag(BaseboardNum)) {
600 : // Initialize
601 12 : ZeroSourceSumHATsurf = 0.0;
602 12 : QBBElecRadSource = 0.0;
603 12 : QBBElecRadSrcAvg = 0.0;
604 12 : LastQBBElecRadSrc = 0.0;
605 12 : LastSysTimeElapsed = 0.0;
606 12 : LastTimeStepSys = 0.0;
607 :
608 12 : state.dataElectBaseboardRad->MyEnvrnFlag(BaseboardNum) = false;
609 : }
610 :
611 9956 : if (!state.dataGlobal->BeginEnvrnFlag) {
612 9894 : state.dataElectBaseboardRad->MyEnvrnFlag(BaseboardNum) = true;
613 : }
614 :
615 9956 : if (state.dataGlobal->BeginTimeStepFlag && FirstHVACIteration) {
616 4054 : ZeroSourceSumHATsurf(ControlledZoneNum) = state.dataHeatBal->Zone(ControlledZoneNum).sumHATsurf(state);
617 4054 : QBBElecRadSrcAvg(BaseboardNum) = 0.0;
618 4054 : LastQBBElecRadSrc(BaseboardNum) = 0.0;
619 4054 : LastSysTimeElapsed(BaseboardNum) = 0.0;
620 4054 : LastTimeStepSys(BaseboardNum) = 0.0;
621 : }
622 :
623 : // Do the every time step initializations
624 9956 : ZoneNode = state.dataZoneEquip->ZoneEquipConfig(ControlledZoneNum).ZoneNode;
625 9956 : ElecBaseboard(BaseboardNum).AirInletTemp = state.dataLoopNodes->Node(ZoneNode).Temp;
626 9956 : ElecBaseboard(BaseboardNum).AirInletHumRat = state.dataLoopNodes->Node(ZoneNode).HumRat;
627 :
628 : // Set the reporting variables to zero at each timestep.
629 9956 : ElecBaseboard(BaseboardNum).TotPower = 0.0;
630 9956 : ElecBaseboard(BaseboardNum).Power = 0.0;
631 9956 : ElecBaseboard(BaseboardNum).ConvPower = 0.0;
632 9956 : ElecBaseboard(BaseboardNum).RadPower = 0.0;
633 9956 : ElecBaseboard(BaseboardNum).TotEnergy = 0.0;
634 9956 : ElecBaseboard(BaseboardNum).Energy = 0.0;
635 9956 : ElecBaseboard(BaseboardNum).ConvEnergy = 0.0;
636 9956 : ElecBaseboard(BaseboardNum).RadEnergy = 0.0;
637 9956 : ElecBaseboard(BaseboardNum).ElecUseLoad = 0.0;
638 9956 : ElecBaseboard(BaseboardNum).ElecUseRate = 0.0;
639 9956 : }
640 :
641 2 : void SizeElectricBaseboard(EnergyPlusData &state, int const BaseboardNum)
642 : {
643 :
644 : // SUBROUTINE INFORMATION:
645 : // AUTHOR Fred Buhl
646 : // DATE WRITTEN February 2002
647 : // MODIFIED August 2013 Daeho Kang, add component sizing table entries
648 : // July 2014, B. Nigusse, added scalable sizing
649 :
650 : // PURPOSE OF THIS SUBROUTINE:
651 : // This subroutine is for sizing electric baseboard components for which nominal capacities have not been
652 : // specified in the input.
653 :
654 : // METHODOLOGY EMPLOYED:
655 : // Obtains flow rates from the zone sizing arrays and plant sizing data. UAs are
656 : // calculated by numerically inverting the baseboard calculation routine.
657 :
658 : // Using/Aliasing
659 : using namespace DataSizing;
660 : using DataHVACGlobals::HeatingCapacitySizing;
661 :
662 : // SUBROUTINE PARAMETER DEFINITIONS:
663 : static constexpr std::string_view RoutineName("SizeElectricBaseboard");
664 :
665 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
666 4 : std::string CompName; // component name
667 4 : std::string CompType; // component type
668 4 : std::string SizingString; // input field sizing description (e.g., Nominal Capacity)
669 : Real64 TempSize; // autosized value of coil input field
670 : Real64 FracOfAutoSzCap; // fraction of autosized capacity
671 2 : int FieldNum = 1; // IDD numeric field number where input field description is found
672 : int SizingMethod; // Integer representation of sizing method name (e.g., CoolingAirflowSizing, HeatingAirflowSizing, CoolingCapacitySizing,
673 : // HeatingCapacitySizing, etc.)
674 : bool PrintFlag; // TRUE when sizing information is reported in the eio file
675 2 : int CapSizingMethod(0); // capacity sizing methods (HeatingDesignCapacity, CapacityPerFloorArea, FractionOfAutosizedCoolingCapacity, and
676 : // FractionOfAutosizedHeatingCapacity )
677 :
678 2 : auto &ZoneEqSizing(state.dataSize->ZoneEqSizing);
679 2 : auto &ElecBaseboard = state.dataElectBaseboardRad->ElecBaseboard;
680 :
681 2 : state.dataSize->DataScalableCapSizingON = false;
682 :
683 2 : if (state.dataSize->CurZoneEqNum > 0) {
684 :
685 2 : CompType = state.dataElectBaseboardRad->cCMO_BBRadiator_Electric;
686 2 : CompName = ElecBaseboard(BaseboardNum).EquipName;
687 2 : state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
688 2 : state.dataSize->DataZoneNumber = ElecBaseboard(BaseboardNum).ZonePtr;
689 2 : SizingMethod = HeatingCapacitySizing;
690 2 : FieldNum = 1;
691 2 : PrintFlag = true;
692 2 : SizingString = state.dataElectBaseboardRad->ElecBaseboardNumericFields(BaseboardNum).FieldNames(FieldNum) + " [W]";
693 2 : CapSizingMethod = ElecBaseboard(BaseboardNum).HeatingCapMethod;
694 2 : ZoneEqSizing(state.dataSize->CurZoneEqNum).SizingMethod(SizingMethod) = CapSizingMethod;
695 2 : if (CapSizingMethod == HeatingDesignCapacity || CapSizingMethod == CapacityPerFloorArea ||
696 : CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
697 2 : if (CapSizingMethod == HeatingDesignCapacity) {
698 2 : if (ElecBaseboard(BaseboardNum).ScaledHeatingCapacity == AutoSize) {
699 2 : CheckZoneSizing(state, CompType, CompName);
700 2 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad =
701 2 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad;
702 : } else {
703 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad = ElecBaseboard(BaseboardNum).ScaledHeatingCapacity;
704 : }
705 2 : ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingCapacity = true;
706 2 : TempSize = ElecBaseboard(BaseboardNum).ScaledHeatingCapacity;
707 0 : } else if (CapSizingMethod == CapacityPerFloorArea) {
708 0 : if (state.dataSize->ZoneSizingRunDone) {
709 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingCapacity = true;
710 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad =
711 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad;
712 : }
713 0 : TempSize = ElecBaseboard(BaseboardNum).ScaledHeatingCapacity * state.dataHeatBal->Zone(state.dataSize->DataZoneNumber).FloorArea;
714 0 : state.dataSize->DataScalableCapSizingON = true;
715 0 : } else if (CapSizingMethod == FractionOfAutosizedHeatingCapacity) {
716 0 : CheckZoneSizing(state, CompType, CompName);
717 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).HeatingCapacity = true;
718 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = ElecBaseboard(BaseboardNum).ScaledHeatingCapacity;
719 0 : ZoneEqSizing(state.dataSize->CurZoneEqNum).DesHeatingLoad =
720 0 : state.dataSize->FinalZoneSizing(state.dataSize->CurZoneEqNum).NonAirSysDesHeatLoad;
721 0 : FracOfAutoSzCap = AutoSize;
722 0 : bool ErrorsFound = false;
723 0 : HeatingCapacitySizer sizerHeatingCapacity;
724 0 : sizerHeatingCapacity.overrideSizingString(SizingString);
725 0 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
726 0 : FracOfAutoSzCap = sizerHeatingCapacity.size(state, FracOfAutoSzCap, ErrorsFound);
727 0 : TempSize = FracOfAutoSzCap;
728 0 : state.dataSize->DataFracOfAutosizedHeatingCapacity = 1.0;
729 0 : state.dataSize->DataScalableCapSizingON = true;
730 : } else {
731 0 : TempSize = ElecBaseboard(BaseboardNum).ScaledHeatingCapacity;
732 : }
733 2 : bool errorsFound = false;
734 4 : HeatingCapacitySizer sizerHeatingCapacity;
735 2 : sizerHeatingCapacity.overrideSizingString(SizingString);
736 2 : sizerHeatingCapacity.initializeWithinEP(state, CompType, CompName, PrintFlag, RoutineName);
737 2 : ElecBaseboard(BaseboardNum).NominalCapacity = sizerHeatingCapacity.size(state, TempSize, errorsFound);
738 2 : state.dataSize->DataScalableCapSizingON = false;
739 : }
740 : }
741 2 : }
742 :
743 9956 : void CalcElectricBaseboard(EnergyPlusData &state, int const BaseboardNum, [[maybe_unused]] int const ControlledZoneNum)
744 : {
745 : // SUBROUTINE INFORMATION:
746 : // AUTHOR Richard Liesen
747 : // DATE WRITTEN Nov 2001
748 : // MODIFIED Feb 2010 Daeho Kang for radiant component
749 : // Sep 2011 LKL/BG - resimulate only zones needing it for Radiant systems
750 :
751 : // PURPOSE OF THIS SUBROUTINE:
752 : // This subroutine calculates the heat exchange rate in a Electric baseboard heater.
753 : // It includes radiant heat transfer to people and surfaces in a space, and the actual convective
754 : // system impact of a electric baseboard heater is determined after the radiant heat distribution.
755 :
756 : // METHODOLOGY EMPLOYED:
757 : // This is primarily modified from Convective Electric Baseboard. An existing algorithm of radiant
758 : // heat transfer calculation in the High Temperature Radiant System module is implemented.
759 :
760 : // Using/Aliasing
761 : using DataHVACGlobals::SmallLoad;
762 : using Psychrometrics::PsyCpAirFnW;
763 : using ScheduleManager::GetCurrentScheduleValue;
764 : using ScheduleManager::GetScheduleIndex;
765 :
766 : // SUBROUTINE PARAMETER DEFINITIONS:
767 9956 : Real64 constexpr SimpConvAirFlowSpeed(0.5); // m/s
768 :
769 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
770 : int ZoneNum;
771 : Real64 AirInletTemp;
772 : Real64 CpAir;
773 : Real64 AirMassFlowRate;
774 : Real64 CapacitanceAir;
775 : Real64 Effic;
776 : Real64 AirOutletTemp;
777 : Real64 QBBCap;
778 : Real64 RadHeat;
779 : Real64 QZnReq;
780 : Real64 LoadMet;
781 9956 : auto &ElecBaseboard = state.dataElectBaseboardRad->ElecBaseboard;
782 :
783 9956 : ZoneNum = ElecBaseboard(BaseboardNum).ZonePtr;
784 9956 : QZnReq = state.dataZoneEnergyDemand->ZoneSysEnergyDemand(ZoneNum).RemainingOutputReqToHeatSP;
785 9956 : AirInletTemp = ElecBaseboard(BaseboardNum).AirInletTemp;
786 9956 : AirOutletTemp = AirInletTemp;
787 9956 : CpAir = PsyCpAirFnW(ElecBaseboard(BaseboardNum).AirInletHumRat);
788 9956 : AirMassFlowRate = SimpConvAirFlowSpeed;
789 9956 : CapacitanceAir = CpAir * AirMassFlowRate;
790 :
791 : // Currently only the efficiency is used to calculate the electric consumption. There could be some
792 : // thermal loss that could be accounted for with this efficiency input.
793 9956 : Effic = ElecBaseboard(BaseboardNum).BaseboardEfficiency;
794 :
795 14615 : if (QZnReq > SmallLoad && !state.dataZoneEnergyDemand->CurDeadBandOrSetback(ZoneNum) &&
796 4659 : GetCurrentScheduleValue(state, ElecBaseboard(BaseboardNum).SchedPtr) > 0.0) {
797 :
798 : // If the load exceeds the capacity than the capacity is set to the BB limit.
799 4659 : if (QZnReq > ElecBaseboard(BaseboardNum).NominalCapacity) {
800 1108 : QBBCap = ElecBaseboard(BaseboardNum).NominalCapacity;
801 : } else {
802 3551 : QBBCap = QZnReq;
803 : }
804 4659 : RadHeat = QBBCap * ElecBaseboard(BaseboardNum).FracRadiant;
805 4659 : state.dataElectBaseboardRad->QBBElecRadSource(BaseboardNum) = RadHeat;
806 :
807 4659 : if (ElecBaseboard(BaseboardNum).FracRadiant > 0.0) { // User defines radiant heat addition
808 : // Now, distribute the radiant energy of all systems to the appropriate surfaces, to people, and the air
809 4659 : DistributeBBElecRadGains(state);
810 : // Now "simulate" the system by recalculating the heat balances
811 4659 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
812 4659 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
813 : // Here an assumption is made regarding radiant heat transfer to people.
814 : // While the radiant heat transfer to people array will be used by the thermal comfort
815 : // routines, the energy transfer to people would get lost from the perspective
816 : // of the heat balance. So, to avoid this net loss of energy which clearly
817 : // gets added to the zones, we must account for it somehow. This assumption
818 : // that all energy radiated to people is converted to convective energy is
819 : // not very precise, but at least it conserves energy. The system impact to heat balance
820 : // should include this.
821 13977 : LoadMet = (state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state) - state.dataElectBaseboardRad->ZeroSourceSumHATsurf(ZoneNum)) +
822 9318 : (QBBCap * ElecBaseboard(BaseboardNum).FracConvect) + (RadHeat * ElecBaseboard(BaseboardNum).FracDistribPerson);
823 :
824 4659 : if (LoadMet < 0.0) {
825 : // This basically means that SumHATsurf is LESS than ZeroSourceSumHATsurf which
826 : // should not happen unless something unusual is happening like a fast change
827 : // in temperature or some sort of change in internal load. This is not a problem
828 : // normally, but when LoadMet goes negative the choice is to either zero out
829 : // the baseboard or give it another shot at getting an accurate reading on
830 : // what is happening in the zone. If it is still predicting a negative heating
831 : // load, then zero everything out.
832 : // First, turn off the baseboard:
833 : Real64 TempZeroSourceSumHATsurf;
834 0 : state.dataElectBaseboardRad->QBBElecRadSource(BaseboardNum) = 0.0;
835 0 : DistributeBBElecRadGains(state);
836 0 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
837 0 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
838 0 : TempZeroSourceSumHATsurf = state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state);
839 : // Now, turn it back on:
840 0 : state.dataElectBaseboardRad->QBBElecRadSource(BaseboardNum) = RadHeat;
841 0 : DistributeBBElecRadGains(state);
842 0 : HeatBalanceSurfaceManager::CalcHeatBalanceOutsideSurf(state, ZoneNum);
843 0 : HeatBalanceSurfaceManager::CalcHeatBalanceInsideSurf(state, ZoneNum);
844 : // Recalculate LoadMet with new ZeroSource... term and see if it is positive now. If not, shut it down.
845 0 : LoadMet = (state.dataHeatBal->Zone(ZoneNum).sumHATsurf(state) - TempZeroSourceSumHATsurf) +
846 0 : (QBBCap * ElecBaseboard(BaseboardNum).FracConvect) + (RadHeat * ElecBaseboard(BaseboardNum).FracDistribPerson);
847 0 : if (LoadMet < 0.0) {
848 : // LoadMet is still less than zero so shut everything down
849 0 : UpdateElectricBaseboardOff(LoadMet,
850 : QBBCap,
851 : RadHeat,
852 0 : state.dataElectBaseboardRad->QBBElecRadSource(BaseboardNum),
853 0 : ElecBaseboard(BaseboardNum).ElecUseRate,
854 : AirOutletTemp,
855 : AirInletTemp);
856 : } else {
857 : // Corrected LoadMet is now positive so use this and move forward with system operating
858 0 : UpdateElectricBaseboardOn(
859 0 : AirOutletTemp, ElecBaseboard(BaseboardNum).ElecUseRate, AirInletTemp, QBBCap, CapacitanceAir, Effic);
860 : }
861 : } else {
862 :
863 4659 : UpdateElectricBaseboardOn(AirOutletTemp, ElecBaseboard(BaseboardNum).ElecUseRate, AirInletTemp, QBBCap, CapacitanceAir, Effic);
864 : }
865 :
866 : } else { // zero radiant fraction, no need of recalculation of heat balances
867 :
868 0 : LoadMet = QBBCap;
869 0 : UpdateElectricBaseboardOn(AirOutletTemp, ElecBaseboard(BaseboardNum).ElecUseRate, AirInletTemp, QBBCap, CapacitanceAir, Effic);
870 : }
871 :
872 : } else { // If there is an off condition the BB does nothing.
873 :
874 10594 : UpdateElectricBaseboardOff(LoadMet,
875 : QBBCap,
876 : RadHeat,
877 5297 : state.dataElectBaseboardRad->QBBElecRadSource(BaseboardNum),
878 5297 : ElecBaseboard(BaseboardNum).ElecUseRate,
879 : AirOutletTemp,
880 : AirInletTemp);
881 : }
882 :
883 : // Assign calculated ones
884 9956 : ElecBaseboard(BaseboardNum).AirOutletTemp = AirOutletTemp;
885 9956 : ElecBaseboard(BaseboardNum).Power = QBBCap;
886 9956 : ElecBaseboard(BaseboardNum).TotPower = LoadMet;
887 9956 : ElecBaseboard(BaseboardNum).RadPower = RadHeat;
888 9956 : ElecBaseboard(BaseboardNum).ConvPower = QBBCap - RadHeat;
889 9956 : }
890 :
891 5297 : void UpdateElectricBaseboardOff(Real64 &LoadMet,
892 : Real64 &QBBCap,
893 : Real64 &RadHeat,
894 : Real64 &QBBElecRadSrc,
895 : Real64 &ElecUseRate,
896 : Real64 &AirOutletTemp,
897 : Real64 const AirInletTemp)
898 : {
899 :
900 : // SUBROUTINE INFORMATION:
901 : // AUTHOR Rick Strand
902 : // DATE WRITTEN August 2017
903 :
904 : // PURPOSE OF THIS SUBROUTINE: Zero out appropriate system variables when it is off
905 :
906 5297 : QBBCap = 0.0;
907 5297 : LoadMet = 0.0;
908 5297 : RadHeat = 0.0;
909 5297 : AirOutletTemp = AirInletTemp;
910 5297 : QBBElecRadSrc = 0.0;
911 5297 : ElecUseRate = 0.0;
912 5297 : }
913 :
914 4659 : void UpdateElectricBaseboardOn(
915 : Real64 &AirOutletTemp, Real64 &ElecUseRate, Real64 const AirInletTemp, Real64 const QBBCap, Real64 const CapacitanceAir, Real64 const Effic)
916 : {
917 :
918 : // SUBROUTINE INFORMATION:
919 : // AUTHOR Rick Strand
920 : // DATE WRITTEN August 2017
921 :
922 : // PURPOSE OF THIS SUBROUTINE: System is on, so calculate some of the result variables
923 :
924 4659 : AirOutletTemp = AirInletTemp + QBBCap / CapacitanceAir;
925 : // This could be utilized somehow or even reported so the data structures are left in place
926 : // The Baseboard electric Load is calculated using the efficiency
927 4659 : ElecUseRate = QBBCap / Effic;
928 4659 : }
929 :
930 9956 : void UpdateElectricBaseboard(EnergyPlusData &state, int const BaseboardNum)
931 : {
932 :
933 : // SUBROUTINE INFORMATION:
934 : // AUTHOR Russ Taylor
935 : // Rick Strand
936 : // DATE WRITTEN Nov 1997
937 : // February 2001
938 : // MODIFIED Feb 2010 Daeho Kang for radiant component
939 :
940 : // Using/Aliasing
941 9956 : auto &SysTimeElapsed = state.dataHVACGlobal->SysTimeElapsed;
942 9956 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
943 :
944 : // First, update the running average if necessary...
945 9956 : if (state.dataElectBaseboardRad->LastSysTimeElapsed(BaseboardNum) == SysTimeElapsed) {
946 28458 : state.dataElectBaseboardRad->QBBElecRadSrcAvg(BaseboardNum) -= state.dataElectBaseboardRad->LastQBBElecRadSrc(BaseboardNum) *
947 18972 : state.dataElectBaseboardRad->LastTimeStepSys(BaseboardNum) /
948 9486 : state.dataGlobal->TimeStepZone;
949 : }
950 : // Update the running average and the "last" values with the current values of the appropriate variables
951 9956 : state.dataElectBaseboardRad->QBBElecRadSrcAvg(BaseboardNum) +=
952 9956 : state.dataElectBaseboardRad->QBBElecRadSource(BaseboardNum) * TimeStepSys / state.dataGlobal->TimeStepZone;
953 :
954 9956 : state.dataElectBaseboardRad->LastQBBElecRadSrc(BaseboardNum) = state.dataElectBaseboardRad->QBBElecRadSource(BaseboardNum);
955 9956 : state.dataElectBaseboardRad->LastSysTimeElapsed(BaseboardNum) = SysTimeElapsed;
956 9956 : state.dataElectBaseboardRad->LastTimeStepSys(BaseboardNum) = TimeStepSys;
957 9956 : }
958 :
959 2568313 : void UpdateBBElecRadSourceValAvg(EnergyPlusData &state, bool &ElecBaseboardSysOn) // .TRUE. if the radiant system has run this zone time step
960 : {
961 :
962 : // SUBROUTINE INFORMATION:
963 : // AUTHOR Rick Strand
964 : // DATE WRITTEN February 2001
965 : // MODIFIED Feb 2010 Daeho Kang for baseboard
966 :
967 : // PURPOSE OF THIS SUBROUTINE:
968 : // To transfer the average value of the heat source over the entire
969 : // zone time step back to the heat balance routines so that the heat
970 : // balance algorithms can simulate one last time with the average source
971 : // to maintain some reasonable amount of continuity and energy balance
972 : // in the temperature and flux histories.
973 :
974 : // METHODOLOGY EMPLOYED:
975 : // All of the record keeping for the average term is done in the Update
976 : // routine so the only other thing that this subroutine does is check to
977 : // see if the system was even on. If any average term is non-zero, then
978 : // one or more of the radiant systems was running.
979 :
980 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
981 : int BaseboardNum; // DO loop counter for surface index
982 :
983 2568313 : ElecBaseboardSysOn = false;
984 :
985 : // If this was never allocated, then there are no radiant systems in this input file (just RETURN)
986 2568313 : if (!allocated(state.dataElectBaseboardRad->QBBElecRadSrcAvg)) return;
987 :
988 : // If it was allocated, then we have to check to see if this was running at all...
989 4072 : for (BaseboardNum = 1; BaseboardNum <= state.dataElectBaseboardRad->NumElecBaseboards; ++BaseboardNum) {
990 3050 : if (state.dataElectBaseboardRad->QBBElecRadSrcAvg(BaseboardNum) != 0.0) {
991 1006 : ElecBaseboardSysOn = true;
992 1006 : break; // DO loop
993 : }
994 : }
995 :
996 2028 : state.dataElectBaseboardRad->QBBElecRadSource = state.dataElectBaseboardRad->QBBElecRadSrcAvg;
997 :
998 : // QBBElecRadSource has been modified so we need to redistribute gains
999 :
1000 2028 : DistributeBBElecRadGains(state);
1001 : }
1002 :
1003 6687 : void DistributeBBElecRadGains(EnergyPlusData &state)
1004 : {
1005 :
1006 : // SUBROUTINE INFORMATION:
1007 : // AUTHOR Rick Strand
1008 : // DATE WRITTEN February 2001
1009 : // MODIFIED Feb 2010 Daeho Kang for baseboard
1010 : // April 2010 Brent Griffith, max limit to protect surface temperature calcs
1011 :
1012 : // PURPOSE OF THIS SUBROUTINE:
1013 : // To distribute the gains from the electric basebaord heater
1014 : // as specified in the user input file. This includes distribution
1015 : // of long wavelength radiant gains to surfaces and "people."
1016 :
1017 : // METHODOLOGY EMPLOYED:
1018 : // We must cycle through all of the radiant systems because each
1019 : // surface could feel the effect of more than one radiant system.
1020 : // Note that the energy radiated to people is assumed to affect them
1021 : // but them it is assumed to be convected to the air.
1022 :
1023 : // Using/Aliasing
1024 : using DataHeatBalFanSys::MaxRadHeatFlux;
1025 :
1026 : // SUBROUTINE PARAMETER DEFINITIONS:
1027 6687 : Real64 constexpr SmallestArea(0.001); // Smallest area in meters squared (to avoid a divide by zero)
1028 :
1029 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1030 : int RadSurfNum; // Counter for surfaces receiving radiation from radiant heater
1031 : int BaseboardNum; // Counter for the baseboard
1032 : int SurfNum; // Pointer to the Surface derived type
1033 : int ZoneNum; // Pointer to the Zone derived type
1034 : Real64 ThisSurfIntensity; // temporary for W/m2 term for rad on a surface
1035 :
1036 : // Initialize arrays
1037 6687 : state.dataHeatBalFanSys->SurfQElecBaseboard = 0.0;
1038 6687 : state.dataHeatBalFanSys->ZoneQElecBaseboardToPerson = 0.0;
1039 :
1040 6687 : auto &ElecBaseboard = state.dataElectBaseboardRad->ElecBaseboard;
1041 20061 : for (BaseboardNum = 1; BaseboardNum <= state.dataElectBaseboardRad->NumElecBaseboards; ++BaseboardNum) {
1042 :
1043 13374 : if (ElecBaseboard(BaseboardNum).ZonePtr >
1044 : 0) { // issue 5806 can be zero during first calls to baseboards, will be set after all are modeled
1045 13374 : ZoneNum = ElecBaseboard(BaseboardNum).ZonePtr;
1046 13374 : state.dataHeatBalFanSys->ZoneQElecBaseboardToPerson(ZoneNum) +=
1047 13374 : state.dataElectBaseboardRad->QBBElecRadSource(BaseboardNum) * ElecBaseboard(BaseboardNum).FracDistribPerson;
1048 :
1049 80244 : for (RadSurfNum = 1; RadSurfNum <= ElecBaseboard(BaseboardNum).TotSurfToDistrib; ++RadSurfNum) {
1050 66870 : SurfNum = ElecBaseboard(BaseboardNum).SurfacePtr(RadSurfNum);
1051 66870 : if (state.dataSurface->Surface(SurfNum).Area > SmallestArea) {
1052 200610 : ThisSurfIntensity = (state.dataElectBaseboardRad->QBBElecRadSource(BaseboardNum) *
1053 133740 : ElecBaseboard(BaseboardNum).FracDistribToSurf(RadSurfNum) / state.dataSurface->Surface(SurfNum).Area);
1054 66870 : state.dataHeatBalFanSys->SurfQElecBaseboard(SurfNum) += ThisSurfIntensity;
1055 66870 : state.dataHeatBalSurf->AnyRadiantSystems = true;
1056 66870 : if (ThisSurfIntensity > MaxRadHeatFlux) {
1057 0 : ShowSevereError(state, "DistributeBBElecRadGains: excessive thermal radiation heat flux intensity detected");
1058 0 : ShowContinueError(state, "Surface = " + state.dataSurface->Surface(SurfNum).Name);
1059 0 : ShowContinueError(state, format("Surface area = {:.3R} [m2]", state.dataSurface->Surface(SurfNum).Area));
1060 0 : ShowContinueError(state,
1061 0 : "Occurs in " + state.dataElectBaseboardRad->cCMO_BBRadiator_Electric + " = " +
1062 0 : ElecBaseboard(BaseboardNum).EquipName);
1063 0 : ShowContinueError(state, format("Radiation intensity = {:.2R} [W/m2]", ThisSurfIntensity));
1064 0 : ShowContinueError(
1065 0 : state, "Assign a larger surface area or more surfaces in " + state.dataElectBaseboardRad->cCMO_BBRadiator_Electric);
1066 0 : ShowFatalError(state, "DistributeBBElecRadGains: excessive thermal radiation heat flux intensity detected");
1067 : }
1068 : } else {
1069 0 : ShowSevereError(state, "DistributeBBElecRadGains: surface not large enough to receive thermal radiation heat flux");
1070 0 : ShowContinueError(state, "Surface = " + state.dataSurface->Surface(SurfNum).Name);
1071 0 : ShowContinueError(state, format("Surface area = {:.3R} [m2]", state.dataSurface->Surface(SurfNum).Area));
1072 0 : ShowContinueError(state,
1073 0 : "Occurs in " + state.dataElectBaseboardRad->cCMO_BBRadiator_Electric + " = " +
1074 0 : ElecBaseboard(BaseboardNum).EquipName);
1075 0 : ShowContinueError(
1076 0 : state, "Assign a larger surface area or more surfaces in " + state.dataElectBaseboardRad->cCMO_BBRadiator_Electric);
1077 0 : ShowFatalError(state, "DistributeBBElecRadGains: surface not large enough to receive thermal radiation heat flux");
1078 : }
1079 : }
1080 : }
1081 : }
1082 6687 : }
1083 :
1084 9956 : void ReportElectricBaseboard(EnergyPlusData &state, int const BaseboardNum)
1085 : {
1086 :
1087 : // SUBROUTINE INFORMATION:
1088 : // AUTHOR Daeho Kang
1089 : // DATE WRITTEN Feb 2010
1090 :
1091 : // Using/Aliasing
1092 9956 : auto &TimeStepSys = state.dataHVACGlobal->TimeStepSys;
1093 9956 : auto &ElecBaseboard = state.dataElectBaseboardRad->ElecBaseboard;
1094 9956 : ElecBaseboard(BaseboardNum).ElecUseLoad = ElecBaseboard(BaseboardNum).ElecUseRate * TimeStepSys * DataGlobalConstants::SecInHour;
1095 9956 : ElecBaseboard(BaseboardNum).TotEnergy = ElecBaseboard(BaseboardNum).TotPower * TimeStepSys * DataGlobalConstants::SecInHour;
1096 9956 : ElecBaseboard(BaseboardNum).Energy = ElecBaseboard(BaseboardNum).Power * TimeStepSys * DataGlobalConstants::SecInHour;
1097 9956 : ElecBaseboard(BaseboardNum).ConvEnergy = ElecBaseboard(BaseboardNum).ConvPower * TimeStepSys * DataGlobalConstants::SecInHour;
1098 9956 : ElecBaseboard(BaseboardNum).RadEnergy = ElecBaseboard(BaseboardNum).RadPower * TimeStepSys * DataGlobalConstants::SecInHour;
1099 9956 : }
1100 :
1101 : } // namespace ElectricBaseboardRadiator
1102 :
1103 2313 : } // namespace EnergyPlus
|