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

Generated by: LCOV version 2.0-1