LCOV - code coverage report
Current view: top level - EnergyPlus - IceThermalStorage.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 1.7 % 929 16
Test Date: 2025-05-22 16:09:37 Functions: 11.1 % 27 3

            Line data    Source code
       1              : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
       2              : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
       3              : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
       4              : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
       5              : // contributors. All rights reserved.
       6              : //
       7              : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
       8              : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
       9              : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
      10              : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
      11              : // derivative works, and perform publicly and display publicly, and to permit others to do so.
      12              : //
      13              : // Redistribution and use in source and binary forms, with or without modification, are permitted
      14              : // provided that the following conditions are met:
      15              : //
      16              : // (1) Redistributions of source code must retain the above copyright notice, this list of
      17              : //     conditions and the following disclaimer.
      18              : //
      19              : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
      20              : //     conditions and the following disclaimer in the documentation and/or other materials
      21              : //     provided with the distribution.
      22              : //
      23              : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
      24              : //     the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
      25              : //     used to endorse or promote products derived from this software without specific prior
      26              : //     written permission.
      27              : //
      28              : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
      29              : //     without changes from the version obtained under this License, or (ii) Licensee makes a
      30              : //     reference solely to the software portion of its product, Licensee must refer to the
      31              : //     software as "EnergyPlus version X" software, where "X" is the version number Licensee
      32              : //     obtained under this License and may not use a different name for the software. Except as
      33              : //     specifically required in this Section (4), Licensee shall not use in a company name, a
      34              : //     product name, in advertising, publicity, or other promotional activities any name, trade
      35              : //     name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
      36              : //     similar designation, without the U.S. Department of Energy's prior written consent.
      37              : //
      38              : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
      39              : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      40              : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
      41              : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      42              : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      43              : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      44              : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      45              : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      46              : // POSSIBILITY OF SUCH DAMAGE.
      47              : 
      48              : // C++ Headers
      49              : #include <cassert>
      50              : #include <cmath>
      51              : 
      52              : // ObjexxFCL Headers
      53              : #include <ObjexxFCL/Fmath.hh>
      54              : 
      55              : // EnergyPlus Headers
      56              : #include <EnergyPlus/BranchNodeConnections.hh>
      57              : #include <EnergyPlus/CurveManager.hh>
      58              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      59              : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
      60              : #include <EnergyPlus/DataHVACGlobals.hh>
      61              : #include <EnergyPlus/DataIPShortCuts.hh>
      62              : #include <EnergyPlus/DataLoopNode.hh>
      63              : #include <EnergyPlus/FluidProperties.hh>
      64              : #include <EnergyPlus/General.hh>
      65              : #include <EnergyPlus/IceThermalStorage.hh>
      66              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      67              : #include <EnergyPlus/NodeInputManager.hh>
      68              : #include <EnergyPlus/OutputProcessor.hh>
      69              : #include <EnergyPlus/Plant/DataPlant.hh>
      70              : #include <EnergyPlus/Plant/PlantLocation.hh>
      71              : #include <EnergyPlus/PlantUtilities.hh>
      72              : #include <EnergyPlus/Psychrometrics.hh>
      73              : #include <EnergyPlus/ScheduleManager.hh>
      74              : #include <EnergyPlus/UtilityRoutines.hh>
      75              : 
      76              : namespace EnergyPlus {
      77              : 
      78              : namespace IceThermalStorage {
      79              : 
      80              :     // MODULE INFORMATION:
      81              :     //       AUTHOR         Pyeongchan Ihm
      82              :     //       DATE WRITTEN   April 2002
      83              :     //       MODIFIED       Modified Refined model, added Simple model, by Guo Zhou, Oct 2002
      84              :     //                      Remove chiller, make just a storage tank, Michael J. Witte, Sep 2005
      85              :     //                      Added detailed ice storage model, Rick Strand, Feb 2006
      86              :     //                      B. Griffith, Sept 2010, plant upgrades, fluid properties
      87              :     //                      Enhancements to detailed ice storage model, Rick Strand, Aug 2012
      88              :     //       RE-ENGINEERED  na
      89              : 
      90              :     // PURPOSE OF THIS MODULE:
      91              :     // This module simulates the performance of Ice Thermal Storage
      92              : 
      93              :     // METHODOLOGY EMPLOYED:
      94              :     // Once the PlantLoopManager determines that the Ice Thermal Storage
      95              :     // is available to meet a loop cooling demand, it calls SimIceStorage
      96              :     // which in turn calls the appropriate Ice Thermal Storage model.
      97              : 
      98              :     // REFERENCES: Dion J. King, ASHRAE Transactions v104, pt1, 1998.
      99              : 
     100              :     std::string const cIceStorageSimple("ThermalStorage:Ice:Simple");
     101              :     std::string const cIceStorageDetailed("ThermalStorage:Ice:Detailed");
     102              : 
     103              :     // ITS parameter
     104              :     constexpr Real64 FreezTemp(0.0);       // Water freezing Temperature, 0[C]
     105              :     constexpr Real64 FreezTempIP(32.0);    // Water freezing Temperature, 32[F]
     106              :     constexpr Real64 TimeInterval(3600.0); // Time Interval (1 hr) [s]
     107              : 
     108              :     // Conversion parameter
     109              :     constexpr Real64 EpsLimitForX(0.0);         // 0.02  ! See Dion's code as eps1
     110              :     constexpr Real64 EpsLimitForDisCharge(0.0); // 0.20  ! See Dion's code as eps2
     111              :     constexpr Real64 EpsLimitForCharge(0.0);    // 0.20  ! See Dion's code as eps3
     112              : 
     113              :     // Parameter used by the Detailed Ice Storage Model
     114              :     constexpr Real64 DeltaTofMin(0.5); // Minimum allowed outlet side temperature difference [C]
     115              :     // This is (Tout - Tfreezing)
     116              :     constexpr Real64 DeltaTifMin(1.0); // Minimum allowed inlet side temperature difference [C]
     117              :     // This is (Tin - Tfreezing)
     118              : 
     119            0 :     PlantComponent *SimpleIceStorageData::factory(EnergyPlusData &state, std::string const &objectName)
     120              :     {
     121              :         // Process the input data for boilers if it hasn't been done already
     122            0 :         if (state.dataIceThermalStorage->getITSInput) {
     123            0 :             GetIceStorageInput(state);
     124            0 :             state.dataIceThermalStorage->getITSInput = false;
     125              :         }
     126              : 
     127              :         // Now look for this particular pipe in the list
     128            0 :         for (auto &ITS : state.dataIceThermalStorage->SimpleIceStorage) {
     129            0 :             if (ITS.Name == objectName) {
     130            0 :                 return &ITS;
     131              :             }
     132              :         }
     133              :         // If we didn't find it, fatal
     134            0 :         ShowFatalError(state,
     135              :                        format("LocalSimpleIceStorageFactory: Error getting inputs for simple ice storage named: {}", objectName)); // LCOV_EXCL_LINE
     136              :         // Shut up the compiler
     137              :         return nullptr; // LCOV_EXCL_LINE
     138              :     }
     139              : 
     140            0 :     PlantComponent *DetailedIceStorageData::factory(EnergyPlusData &state, std::string const &objectName)
     141              :     {
     142              :         // Process the input data for boilers if it hasn't been done already
     143            0 :         if (state.dataIceThermalStorage->getITSInput) {
     144            0 :             GetIceStorageInput(state);
     145            0 :             state.dataIceThermalStorage->getITSInput = false;
     146              :         }
     147              : 
     148              :         // Now look for this particular pipe in the list
     149            0 :         for (auto &ITS : state.dataIceThermalStorage->DetailedIceStorage) {
     150            0 :             if (ITS.Name == objectName) {
     151            0 :                 return &ITS;
     152              :             }
     153              :         }
     154              :         // If we didn't find it, fatal
     155            0 :         ShowFatalError(
     156              :             state, format("LocalDetailedIceStorageFactory: Error getting inputs for detailed ice storage named: {}", objectName)); // LCOV_EXCL_LINE
     157              :         // Shut up the compiler
     158              :         return nullptr; // LCOV_EXCL_LINE
     159              :     }
     160              : 
     161            0 :     void SimpleIceStorageData::simulate(EnergyPlusData &state,
     162              :                                         const PlantLocation &calledFromLocation,
     163              :                                         [[maybe_unused]] bool FirstHVACIteration,
     164              :                                         [[maybe_unused]] Real64 &CurLoad,
     165              :                                         bool RunFlag)
     166              :     {
     167              :         static constexpr std::string_view RoutineName("SimpleIceStorageData::simulate");
     168              : 
     169              :         // this was happening in PlantLoopEquip before
     170            0 :         auto &thisComp(state.dataPlnt->PlantLoop(calledFromLocation.loopNum)
     171            0 :                            .LoopSide(calledFromLocation.loopSideNum)
     172            0 :                            .Branch(calledFromLocation.branchNum)
     173            0 :                            .Comp(calledFromLocation.compNum));
     174              : 
     175              :         // If component setpoint based control is active for this equipment
     176              :         // then reset CurLoad to original EquipDemand.
     177              :         // Allow negative CurLoad.  For cold storage this means the storage should
     178              :         // charge, for hot storage, this means the storage should discharge.
     179            0 :         if (thisComp.CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) {
     180            0 :             Real64 localCurLoad = thisComp.EquipDemand;
     181            0 :             if (localCurLoad != 0) RunFlag = true;
     182              :         }
     183              : 
     184            0 :         if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
     185            0 :             this->ResetXForITSFlag = true;
     186            0 :             this->MyEnvrnFlag = false;
     187              :         }
     188              : 
     189            0 :         if (!state.dataGlobal->BeginEnvrnFlag) {
     190            0 :             this->MyEnvrnFlag = true;
     191              :         }
     192              : 
     193            0 :         this->oneTimeInit(state);
     194              : 
     195              :         //------------------------------------------------------------------------
     196              :         // FIRST PROCESS (MyLoad = 0.0 as IN)
     197              :         // At this moment as first calling of ITS, ITS provide ONLY MaxCap/OptCap/MinCap.
     198              :         //------------------------------------------------------------------------
     199              :         // First process is in subroutine CalcIceStorageCapacity(MaxCap,MinCap,OptCap) shown bellow.
     200              : 
     201              :         //------------------------------------------------------------------------
     202              :         // SECOND PROCESS (MyLoad is provided by E+ based on MaxCap/OptCap/MinCap)
     203              :         //------------------------------------------------------------------------
     204              :         // Below routines are starting when second calling.
     205              :         // After previous return, MyLoad is calculated based on MaxCap, OptCap, and MinCap.
     206              :         // Then PlandSupplySideManager provides MyLoad to simulate Ice Thermal Storage.
     207              :         // The process will be decided based on sign(+,-,0) of input U.
     208              : 
     209              :         // MJW 19 Sep 2005 - New approach - calculate MyLoad locally from inlet node temp
     210              :         //                   and outlet node setpoint until MyLoad that is passed in behaves well
     211              : 
     212            0 :         Real64 TempSetPt(0.0);
     213            0 :         Real64 TempIn = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
     214            0 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
     215            0 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     216            0 :             TempSetPt = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPoint;
     217            0 :         } break;
     218            0 :         case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
     219            0 :             TempSetPt = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPointHi;
     220            0 :         } break;
     221            0 :         default: {
     222            0 :             assert(false);
     223              :         } break;
     224              :         }
     225            0 :         Real64 DemandMdot = this->DesignMassFlowRate;
     226              : 
     227            0 :         Real64 Cp = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getSpecificHeat(state, TempIn, RoutineName);
     228              : 
     229            0 :         Real64 MyLoad2 = (DemandMdot * Cp * (TempIn - TempSetPt));
     230            0 :         MyLoad = MyLoad2;
     231              : 
     232              :         //     Set fraction of ice remaining in storage
     233            0 :         this->XCurIceFrac = this->IceFracRemain;
     234              : 
     235              :         //***** Dormant Process for ITS *****************************************
     236              :         //************************************************************************
     237              :         //        IF( U .EQ. 0.0 ) THEN
     238            0 :         if ((MyLoad2 == 0.0) || (DemandMdot == 0.0)) {
     239            0 :             this->CalcIceStorageDormant(state);
     240              : 
     241              :             //***** Charging Process for ITS *****************************************
     242              :             //************************************************************************
     243              :             //        ELSE IF( U .GT. 0.0 ) THEN
     244            0 :         } else if (MyLoad2 < 0.0) {
     245              : 
     246              :             Real64 MaxCap;
     247              :             Real64 MinCap;
     248              :             Real64 OptCap;
     249            0 :             this->CalcIceStorageCapacity(state, MaxCap, MinCap, OptCap);
     250            0 :             this->CalcIceStorageCharge(state);
     251              : 
     252              :             //***** Discharging Process for ITS *****************************************
     253              :             //************************************************************************
     254              :             //        ELSE IF( U .LT. 0.0 ) THEN
     255            0 :         } else if (MyLoad2 > 0.0) {
     256              : 
     257              :             Real64 MaxCap;
     258              :             Real64 MinCap;
     259              :             Real64 OptCap;
     260            0 :             this->CalcIceStorageCapacity(state, MaxCap, MinCap, OptCap);
     261            0 :             this->CalcIceStorageDischarge(state, MyLoad, RunFlag, MaxCap);
     262              :         } // Based on input of U value, deciding Dormant/Charge/Discharge process
     263              : 
     264              :         // Update Node properties: mdot and Temperature
     265            0 :         this->UpdateNode(state, MyLoad2, RunFlag);
     266              : 
     267              :         // Update report variables.
     268            0 :         this->RecordOutput(MyLoad2, RunFlag);
     269            0 :     }
     270              : 
     271            0 :     void DetailedIceStorageData::simulate(EnergyPlusData &state,
     272              :                                           [[maybe_unused]] const PlantLocation &calledFromLocation,
     273              :                                           [[maybe_unused]] bool FirstHVACIteration,
     274              :                                           [[maybe_unused]] Real64 &CurLoad,
     275              :                                           [[maybe_unused]] bool RunFlag)
     276              :     {
     277              : 
     278            0 :         if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
     279            0 :             this->ResetXForITSFlag = true;
     280            0 :             this->MyEnvrnFlag = false;
     281              :         }
     282              : 
     283            0 :         if (!state.dataGlobal->BeginEnvrnFlag) {
     284            0 :             this->MyEnvrnFlag = true;
     285              :         }
     286              : 
     287            0 :         this->oneTimeInit(state); // Initialize detailed ice storage
     288              : 
     289            0 :         this->SimDetailedIceStorage(state); // Simulate detailed ice storage
     290              : 
     291            0 :         this->UpdateDetailedIceStorage(state); // Update detailed ice storage
     292              : 
     293            0 :         this->ReportDetailedIceStorage(state); // Report detailed ice storage
     294            0 :     }
     295              : 
     296            0 :     void DetailedIceStorageData::SimDetailedIceStorage(EnergyPlusData &state)
     297              :     {
     298              : 
     299              :         // SUBROUTINE INFORMATION:
     300              :         //       AUTHOR         Rick Strand
     301              :         //       DATE WRITTEN   February 2006
     302              :         //       MODIFIED       na
     303              :         //       RE-ENGINEERED  na
     304              : 
     305              :         // PURPOSE OF THIS SUBROUTINE:
     306              :         // This subroutine is the main simulation subroutine for the detailed
     307              :         // ice storage model.
     308              : 
     309              :         // METHODOLOGY EMPLOYED:
     310              :         // Based on whether the unit is dormant, in charging mode, or in discharging
     311              :         // mode, the code either passes the flow through the bypass, through the tank,
     312              :         // or both.  This depends on the temperature relative to the setpoint temperature
     313              :         // and other features of the model.  The model itself is a LMTD model that uses
     314              :         // performance curve fits that are quadratic in fraction charged/discharged and
     315              :         // linear in LMTD for the calculation of Q.  The equations are actually non-
     316              :         // dimensionalized.
     317              : 
     318              :         // REFERENCES:
     319              :         // Ice Storage Component Model Proposal (Revised).doc by Rick Strand (Dec 2005/Jan 2006)
     320              : 
     321            0 :         int constexpr MaxIterNum(100);                      // Maximum number of internal iterations for ice storage solution
     322            0 :         Real64 constexpr SmallestLoad(0.1);                 // Smallest load to actually run the ice storage unit [Watts]
     323            0 :         Real64 constexpr TankDischargeToler(0.001);         // Below this fraction, there is nothing left to discharge
     324            0 :         Real64 constexpr TankChargeToler(0.999);            // Above this fraction, we don't have anything left to charge
     325            0 :         Real64 constexpr TemperatureToler(0.1);             // Temperature difference between iterations that indicates convergence [C]
     326            0 :         Real64 constexpr SIEquiv100GPMinMassFlowRate(6.31); // Used to non-dimensionalize flow rate for use in CubicLinear charging equation
     327              :                                                             // Flow rate divided by nominal 100GPM used to non-dimensionalize volume flow rate
     328              :                                                             // Assumes approximate density of 1000 kg/m3 to get an estimate for mass flow rate
     329              :         static constexpr std::string_view RoutineName("DetailedIceStorageData::SimDetailedIceStorage");
     330              : 
     331            0 :         int NodeNumIn = this->PlantInNodeNum;                      // Plant loop inlet node number for component
     332            0 :         int NodeNumOut = this->PlantOutNodeNum;                    // Plant loop outlet node number for component
     333            0 :         Real64 TempIn = state.dataLoopNodes->Node(NodeNumIn).Temp; // Inlet temperature to component (from plant loop) [C]
     334            0 :         Real64 TempSetPt(0.0);                                     // Setpoint temperature defined by loop controls [C]
     335            0 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
     336            0 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     337            0 :             TempSetPt = state.dataLoopNodes->Node(NodeNumOut).TempSetPoint;
     338            0 :         } break;
     339            0 :         case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
     340            0 :             TempSetPt = state.dataLoopNodes->Node(NodeNumOut).TempSetPointHi;
     341            0 :         } break;
     342            0 :         default: {
     343            0 :             assert(false);
     344              :         } break;
     345              :         }
     346              : 
     347            0 :         int IterNum = 0;
     348              : 
     349              :         // Set derived type variables
     350            0 :         this->InletTemp = TempIn;
     351            0 :         this->MassFlowRate = state.dataLoopNodes->Node(NodeNumIn).MassFlowRate;
     352              : 
     353              :         // if two-way common pipe and no mass flow and tank is not full, then use design flow rate
     354            0 :         if ((state.dataPlnt->PlantLoop(this->plantLoc.loopNum).CommonPipeType == DataPlant::CommonPipeType::TwoWay) &&
     355            0 :             (std::abs(this->MassFlowRate) < DataBranchAirLoopPlant::MassFlowTolerance) && (this->IceFracRemaining < TankChargeToler)) {
     356            0 :             this->MassFlowRate = this->DesignMassFlowRate;
     357              :         }
     358              : 
     359              :         // Calculate the current load on the ice storage unit
     360            0 :         Real64 Cp = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getSpecificHeat(state, TempIn, RoutineName);
     361              : 
     362              :         // Estimated load on the ice storage unit [W]
     363            0 :         Real64 LocalLoad = this->MassFlowRate * Cp * (TempIn - TempSetPt);
     364              : 
     365              :         // Determine what the status is regarding the ice storage unit and the loop level flow
     366            0 :         if ((std::abs(LocalLoad) <= SmallestLoad) || (this->availSched->getCurrentVal() <= 0)) {
     367              :             // No real load on the ice storage device or ice storage OFF--bypass all of the flow and leave the tank alone
     368            0 :             this->CompLoad = 0.0;
     369            0 :             this->OutletTemp = TempIn;
     370            0 :             this->TankOutletTemp = TempIn;
     371            0 :             Real64 mdot = 0.0;
     372            0 :             PlantUtilities::SetComponentFlowRate(state, mdot, this->PlantInNodeNum, this->PlantOutNodeNum, this->plantLoc);
     373              : 
     374            0 :             this->BypassMassFlowRate = mdot;
     375            0 :             this->TankMassFlowRate = 0.0;
     376            0 :             this->MassFlowRate = mdot;
     377              : 
     378            0 :         } else if (LocalLoad < 0.0) {
     379              :             // The load is less than zero so we should be charging
     380              :             // Before we do anything, we should check to make sure that we will actually be charging the unit
     381              : 
     382            0 :             if ((TempIn > (this->FreezingTemp - DeltaTifMin)) || (this->IceFracRemaining >= TankChargeToler)) {
     383              :                 // If the inlet temperature is not below the freezing temperature of the
     384              :                 // device, then we cannot actually do any charging.  Bypass all of the flow.
     385              :                 // Also, if the tank is already sufficiently charged, we don't need to
     386              :                 // do any further charging.  So, bypass all of the flow.
     387            0 :                 this->CompLoad = 0.0;
     388            0 :                 this->OutletTemp = TempIn;
     389            0 :                 this->TankOutletTemp = TempIn;
     390            0 :                 Real64 mdot = 0.0;
     391            0 :                 PlantUtilities::SetComponentFlowRate(state, mdot, this->PlantInNodeNum, this->PlantOutNodeNum, this->plantLoc);
     392              : 
     393            0 :                 this->BypassMassFlowRate = mdot;
     394            0 :                 this->TankMassFlowRate = 0.0;
     395            0 :                 this->MassFlowRate = mdot;
     396              : 
     397            0 :             } else {
     398              :                 // make flow request so tank will get flow
     399            0 :                 Real64 mdot = this->DesignMassFlowRate;
     400            0 :                 PlantUtilities::SetComponentFlowRate(state, mdot, this->PlantInNodeNum, this->PlantOutNodeNum, this->plantLoc);
     401              : 
     402              :                 // We are in charging mode, the temperatures are low enough to charge
     403              :                 // the tank, and we have some charging left to do.
     404              :                 // Make first guess at Qstar based on the current ice fraction remaining
     405              :                 // and LMTDstar that is based on the freezing or TempSetPt temperature.
     406            0 :                 if (TempSetPt > (this->FreezingTemp - DeltaTofMin)) {
     407              :                     // Outlet temperature cannot be above the freezing temperature so set
     408              :                     // the outlet temperature to the freezing temperature and calculate
     409              :                     // LMTDstar based on that assumption.
     410            0 :                     TempSetPt = this->FreezingTemp - DeltaTofMin;
     411              :                 }
     412              : 
     413              :                 // Tank outlet temperature from the last iteration [C]
     414            0 :                 Real64 ToutOld = TempSetPt;
     415              :                 // Non-dimensional log mean temperature difference of ice storage unit [non-dimensional]
     416            0 :                 Real64 LMTDstar = CalcDetIceStorLMTDstar(TempIn, ToutOld, this->FreezingTemp);
     417            0 :                 Real64 MassFlowstar = this->MassFlowRate / SIEquiv100GPMinMassFlowRate;
     418              : 
     419              :                 // Find initial guess at average fraction charged during time step
     420              :                 // Fraction of tank to be charged in the current time step
     421            0 :                 Real64 ChargeFrac = LocalLoad * state.dataHVACGlobal->TimeStepSys / this->NomCapacity;
     422            0 :                 if ((this->IceFracRemaining + ChargeFrac) > 1.0) {
     423            0 :                     ChargeFrac = 1.0 - this->IceFracRemaining;
     424              :                 }
     425              : 
     426              :                 Real64 AvgFracCharged; // Average fraction charged for the current time step
     427            0 :                 if (this->ThawProcessIndex == DetIce::InsideMelt) {
     428            0 :                     AvgFracCharged = this->IceFracOnCoil + (ChargeFrac / 2.0);
     429              :                 } else { // (DetailedIceStorage(IceNum)%ThawProcessIndex == DetIce::OutsideMelt)
     430            0 :                     AvgFracCharged = this->IceFracRemaining + (ChargeFrac / 2.0);
     431              :                 }
     432              : 
     433              :                 // Current load on the ice storage unit [non-dimensional]
     434            0 :                 Real64 Qstar = std::abs(CalcQstar(state, this->ChargeCurveNum, this->ChargeCurveTypeNum, AvgFracCharged, LMTDstar, MassFlowstar));
     435              : 
     436              :                 // Actual load on the ice storage unit [W]
     437            0 :                 Real64 ActualLoad = Qstar * this->NomCapacity / this->CurveFitTimeStep;
     438              : 
     439              :                 // Updated outlet temperature from the tank [C]
     440            0 :                 Real64 ToutNew = TempIn + (ActualLoad / (this->MassFlowRate * Cp));
     441              :                 // Again, the outlet temperature cannot be above the freezing temperature (factoring in the tolerance)
     442            0 :                 if (ToutNew > (this->FreezingTemp - DeltaTofMin)) ToutNew = this->FreezingTemp - DeltaTofMin;
     443              : 
     444            0 :                 if (ActualLoad > std::abs(LocalLoad)) {
     445              :                     // We have more than enough capacity to meet the load so no need to iterate to find a solution
     446            0 :                     this->OutletTemp = TempSetPt;
     447            0 :                     this->TankOutletTemp = ToutNew;
     448            0 :                     this->CompLoad = this->MassFlowRate * Cp * std::abs(TempIn - TempSetPt);
     449            0 :                     this->TankMassFlowRate = this->CompLoad / Cp / std::abs(TempIn - ToutNew);
     450            0 :                     this->BypassMassFlowRate = this->MassFlowRate - this->TankMassFlowRate;
     451              : 
     452              :                 } else {
     453              : 
     454            0 :                     while (IterNum < MaxIterNum) {
     455            0 :                         if (std::abs(ToutOld - ToutNew) > TemperatureToler) {
     456              :                             // Not converged yet so recalculated what is needed and keep iterating
     457              :                             // Calculate new values for LMTDstar and Qstar based on updated outlet temperature
     458            0 :                             ToutOld = ToutNew;
     459            0 :                             LMTDstar = CalcDetIceStorLMTDstar(TempIn, ToutOld, this->FreezingTemp);
     460            0 :                             MassFlowstar = this->MassFlowRate / SIEquiv100GPMinMassFlowRate;
     461              :                             Qstar =
     462            0 :                                 std::abs(CalcQstar(state, this->ChargeCurveNum, this->ChargeCurveTypeNum, AvgFracCharged, LMTDstar, MassFlowstar));
     463              : 
     464              :                             // Now make sure that we don't go above 100% charged and calculate the new average fraction
     465            0 :                             ChargeFrac = Qstar * (state.dataHVACGlobal->TimeStepSys / this->CurveFitTimeStep);
     466            0 :                             if ((this->IceFracRemaining + ChargeFrac) > 1.0) {
     467            0 :                                 ChargeFrac = 1.0 - this->IceFracRemaining;
     468            0 :                                 Qstar = ChargeFrac;
     469              :                             }
     470            0 :                             if (this->ThawProcessIndex == DetIce::InsideMelt) {
     471            0 :                                 AvgFracCharged = this->IceFracOnCoil + (ChargeFrac / 2.0);
     472              :                             } else { // (DetailedIceStorage(IceNum)%ThawProcessIndex == DetIce::OutsideMelt)
     473            0 :                                 AvgFracCharged = this->IceFracRemaining + (ChargeFrac / 2.0);
     474              :                             }
     475              : 
     476              :                             // Finally, update the actual load and calculate the new outlet temperature; increment iteration counter
     477            0 :                             ActualLoad = Qstar * this->NomCapacity / this->CurveFitTimeStep;
     478            0 :                             ToutNew = TempIn + (ActualLoad / (this->MassFlowRate * Cp));
     479              :                             // Again, the outlet temperature cannot be above the freezing temperature (factoring in the tolerance)
     480            0 :                             if (ToutNew < (this->FreezingTemp - DeltaTofMin)) ToutNew = this->FreezingTemp - DeltaTofMin;
     481            0 :                             ++IterNum;
     482              : 
     483              :                         } else {
     484              :                             // Converged to acceptable tolerance so set output variables and exit DO WHILE loop
     485            0 :                             break;
     486              :                         }
     487              : 
     488              :                     } // ...loop iterating for the ice storage outlet temperature
     489              : 
     490              :                     // Keep track of times that the iterations got excessive and report if necessary
     491            0 :                     if (IterNum >= MaxIterNum) {
     492            0 :                         ++this->ChargeIterErrors;
     493            0 :                         if (this->ChargeIterErrors <= 25) {
     494            0 :                             ShowWarningError(state, "Detailed Ice Storage model exceeded its internal charging maximum iteration limit");
     495            0 :                             ShowContinueError(state, format("Detailed Ice Storage System Name = {}", this->Name));
     496            0 :                             ShowContinueErrorTimeStamp(state, "");
     497              :                         } else {
     498            0 :                             ShowRecurringWarningErrorAtEnd(state,
     499            0 :                                                            "Detailed Ice Storage system [" + this->Name +
     500              :                                                                "]  charging maximum iteration limit exceeded occurrence continues.",
     501            0 :                                                            this->ChargeErrorCount);
     502              :                         }
     503              :                     }
     504              : 
     505              :                     // Set the values for the key outlet parameters
     506              :                     // Note that in REAL(r64)ity the tank will probably bypass some flow when it
     507              :                     // gets close to full charge.  This is a simplification that assumes
     508              :                     // all flow through the tank during charging and a lower delta T near
     509              :                     // the full charge level.  From an energy perspective, this is a reasonable
     510              :                     // approximation.
     511            0 :                     this->OutletTemp = ToutNew;
     512            0 :                     this->TankOutletTemp = ToutNew;
     513            0 :                     this->BypassMassFlowRate = 0.0;
     514            0 :                     this->TankMassFlowRate = this->MassFlowRate;
     515            0 :                     this->CompLoad = this->MassFlowRate * Cp * std::abs(TempIn - ToutNew);
     516              :                 }
     517              :             }
     518              : 
     519            0 :         } else if (LocalLoad > 0.0) {
     520              :             // The load is greater than zero so we should be discharging
     521              :             // Before we do anything, we should check to make sure that we will actually be discharging the unit
     522              : 
     523            0 :             if ((this->InletTemp < (this->FreezingTemp + DeltaTifMin)) || (this->IceFracRemaining <= TankDischargeToler)) {
     524              :                 // If the inlet temperature is below the freezing temperature of the
     525              :                 // device, then we cannot actually do any discharging.  Bypass all of the flow.
     526              :                 // Also, if the tank is already discharged, we can't to do any further
     527              :                 // discharging.  So, bypass all of the flow.
     528            0 :                 this->CompLoad = 0.0;
     529            0 :                 this->OutletTemp = this->InletTemp;
     530            0 :                 this->TankOutletTemp = this->InletTemp;
     531            0 :                 Real64 mdot = 0.0;
     532            0 :                 PlantUtilities::SetComponentFlowRate(state, mdot, this->PlantInNodeNum, this->PlantOutNodeNum, this->plantLoc);
     533              : 
     534            0 :                 this->BypassMassFlowRate = mdot;
     535            0 :                 this->TankMassFlowRate = 0.0;
     536            0 :                 this->MassFlowRate = mdot;
     537              : 
     538            0 :             } else {
     539              : 
     540              :                 // make flow request so tank will get flow
     541            0 :                 Real64 mdot = this->DesignMassFlowRate;
     542            0 :                 PlantUtilities::SetComponentFlowRate(state, mdot, this->PlantInNodeNum, this->PlantOutNodeNum, this->plantLoc);
     543              : 
     544              :                 // We are in discharging mode, the temperatures are high enough to discharge
     545              :                 // the tank, and we have some discharging left to do.
     546            0 :                 if (TempSetPt < (this->FreezingTemp + DeltaTofMin)) {
     547              :                     // Outlet temperature cannot be below the freezing temperature so set
     548              :                     // the outlet temperature to the freezing temperature and calculate
     549              :                     // LMTDstar based on that assumption.
     550            0 :                     TempSetPt = this->FreezingTemp + DeltaTofMin;
     551              :                 }
     552              : 
     553              :                 // Tank outlet temperature from the last iteration [C]
     554            0 :                 Real64 ToutOld = TempSetPt;
     555              :                 // Non-dimensional log mean temperature difference of ice storage unit [non-dimensional]
     556            0 :                 Real64 LMTDstar = CalcDetIceStorLMTDstar(TempIn, ToutOld, this->FreezingTemp);
     557            0 :                 Real64 MassFlowstar = this->MassFlowRate / SIEquiv100GPMinMassFlowRate;
     558              : 
     559              :                 // Find initial guess at average fraction charged during time step
     560            0 :                 Real64 ChargeFrac = LocalLoad * state.dataHVACGlobal->TimeStepSys / this->NomCapacity;
     561            0 :                 if ((this->IceFracRemaining - ChargeFrac) < 0.0) ChargeFrac = this->IceFracRemaining;
     562            0 :                 Real64 AvgFracCharged = this->IceFracRemaining - (ChargeFrac / 2.0);
     563              : 
     564              :                 // Current load on the ice storage unit [non-dimensional]
     565              :                 Real64 Qstar =
     566            0 :                     std::abs(CalcQstar(state, this->DischargeCurveNum, this->DischargeCurveTypeNum, AvgFracCharged, LMTDstar, MassFlowstar));
     567              : 
     568              :                 // Actual load on the ice storage unit [W]
     569            0 :                 Real64 ActualLoad = Qstar * this->NomCapacity / this->CurveFitTimeStep;
     570              : 
     571              :                 // Updated outlet temperature from the tank [C]
     572            0 :                 Real64 ToutNew = TempIn - (ActualLoad / (this->MassFlowRate * Cp));
     573              :                 // Again, the outlet temperature cannot be below the freezing temperature (factoring in the tolerance)
     574            0 :                 if (ToutNew < (this->FreezingTemp + DeltaTofMin)) ToutNew = this->FreezingTemp + DeltaTofMin;
     575              : 
     576            0 :                 if (ActualLoad > LocalLoad) {
     577              :                     // We have more than enough storage to meet the load so no need to iterate to find a solution
     578            0 :                     this->OutletTemp = TempSetPt;
     579            0 :                     this->TankOutletTemp = ToutNew;
     580            0 :                     this->CompLoad = this->MassFlowRate * Cp * std::abs(TempIn - TempSetPt);
     581            0 :                     this->TankMassFlowRate = this->CompLoad / Cp / std::abs(TempIn - ToutNew);
     582            0 :                     this->BypassMassFlowRate = this->MassFlowRate - this->TankMassFlowRate;
     583              : 
     584              :                 } else {
     585              : 
     586            0 :                     while (IterNum < MaxIterNum) {
     587            0 :                         if (std::abs(ToutOld - ToutNew) > TemperatureToler) {
     588              :                             // Not converged yet so recalculated what is needed and keep iterating
     589              :                             // Calculate new values for LMTDstar and Qstar based on updated outlet temperature
     590            0 :                             ToutOld = ToutNew;
     591            0 :                             LMTDstar = CalcDetIceStorLMTDstar(TempIn, ToutOld, this->FreezingTemp);
     592              : 
     593            0 :                             Qstar = std::abs(
     594              :                                 CalcQstar(state, this->DischargeCurveNum, this->DischargeCurveTypeNum, AvgFracCharged, LMTDstar, MassFlowstar));
     595              : 
     596              :                             // Now make sure that we don't go below 100% discharged and calculate the new average fraction
     597            0 :                             ChargeFrac = Qstar * (state.dataHVACGlobal->TimeStepSys / this->CurveFitTimeStep);
     598            0 :                             if ((this->IceFracRemaining - ChargeFrac) < 0.0) {
     599            0 :                                 ChargeFrac = this->IceFracRemaining;
     600            0 :                                 Qstar = ChargeFrac;
     601              :                             }
     602            0 :                             AvgFracCharged = this->IceFracRemaining - (ChargeFrac / 2.0);
     603              : 
     604              :                             // Finally, update the actual load and calculate the new outlet temperature; increment iteration counter
     605            0 :                             ActualLoad = Qstar * this->NomCapacity / this->CurveFitTimeStep;
     606            0 :                             ToutNew = TempIn - (ActualLoad / (this->MassFlowRate * Cp));
     607              :                             // Again, the outlet temperature cannot be below the freezing temperature (factoring in the tolerance)
     608            0 :                             if (ToutNew < (this->FreezingTemp + DeltaTofMin)) ToutNew = this->FreezingTemp + DeltaTofMin;
     609            0 :                             ++IterNum;
     610              : 
     611              :                         } else {
     612              :                             // Converged to acceptable tolerance so set output variables and exit DO WHILE loop
     613            0 :                             break;
     614              :                         }
     615              : 
     616              :                     } // ...loop iterating for the ice storage outlet temperature
     617              : 
     618              :                     // Keep track of times that the iterations got excessive
     619            0 :                     if (IterNum >= MaxIterNum && (!state.dataGlobal->WarmupFlag)) {
     620            0 :                         ++this->DischargeIterErrors;
     621            0 :                         if (this->DischargeIterErrors <= 25) {
     622            0 :                             ShowWarningError(state, "Detailed Ice Storage model exceeded its internal discharging maximum iteration limit");
     623            0 :                             ShowContinueError(state, format("Detailed Ice Storage System Name = {}", this->Name));
     624            0 :                             ShowContinueErrorTimeStamp(state, "");
     625              :                         } else {
     626            0 :                             ShowRecurringWarningErrorAtEnd(state,
     627            0 :                                                            "Detailed Ice Storage system [" + this->Name +
     628              :                                                                "]  discharging maximum iteration limit exceeded occurrence continues.",
     629            0 :                                                            this->DischargeErrorCount);
     630              :                         }
     631              :                     }
     632              : 
     633              :                     // We are now done finding the outlet temperature of the tank.  We need
     634              :                     // to compare the outlet temperature to the setpoint temperature again
     635              :                     // to see where we are at and then we can set the values for the key
     636              :                     // outlet parameters.  If outlet temperature is greater than or equal
     637              :                     // to the setpoint temperature, then send all flow through the tank.
     638              :                     // Otherwise, we have more capacity than needed so let's bypass some
     639              :                     // flow and meet the setpoint temperature.
     640            0 :                     if (ToutNew >= TempSetPt) {
     641            0 :                         this->OutletTemp = ToutNew;
     642            0 :                         this->TankOutletTemp = ToutNew;
     643            0 :                         this->BypassMassFlowRate = 0.0;
     644            0 :                         this->TankMassFlowRate = this->MassFlowRate;
     645            0 :                         this->CompLoad = this->MassFlowRate * Cp * std::abs(TempIn - ToutNew);
     646              :                     } else {
     647            0 :                         this->OutletTemp = TempSetPt;
     648            0 :                         this->TankOutletTemp = ToutNew;
     649            0 :                         this->CompLoad = this->MassFlowRate * Cp * std::abs(TempIn - TempSetPt);
     650            0 :                         this->TankMassFlowRate = this->CompLoad / (Cp * std::abs(TempIn - ToutNew));
     651            0 :                         this->BypassMassFlowRate = this->MassFlowRate - this->TankMassFlowRate;
     652              :                     }
     653              :                 }
     654              :             }
     655              : 
     656              :         } else { // Shouldn't get here ever (print error if we do)
     657              : 
     658            0 :             ShowFatalError(state, "Detailed Ice Storage systemic code error--contact EnergyPlus support");
     659              :         }
     660            0 :     }
     661              : 
     662            0 :     void GetIceStorageInput(EnergyPlusData &state)
     663              :     {
     664              :         // SUBROUTINE INFORMATION:
     665              :         //       AUTHOR:
     666              :         //       DATE WRITTEN:
     667              : 
     668              :         // PURPOSE OF THIS SUBROUTINE:!This routine will get the input
     669              :         // required by the PrimaryPlantLoopManager.  As such
     670              :         // it will interact with the Input Scanner to retrieve
     671              :         // information from the input file, count the number of
     672              :         // heating and cooling loops and begin to fill the
     673              :         // arrays associated with the type PlantLoopProps.
     674              : 
     675              :         static constexpr std::string_view routineName = "GetIceStorageInput";
     676              : 
     677              :         bool ErrorsFound;
     678              : 
     679            0 :         ErrorsFound = false; // Always need to reset this since there are multiple types of ice storage systems
     680              : 
     681              :         // LOAD ARRAYS WITH SimpleIceStorage DATA
     682            0 :         state.dataIceThermalStorage->NumSimpleIceStorage =
     683            0 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cIceStorageSimple); // by ZG
     684            0 :         state.dataIceThermalStorage->NumDetailedIceStorage =
     685            0 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cIceStorageDetailed);
     686              : 
     687              :         // Allocate SimpleIceStorage based on NumOfIceStorage
     688            0 :         state.dataIceThermalStorage->SimpleIceStorage.allocate(state.dataIceThermalStorage->NumSimpleIceStorage);
     689              : 
     690            0 :         state.dataIPShortCut->cCurrentModuleObject = cIceStorageSimple;
     691            0 :         for (int iceNum = 1; iceNum <= state.dataIceThermalStorage->NumSimpleIceStorage; ++iceNum) {
     692              : 
     693              :             int NumAlphas;
     694              :             int NumNums;
     695              :             int IOStat;
     696            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     697            0 :                                                                      state.dataIPShortCut->cCurrentModuleObject,
     698              :                                                                      iceNum,
     699            0 :                                                                      state.dataIPShortCut->cAlphaArgs,
     700              :                                                                      NumAlphas,
     701            0 :                                                                      state.dataIPShortCut->rNumericArgs,
     702              :                                                                      NumNums,
     703              :                                                                      IOStat,
     704              :                                                                      _,
     705              :                                                                      _,
     706              :                                                                      _,
     707            0 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     708            0 :             Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
     709              : 
     710            0 :             ++state.dataIceThermalStorage->TotalNumIceStorage;
     711            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).MapNum = state.dataIceThermalStorage->TotalNumIceStorage;
     712              : 
     713              :             // ITS name
     714            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).Name = state.dataIPShortCut->cAlphaArgs(1);
     715              : 
     716              :             // Get Ice Thermal Storage Type
     717            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSType = state.dataIPShortCut->cAlphaArgs(2);
     718            0 :             if (Util::SameString(state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSType, "IceOnCoilInternal")) {
     719            0 :                 state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSType_Num = ITSType::IceOnCoilInternal;
     720            0 :             } else if (Util::SameString(state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSType, "IceOnCoilExternal")) {
     721            0 :                 state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSType_Num = ITSType::IceOnCoilExternal;
     722              :             } else {
     723            0 :                 ShowSevereError(state, format("{}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     724            0 :                 ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2)));
     725            0 :                 ErrorsFound = true;
     726              :             }
     727              : 
     728              :             // Get and Verify ITS nominal Capacity (user input is in GJ, internal value in in J)
     729            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSNomCap = state.dataIPShortCut->rNumericArgs(1) * 1.e+09;
     730            0 :             if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
     731            0 :                 ShowSevereError(state, format("{}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     732            0 :                 ShowContinueError(state,
     733            0 :                                   format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->rNumericArgs(1)));
     734            0 :                 ErrorsFound = true;
     735              :             }
     736              : 
     737              :             // Get Plant Inlet Node Num
     738            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).PltInletNodeNum =
     739            0 :                 NodeInputManager::GetOnlySingleNode(state,
     740            0 :                                                     state.dataIPShortCut->cAlphaArgs(3),
     741              :                                                     ErrorsFound,
     742              :                                                     DataLoopNode::ConnectionObjectType::ThermalStorageIceSimple,
     743            0 :                                                     state.dataIPShortCut->cAlphaArgs(1),
     744              :                                                     DataLoopNode::NodeFluidType::Water,
     745              :                                                     DataLoopNode::ConnectionType::Inlet,
     746              :                                                     NodeInputManager::CompFluidStream::Primary,
     747              :                                                     DataLoopNode::ObjectIsNotParent);
     748              : 
     749              :             // Get Plant Outlet Node Num
     750            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).PltOutletNodeNum =
     751            0 :                 NodeInputManager::GetOnlySingleNode(state,
     752            0 :                                                     state.dataIPShortCut->cAlphaArgs(4),
     753              :                                                     ErrorsFound,
     754              :                                                     DataLoopNode::ConnectionObjectType::ThermalStorageIceSimple,
     755            0 :                                                     state.dataIPShortCut->cAlphaArgs(1),
     756              :                                                     DataLoopNode::NodeFluidType::Water,
     757              :                                                     DataLoopNode::ConnectionType::Outlet,
     758              :                                                     NodeInputManager::CompFluidStream::Primary,
     759              :                                                     DataLoopNode::ObjectIsNotParent);
     760              : 
     761              :             // Test InletNode and OutletNode
     762            0 :             BranchNodeConnections::TestCompSet(state,
     763            0 :                                                state.dataIPShortCut->cCurrentModuleObject,
     764            0 :                                                state.dataIPShortCut->cAlphaArgs(1),
     765            0 :                                                state.dataIPShortCut->cAlphaArgs(3),
     766            0 :                                                state.dataIPShortCut->cAlphaArgs(4),
     767              :                                                "Chilled Water Nodes");
     768              : 
     769              :             // Initialize Report Variables
     770            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).MyLoad = 0.0;
     771            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).Urate = 0.0;
     772            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).IceFracRemain = 1.0;
     773            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSCoolingRate_rep = 0.0;
     774            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSCoolingEnergy_rep = 0.0;
     775            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSChargingRate = 0.0;
     776            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSChargingEnergy = 0.0;
     777            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSmdot = 0.0;
     778            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSInletTemp = 0.0;
     779            0 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSOutletTemp = 0.0;
     780              : 
     781              :         } // IceNum
     782              : 
     783            0 :         if (ErrorsFound) {
     784            0 :             ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
     785              :         }
     786              : 
     787            0 :         ErrorsFound = false; // Always need to reset this since there are multiple types of ice storage systems
     788              : 
     789              :         // Determine the number of detailed ice storage devices are in the input file and allocate appropriately
     790            0 :         state.dataIPShortCut->cCurrentModuleObject = cIceStorageDetailed;
     791              : 
     792            0 :         state.dataIceThermalStorage->DetailedIceStorage.allocate(
     793            0 :             state.dataIceThermalStorage->NumDetailedIceStorage); // Allocate DetIceStorage based on NumDetIceStorages
     794              : 
     795            0 :         for (int iceNum = 1; iceNum <= state.dataIceThermalStorage->NumDetailedIceStorage; ++iceNum) {
     796              : 
     797              :             int NumAlphas;
     798              :             int NumNums;
     799              :             int IOStat;
     800            0 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     801            0 :                                                                      state.dataIPShortCut->cCurrentModuleObject,
     802              :                                                                      iceNum,
     803            0 :                                                                      state.dataIPShortCut->cAlphaArgs,
     804              :                                                                      NumAlphas,
     805            0 :                                                                      state.dataIPShortCut->rNumericArgs,
     806              :                                                                      NumNums,
     807              :                                                                      IOStat,
     808              :                                                                      _,
     809            0 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     810            0 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     811            0 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     812              : 
     813            0 :             ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
     814              : 
     815            0 :             Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
     816              : 
     817            0 :             ++state.dataIceThermalStorage->TotalNumIceStorage;
     818              : 
     819            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).MapNum = state.dataIceThermalStorage->TotalNumIceStorage;
     820            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).Name = state.dataIPShortCut->cAlphaArgs(1); // Detailed ice storage name
     821              : 
     822              :             // Get and verify availability schedule
     823            0 :             if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
     824            0 :                 state.dataIceThermalStorage->DetailedIceStorage(iceNum).availSched = Sched::GetScheduleAlwaysOn(state);
     825            0 :             } else if ((state.dataIceThermalStorage->DetailedIceStorage(iceNum).availSched =
     826            0 :                             Sched::GetSchedule(state, state.dataIPShortCut->cAlphaArgs(2))) == nullptr) {
     827            0 :                 ShowSevereItemNotFound(state, eoh, state.dataIPShortCut->cAlphaFieldNames(2), state.dataIPShortCut->cAlphaArgs(2));
     828            0 :                 ErrorsFound = true;
     829              :             }
     830              : 
     831              :             // Get and Verify ITS nominal Capacity (user input is in GJ, internal value is in W-hr)
     832              :             // Convert GJ to J by multiplying by 10^9
     833              :             // Convert J to W-hr by dividing by number of seconds in an hour (3600)
     834            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).NomCapacity =
     835            0 :                 state.dataIPShortCut->rNumericArgs(1) * (1.e+09) / Constant::rSecsInHour;
     836              : 
     837            0 :             if (state.dataIPShortCut->rNumericArgs(1) <= 0.0) {
     838            0 :                 ShowSevereError(state,
     839            0 :                                 format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->rNumericArgs(1)));
     840            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     841            0 :                 ErrorsFound = true;
     842              :             }
     843              : 
     844              :             // Get Plant Inlet Node Num
     845            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).PlantInNodeNum =
     846            0 :                 NodeInputManager::GetOnlySingleNode(state,
     847            0 :                                                     state.dataIPShortCut->cAlphaArgs(3),
     848              :                                                     ErrorsFound,
     849              :                                                     DataLoopNode::ConnectionObjectType::ThermalStorageIceDetailed,
     850            0 :                                                     state.dataIPShortCut->cAlphaArgs(1),
     851              :                                                     DataLoopNode::NodeFluidType::Water,
     852              :                                                     DataLoopNode::ConnectionType::Inlet,
     853              :                                                     NodeInputManager::CompFluidStream::Primary,
     854              :                                                     DataLoopNode::ObjectIsNotParent);
     855              : 
     856              :             // Get Plant Outlet Node Num
     857            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).PlantOutNodeNum =
     858            0 :                 NodeInputManager::GetOnlySingleNode(state,
     859            0 :                                                     state.dataIPShortCut->cAlphaArgs(4),
     860              :                                                     ErrorsFound,
     861              :                                                     DataLoopNode::ConnectionObjectType::ThermalStorageIceDetailed,
     862            0 :                                                     state.dataIPShortCut->cAlphaArgs(1),
     863              :                                                     DataLoopNode::NodeFluidType::Water,
     864              :                                                     DataLoopNode::ConnectionType::Outlet,
     865              :                                                     NodeInputManager::CompFluidStream::Primary,
     866              :                                                     DataLoopNode::ObjectIsNotParent);
     867              : 
     868              :             // Test InletNode and OutletNode
     869            0 :             BranchNodeConnections::TestCompSet(state,
     870            0 :                                                state.dataIPShortCut->cCurrentModuleObject,
     871            0 :                                                state.dataIPShortCut->cAlphaArgs(1),
     872            0 :                                                state.dataIPShortCut->cAlphaArgs(3),
     873            0 :                                                state.dataIPShortCut->cAlphaArgs(4),
     874              :                                                "Chilled Water Nodes");
     875              : 
     876              :             // Obtain the Charging and Discharging Curve types and names
     877            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveName = state.dataIPShortCut->cAlphaArgs(6);
     878            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveNum =
     879            0 :                 Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(6));
     880            0 :             if (state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveNum <= 0) {
     881            0 :                 ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
     882            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     883            0 :                 ErrorsFound = true;
     884              :             }
     885              : 
     886              :             int dischargeCurveDim =
     887            0 :                 state.dataCurveManager->curves(state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveNum)->numDims;
     888            0 :             if (dischargeCurveDim != 2) {
     889            0 :                 ShowSevereError(state, format("{}: Discharge curve must have 2 independent variables", state.dataIPShortCut->cCurrentModuleObject));
     890            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     891            0 :                 ShowContinueError(state,
     892            0 :                                   format("{} does not have 2 independent variables and thus cannot be used for detailed ice storage",
     893            0 :                                          state.dataIPShortCut->cAlphaArgs(6)));
     894            0 :                 ErrorsFound = true;
     895              :             } else {
     896            0 :                 if (state.dataIPShortCut->cAlphaArgs(5) == "FRACTIONCHARGEDLMTD") {
     897            0 :                     state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveTypeNum = CurveVars::FracChargedLMTD;
     898            0 :                 } else if (state.dataIPShortCut->cAlphaArgs(5) == "FRACTIONDISCHARGEDLMTD") {
     899            0 :                     state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveTypeNum = CurveVars::FracDischargedLMTD;
     900            0 :                 } else if (state.dataIPShortCut->cAlphaArgs(5) == "LMTDMASSFLOW") {
     901            0 :                     state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveTypeNum = CurveVars::LMTDMassFlow;
     902            0 :                 } else if (state.dataIPShortCut->cAlphaArgs(5) == "LMTDFRACTIONCHARGED") {
     903            0 :                     state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveTypeNum = CurveVars::LMTDFracCharged;
     904              :                 } else {
     905            0 :                     ShowSevereError(state,
     906            0 :                                     format("{}: Discharge curve independent variable options not valid, option={}",
     907            0 :                                            state.dataIPShortCut->cCurrentModuleObject,
     908            0 :                                            state.dataIPShortCut->cAlphaArgs(5)));
     909            0 :                     ShowContinueError(state,
     910            0 :                                       format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     911            0 :                     ShowContinueError(state,
     912              :                                       "The valid options are: FractionChargedLMTD, FractionDischargedLMTD, LMTDMassFlow or LMTDFractionCharged");
     913            0 :                     ErrorsFound = true;
     914              :                 }
     915              :             }
     916              : 
     917            0 :             ErrorsFound |= Curve::CheckCurveDims(state,
     918            0 :                                                  state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveNum, // Curve index
     919              :                                                  {2},                                                                       // Valid dimensions
     920              :                                                  "GetIceStorageInput: ",                                                    // Routine name
     921            0 :                                                  state.dataIPShortCut->cCurrentModuleObject,                                // Object Type
     922            0 :                                                  state.dataIceThermalStorage->DetailedIceStorage(iceNum).Name,              // Object Name
     923            0 :                                                  state.dataIPShortCut->cAlphaFieldNames(6));                                // Field Name
     924              : 
     925            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveName = state.dataIPShortCut->cAlphaArgs(8);
     926            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveNum = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(8));
     927            0 :             if (state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveNum <= 0) {
     928            0 :                 ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(8), state.dataIPShortCut->cAlphaArgs(8)));
     929            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     930            0 :                 ErrorsFound = true;
     931              :             }
     932              : 
     933            0 :             int chargeCurveDim = state.dataCurveManager->curves(state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveNum)->numDims;
     934            0 :             if (chargeCurveDim != 2) {
     935            0 :                 ShowSevereError(state, format("{}: Charge curve must have 2 independent variables", state.dataIPShortCut->cCurrentModuleObject));
     936            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     937            0 :                 ShowContinueError(state,
     938            0 :                                   format("{} does not have 2 independent variables and thus cannot be used for detailed ice storage",
     939            0 :                                          state.dataIPShortCut->cAlphaArgs(8)));
     940            0 :                 ErrorsFound = true;
     941              :             } else {
     942            0 :                 if (state.dataIPShortCut->cAlphaArgs(7) == "FRACTIONCHARGEDLMTD") {
     943            0 :                     state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveTypeNum = CurveVars::FracChargedLMTD;
     944            0 :                 } else if (state.dataIPShortCut->cAlphaArgs(7) == "FRACTIONDISCHARGEDLMTD") {
     945            0 :                     state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveTypeNum = CurveVars::FracDischargedLMTD;
     946            0 :                 } else if (state.dataIPShortCut->cAlphaArgs(7) == "LMTDMASSFLOW") {
     947            0 :                     state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveTypeNum = CurveVars::LMTDMassFlow;
     948            0 :                 } else if (state.dataIPShortCut->cAlphaArgs(7) == "LMTDFRACTIONCHARGED") {
     949            0 :                     state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveTypeNum = CurveVars::LMTDFracCharged;
     950              :                 } else {
     951            0 :                     ShowSevereError(state,
     952            0 :                                     format("{}: Charge curve independent variable options not valid, option={}",
     953            0 :                                            state.dataIPShortCut->cCurrentModuleObject,
     954            0 :                                            state.dataIPShortCut->cAlphaArgs(7)));
     955            0 :                     ShowContinueError(state,
     956            0 :                                       format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     957            0 :                     ShowContinueError(state,
     958              :                                       "The valid options are: FractionChargedLMTD, FractionDischargedLMTD, LMTDMassFlow or LMTDFractionCharged");
     959            0 :                     ErrorsFound = true;
     960              :                 }
     961              :             }
     962              : 
     963            0 :             ErrorsFound |= Curve::CheckCurveDims(state,
     964            0 :                                                  state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveNum, // Curve index
     965              :                                                  {2},                                                                    // Valid dimensions
     966              :                                                  "GetIceStorageInput: ",                                                 // Routine name
     967            0 :                                                  state.dataIPShortCut->cCurrentModuleObject,                             // Object Type
     968            0 :                                                  state.dataIceThermalStorage->DetailedIceStorage(iceNum).Name,           // Object Name
     969            0 :                                                  state.dataIPShortCut->cAlphaFieldNames(8));                             // Field Name
     970              : 
     971            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).CurveFitTimeStep = state.dataIPShortCut->rNumericArgs(2);
     972            0 :             if ((state.dataIceThermalStorage->DetailedIceStorage(iceNum).CurveFitTimeStep <= 0.0) ||
     973            0 :                 (state.dataIceThermalStorage->DetailedIceStorage(iceNum).CurveFitTimeStep > 1.0)) {
     974            0 :                 ShowSevereError(state,
     975            0 :                                 format("Invalid {}={:.3R}", state.dataIPShortCut->cNumericFieldNames(2), state.dataIPShortCut->rNumericArgs(2)));
     976            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     977            0 :                 ShowContinueError(
     978            0 :                     state, format("Curve fit time step invalid, less than zero or greater than 1 for {}", state.dataIPShortCut->cAlphaArgs(1)));
     979            0 :                 ErrorsFound = true;
     980              :             }
     981              : 
     982            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ThawProcessIndicator = state.dataIPShortCut->cAlphaArgs(9);
     983            0 :             if (Util::SameString(state.dataIceThermalStorage->DetailedIceStorage(iceNum).ThawProcessIndicator, "INSIDEMELT")) {
     984            0 :                 state.dataIceThermalStorage->DetailedIceStorage(iceNum).ThawProcessIndex = DetIce::InsideMelt;
     985            0 :             } else if ((Util::SameString(state.dataIceThermalStorage->DetailedIceStorage(iceNum).ThawProcessIndicator, "OUTSIDEMELT")) ||
     986            0 :                        (state.dataIceThermalStorage->DetailedIceStorage(iceNum).ThawProcessIndicator.empty())) {
     987            0 :                 state.dataIceThermalStorage->DetailedIceStorage(iceNum).ThawProcessIndex = DetIce::OutsideMelt;
     988              :             } else {
     989            0 :                 ShowSevereError(state, format("Invalid thaw process indicator of {} was entered", state.dataIPShortCut->cAlphaArgs(9)));
     990            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
     991            0 :                 ShowContinueError(state, R"(Value should either be "InsideMelt" or "OutsideMelt")");
     992            0 :                 state.dataIceThermalStorage->DetailedIceStorage(iceNum).ThawProcessIndex =
     993              :                     DetIce::InsideMelt; // Severe error will end simulation, but just in case...
     994            0 :                 ErrorsFound = true;
     995              :             }
     996              : 
     997              :             // Get the other ice storage parameters (electric, heat loss, freezing temperature) and stupidity check each one
     998            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeParaElecLoad = state.dataIPShortCut->rNumericArgs(3);
     999            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeParaElecLoad = state.dataIPShortCut->rNumericArgs(4);
    1000            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).TankLossCoeff = state.dataIPShortCut->rNumericArgs(5);
    1001            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).FreezingTemp = state.dataIPShortCut->rNumericArgs(6);
    1002              : 
    1003            0 :             if ((state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeParaElecLoad < 0.0) ||
    1004            0 :                 (state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeParaElecLoad > 1.0)) {
    1005            0 :                 ShowSevereError(state,
    1006            0 :                                 format("Invalid {}={:.3R}", state.dataIPShortCut->cNumericFieldNames(3), state.dataIPShortCut->rNumericArgs(3)));
    1007            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    1008            0 :                 ShowContinueError(state, "Value is either less than/equal to zero or greater than 1");
    1009            0 :                 ErrorsFound = true;
    1010              :             }
    1011              : 
    1012            0 :             if ((state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeParaElecLoad < 0.0) ||
    1013            0 :                 (state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeParaElecLoad > 1.0)) {
    1014            0 :                 ShowSevereError(state,
    1015            0 :                                 format("Invalid {}={:.3R}", state.dataIPShortCut->cNumericFieldNames(4), state.dataIPShortCut->rNumericArgs(4)));
    1016            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    1017            0 :                 ShowContinueError(state, "Value is either less than/equal to zero or greater than 1");
    1018            0 :                 ErrorsFound = true;
    1019              :             }
    1020              : 
    1021            0 :             if ((state.dataIceThermalStorage->DetailedIceStorage(iceNum).TankLossCoeff < 0.0) ||
    1022            0 :                 (state.dataIceThermalStorage->DetailedIceStorage(iceNum).TankLossCoeff > 0.1)) {
    1023            0 :                 ShowSevereError(state,
    1024            0 :                                 format("Invalid {}={:.3R}", state.dataIPShortCut->cNumericFieldNames(5), state.dataIPShortCut->rNumericArgs(5)));
    1025            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    1026            0 :                 ShowContinueError(state, "Value is either less than/equal to zero or greater than 0.1 (10%)");
    1027            0 :                 ErrorsFound = true;
    1028              :             }
    1029              : 
    1030            0 :             if ((state.dataIceThermalStorage->DetailedIceStorage(iceNum).FreezingTemp < -10.0) ||
    1031            0 :                 (state.dataIceThermalStorage->DetailedIceStorage(iceNum).FreezingTemp > 10.0)) {
    1032            0 :                 ShowWarningError(
    1033              :                     state,
    1034            0 :                     format("Potentially invalid {}={:.3R}", state.dataIPShortCut->cNumericFieldNames(6), state.dataIPShortCut->rNumericArgs(6)));
    1035            0 :                 ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
    1036            0 :                 ShowContinueError(state, "Value is either less than -10.0C or greater than 10.0C");
    1037            0 :                 ShowContinueError(state, "This value will be allowed but the user should verify that this temperature is correct");
    1038              :             }
    1039              : 
    1040              :             // Initialize Report Variables
    1041            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).CompLoad = 0.0;
    1042            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).IceFracChange = 0.0;
    1043            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).IceFracRemaining = 1.0;
    1044            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).IceFracOnCoil = 1.0;
    1045            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargingRate = 0.0;
    1046            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargingEnergy = 0.0;
    1047            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargingRate = 0.0;
    1048            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargingEnergy = 0.0;
    1049            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).MassFlowRate = 0.0;
    1050            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).BypassMassFlowRate = 0.0;
    1051            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).TankMassFlowRate = 0.0;
    1052            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).InletTemp = 0.0;
    1053            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).OutletTemp = 0.0;
    1054            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).TankOutletTemp = 0.0;
    1055            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ParasiticElecRate = 0.0;
    1056            0 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ParasiticElecEnergy = 0.0;
    1057              : 
    1058              :         } // ...over detailed ice storage units
    1059              : 
    1060            0 :         if ((state.dataIceThermalStorage->NumSimpleIceStorage + state.dataIceThermalStorage->NumDetailedIceStorage) <= 0) {
    1061            0 :             ShowSevereError(state, "No Ice Storage Equipment found in GetIceStorage");
    1062            0 :             ErrorsFound = true;
    1063              :         }
    1064              : 
    1065            0 :         if (ErrorsFound) {
    1066            0 :             ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
    1067              :         }
    1068            0 :     }
    1069              : 
    1070            0 :     void SimpleIceStorageData::setupOutputVars(EnergyPlusData &state)
    1071              :     {
    1072            0 :         SetupOutputVariable(state,
    1073              :                             "Ice Thermal Storage Requested Load",
    1074              :                             Constant::Units::W,
    1075            0 :                             this->MyLoad,
    1076              :                             OutputProcessor::TimeStepType::System,
    1077              :                             OutputProcessor::StoreType::Average,
    1078            0 :                             this->Name);
    1079              : 
    1080            0 :         SetupOutputVariable(state,
    1081              :                             "Ice Thermal Storage End Fraction",
    1082              :                             Constant::Units::None,
    1083            0 :                             this->IceFracRemain,
    1084              :                             OutputProcessor::TimeStepType::Zone,
    1085              :                             OutputProcessor::StoreType::Average,
    1086            0 :                             this->Name);
    1087              : 
    1088            0 :         SetupOutputVariable(state,
    1089              :                             "Ice Thermal Storage Mass Flow Rate",
    1090              :                             Constant::Units::kg_s,
    1091            0 :                             this->ITSmdot,
    1092              :                             OutputProcessor::TimeStepType::System,
    1093              :                             OutputProcessor::StoreType::Average,
    1094            0 :                             this->Name);
    1095              : 
    1096            0 :         SetupOutputVariable(state,
    1097              :                             "Ice Thermal Storage Inlet Temperature",
    1098              :                             Constant::Units::C,
    1099            0 :                             this->ITSInletTemp,
    1100              :                             OutputProcessor::TimeStepType::System,
    1101              :                             OutputProcessor::StoreType::Average,
    1102            0 :                             this->Name);
    1103              : 
    1104            0 :         SetupOutputVariable(state,
    1105              :                             "Ice Thermal Storage Outlet Temperature",
    1106              :                             Constant::Units::C,
    1107            0 :                             this->ITSOutletTemp,
    1108              :                             OutputProcessor::TimeStepType::System,
    1109              :                             OutputProcessor::StoreType::Average,
    1110            0 :                             this->Name);
    1111              : 
    1112            0 :         SetupOutputVariable(state,
    1113              :                             "Ice Thermal Storage Cooling Discharge Rate",
    1114              :                             Constant::Units::W,
    1115            0 :                             this->ITSCoolingRate_rep,
    1116              :                             OutputProcessor::TimeStepType::System,
    1117              :                             OutputProcessor::StoreType::Average,
    1118            0 :                             this->Name);
    1119              : 
    1120            0 :         SetupOutputVariable(state,
    1121              :                             "Ice Thermal Storage Cooling Discharge Energy",
    1122              :                             Constant::Units::J,
    1123            0 :                             this->ITSCoolingEnergy_rep,
    1124              :                             OutputProcessor::TimeStepType::System,
    1125              :                             OutputProcessor::StoreType::Sum,
    1126            0 :                             this->Name);
    1127              : 
    1128            0 :         SetupOutputVariable(state,
    1129              :                             "Ice Thermal Storage Cooling Charge Rate",
    1130              :                             Constant::Units::W,
    1131            0 :                             this->ITSChargingRate,
    1132              :                             OutputProcessor::TimeStepType::System,
    1133              :                             OutputProcessor::StoreType::Average,
    1134            0 :                             this->Name);
    1135              : 
    1136            0 :         SetupOutputVariable(state,
    1137              :                             "Ice Thermal Storage Cooling Charge Energy",
    1138              :                             Constant::Units::J,
    1139            0 :                             this->ITSChargingEnergy,
    1140              :                             OutputProcessor::TimeStepType::System,
    1141              :                             OutputProcessor::StoreType::Sum,
    1142            0 :                             this->Name);
    1143            0 :     }
    1144              : 
    1145            0 :     void DetailedIceStorageData::setupOutputVars(EnergyPlusData &state)
    1146              :     {
    1147            0 :         SetupOutputVariable(state,
    1148              :                             "Ice Thermal Storage Cooling Rate",
    1149              :                             Constant::Units::W,
    1150            0 :                             this->CompLoad,
    1151              :                             OutputProcessor::TimeStepType::System,
    1152              :                             OutputProcessor::StoreType::Average,
    1153            0 :                             this->Name);
    1154              : 
    1155            0 :         SetupOutputVariable(state,
    1156              :                             "Ice Thermal Storage Change Fraction",
    1157              :                             Constant::Units::None,
    1158            0 :                             this->IceFracChange,
    1159              :                             OutputProcessor::TimeStepType::System,
    1160              :                             OutputProcessor::StoreType::Average,
    1161            0 :                             this->Name);
    1162              : 
    1163            0 :         SetupOutputVariable(state,
    1164              :                             "Ice Thermal Storage End Fraction",
    1165              :                             Constant::Units::None,
    1166            0 :                             this->IceFracRemaining,
    1167              :                             OutputProcessor::TimeStepType::System,
    1168              :                             OutputProcessor::StoreType::Average,
    1169            0 :                             this->Name);
    1170              : 
    1171            0 :         SetupOutputVariable(state,
    1172              :                             "Ice Thermal Storage On Coil Fraction",
    1173              :                             Constant::Units::None,
    1174            0 :                             this->IceFracOnCoil,
    1175              :                             OutputProcessor::TimeStepType::System,
    1176              :                             OutputProcessor::StoreType::Average,
    1177            0 :                             this->Name);
    1178              : 
    1179            0 :         SetupOutputVariable(state,
    1180              :                             "Ice Thermal Storage Mass Flow Rate",
    1181              :                             Constant::Units::kg_s,
    1182            0 :                             this->MassFlowRate,
    1183              :                             OutputProcessor::TimeStepType::System,
    1184              :                             OutputProcessor::StoreType::Average,
    1185            0 :                             this->Name);
    1186              : 
    1187            0 :         SetupOutputVariable(state,
    1188              :                             "Ice Thermal Storage Bypass Mass Flow Rate",
    1189              :                             Constant::Units::kg_s,
    1190            0 :                             this->BypassMassFlowRate,
    1191              :                             OutputProcessor::TimeStepType::System,
    1192              :                             OutputProcessor::StoreType::Average,
    1193            0 :                             this->Name);
    1194              : 
    1195            0 :         SetupOutputVariable(state,
    1196              :                             "Ice Thermal Storage Tank Mass Flow Rate",
    1197              :                             Constant::Units::kg_s,
    1198            0 :                             this->TankMassFlowRate,
    1199              :                             OutputProcessor::TimeStepType::System,
    1200              :                             OutputProcessor::StoreType::Average,
    1201            0 :                             this->Name);
    1202              : 
    1203            0 :         SetupOutputVariable(state,
    1204              :                             "Ice Thermal Storage Fluid Inlet Temperature",
    1205              :                             Constant::Units::C,
    1206            0 :                             this->InletTemp,
    1207              :                             OutputProcessor::TimeStepType::System,
    1208              :                             OutputProcessor::StoreType::Average,
    1209            0 :                             this->Name);
    1210              : 
    1211            0 :         SetupOutputVariable(state,
    1212              :                             "Ice Thermal Storage Blended Outlet Temperature",
    1213              :                             Constant::Units::C,
    1214            0 :                             this->OutletTemp,
    1215              :                             OutputProcessor::TimeStepType::System,
    1216              :                             OutputProcessor::StoreType::Average,
    1217            0 :                             this->Name);
    1218              : 
    1219            0 :         SetupOutputVariable(state,
    1220              :                             "Ice Thermal Storage Tank Outlet Temperature",
    1221              :                             Constant::Units::C,
    1222            0 :                             this->TankOutletTemp,
    1223              :                             OutputProcessor::TimeStepType::System,
    1224              :                             OutputProcessor::StoreType::Average,
    1225            0 :                             this->Name);
    1226              : 
    1227            0 :         SetupOutputVariable(state,
    1228              :                             "Ice Thermal Storage Cooling Discharge Rate",
    1229              :                             Constant::Units::W,
    1230            0 :                             this->DischargingRate,
    1231              :                             OutputProcessor::TimeStepType::System,
    1232              :                             OutputProcessor::StoreType::Average,
    1233            0 :                             this->Name);
    1234              : 
    1235            0 :         SetupOutputVariable(state,
    1236              :                             "Ice Thermal Storage Cooling Discharge Energy",
    1237              :                             Constant::Units::J,
    1238            0 :                             this->DischargingEnergy,
    1239              :                             OutputProcessor::TimeStepType::System,
    1240              :                             OutputProcessor::StoreType::Sum,
    1241            0 :                             this->Name);
    1242              : 
    1243            0 :         SetupOutputVariable(state,
    1244              :                             "Ice Thermal Storage Cooling Charge Rate",
    1245              :                             Constant::Units::W,
    1246            0 :                             this->ChargingRate,
    1247              :                             OutputProcessor::TimeStepType::System,
    1248              :                             OutputProcessor::StoreType::Average,
    1249            0 :                             this->Name);
    1250              : 
    1251            0 :         SetupOutputVariable(state,
    1252              :                             "Ice Thermal Storage Cooling Charge Energy",
    1253              :                             Constant::Units::J,
    1254            0 :                             this->ChargingEnergy,
    1255              :                             OutputProcessor::TimeStepType::System,
    1256              :                             OutputProcessor::StoreType::Sum,
    1257            0 :                             this->Name);
    1258              : 
    1259            0 :         SetupOutputVariable(state,
    1260              :                             "Ice Thermal Storage Ancillary Electricity Rate",
    1261              :                             Constant::Units::W,
    1262            0 :                             this->ParasiticElecRate,
    1263              :                             OutputProcessor::TimeStepType::System,
    1264              :                             OutputProcessor::StoreType::Average,
    1265            0 :                             this->Name);
    1266              : 
    1267            0 :         SetupOutputVariable(state,
    1268              :                             "Ice Thermal Storage Ancillary Electricity Energy",
    1269              :                             Constant::Units::J,
    1270            0 :                             this->ParasiticElecEnergy,
    1271              :                             OutputProcessor::TimeStepType::System,
    1272              :                             OutputProcessor::StoreType::Sum,
    1273            0 :                             this->Name,
    1274              :                             Constant::eResource::Electricity,
    1275              :                             OutputProcessor::Group::HVAC,
    1276              :                             OutputProcessor::EndUseCat::Invalid);
    1277            0 :     }
    1278              : 
    1279            0 :     void DetailedIceStorageData::oneTimeInit(EnergyPlusData &state)
    1280              :     {
    1281              : 
    1282              :         // SUBROUTINE INFORMATION:
    1283              :         //       AUTHOR         Rick Strand
    1284              :         //       DATE WRITTEN   February 2006
    1285              :         //       MODIFIED       na
    1286              :         //       RE-ENGINEERED  na
    1287              : 
    1288              :         // PURPOSE OF THIS SUBROUTINE:
    1289              :         // This subroutine initializes variables for the detailed ice storage model.
    1290              : 
    1291              :         // METHODOLOGY EMPLOYED:
    1292              :         // Initializes parameters based on current status flag values.
    1293              : 
    1294            0 :         if (this->MyPlantScanFlag) {
    1295            0 :             bool errFlag = false;
    1296            0 :             PlantUtilities::ScanPlantLoopsForObject(state, this->Name, DataPlant::PlantEquipmentType::TS_IceDetailed, this->plantLoc, errFlag);
    1297              : 
    1298            0 :             if (errFlag) {
    1299            0 :                 ShowFatalError(state, "DetailedIceStorageData: oneTimeInit: Program terminated due to previous condition(s).");
    1300              :             }
    1301              : 
    1302            0 :             this->setupOutputVars(state);
    1303            0 :             this->MyPlantScanFlag = false;
    1304              :         }
    1305              : 
    1306            0 :         if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag2) { // Beginning of environment initializations
    1307              :             // Make sure all state variables are reset at the beginning of every environment to avoid problems.
    1308              :             // The storage unit is assumed to be fully charged at the start of any environment.
    1309              :             // The IceNum variable is a module level variable that is already set before this subroutine is called.
    1310            0 :             this->IceFracChange = 0.0;
    1311            0 :             this->IceFracRemaining = 1.0;
    1312            0 :             this->IceFracOnCoil = 1.0;
    1313            0 :             this->InletTemp = 0.0;
    1314            0 :             this->OutletTemp = 0.0;
    1315            0 :             this->TankOutletTemp = 0.0;
    1316            0 :             this->DischargeIterErrors = 0;
    1317            0 :             this->ChargeIterErrors = 0;
    1318            0 :             this->DesignMassFlowRate = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).MaxMassFlowRate;
    1319              :             // no design flow rates for model, assume min is zero and max is plant loop's max
    1320            0 :             PlantUtilities::InitComponentNodes(state, 0.0, this->DesignMassFlowRate, this->PlantInNodeNum, this->PlantOutNodeNum);
    1321              : 
    1322            0 :             if ((state.dataPlnt->PlantLoop(this->plantLoc.loopNum).CommonPipeType == DataPlant::CommonPipeType::TwoWay) &&
    1323            0 :                 (this->plantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply)) {
    1324              :                 // up flow priority of other components on the same branch as the Ice tank
    1325            0 :                 for (int CompNum = 1; CompNum <= state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
    1326            0 :                                                      .LoopSide(DataPlant::LoopSideLocation::Supply)
    1327            0 :                                                      .Branch(this->plantLoc.branchNum)
    1328            0 :                                                      .TotalComponents;
    1329              :                      ++CompNum) {
    1330            0 :                     state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
    1331            0 :                         .LoopSide(DataPlant::LoopSideLocation::Supply)
    1332            0 :                         .Branch(this->plantLoc.branchNum)
    1333            0 :                         .Comp(CompNum)
    1334            0 :                         .FlowPriority = DataPlant::LoopFlowStatus::NeedyAndTurnsLoopOn;
    1335              :                 }
    1336              :             }
    1337              : 
    1338            0 :             this->MyEnvrnFlag2 = false;
    1339              :         }
    1340            0 :         if (!state.dataGlobal->BeginEnvrnFlag) this->MyEnvrnFlag2 = true;
    1341              : 
    1342              :         // Initializations that are done every iteration
    1343              :         // Make sure all of the reporting variables are always reset at the start of any iteration
    1344            0 :         this->CompLoad = 0.0;
    1345            0 :         this->IceFracChange = 0.0;
    1346            0 :         this->DischargingRate = 0.0;
    1347            0 :         this->DischargingEnergy = 0.0;
    1348            0 :         this->ChargingRate = 0.0;
    1349            0 :         this->ChargingEnergy = 0.0;
    1350            0 :         this->MassFlowRate = 0.0;
    1351            0 :         this->BypassMassFlowRate = 0.0;
    1352            0 :         this->TankMassFlowRate = 0.0;
    1353            0 :         this->ParasiticElecRate = 0.0;
    1354            0 :         this->ParasiticElecEnergy = 0.0;
    1355            0 :     }
    1356              : 
    1357            0 :     void SimpleIceStorageData::oneTimeInit(EnergyPlusData &state)
    1358              :     {
    1359              : 
    1360            0 :         if (this->MyPlantScanFlag) {
    1361              :             // Locate the storage on the plant loops for later usage
    1362            0 :             bool errFlag = false;
    1363            0 :             PlantUtilities::ScanPlantLoopsForObject(
    1364            0 :                 state, this->Name, DataPlant::PlantEquipmentType::TS_IceSimple, this->plantLoc, errFlag, _, _, _, _, _);
    1365            0 :             if (errFlag) {
    1366            0 :                 ShowFatalError(state, "SimpleIceStorageData:oneTimeInit: Program terminated due to previous condition(s).");
    1367              :             }
    1368              : 
    1369            0 :             this->setupOutputVars(state);
    1370            0 :             this->MyPlantScanFlag = false;
    1371              :         }
    1372              : 
    1373            0 :         if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag2) {
    1374            0 :             this->DesignMassFlowRate = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).MaxMassFlowRate;
    1375              :             // no design flow rates for model, assume min is zero and max is plant loop's max
    1376            0 :             PlantUtilities::InitComponentNodes(state, 0.0, this->DesignMassFlowRate, this->PltInletNodeNum, this->PltOutletNodeNum);
    1377            0 :             if ((state.dataPlnt->PlantLoop(this->plantLoc.loopNum).CommonPipeType == DataPlant::CommonPipeType::TwoWay) &&
    1378            0 :                 (this->plantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply)) {
    1379              :                 // up flow priority of other components on the same branch as the Ice tank
    1380            0 :                 for (int compNum = 1; compNum <= state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
    1381            0 :                                                      .LoopSide(DataPlant::LoopSideLocation::Supply)
    1382            0 :                                                      .Branch(this->plantLoc.branchNum)
    1383            0 :                                                      .TotalComponents;
    1384              :                      ++compNum) {
    1385            0 :                     state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
    1386            0 :                         .LoopSide(DataPlant::LoopSideLocation::Supply)
    1387            0 :                         .Branch(this->plantLoc.branchNum)
    1388            0 :                         .Comp(compNum)
    1389            0 :                         .FlowPriority = DataPlant::LoopFlowStatus::NeedyAndTurnsLoopOn;
    1390              :                 }
    1391              :             }
    1392            0 :             this->MyLoad = 0.0;
    1393            0 :             this->Urate = 0.0;
    1394            0 :             this->IceFracRemain = 1.0;
    1395            0 :             this->ITSCoolingRate = 0.0;
    1396            0 :             this->ITSCoolingEnergy_rep = 0.0;
    1397            0 :             this->ITSChargingRate = 0.0;
    1398            0 :             this->ITSChargingEnergy = 0.0;
    1399            0 :             this->ITSmdot = 0.0;
    1400            0 :             this->ITSInletTemp = 0.0;
    1401            0 :             this->ITSOutletTemp = 0.0;
    1402              : 
    1403            0 :             this->MyEnvrnFlag2 = false;
    1404              :         }
    1405              : 
    1406            0 :         if (!state.dataGlobal->BeginEnvrnFlag) this->MyEnvrnFlag2 = true;
    1407            0 :     }
    1408              : 
    1409              :     //******************************************************************************
    1410              : 
    1411            0 :     void SimpleIceStorageData::CalcIceStorageCapacity(EnergyPlusData &state, Real64 &MaxCap, Real64 &MinCap, Real64 &OptCap)
    1412              :     {
    1413              :         //------------------------------------------------------------------------
    1414              :         // FIRST PROCESS (MyLoad = 0.0 as IN)
    1415              :         // At this moment as first calling of ITS, ITS provide ONLY MaxCap/OptCap/MinCap.
    1416              :         //------------------------------------------------------------------------
    1417              : 
    1418              :         // Initialize Capacity
    1419            0 :         MaxCap = 0.0;
    1420            0 :         MinCap = 0.0;
    1421            0 :         OptCap = 0.0;
    1422              : 
    1423              :         // XCurIceFrac is reset to 1.0 when first hour of day.
    1424              :         // Starting full is assumed, because most ice systems are fully charged overnight
    1425            0 :         if (this->ResetXForITSFlag) {
    1426            0 :             this->XCurIceFrac = 1.0;
    1427            0 :             this->IceFracRemain = 1.0;
    1428            0 :             this->Urate = 0.0;
    1429            0 :             this->ResetXForITSFlag = false;
    1430              :         }
    1431              : 
    1432              :         // Calculate UAIceDisch[W/C] and UAIceCh[W/F] based on ONLY XCurIceFrac
    1433            0 :         this->CalcUAIce(this->XCurIceFrac, this->UAIceCh, this->UAIceDisCh, this->HLoss);
    1434              : 
    1435              :         // Calculate QiceMin by UAIceDisCh*deltaTlm
    1436              :         //   with UAIceDisCh(function of XCurIceFrac), ITSInletTemp and ITSOutletTemp(=Node(OutletNodeNum)%TempSetPoint by E+[C])
    1437              :         // QiceMin is REAL(r64) ITS capacity.
    1438              :         Real64 QiceMin;
    1439            0 :         this->CalcQiceDischageMax(state, QiceMin);
    1440              : 
    1441              :         // At the first call of ITS model, MyLoad is 0. After that proper MyLoad will be provided by E+.
    1442              :         // Therefore, Umin is decided between input U and ITS REAL(r64) capacity.
    1443            0 :         Real64 Umin = min(max((-(1.0 - EpsLimitForDisCharge) * QiceMin * TimeInterval / this->ITSNomCap), (-this->XCurIceFrac + EpsLimitForX)), 0.0);
    1444              : 
    1445              :         // Calculate CoolingRate with Uact to provide E+.
    1446            0 :         Real64 Uact = Umin;
    1447            0 :         Real64 ITSCoolingRateMax = std::abs(Uact * this->ITSNomCap / TimeInterval);
    1448            0 :         Real64 ITSCoolingRateOpt = ITSCoolingRateMax;
    1449            0 :         Real64 ITSCoolingRateMin = 0.0;
    1450              : 
    1451              :         // Define MaxCap, OptCap, and MinCap
    1452            0 :         MaxCap = ITSCoolingRateMax;
    1453            0 :         OptCap = ITSCoolingRateOpt;
    1454            0 :         MinCap = ITSCoolingRateMin;
    1455            0 :     }
    1456              : 
    1457              :     //******************************************************************************
    1458              : 
    1459            0 :     void SimpleIceStorageData::CalcIceStorageDormant(EnergyPlusData &state)
    1460              :     {
    1461              :         // Provide output results for ITS.
    1462            0 :         this->ITSMassFlowRate = 0.0; //[kg/s]
    1463              : 
    1464            0 :         PlantUtilities::SetComponentFlowRate(state, this->ITSMassFlowRate, this->PltInletNodeNum, this->PltOutletNodeNum, this->plantLoc);
    1465              : 
    1466            0 :         this->ITSInletTemp = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp; //[C]
    1467            0 :         this->ITSOutletTemp = this->ITSInletTemp;                                   //[C]
    1468            0 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
    1469            0 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
    1470            0 :             this->ITSOutletSetPointTemp = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPoint;
    1471            0 :         } break;
    1472            0 :         case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
    1473            0 :             this->ITSOutletSetPointTemp = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPointHi;
    1474            0 :         } break;
    1475            0 :         default:
    1476            0 :             break;
    1477              :         }
    1478            0 :         this->ITSCoolingRate = 0.0;   //[W]
    1479            0 :         this->ITSCoolingEnergy = 0.0; //[J]
    1480              : 
    1481            0 :         this->Urate = 0.0; //[n/a]
    1482            0 :     }
    1483              : 
    1484              :     //******************************************************************************
    1485              : 
    1486            0 :     void SimpleIceStorageData::CalcIceStorageCharge(EnergyPlusData &state)
    1487              :     {
    1488              :         //--------------------------------------------------------
    1489              :         // Initialize
    1490              :         //--------------------------------------------------------
    1491              :         // Below values for ITS are reported forCharging process.
    1492            0 :         this->ITSMassFlowRate = this->DesignMassFlowRate; //[kg/s]
    1493              : 
    1494            0 :         PlantUtilities::SetComponentFlowRate(state, this->ITSMassFlowRate, this->PltInletNodeNum, this->PltOutletNodeNum, this->plantLoc);
    1495              : 
    1496            0 :         this->ITSInletTemp = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp; //[C]
    1497            0 :         this->ITSOutletTemp = this->ITSInletTemp;                                   //[C]
    1498            0 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
    1499            0 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
    1500            0 :             this->ITSOutletSetPointTemp = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPoint;
    1501            0 :         } break;
    1502            0 :         case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
    1503            0 :             this->ITSOutletSetPointTemp = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPointHi;
    1504            0 :         } break;
    1505            0 :         default:
    1506            0 :             break;
    1507              :         }
    1508            0 :         this->ITSCoolingRate = 0.0;   //[W]
    1509            0 :         this->ITSCoolingEnergy = 0.0; //[J]
    1510              : 
    1511              :         // Initialize processed U values
    1512            0 :         this->Urate = 0.0;
    1513              : 
    1514              :         // Calculate QiceMax which is REAL(r64) ITS capacity.
    1515              :         // There are three possible to calculate QiceMax
    1516              :         //   with ChillerCapacity(Chiller+ITS), ITS capacity(ITS), and QchillerMax(Chiller).
    1517              :         //--------------------------------------------------------
    1518              :         // Calculate QiceMax with QiceMaxByChiller, QiceMaxByITS, QchillerMax
    1519              :         //--------------------------------------------------------
    1520              :         // Calculate Qice charge max by Chiller with Twb and UAIceCh
    1521              :         Real64 QiceMaxByChiller;
    1522            0 :         this->CalcQiceChargeMaxByChiller(state, QiceMaxByChiller); //[W]
    1523              : 
    1524              :         // Chiller is remote now, so chiller out is inlet node temp
    1525            0 :         Real64 chillerOutletTemp = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
    1526              :         // Calculate Qice charge max by ITS with ChillerOutletTemp
    1527              :         Real64 QiceMaxByITS;
    1528            0 :         this->CalcQiceChargeMaxByITS(chillerOutletTemp, QiceMaxByITS); //[W]
    1529              : 
    1530              :         // Select minimum as QiceMax
    1531              :         // Because It is uncertain that QiceMax by chiller is same as QiceMax by ITS.
    1532            0 :         Real64 QiceMax = min(QiceMaxByChiller, QiceMaxByITS);
    1533              : 
    1534              :         //--------------------------------------------------------
    1535              :         // Calculate Umin,Umax,Uact
    1536              :         //--------------------------------------------------------
    1537              :         // Set Umin
    1538              :         // Calculate Umax based on real ITS Max Capacity and remained XCurIceFrac.
    1539              :         // Umax should be equal or larger than 0.02 for realistic purpose by Dion.
    1540            0 :         Real64 Umax = max(min(((1.0 - EpsLimitForCharge) * QiceMax * TimeInterval / this->ITSNomCap), (1.0 - this->XCurIceFrac - EpsLimitForX)), 0.0);
    1541              : 
    1542              :         // Cannot charge more than the fraction that is left uncharged
    1543            0 :         Umax = min(Umax, (1.0 - this->IceFracRemain) / state.dataHVACGlobal->TimeStepSys);
    1544              :         // First, check input U value.
    1545              :         // Based on Umax and Umin, if necessary to run E+, calculate proper Uact.
    1546              :         Real64 Uact;
    1547            0 :         if (Umax == 0.0) { //(No Capacity of ITS), ITS is OFF.
    1548            0 :             Uact = 0.0;
    1549              : 
    1550              :         } else { // Umax non-zero
    1551            0 :             Uact = Umax;
    1552              :         } // Check Uact for Discharging Process
    1553              : 
    1554              :         //--------------------------------------------------------
    1555              :         // Calculate possible ITSChargingRate with Uact, Then error check
    1556              :         //--------------------------------------------------------
    1557              :         // Calculate possible ITSChargingRate with Uact
    1558            0 :         Real64 Qice = Uact * this->ITSNomCap / TimeInterval; //[W]
    1559              :         // If Qice is equal or less than 0.0, no need to calculate anymore.
    1560            0 :         if (Qice <= 0.0) {
    1561            0 :             this->Urate = 0.0; //[ratio]
    1562              :         }
    1563              : 
    1564              :         // Calculate leaving water temperature
    1565            0 :         if ((Qice <= 0.0) || (this->XCurIceFrac >= 1.0)) {
    1566            0 :             this->ITSOutletTemp = this->ITSInletTemp;
    1567            0 :             Qice = 0.0;
    1568            0 :             Uact = 0.0;
    1569              :         } else {
    1570            0 :             Real64 DeltaTemp = Qice / Psychrometrics::CPCW(this->ITSInletTemp) / this->ITSMassFlowRate;
    1571            0 :             this->ITSOutletTemp = this->ITSInletTemp + DeltaTemp;
    1572              :             // Limit leaving temp to be no greater than setpoint or freezing temp minus 1C
    1573            0 :             this->ITSOutletTemp = min(this->ITSOutletTemp, this->ITSOutletSetPointTemp, (FreezTemp - 1));
    1574              :             // Limit leaving temp to be no less than inlet temp
    1575            0 :             this->ITSOutletTemp = max(this->ITSOutletTemp, this->ITSInletTemp);
    1576            0 :             DeltaTemp = this->ITSOutletTemp - this->ITSInletTemp;
    1577            0 :             Qice = DeltaTemp * Psychrometrics::CPCW(this->ITSInletTemp) * this->ITSMassFlowRate;
    1578            0 :             Uact = Qice / (this->ITSNomCap / TimeInterval);
    1579              :         } // End of leaving temp checks
    1580              : 
    1581            0 :         this->Urate = Uact;
    1582            0 :         this->ITSCoolingRate = -Qice;
    1583            0 :         this->ITSCoolingEnergy = this->ITSCoolingRate * state.dataHVACGlobal->TimeStepSysSec;
    1584            0 :     }
    1585              : 
    1586              :     //******************************************************************************
    1587              : 
    1588            0 :     void SimpleIceStorageData::CalcQiceChargeMaxByChiller(EnergyPlusData &state, Real64 &QiceMaxByChiller)
    1589              :     {
    1590              :         // METHODOLOGY EMPLOYED:
    1591              :         // Calculation inside is IP unit, then return QiceMaxByChiller as SI [W] unit.
    1592              : 
    1593              :         // Chiller is remote now, so chiller out is inlet node temp
    1594            0 :         Real64 TchillerOut = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
    1595            0 :         QiceMaxByChiller = this->UAIceCh * (FreezTemp - TchillerOut); //[W] = [W/degC]*[degC]
    1596              : 
    1597              :         // If it happened, it is occurred at the Discharging or Dormant process.
    1598            0 :         if (QiceMaxByChiller <= 0.0) {
    1599            0 :             QiceMaxByChiller = 0.0;
    1600              :         }
    1601            0 :     }
    1602              : 
    1603            0 :     void SimpleIceStorageData::CalcQiceChargeMaxByITS(Real64 const chillerOutletTemp, // [degC]
    1604              :                                                       Real64 &QiceMaxByITS            // [W]
    1605              :     )
    1606              :     {
    1607              :         // Qice is maximized when ChillerInletTemp and ChillerOutletTemp(input data) is almost same due to LMTD method.
    1608              :         // Qice is minimized(=0) when ChillerInletTemp is almost same as FreezTemp(=0).
    1609              : 
    1610              :         // Initialize
    1611            0 :         Real64 Tfr = FreezTempIP;
    1612            0 :         Real64 ChOutletTemp = TempSItoIP(chillerOutletTemp); //[degF] = ConvertSItoIP[degC]
    1613              :         // Chiller outlet temp must be below freeze temp, or else no charge
    1614            0 :         if (ChOutletTemp >= Tfr) {
    1615            0 :             QiceMaxByITS = 0.0;
    1616              :         } else {
    1617              :             // Make ChillerInletTemp as almost same as ChillerOutletTemp(input data)
    1618            0 :             Real64 ChillerInletTemp = ChOutletTemp + 0.01;
    1619              :             // ChillerInletTemp cannot be greater than or equal to freeze temp
    1620            0 :             if (ChillerInletTemp >= Tfr) {
    1621            0 :                 ChillerInletTemp = ChOutletTemp + (Tfr - ChOutletTemp) / 2;
    1622              :             }
    1623              : 
    1624            0 :             Real64 LogTerm = (Tfr - ChOutletTemp) / (Tfr - ChillerInletTemp);
    1625              :             // Need to protect this from LogTerm <= 0 - not sure what it should do then
    1626            0 :             if (LogTerm <= 0.0) {
    1627            0 :                 ChillerInletTemp = ChOutletTemp;
    1628            0 :                 QiceMaxByITS = 0.0;
    1629              :             }
    1630            0 :             QiceMaxByITS = this->UAIceCh * (TempIPtoSI(ChillerInletTemp) - TempIPtoSI(ChOutletTemp)) / std::log(LogTerm);
    1631              :         }
    1632            0 :     }
    1633              : 
    1634            0 :     void SimpleIceStorageData::CalcIceStorageDischarge(EnergyPlusData &state,
    1635              :                                                        Real64 const myLoad, // operating load
    1636              :                                                        bool const RunFlag,  // TRUE when ice storage operating
    1637              :                                                        Real64 const MaxCap  // Max possible discharge rate (positive value)
    1638              :     )
    1639              :     {
    1640              :         static constexpr std::string_view RoutineName("SimpleIceStorageData::CalcIceStorageDischarge");
    1641              : 
    1642              :         // Initialize processed Rate and Energy
    1643            0 :         this->ITSMassFlowRate = 0.0;
    1644            0 :         this->ITSCoolingRate = 0.0;
    1645            0 :         this->ITSCoolingEnergy = 0.0;
    1646              : 
    1647            0 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
    1648            0 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
    1649            0 :             this->ITSOutletSetPointTemp = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPoint;
    1650            0 :         } break;
    1651            0 :         case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
    1652            0 :             this->ITSOutletSetPointTemp = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPointHi;
    1653            0 :         } break;
    1654            0 :         default:
    1655            0 :             break;
    1656              :         }
    1657              : 
    1658              :         // Initialize processed U values
    1659            0 :         this->Urate = 0.0;
    1660              : 
    1661              :         // If no component demand or ITS OFF, then RETURN.
    1662            0 :         if (myLoad == 0 || !RunFlag) {
    1663            0 :             this->ITSMassFlowRate = 0.0;
    1664            0 :             this->ITSInletTemp = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
    1665            0 :             this->ITSOutletTemp = this->ITSInletTemp;
    1666            0 :             this->ITSCoolingRate = 0.0;
    1667            0 :             this->ITSCoolingEnergy = 0.0;
    1668            0 :             return;
    1669              :         }
    1670              : 
    1671              :         // If FlowLock(provided by PlantSupplyManager) is False(=0), that is, MyLoad is not changed.
    1672              :         // then based on MyLoad, new ITSMassFlowRate will be calculated.
    1673              : 
    1674              :         //----------------------------
    1675            0 :         int loopNum = this->plantLoc.loopNum;
    1676              : 
    1677              :         Real64 CpFluid =
    1678            0 :             state.dataPlnt->PlantLoop(loopNum).glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->PltInletNodeNum).Temp, RoutineName);
    1679              : 
    1680              :         // Calculate Umyload based on MyLoad from E+
    1681            0 :         Real64 Umyload = -myLoad * TimeInterval / this->ITSNomCap;
    1682              :         // Calculate Umax and Umin
    1683              :         // Cannot discharge more than the fraction that is left
    1684            0 :         Real64 Umax = -this->IceFracRemain / state.dataHVACGlobal->TimeStepSys;
    1685              :         // Calculate Umin based on returned MyLoad from E+.
    1686            0 :         Real64 Umin = min(Umyload, 0.0);
    1687              :         // Based on Umax and Umin, if necessary to run E+, calculate proper Uact
    1688              :         // U is negative here.
    1689            0 :         Real64 Uact = max(Umin, Umax);
    1690              : 
    1691              :         // Set ITSInletTemp provided by E+
    1692            0 :         this->ITSInletTemp = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
    1693              :         // The first thing is to set the ITSMassFlowRate
    1694            0 :         this->ITSMassFlowRate = this->DesignMassFlowRate; //[kg/s]
    1695              : 
    1696            0 :         PlantUtilities::SetComponentFlowRate(state, this->ITSMassFlowRate, this->PltInletNodeNum, this->PltOutletNodeNum, this->plantLoc);
    1697              : 
    1698              :         // Qice is calculate input U which is within boundary between Umin and Umax.
    1699            0 :         Real64 Qice = Uact * this->ITSNomCap / TimeInterval;
    1700              :         // Qice cannot exceed MaxCap calculated by CalcIceStorageCapacity
    1701              :         // Note Qice is negative here, MaxCap is positive
    1702            0 :         Qice = max(Qice, -MaxCap);
    1703              : 
    1704              :         // Calculate leaving water temperature
    1705            0 :         if ((Qice >= 0.0) || (this->XCurIceFrac <= 0.0) || (this->ITSMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance)) {
    1706            0 :             this->ITSOutletTemp = this->ITSInletTemp;
    1707            0 :             Qice = 0.0;
    1708            0 :             Uact = 0.0;
    1709              :         } else {
    1710            0 :             Real64 DeltaTemp = Qice / CpFluid / this->ITSMassFlowRate;
    1711            0 :             this->ITSOutletTemp = this->ITSInletTemp + DeltaTemp;
    1712              :             // Limit leaving temp to be no less than setpoint or freezing temp plus 1C
    1713            0 :             this->ITSOutletTemp = max(this->ITSOutletTemp, this->ITSOutletSetPointTemp, (FreezTemp + 1));
    1714              :             // Limit leaving temp to be no greater than inlet temp
    1715            0 :             this->ITSOutletTemp = min(this->ITSOutletTemp, this->ITSInletTemp);
    1716            0 :             DeltaTemp = this->ITSOutletTemp - this->ITSInletTemp;
    1717            0 :             Qice = DeltaTemp * CpFluid * this->ITSMassFlowRate;
    1718            0 :             Uact = Qice / (this->ITSNomCap / TimeInterval);
    1719              :         } // End of leaving temp checks
    1720              : 
    1721              :         // Calculate reported U value
    1722            0 :         this->Urate = Uact;
    1723              :         // Calculate ITSCoolingEnergy [J]
    1724            0 :         this->ITSCoolingRate = -Qice;
    1725            0 :         this->ITSCoolingEnergy = this->ITSCoolingRate * state.dataHVACGlobal->TimeStepSysSec;
    1726              :     }
    1727              : 
    1728            0 :     void SimpleIceStorageData::CalcQiceDischageMax(EnergyPlusData &state, Real64 &QiceMin)
    1729              :     {
    1730              : 
    1731              :         // Qice is minimized when ITSInletTemp and ITSOutletTemp is almost same due to LMTD method.
    1732              :         // Qice is maximized(=0) when ITSOutletTemp is almost same as FreezTemp(=0).
    1733              : 
    1734            0 :         Real64 ITSInletTemp_loc = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
    1735            0 :         Real64 ITSOutletTemp_loc = 0.0;
    1736            0 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
    1737            0 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
    1738            0 :             ITSOutletTemp_loc = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPoint;
    1739            0 :         } break;
    1740            0 :         case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
    1741            0 :             ITSOutletTemp_loc = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPointHi;
    1742            0 :         } break;
    1743            0 :         default: {
    1744            0 :             assert(false);
    1745              :         } break;
    1746              :         }
    1747              : 
    1748            0 :         Real64 LogTerm = (ITSInletTemp_loc - FreezTemp) / (ITSOutletTemp_loc - FreezTemp);
    1749              : 
    1750            0 :         if (LogTerm <= 1) {
    1751            0 :             QiceMin = 0.0;
    1752              :         } else {
    1753            0 :             QiceMin = this->UAIceDisCh * (ITSInletTemp_loc - ITSOutletTemp_loc) / std::log(LogTerm);
    1754              :         }
    1755            0 :     }
    1756              : 
    1757            0 :     void SimpleIceStorageData::CalcUAIce(Real64 const XCurIceFrac_loc, Real64 &UAIceCh_loc, Real64 &UAIceDisCh_loc, Real64 &HLoss_loc)
    1758              :     {
    1759              :         // SUBROUTINE INFORMATION:
    1760              :         //       AUTHOR
    1761              :         //       DATE WRITTEN
    1762              :         //       MODIFIED
    1763              :         //       RE-ENGINEERED
    1764              : 
    1765              :         // PURPOSE OF THIS SUBROUTINE:
    1766              : 
    1767              :         // METHODOLOGY EMPLOYED:
    1768              :         // This routine is function of XCurIceFrac, and UA value is based on 1 hour.
    1769              : 
    1770            0 :         switch (this->ITSType_Num) {
    1771            0 :         case ITSType::IceOnCoilInternal: {
    1772            0 :             Real64 y = XCurIceFrac_loc;
    1773            0 :             UAIceCh_loc = (1.3879 - 7.6333 * y + 26.3423 * pow_2(y) - 47.6084 * pow_3(y) + 41.8498 * pow_4(y) - 14.2948 * pow_5(y)) *
    1774            0 :                           this->ITSNomCap / TimeInterval / 10.0; // [W/C]
    1775            0 :             y = 1.0 - XCurIceFrac_loc;
    1776            0 :             UAIceDisCh_loc = (1.3879 - 7.6333 * y + 26.3423 * pow_2(y) - 47.6084 * pow_3(y) + 41.8498 * pow_4(y) - 14.2948 * pow_5(y)) *
    1777            0 :                              this->ITSNomCap / TimeInterval / 10.0; // [W/C]
    1778            0 :             HLoss_loc = 0.0;
    1779            0 :         } break;
    1780            0 :         case ITSType::IceOnCoilExternal: {
    1781            0 :             Real64 y = XCurIceFrac_loc;
    1782            0 :             UAIceCh_loc = (1.3879 - 7.6333 * y + 26.3423 * pow_2(y) - 47.6084 * pow_3(y) + 41.8498 * pow_4(y) - 14.2948 * pow_5(y)) *
    1783            0 :                           this->ITSNomCap / TimeInterval / 10.0; // [W/C]
    1784            0 :             y = 1.0 - XCurIceFrac_loc;
    1785            0 :             UAIceDisCh_loc = (1.1756 - 5.3689 * y + 17.3602 * pow_2(y) - 30.1077 * pow_3(y) + 25.6387 * pow_4(y) - 8.5102 * pow_5(y)) *
    1786            0 :                              this->ITSNomCap / TimeInterval / 10.0; // [W/C]
    1787            0 :             HLoss_loc = 0.0;
    1788            0 :         } break;
    1789            0 :         default:
    1790            0 :             break;
    1791              :         }
    1792            0 :     }
    1793              : 
    1794            0 :     Real64 CalcDetIceStorLMTDstar(Real64 const Tin,  // ice storage unit inlet temperature
    1795              :                                   Real64 const Tout, // ice storage unit outlet (setpoint) temperature
    1796              :                                   Real64 const Tfr   // freezing temperature
    1797              :     )
    1798              :     {
    1799              : 
    1800              :         // SUBROUTINE INFORMATION:
    1801              :         //       AUTHOR         Rick Strand
    1802              :         //       DATE WRITTEN   February 2006
    1803              :         //       MODIFIED       na
    1804              :         //       RE-ENGINEERED  na
    1805              : 
    1806              :         // PURPOSE OF THIS SUBROUTINE:
    1807              :         // This subroutine calculates the log mean temperature difference for
    1808              :         // the detailed ice storage unit.  The temperature difference is non-
    1809              :         // dimensionalized using a nominal temperature difference of 10C.
    1810              :         // This value must be used when obtaining the curve fit coefficients.
    1811              : 
    1812              :         // METHODOLOGY EMPLOYED:
    1813              :         // Straight-forward calculation where:
    1814              :         // LMTD* = LMTD/Tnom
    1815              :         // LMTD = (Tin-Tout)/ln((Tin-Tfr)/(Tout-Tfr))
    1816              : 
    1817              :         Real64 CalcDetIceStorLMTDstar;
    1818            0 :         Real64 constexpr Tnom(10.0); // Nominal temperature difference across the ice storage unit [C]
    1819              : 
    1820              :         // First set the temperature differences and avoid problems with the LOG
    1821              :         // term by setting some reasonable minimums
    1822            0 :         Real64 DeltaTio = std::abs(Tin - Tout); // Inlet to outlet temperature difference
    1823            0 :         Real64 DeltaTif = std::abs(Tin - Tfr);  // Inlet to freezing temperature difference
    1824            0 :         Real64 DeltaTof = std::abs(Tout - Tfr); // Outlet to freezing temperature difference
    1825              : 
    1826            0 :         if (DeltaTif < DeltaTifMin) DeltaTif = DeltaTifMin;
    1827            0 :         if (DeltaTof < DeltaTofMin) DeltaTof = DeltaTofMin;
    1828              : 
    1829            0 :         CalcDetIceStorLMTDstar = (DeltaTio / std::log(DeltaTif / DeltaTof)) / Tnom;
    1830              : 
    1831            0 :         return CalcDetIceStorLMTDstar;
    1832              :     }
    1833              : 
    1834            4 :     Real64 CalcQstar(EnergyPlusData &state,
    1835              :                      int const CurveIndex,           // curve index
    1836              :                      enum CurveVars CurveIndVarType, // independent variable type for ice storage
    1837              :                      Real64 const FracCharged,       // fraction charged for ice storage unit
    1838              :                      Real64 const LMTDstar,          // normalized log mean temperature difference across the ice storage unit
    1839              :                      Real64 const MassFlowstar       // normalized mass flow rate through the ice storage unit
    1840              :     )
    1841              :     {
    1842              : 
    1843              :         Real64 CalcQstar;
    1844              : 
    1845            4 :         if (CurveIndVarType == CurveVars::FracChargedLMTD) {
    1846            1 :             CalcQstar = std::abs(Curve::CurveValue(state, CurveIndex, FracCharged, LMTDstar));
    1847            3 :         } else if (CurveIndVarType == CurveVars::FracDischargedLMTD) {
    1848            1 :             CalcQstar = std::abs(Curve::CurveValue(state, CurveIndex, (1.0 - FracCharged), LMTDstar));
    1849            2 :         } else if (CurveIndVarType == CurveVars::LMTDMassFlow) {
    1850            1 :             CalcQstar = std::abs(Curve::CurveValue(state, CurveIndex, LMTDstar, MassFlowstar));
    1851            1 :         } else if (CurveIndVarType == CurveVars::LMTDFracCharged) {
    1852            1 :             CalcQstar = std::abs(Curve::CurveValue(state, CurveIndex, LMTDstar, FracCharged));
    1853              :         } else { // should never get here as this is checked on input
    1854            0 :             CalcQstar = 0.0;
    1855              :         }
    1856              : 
    1857            4 :         return CalcQstar;
    1858              :     }
    1859              : 
    1860            0 :     Real64 TempSItoIP(Real64 const Temp)
    1861              :     {
    1862            0 :         return (Temp * 9.0 / 5.0) + 32.0;
    1863              :     }
    1864              : 
    1865          208 :     Real64 TempIPtoSI(Real64 const Temp)
    1866              :     {
    1867          208 :         return (Temp - 32.0) * 5.0 / 9.0;
    1868              :     }
    1869              : 
    1870            0 :     void SimpleIceStorageData::UpdateNode(EnergyPlusData &state, Real64 const myLoad, bool const RunFlag)
    1871              :     {
    1872              :         // SUBROUTINE INFORMATION:
    1873              :         //       AUTHOR:          Dan Fisher
    1874              :         //       DATE WRITTEN:    October 1998
    1875              : 
    1876              :         // Update Node Inlet & Outlet MassFlowRat
    1877            0 :         PlantUtilities::SafeCopyPlantNode(state, this->PltInletNodeNum, this->PltOutletNodeNum);
    1878            0 :         if (myLoad == 0 || !RunFlag) {
    1879              :             // Update Outlet Conditions so that same as Inlet, so component can be bypassed if necessary
    1880            0 :             state.dataLoopNodes->Node(this->PltOutletNodeNum).Temp = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
    1881              :         } else {
    1882            0 :             state.dataLoopNodes->Node(this->PltOutletNodeNum).Temp = this->ITSOutletTemp;
    1883              :         }
    1884            0 :     }
    1885              : 
    1886            0 :     void SimpleIceStorageData::RecordOutput(Real64 const myLoad, bool const RunFlag)
    1887              :     {
    1888            0 :         if (myLoad == 0 || !RunFlag) {
    1889            0 :             this->MyLoad = myLoad;
    1890            0 :             this->ITSCoolingRate_rep = 0.0;
    1891            0 :             this->ITSCoolingEnergy_rep = 0.0;
    1892            0 :             this->ITSChargingRate = 0.0;
    1893            0 :             this->ITSChargingEnergy = 0.0;
    1894            0 :             this->ITSmdot = 0.0;
    1895              : 
    1896              :         } else {
    1897            0 :             this->MyLoad = myLoad;
    1898            0 :             if (this->ITSCoolingRate > 0.0) {
    1899            0 :                 this->ITSCoolingRate_rep = this->ITSCoolingRate;
    1900            0 :                 this->ITSCoolingEnergy_rep = this->ITSCoolingEnergy;
    1901            0 :                 this->ITSChargingRate = 0.0;
    1902            0 :                 this->ITSChargingEnergy = 0.0;
    1903              :             } else {
    1904            0 :                 this->ITSCoolingRate_rep = 0.0;
    1905            0 :                 this->ITSCoolingEnergy_rep = 0.0;
    1906            0 :                 this->ITSChargingRate = -this->ITSCoolingRate;
    1907            0 :                 this->ITSChargingEnergy = -this->ITSCoolingEnergy;
    1908              :             }
    1909            0 :             this->ITSmdot = this->ITSMassFlowRate;
    1910              :         }
    1911            0 :     }
    1912              : 
    1913       287262 :     void UpdateIceFractions(EnergyPlusData const &state)
    1914              :     {
    1915              : 
    1916              :         // SUBROUTINE INFORMATION:
    1917              :         //       AUTHOR         Mike Witte
    1918              :         //       DATE WRITTEN   September 2005
    1919              :         //       MODIFIED       Rick Strand (Feb 2006, for detailed ice storage model)
    1920              :         //       RE-ENGINEERED  na
    1921              : 
    1922              :         // PURPOSE OF THIS SUBROUTINE:
    1923              :         // Update all ice fractions at end of system time step.
    1924              : 
    1925              :         // METHODOLOGY EMPLOYED:
    1926              :         // This is called from HVACManager once we have actually stepped forward
    1927              :         // a system time step.
    1928              : 
    1929       287262 :         for (auto &thisITS : state.dataIceThermalStorage->SimpleIceStorage) {
    1930            0 :             thisITS.IceFracRemain += thisITS.Urate * state.dataHVACGlobal->TimeStepSys;
    1931            0 :             if (thisITS.IceFracRemain <= 0.001) thisITS.IceFracRemain = 0.0;
    1932            0 :             if (thisITS.IceFracRemain > 1.0) thisITS.IceFracRemain = 1.0;
    1933              :         }
    1934              : 
    1935       287262 :         for (auto &thisITS : state.dataIceThermalStorage->DetailedIceStorage) {
    1936            0 :             thisITS.IceFracRemaining += thisITS.IceFracChange - (thisITS.TankLossCoeff * state.dataHVACGlobal->TimeStepSys);
    1937            0 :             if (thisITS.IceFracRemaining < 0.001) thisITS.IceFracRemaining = 0.0;
    1938            0 :             if (thisITS.IceFracRemaining > 1.000) thisITS.IceFracRemaining = 1.0;
    1939              :             // Reset the ice on the coil to zero for inside melt whenever discharging takes place.
    1940              :             // This assumes that any remaining ice floats away from the coil and resettles perfectly.
    1941              :             // While this is not exactly what happens and it is possible theoretically to have multiple
    1942              :             // freeze thaw cycles that are not complete, this is the best we can do.
    1943            0 :             if (thisITS.ThawProcessIndex == DetIce::InsideMelt) {
    1944            0 :                 if (thisITS.IceFracChange < 0.0) {
    1945            0 :                     thisITS.IceFracOnCoil = 0.0;
    1946              :                 } else {
    1947              :                     // Assume loss term does not impact ice on the coil but what is remaining
    1948            0 :                     thisITS.IceFracOnCoil += thisITS.IceFracChange;
    1949              :                     // If the ice remaining has run out because of tank losses, reset ice fraction on coil so that it keeps track of losses
    1950            0 :                     if (thisITS.IceFracOnCoil > thisITS.IceFracRemaining) thisITS.IceFracOnCoil = thisITS.IceFracRemaining;
    1951              :                 }
    1952              :             } else { // Outside melt system so IceFracOnCoil is always the same as IceFracRemaining (needs to be done for reporting only)
    1953            0 :                 thisITS.IceFracOnCoil = thisITS.IceFracRemaining;
    1954              :             }
    1955              :         }
    1956       287262 :     }
    1957              : 
    1958            0 :     void DetailedIceStorageData::UpdateDetailedIceStorage(EnergyPlusData &state)
    1959              :     {
    1960              : 
    1961              :         // SUBROUTINE INFORMATION:
    1962              :         //       AUTHOR         Rick Strand
    1963              :         //       DATE WRITTEN   February 2006
    1964              :         //       MODIFIED       na
    1965              :         //       RE-ENGINEERED  na
    1966              : 
    1967              :         // PURPOSE OF THIS SUBROUTINE:
    1968              :         // This subroutine takes the necessary information from the local data
    1969              :         // structure and moves it back to the loop node data structure.
    1970              : 
    1971              :         // METHODOLOGY EMPLOYED:
    1972              :         // Not much mystery here--just move the data to the appropriate place
    1973              :         // for the detailed ice storage system in question.
    1974              : 
    1975              :         // Set the temperature and flow rate for the component outlet node
    1976            0 :         int InNodeNum = this->PlantInNodeNum;
    1977            0 :         int OutNodeNum = this->PlantOutNodeNum;
    1978              : 
    1979            0 :         PlantUtilities::SafeCopyPlantNode(state, InNodeNum, OutNodeNum);
    1980              : 
    1981            0 :         state.dataLoopNodes->Node(OutNodeNum).Temp = this->OutletTemp;
    1982            0 :     }
    1983              : 
    1984            0 :     void DetailedIceStorageData::ReportDetailedIceStorage(EnergyPlusData &state)
    1985              :     {
    1986              : 
    1987              :         // SUBROUTINE INFORMATION:
    1988              :         //       AUTHOR         Rick Strand
    1989              :         //       DATE WRITTEN   February 2006
    1990              :         //       MODIFIED       na
    1991              :         //       RE-ENGINEERED  na
    1992              : 
    1993              :         // PURPOSE OF THIS SUBROUTINE:
    1994              :         // This subroutine reports all of the output necessary for the model.
    1995              : 
    1996              :         // METHODOLOGY EMPLOYED:
    1997              :         // Just take what has already been calculated or calculate the appropriate
    1998              :         // output value based on simulation data.
    1999              : 
    2000            0 :         Real64 constexpr LowLoadLimit(0.1); // Load below which device can be assumed off [W]
    2001              : 
    2002            0 :         if (this->CompLoad < LowLoadLimit) { // No load condition
    2003              : 
    2004            0 :             this->IceFracChange = 0.0;
    2005            0 :             this->DischargingRate = 0.0;
    2006            0 :             this->DischargingEnergy = 0.0;
    2007            0 :             this->ChargingRate = 0.0;
    2008            0 :             this->ChargingEnergy = 0.0;
    2009            0 :             this->ParasiticElecRate = 0.0;
    2010            0 :             this->ParasiticElecEnergy = 0.0;
    2011              : 
    2012              :         } else { // There is a load, determine whether we are charging or discharging based on inlet and outlet temperature
    2013              : 
    2014            0 :             if (this->InletTemp < this->OutletTemp) { // Charging Mode
    2015              : 
    2016            0 :                 this->ChargingRate = this->CompLoad;
    2017            0 :                 this->ChargingEnergy = this->CompLoad * (state.dataHVACGlobal->TimeStepSysSec);
    2018            0 :                 this->IceFracChange = this->CompLoad * state.dataHVACGlobal->TimeStepSys / this->NomCapacity;
    2019            0 :                 this->DischargingRate = 0.0;
    2020            0 :                 this->DischargingEnergy = 0.0;
    2021            0 :                 this->ParasiticElecRate = this->ChargeParaElecLoad * this->CompLoad;
    2022            0 :                 this->ParasiticElecEnergy = this->ChargeParaElecLoad * this->ChargingEnergy;
    2023              : 
    2024              :             } else { // (DetailedIceStorage(IceNum)%InletTemp < DetailedIceStorage(IceNum)%OutletTemp) Discharging Mode
    2025              : 
    2026            0 :                 this->DischargingRate = this->CompLoad;
    2027            0 :                 this->DischargingEnergy = this->CompLoad * (state.dataHVACGlobal->TimeStepSysSec);
    2028            0 :                 this->IceFracChange = -this->CompLoad * state.dataHVACGlobal->TimeStepSys / this->NomCapacity;
    2029            0 :                 this->ChargingRate = 0.0;
    2030            0 :                 this->ChargingEnergy = 0.0;
    2031            0 :                 this->ParasiticElecRate = this->DischargeParaElecLoad * this->CompLoad;
    2032            0 :                 this->ParasiticElecEnergy = this->DischargeParaElecLoad * this->ChargingEnergy;
    2033              :             }
    2034              :         }
    2035            0 :     }
    2036              : 
    2037              : } // namespace IceThermalStorage
    2038              : 
    2039              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1