LCOV - code coverage report
Current view: top level - EnergyPlus - ElectricBaseboardRadiator.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 70.1 % 448 314
Test Date: 2025-05-22 16:09:37 Functions: 100.0 % 11 11

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

Generated by: LCOV version 2.0-1