LCOV - code coverage report
Current view: top level - EnergyPlus - IceThermalStorage.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 80.8 % 948 766
Test Date: 2025-06-02 07:23:51 Functions: 100.0 % 27 27

            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            2 :     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            2 :         if (state.dataIceThermalStorage->getITSInput) {
     123            2 :             GetIceStorageInput(state);
     124            2 :             state.dataIceThermalStorage->getITSInput = false;
     125              :         }
     126              : 
     127              :         // Now look for this particular pipe in the list
     128            2 :         for (auto &ITS : state.dataIceThermalStorage->SimpleIceStorage) {
     129            2 :             if (ITS.Name == objectName) {
     130            2 :                 return &ITS;
     131              :             }
     132            4 :         }
     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            7 :     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            7 :         if (state.dataIceThermalStorage->getITSInput) {
     144            7 :             GetIceStorageInput(state);
     145            7 :             state.dataIceThermalStorage->getITSInput = false;
     146              :         }
     147              : 
     148              :         // Now look for this particular pipe in the list
     149            7 :         for (auto &ITS : state.dataIceThermalStorage->DetailedIceStorage) {
     150            7 :             if (ITS.Name == objectName) {
     151            7 :                 return &ITS;
     152              :             }
     153           14 :         }
     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       103633 :     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       103633 :         auto &thisComp(state.dataPlnt->PlantLoop(calledFromLocation.loopNum)
     171       103633 :                            .LoopSide(calledFromLocation.loopSideNum)
     172       103633 :                            .Branch(calledFromLocation.branchNum)
     173       103633 :                            .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       103633 :         if (thisComp.CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) {
     180       103622 :             Real64 localCurLoad = thisComp.EquipDemand;
     181       103622 :             if (localCurLoad != 0) {
     182        93653 :                 RunFlag = true;
     183              :             }
     184              :         }
     185              : 
     186       103633 :         if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
     187           20 :             this->ResetXForITSFlag = true;
     188           20 :             this->MyEnvrnFlag = false;
     189              :         }
     190              : 
     191       103633 :         if (!state.dataGlobal->BeginEnvrnFlag) {
     192       102800 :             this->MyEnvrnFlag = true;
     193              :         }
     194              : 
     195       103633 :         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       103633 :         Real64 TempSetPt(0.0);
     215       103633 :         Real64 TempIn = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
     216       103633 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
     217       103633 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     218       103633 :             TempSetPt = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPoint;
     219       103633 :         } 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       103633 :         Real64 DemandMdot = this->DesignMassFlowRate;
     228              : 
     229       103633 :         Real64 Cp = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getSpecificHeat(state, TempIn, RoutineName);
     230              : 
     231       103633 :         Real64 MyLoad2 = (DemandMdot * Cp * (TempIn - TempSetPt));
     232       103633 :         MyLoad = MyLoad2;
     233              : 
     234              :         //     Set fraction of ice remaining in storage
     235       103633 :         this->XCurIceFrac = this->IceFracRemain;
     236              : 
     237              :         //***** Dormant Process for ITS *****************************************
     238              :         //************************************************************************
     239              :         //        IF( U .EQ. 0.0 ) THEN
     240       103633 :         if ((MyLoad2 == 0.0) || (DemandMdot == 0.0)) {
     241         9964 :             this->CalcIceStorageDormant(state);
     242              : 
     243              :             //***** Charging Process for ITS *****************************************
     244              :             //************************************************************************
     245              :             //        ELSE IF( U .GT. 0.0 ) THEN
     246        93669 :         } else if (MyLoad2 < 0.0) {
     247              : 
     248              :             Real64 MaxCap;
     249              :             Real64 MinCap;
     250              :             Real64 OptCap;
     251        39773 :             this->CalcIceStorageCapacity(state, MaxCap, MinCap, OptCap);
     252        39773 :             this->CalcIceStorageCharge(state);
     253              : 
     254              :             //***** Discharging Process for ITS *****************************************
     255              :             //************************************************************************
     256              :             //        ELSE IF( U .LT. 0.0 ) THEN
     257        53896 :         } else if (MyLoad2 > 0.0) {
     258              : 
     259              :             Real64 MaxCap;
     260              :             Real64 MinCap;
     261              :             Real64 OptCap;
     262        53896 :             this->CalcIceStorageCapacity(state, MaxCap, MinCap, OptCap);
     263        53896 :             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       103633 :         this->UpdateNode(state, MyLoad2, RunFlag);
     268              : 
     269              :         // Update report variables.
     270       103633 :         this->RecordOutput(MyLoad2, RunFlag);
     271       103633 :     }
     272              : 
     273       272104 :     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       272104 :         if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
     281           42 :             this->ResetXForITSFlag = true;
     282           42 :             this->MyEnvrnFlag = false;
     283              :         }
     284              : 
     285       272104 :         if (!state.dataGlobal->BeginEnvrnFlag) {
     286       269684 :             this->MyEnvrnFlag = true;
     287              :         }
     288              : 
     289       272104 :         this->oneTimeInit(state); // Initialize detailed ice storage
     290              : 
     291       272104 :         this->SimDetailedIceStorage(state); // Simulate detailed ice storage
     292              : 
     293       272104 :         this->UpdateDetailedIceStorage(state); // Update detailed ice storage
     294              : 
     295       272104 :         this->ReportDetailedIceStorage(state); // Report detailed ice storage
     296       272104 :     }
     297              : 
     298       272104 :     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       272104 :         int constexpr MaxIterNum(100);                      // Maximum number of internal iterations for ice storage solution
     324       272104 :         Real64 constexpr SmallestLoad(0.1);                 // Smallest load to actually run the ice storage unit [Watts]
     325       272104 :         Real64 constexpr TankDischargeToler(0.001);         // Below this fraction, there is nothing left to discharge
     326       272104 :         Real64 constexpr TankChargeToler(0.999);            // Above this fraction, we don't have anything left to charge
     327       272104 :         Real64 constexpr TemperatureToler(0.1);             // Temperature difference between iterations that indicates convergence [C]
     328       272104 :         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       272104 :         int NodeNumIn = this->PlantInNodeNum;                      // Plant loop inlet node number for component
     334       272104 :         int NodeNumOut = this->PlantOutNodeNum;                    // Plant loop outlet node number for component
     335       272104 :         Real64 TempIn = state.dataLoopNodes->Node(NodeNumIn).Temp; // Inlet temperature to component (from plant loop) [C]
     336       272104 :         Real64 TempSetPt(0.0);                                     // Setpoint temperature defined by loop controls [C]
     337       272104 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
     338       272104 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
     339       272104 :             TempSetPt = state.dataLoopNodes->Node(NodeNumOut).TempSetPoint;
     340       272104 :         } 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       272104 :         int IterNum = 0;
     350              : 
     351              :         // Set derived type variables
     352       272104 :         this->InletTemp = TempIn;
     353       272104 :         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       406828 :         if ((state.dataPlnt->PlantLoop(this->plantLoc.loopNum).CommonPipeType == DataPlant::CommonPipeType::TwoWay) &&
     357       406828 :             (std::abs(this->MassFlowRate) < DataBranchAirLoopPlant::MassFlowTolerance) && (this->IceFracRemaining < TankChargeToler)) {
     358        62353 :             this->MassFlowRate = this->DesignMassFlowRate;
     359              :         }
     360              : 
     361              :         // Calculate the current load on the ice storage unit
     362       272104 :         Real64 Cp = state.dataPlnt->PlantLoop(this->plantLoc.loopNum).glycol->getSpecificHeat(state, TempIn, RoutineName);
     363              : 
     364              :         // Estimated load on the ice storage unit [W]
     365       272104 :         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       272104 :         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        83137 :             this->CompLoad = 0.0;
     371        83137 :             this->OutletTemp = TempIn;
     372        83137 :             this->TankOutletTemp = TempIn;
     373        83137 :             Real64 mdot = 0.0;
     374        83137 :             PlantUtilities::SetComponentFlowRate(state, mdot, this->PlantInNodeNum, this->PlantOutNodeNum, this->plantLoc);
     375              : 
     376        83137 :             this->BypassMassFlowRate = mdot;
     377        83137 :             this->TankMassFlowRate = 0.0;
     378        83137 :             this->MassFlowRate = mdot;
     379              : 
     380       188967 :         } 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        78739 :             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        69953 :                 this->CompLoad = 0.0;
     390        69953 :                 this->OutletTemp = TempIn;
     391        69953 :                 this->TankOutletTemp = TempIn;
     392        69953 :                 Real64 mdot = 0.0;
     393        69953 :                 PlantUtilities::SetComponentFlowRate(state, mdot, this->PlantInNodeNum, this->PlantOutNodeNum, this->plantLoc);
     394              : 
     395        69953 :                 this->BypassMassFlowRate = mdot;
     396        69953 :                 this->TankMassFlowRate = 0.0;
     397        69953 :                 this->MassFlowRate = mdot;
     398              : 
     399        69953 :             } else {
     400              :                 // make flow request so tank will get flow
     401         8786 :                 Real64 mdot = this->DesignMassFlowRate;
     402         8786 :                 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         8786 :                 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         8786 :                     TempSetPt = this->FreezingTemp - DeltaTofMin;
     413              :                 }
     414              : 
     415              :                 // Tank outlet temperature from the last iteration [C]
     416         8786 :                 Real64 ToutOld = TempSetPt;
     417              :                 // Non-dimensional log mean temperature difference of ice storage unit [non-dimensional]
     418         8786 :                 Real64 LMTDstar = CalcDetIceStorLMTDstar(TempIn, ToutOld, this->FreezingTemp);
     419         8786 :                 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         8786 :                 Real64 ChargeFrac = LocalLoad * state.dataHVACGlobal->TimeStepSys / this->NomCapacity;
     424         8786 :                 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         8786 :                 if (this->ThawProcessIndex == DetIce::InsideMelt) {
     430         1594 :                     AvgFracCharged = this->IceFracOnCoil + (ChargeFrac / 2.0);
     431              :                 } else { // (DetailedIceStorage(IceNum)%ThawProcessIndex == DetIce::OutsideMelt)
     432         7192 :                     AvgFracCharged = this->IceFracRemaining + (ChargeFrac / 2.0);
     433              :                 }
     434              : 
     435              :                 // Current load on the ice storage unit [non-dimensional]
     436         8786 :                 Real64 Qstar = std::abs(CalcQstar(state, this->ChargeCurveNum, this->ChargeCurveTypeNum, AvgFracCharged, LMTDstar, MassFlowstar));
     437              : 
     438              :                 // Actual load on the ice storage unit [W]
     439         8786 :                 Real64 ActualLoad = Qstar * this->NomCapacity / this->CurveFitTimeStep;
     440              : 
     441              :                 // Updated outlet temperature from the tank [C]
     442         8786 :                 Real64 ToutNew = TempIn + (ActualLoad / (this->MassFlowRate * Cp));
     443              :                 // Again, the outlet temperature cannot be above the freezing temperature (factoring in the tolerance)
     444         8786 :                 if (ToutNew > (this->FreezingTemp - DeltaTofMin)) {
     445         6604 :                     ToutNew = this->FreezingTemp - DeltaTofMin;
     446              :                 }
     447              : 
     448         8786 :                 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        12956 :                     while (IterNum < MaxIterNum) {
     459        12956 :                         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         4170 :                             ToutOld = ToutNew;
     463         4170 :                             LMTDstar = CalcDetIceStorLMTDstar(TempIn, ToutOld, this->FreezingTemp);
     464         4170 :                             MassFlowstar = this->MassFlowRate / SIEquiv100GPMinMassFlowRate;
     465              :                             Qstar =
     466         4170 :                                 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         4170 :                             ChargeFrac = Qstar * (state.dataHVACGlobal->TimeStepSys / this->CurveFitTimeStep);
     470         4170 :                             if ((this->IceFracRemaining + ChargeFrac) > 1.0) {
     471          738 :                                 ChargeFrac = 1.0 - this->IceFracRemaining;
     472          738 :                                 Qstar = ChargeFrac;
     473              :                             }
     474         4170 :                             if (this->ThawProcessIndex == DetIce::InsideMelt) {
     475           70 :                                 AvgFracCharged = this->IceFracOnCoil + (ChargeFrac / 2.0);
     476              :                             } else { // (DetailedIceStorage(IceNum)%ThawProcessIndex == DetIce::OutsideMelt)
     477         4100 :                                 AvgFracCharged = this->IceFracRemaining + (ChargeFrac / 2.0);
     478              :                             }
     479              : 
     480              :                             // Finally, update the actual load and calculate the new outlet temperature; increment iteration counter
     481         4170 :                             ActualLoad = Qstar * this->NomCapacity / this->CurveFitTimeStep;
     482         4170 :                             ToutNew = TempIn + (ActualLoad / (this->MassFlowRate * Cp));
     483              :                             // Again, the outlet temperature cannot be above the freezing temperature (factoring in the tolerance)
     484         4170 :                             if (ToutNew < (this->FreezingTemp - DeltaTofMin)) {
     485         3996 :                                 ToutNew = this->FreezingTemp - DeltaTofMin;
     486              :                             }
     487         4170 :                             ++IterNum;
     488              : 
     489              :                         } else {
     490              :                             // Converged to acceptable tolerance so set output variables and exit DO WHILE loop
     491         8786 :                             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         8786 :                     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         8786 :                     this->OutletTemp = ToutNew;
     518         8786 :                     this->TankOutletTemp = ToutNew;
     519         8786 :                     this->BypassMassFlowRate = 0.0;
     520         8786 :                     this->TankMassFlowRate = this->MassFlowRate;
     521         8786 :                     this->CompLoad = this->MassFlowRate * Cp * std::abs(TempIn - ToutNew);
     522              :                 }
     523              :             }
     524              : 
     525       110228 :         } 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       110228 :             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        18819 :                 this->CompLoad = 0.0;
     535        18819 :                 this->OutletTemp = this->InletTemp;
     536        18819 :                 this->TankOutletTemp = this->InletTemp;
     537        18819 :                 Real64 mdot = 0.0;
     538        18819 :                 PlantUtilities::SetComponentFlowRate(state, mdot, this->PlantInNodeNum, this->PlantOutNodeNum, this->plantLoc);
     539              : 
     540        18819 :                 this->BypassMassFlowRate = mdot;
     541        18819 :                 this->TankMassFlowRate = 0.0;
     542        18819 :                 this->MassFlowRate = mdot;
     543              : 
     544        18819 :             } else {
     545              : 
     546              :                 // make flow request so tank will get flow
     547        91409 :                 Real64 mdot = this->DesignMassFlowRate;
     548        91409 :                 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        91409 :                 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           19 :                     TempSetPt = this->FreezingTemp + DeltaTofMin;
     557              :                 }
     558              : 
     559              :                 // Tank outlet temperature from the last iteration [C]
     560        91409 :                 Real64 ToutOld = TempSetPt;
     561              :                 // Non-dimensional log mean temperature difference of ice storage unit [non-dimensional]
     562        91409 :                 Real64 LMTDstar = CalcDetIceStorLMTDstar(TempIn, ToutOld, this->FreezingTemp);
     563        91409 :                 Real64 MassFlowstar = this->MassFlowRate / SIEquiv100GPMinMassFlowRate;
     564              : 
     565              :                 // Find initial guess at average fraction charged during time step
     566        91409 :                 Real64 ChargeFrac = LocalLoad * state.dataHVACGlobal->TimeStepSys / this->NomCapacity;
     567        91409 :                 if ((this->IceFracRemaining - ChargeFrac) < 0.0) {
     568         3670 :                     ChargeFrac = this->IceFracRemaining;
     569              :                 }
     570        91409 :                 Real64 AvgFracCharged = this->IceFracRemaining - (ChargeFrac / 2.0);
     571              : 
     572              :                 // Current load on the ice storage unit [non-dimensional]
     573              :                 Real64 Qstar =
     574        91409 :                     std::abs(CalcQstar(state, this->DischargeCurveNum, this->DischargeCurveTypeNum, AvgFracCharged, LMTDstar, MassFlowstar));
     575              : 
     576              :                 // Actual load on the ice storage unit [W]
     577        91409 :                 Real64 ActualLoad = Qstar * this->NomCapacity / this->CurveFitTimeStep;
     578              : 
     579              :                 // Updated outlet temperature from the tank [C]
     580        91409 :                 Real64 ToutNew = TempIn - (ActualLoad / (this->MassFlowRate * Cp));
     581              :                 // Again, the outlet temperature cannot be below the freezing temperature (factoring in the tolerance)
     582        91409 :                 if (ToutNew < (this->FreezingTemp + DeltaTofMin)) {
     583        61831 :                     ToutNew = this->FreezingTemp + DeltaTofMin;
     584              :                 }
     585              : 
     586        91409 :                 if (ActualLoad > LocalLoad) {
     587              :                     // We have more than enough storage to meet the load so no need to iterate to find a solution
     588        86456 :                     this->OutletTemp = TempSetPt;
     589        86456 :                     this->TankOutletTemp = ToutNew;
     590        86456 :                     this->CompLoad = this->MassFlowRate * Cp * std::abs(TempIn - TempSetPt);
     591        86456 :                     this->TankMassFlowRate = this->CompLoad / Cp / std::abs(TempIn - ToutNew);
     592        86456 :                     this->BypassMassFlowRate = this->MassFlowRate - this->TankMassFlowRate;
     593              : 
     594              :                 } else {
     595              : 
     596        15843 :                     while (IterNum < MaxIterNum) {
     597        15842 :                         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        10890 :                             ToutOld = ToutNew;
     601        10890 :                             LMTDstar = CalcDetIceStorLMTDstar(TempIn, ToutOld, this->FreezingTemp);
     602              : 
     603        10890 :                             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        10890 :                             ChargeFrac = Qstar * (state.dataHVACGlobal->TimeStepSys / this->CurveFitTimeStep);
     608        10890 :                             if ((this->IceFracRemaining - ChargeFrac) < 0.0) {
     609         6162 :                                 ChargeFrac = this->IceFracRemaining;
     610         6162 :                                 Qstar = ChargeFrac;
     611              :                             }
     612        10890 :                             AvgFracCharged = this->IceFracRemaining - (ChargeFrac / 2.0);
     613              : 
     614              :                             // Finally, update the actual load and calculate the new outlet temperature; increment iteration counter
     615        10890 :                             ActualLoad = Qstar * this->NomCapacity / this->CurveFitTimeStep;
     616        10890 :                             ToutNew = TempIn - (ActualLoad / (this->MassFlowRate * Cp));
     617              :                             // Again, the outlet temperature cannot be below the freezing temperature (factoring in the tolerance)
     618        10890 :                             if (ToutNew < (this->FreezingTemp + DeltaTofMin)) {
     619           47 :                                 ToutNew = this->FreezingTemp + DeltaTofMin;
     620              :                             }
     621        10890 :                             ++IterNum;
     622              : 
     623              :                         } else {
     624              :                             // Converged to acceptable tolerance so set output variables and exit DO WHILE loop
     625         4952 :                             break;
     626              :                         }
     627              : 
     628              :                     } // ...loop iterating for the ice storage outlet temperature
     629              : 
     630              :                     // Keep track of times that the iterations got excessive
     631         4953 :                     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         4953 :                     if (ToutNew >= TempSetPt) {
     653         4953 :                         this->OutletTemp = ToutNew;
     654         4953 :                         this->TankOutletTemp = ToutNew;
     655         4953 :                         this->BypassMassFlowRate = 0.0;
     656         4953 :                         this->TankMassFlowRate = this->MassFlowRate;
     657         4953 :                         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       272104 :     }
     673              : 
     674            9 :     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            9 :         ErrorsFound = false; // Always need to reset this since there are multiple types of ice storage systems
     692              : 
     693              :         // LOAD ARRAYS WITH SimpleIceStorage DATA
     694           18 :         state.dataIceThermalStorage->NumSimpleIceStorage =
     695            9 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cIceStorageSimple); // by ZG
     696           18 :         state.dataIceThermalStorage->NumDetailedIceStorage =
     697            9 :             state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cIceStorageDetailed);
     698              : 
     699              :         // Allocate SimpleIceStorage based on NumOfIceStorage
     700            9 :         state.dataIceThermalStorage->SimpleIceStorage.allocate(state.dataIceThermalStorage->NumSimpleIceStorage);
     701              : 
     702            9 :         state.dataIPShortCut->cCurrentModuleObject = cIceStorageSimple;
     703           11 :         for (int iceNum = 1; iceNum <= state.dataIceThermalStorage->NumSimpleIceStorage; ++iceNum) {
     704              : 
     705              :             int NumAlphas;
     706              :             int NumNums;
     707              :             int IOStat;
     708            6 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     709            2 :                                                                      state.dataIPShortCut->cCurrentModuleObject,
     710              :                                                                      iceNum,
     711            2 :                                                                      state.dataIPShortCut->cAlphaArgs,
     712              :                                                                      NumAlphas,
     713            2 :                                                                      state.dataIPShortCut->rNumericArgs,
     714              :                                                                      NumNums,
     715              :                                                                      IOStat,
     716              :                                                                      _,
     717              :                                                                      _,
     718              :                                                                      _,
     719            2 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     720            2 :             Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
     721              : 
     722            2 :             ++state.dataIceThermalStorage->TotalNumIceStorage;
     723            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).MapNum = state.dataIceThermalStorage->TotalNumIceStorage;
     724              : 
     725              :             // ITS name
     726            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).Name = state.dataIPShortCut->cAlphaArgs(1);
     727              : 
     728              :             // Get Ice Thermal Storage Type
     729            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSType = state.dataIPShortCut->cAlphaArgs(2);
     730            2 :             if (Util::SameString(state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSType, "IceOnCoilInternal")) {
     731            2 :                 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            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSNomCap = state.dataIPShortCut->rNumericArgs(1) * 1.e+09;
     742            2 :             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            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).PltInletNodeNum =
     751            4 :                 NodeInputManager::GetOnlySingleNode(state,
     752            2 :                                                     state.dataIPShortCut->cAlphaArgs(3),
     753              :                                                     ErrorsFound,
     754              :                                                     DataLoopNode::ConnectionObjectType::ThermalStorageIceSimple,
     755            2 :                                                     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            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).PltOutletNodeNum =
     763            6 :                 NodeInputManager::GetOnlySingleNode(state,
     764            2 :                                                     state.dataIPShortCut->cAlphaArgs(4),
     765              :                                                     ErrorsFound,
     766              :                                                     DataLoopNode::ConnectionObjectType::ThermalStorageIceSimple,
     767            2 :                                                     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            4 :             BranchNodeConnections::TestCompSet(state,
     775            2 :                                                state.dataIPShortCut->cCurrentModuleObject,
     776            2 :                                                state.dataIPShortCut->cAlphaArgs(1),
     777            2 :                                                state.dataIPShortCut->cAlphaArgs(3),
     778            2 :                                                state.dataIPShortCut->cAlphaArgs(4),
     779              :                                                "Chilled Water Nodes");
     780              : 
     781              :             // Initialize Report Variables
     782            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).MyLoad = 0.0;
     783            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).Urate = 0.0;
     784            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).IceFracRemain = 1.0;
     785            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSCoolingRate_rep = 0.0;
     786            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSCoolingEnergy_rep = 0.0;
     787            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSChargingRate = 0.0;
     788            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSChargingEnergy = 0.0;
     789            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSmdot = 0.0;
     790            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSInletTemp = 0.0;
     791            2 :             state.dataIceThermalStorage->SimpleIceStorage(iceNum).ITSOutletTemp = 0.0;
     792              : 
     793              :         } // IceNum
     794              : 
     795            9 :         if (ErrorsFound) {
     796            0 :             ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
     797              :         }
     798              : 
     799            9 :         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            9 :         state.dataIPShortCut->cCurrentModuleObject = cIceStorageDetailed;
     803              : 
     804            9 :         state.dataIceThermalStorage->DetailedIceStorage.allocate(
     805            9 :             state.dataIceThermalStorage->NumDetailedIceStorage); // Allocate DetIceStorage based on NumDetIceStorages
     806              : 
     807           16 :         for (int iceNum = 1; iceNum <= state.dataIceThermalStorage->NumDetailedIceStorage; ++iceNum) {
     808              : 
     809              :             int NumAlphas;
     810              :             int NumNums;
     811              :             int IOStat;
     812           21 :             state.dataInputProcessing->inputProcessor->getObjectItem(state,
     813            7 :                                                                      state.dataIPShortCut->cCurrentModuleObject,
     814              :                                                                      iceNum,
     815            7 :                                                                      state.dataIPShortCut->cAlphaArgs,
     816              :                                                                      NumAlphas,
     817            7 :                                                                      state.dataIPShortCut->rNumericArgs,
     818              :                                                                      NumNums,
     819              :                                                                      IOStat,
     820              :                                                                      _,
     821            7 :                                                                      state.dataIPShortCut->lAlphaFieldBlanks,
     822            7 :                                                                      state.dataIPShortCut->cAlphaFieldNames,
     823            7 :                                                                      state.dataIPShortCut->cNumericFieldNames);
     824              : 
     825            7 :             ErrorObjectHeader eoh{routineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)};
     826              : 
     827            7 :             Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
     828              : 
     829            7 :             ++state.dataIceThermalStorage->TotalNumIceStorage;
     830              : 
     831            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).MapNum = state.dataIceThermalStorage->TotalNumIceStorage;
     832            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).Name = state.dataIPShortCut->cAlphaArgs(1); // Detailed ice storage name
     833              : 
     834              :             // Get and verify availability schedule
     835            7 :             if (state.dataIPShortCut->lAlphaFieldBlanks(2)) {
     836            0 :                 state.dataIceThermalStorage->DetailedIceStorage(iceNum).availSched = Sched::GetScheduleAlwaysOn(state);
     837            7 :             } else if ((state.dataIceThermalStorage->DetailedIceStorage(iceNum).availSched =
     838           14 :                             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            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).NomCapacity =
     847            7 :                 state.dataIPShortCut->rNumericArgs(1) * (1.e+09) / Constant::rSecsInHour;
     848              : 
     849            7 :             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            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).PlantInNodeNum =
     858           14 :                 NodeInputManager::GetOnlySingleNode(state,
     859            7 :                                                     state.dataIPShortCut->cAlphaArgs(3),
     860              :                                                     ErrorsFound,
     861              :                                                     DataLoopNode::ConnectionObjectType::ThermalStorageIceDetailed,
     862            7 :                                                     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            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).PlantOutNodeNum =
     870           21 :                 NodeInputManager::GetOnlySingleNode(state,
     871            7 :                                                     state.dataIPShortCut->cAlphaArgs(4),
     872              :                                                     ErrorsFound,
     873              :                                                     DataLoopNode::ConnectionObjectType::ThermalStorageIceDetailed,
     874            7 :                                                     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           14 :             BranchNodeConnections::TestCompSet(state,
     882            7 :                                                state.dataIPShortCut->cCurrentModuleObject,
     883            7 :                                                state.dataIPShortCut->cAlphaArgs(1),
     884            7 :                                                state.dataIPShortCut->cAlphaArgs(3),
     885            7 :                                                state.dataIPShortCut->cAlphaArgs(4),
     886              :                                                "Chilled Water Nodes");
     887              : 
     888              :             // Obtain the Charging and Discharging Curve types and names
     889            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveName = state.dataIPShortCut->cAlphaArgs(6);
     890            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveNum =
     891            7 :                 Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(6));
     892            7 :             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            7 :                 state.dataCurveManager->curves(state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveNum)->numDims;
     900            7 :             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            7 :                 if (state.dataIPShortCut->cAlphaArgs(5) == "FRACTIONCHARGEDLMTD") {
     909            0 :                     state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveTypeNum = CurveVars::FracChargedLMTD;
     910            7 :                 } else if (state.dataIPShortCut->cAlphaArgs(5) == "FRACTIONDISCHARGEDLMTD") {
     911            6 :                     state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveTypeNum = CurveVars::FracDischargedLMTD;
     912            1 :                 } else if (state.dataIPShortCut->cAlphaArgs(5) == "LMTDMASSFLOW") {
     913            1 :                     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           21 :             ErrorsFound |= Curve::CheckCurveDims(state,
     930            7 :                                                  state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeCurveNum, // Curve index
     931              :                                                  {2},                                                                       // Valid dimensions
     932              :                                                  "GetIceStorageInput: ",                                                    // Routine name
     933            7 :                                                  state.dataIPShortCut->cCurrentModuleObject,                                // Object Type
     934            7 :                                                  state.dataIceThermalStorage->DetailedIceStorage(iceNum).Name,              // Object Name
     935            7 :                                                  state.dataIPShortCut->cAlphaFieldNames(6));                                // Field Name
     936              : 
     937            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveName = state.dataIPShortCut->cAlphaArgs(8);
     938            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveNum = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(8));
     939            7 :             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            7 :             int chargeCurveDim = state.dataCurveManager->curves(state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveNum)->numDims;
     946            7 :             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            7 :                 if (state.dataIPShortCut->cAlphaArgs(7) == "FRACTIONCHARGEDLMTD") {
     955            6 :                     state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveTypeNum = CurveVars::FracChargedLMTD;
     956            1 :                 } else if (state.dataIPShortCut->cAlphaArgs(7) == "FRACTIONDISCHARGEDLMTD") {
     957            0 :                     state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveTypeNum = CurveVars::FracDischargedLMTD;
     958            1 :                 } else if (state.dataIPShortCut->cAlphaArgs(7) == "LMTDMASSFLOW") {
     959            1 :                     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           21 :             ErrorsFound |= Curve::CheckCurveDims(state,
     976            7 :                                                  state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeCurveNum, // Curve index
     977              :                                                  {2},                                                                    // Valid dimensions
     978              :                                                  "GetIceStorageInput: ",                                                 // Routine name
     979            7 :                                                  state.dataIPShortCut->cCurrentModuleObject,                             // Object Type
     980            7 :                                                  state.dataIceThermalStorage->DetailedIceStorage(iceNum).Name,           // Object Name
     981            7 :                                                  state.dataIPShortCut->cAlphaFieldNames(8));                             // Field Name
     982              : 
     983            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).CurveFitTimeStep = state.dataIPShortCut->rNumericArgs(2);
     984           14 :             if ((state.dataIceThermalStorage->DetailedIceStorage(iceNum).CurveFitTimeStep <= 0.0) ||
     985            7 :                 (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            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ThawProcessIndicator = state.dataIPShortCut->cAlphaArgs(9);
     995            7 :             if (Util::SameString(state.dataIceThermalStorage->DetailedIceStorage(iceNum).ThawProcessIndicator, "INSIDEMELT")) {
     996            2 :                 state.dataIceThermalStorage->DetailedIceStorage(iceNum).ThawProcessIndex = DetIce::InsideMelt;
     997            5 :             } else if ((Util::SameString(state.dataIceThermalStorage->DetailedIceStorage(iceNum).ThawProcessIndicator, "OUTSIDEMELT")) ||
     998            0 :                        (state.dataIceThermalStorage->DetailedIceStorage(iceNum).ThawProcessIndicator.empty())) {
     999            5 :                 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            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeParaElecLoad = state.dataIPShortCut->rNumericArgs(3);
    1011            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeParaElecLoad = state.dataIPShortCut->rNumericArgs(4);
    1012            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).TankLossCoeff = state.dataIPShortCut->rNumericArgs(5);
    1013            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).FreezingTemp = state.dataIPShortCut->rNumericArgs(6);
    1014              : 
    1015           14 :             if ((state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargeParaElecLoad < 0.0) ||
    1016            7 :                 (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           14 :             if ((state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargeParaElecLoad < 0.0) ||
    1025            7 :                 (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           14 :             if ((state.dataIceThermalStorage->DetailedIceStorage(iceNum).TankLossCoeff < 0.0) ||
    1034            7 :                 (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           14 :             if ((state.dataIceThermalStorage->DetailedIceStorage(iceNum).FreezingTemp < -10.0) ||
    1043            7 :                 (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            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).CompLoad = 0.0;
    1054            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).IceFracChange = 0.0;
    1055            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).IceFracRemaining = 1.0;
    1056            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).IceFracOnCoil = 1.0;
    1057            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargingRate = 0.0;
    1058            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).DischargingEnergy = 0.0;
    1059            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargingRate = 0.0;
    1060            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ChargingEnergy = 0.0;
    1061            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).MassFlowRate = 0.0;
    1062            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).BypassMassFlowRate = 0.0;
    1063            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).TankMassFlowRate = 0.0;
    1064            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).InletTemp = 0.0;
    1065            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).OutletTemp = 0.0;
    1066            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).TankOutletTemp = 0.0;
    1067            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ParasiticElecRate = 0.0;
    1068            7 :             state.dataIceThermalStorage->DetailedIceStorage(iceNum).ParasiticElecEnergy = 0.0;
    1069              : 
    1070              :         } // ...over detailed ice storage units
    1071              : 
    1072            9 :         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            9 :         if (ErrorsFound) {
    1078            0 :             ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
    1079              :         }
    1080            9 :     }
    1081              : 
    1082            2 :     void SimpleIceStorageData::setupOutputVars(EnergyPlusData &state)
    1083              :     {
    1084            4 :         SetupOutputVariable(state,
    1085              :                             "Ice Thermal Storage Requested Load",
    1086              :                             Constant::Units::W,
    1087            2 :                             this->MyLoad,
    1088              :                             OutputProcessor::TimeStepType::System,
    1089              :                             OutputProcessor::StoreType::Average,
    1090            2 :                             this->Name);
    1091              : 
    1092            4 :         SetupOutputVariable(state,
    1093              :                             "Ice Thermal Storage End Fraction",
    1094              :                             Constant::Units::None,
    1095            2 :                             this->IceFracRemain,
    1096              :                             OutputProcessor::TimeStepType::Zone,
    1097              :                             OutputProcessor::StoreType::Average,
    1098            2 :                             this->Name);
    1099              : 
    1100            4 :         SetupOutputVariable(state,
    1101              :                             "Ice Thermal Storage Mass Flow Rate",
    1102              :                             Constant::Units::kg_s,
    1103            2 :                             this->ITSmdot,
    1104              :                             OutputProcessor::TimeStepType::System,
    1105              :                             OutputProcessor::StoreType::Average,
    1106            2 :                             this->Name);
    1107              : 
    1108            4 :         SetupOutputVariable(state,
    1109              :                             "Ice Thermal Storage Inlet Temperature",
    1110              :                             Constant::Units::C,
    1111            2 :                             this->ITSInletTemp,
    1112              :                             OutputProcessor::TimeStepType::System,
    1113              :                             OutputProcessor::StoreType::Average,
    1114            2 :                             this->Name);
    1115              : 
    1116            4 :         SetupOutputVariable(state,
    1117              :                             "Ice Thermal Storage Outlet Temperature",
    1118              :                             Constant::Units::C,
    1119            2 :                             this->ITSOutletTemp,
    1120              :                             OutputProcessor::TimeStepType::System,
    1121              :                             OutputProcessor::StoreType::Average,
    1122            2 :                             this->Name);
    1123              : 
    1124            4 :         SetupOutputVariable(state,
    1125              :                             "Ice Thermal Storage Cooling Discharge Rate",
    1126              :                             Constant::Units::W,
    1127            2 :                             this->ITSCoolingRate_rep,
    1128              :                             OutputProcessor::TimeStepType::System,
    1129              :                             OutputProcessor::StoreType::Average,
    1130            2 :                             this->Name);
    1131              : 
    1132            4 :         SetupOutputVariable(state,
    1133              :                             "Ice Thermal Storage Cooling Discharge Energy",
    1134              :                             Constant::Units::J,
    1135            2 :                             this->ITSCoolingEnergy_rep,
    1136              :                             OutputProcessor::TimeStepType::System,
    1137              :                             OutputProcessor::StoreType::Sum,
    1138            2 :                             this->Name);
    1139              : 
    1140            4 :         SetupOutputVariable(state,
    1141              :                             "Ice Thermal Storage Cooling Charge Rate",
    1142              :                             Constant::Units::W,
    1143            2 :                             this->ITSChargingRate,
    1144              :                             OutputProcessor::TimeStepType::System,
    1145              :                             OutputProcessor::StoreType::Average,
    1146            2 :                             this->Name);
    1147              : 
    1148            4 :         SetupOutputVariable(state,
    1149              :                             "Ice Thermal Storage Cooling Charge Energy",
    1150              :                             Constant::Units::J,
    1151            2 :                             this->ITSChargingEnergy,
    1152              :                             OutputProcessor::TimeStepType::System,
    1153              :                             OutputProcessor::StoreType::Sum,
    1154            2 :                             this->Name);
    1155            2 :     }
    1156              : 
    1157            7 :     void DetailedIceStorageData::setupOutputVars(EnergyPlusData &state)
    1158              :     {
    1159           14 :         SetupOutputVariable(state,
    1160              :                             "Ice Thermal Storage Cooling Rate",
    1161              :                             Constant::Units::W,
    1162            7 :                             this->CompLoad,
    1163              :                             OutputProcessor::TimeStepType::System,
    1164              :                             OutputProcessor::StoreType::Average,
    1165            7 :                             this->Name);
    1166              : 
    1167           14 :         SetupOutputVariable(state,
    1168              :                             "Ice Thermal Storage Change Fraction",
    1169              :                             Constant::Units::None,
    1170            7 :                             this->IceFracChange,
    1171              :                             OutputProcessor::TimeStepType::System,
    1172              :                             OutputProcessor::StoreType::Average,
    1173            7 :                             this->Name);
    1174              : 
    1175           14 :         SetupOutputVariable(state,
    1176              :                             "Ice Thermal Storage End Fraction",
    1177              :                             Constant::Units::None,
    1178            7 :                             this->IceFracRemaining,
    1179              :                             OutputProcessor::TimeStepType::System,
    1180              :                             OutputProcessor::StoreType::Average,
    1181            7 :                             this->Name);
    1182              : 
    1183           14 :         SetupOutputVariable(state,
    1184              :                             "Ice Thermal Storage On Coil Fraction",
    1185              :                             Constant::Units::None,
    1186            7 :                             this->IceFracOnCoil,
    1187              :                             OutputProcessor::TimeStepType::System,
    1188              :                             OutputProcessor::StoreType::Average,
    1189            7 :                             this->Name);
    1190              : 
    1191           14 :         SetupOutputVariable(state,
    1192              :                             "Ice Thermal Storage Mass Flow Rate",
    1193              :                             Constant::Units::kg_s,
    1194            7 :                             this->MassFlowRate,
    1195              :                             OutputProcessor::TimeStepType::System,
    1196              :                             OutputProcessor::StoreType::Average,
    1197            7 :                             this->Name);
    1198              : 
    1199           14 :         SetupOutputVariable(state,
    1200              :                             "Ice Thermal Storage Bypass Mass Flow Rate",
    1201              :                             Constant::Units::kg_s,
    1202            7 :                             this->BypassMassFlowRate,
    1203              :                             OutputProcessor::TimeStepType::System,
    1204              :                             OutputProcessor::StoreType::Average,
    1205            7 :                             this->Name);
    1206              : 
    1207           14 :         SetupOutputVariable(state,
    1208              :                             "Ice Thermal Storage Tank Mass Flow Rate",
    1209              :                             Constant::Units::kg_s,
    1210            7 :                             this->TankMassFlowRate,
    1211              :                             OutputProcessor::TimeStepType::System,
    1212              :                             OutputProcessor::StoreType::Average,
    1213            7 :                             this->Name);
    1214              : 
    1215           14 :         SetupOutputVariable(state,
    1216              :                             "Ice Thermal Storage Fluid Inlet Temperature",
    1217              :                             Constant::Units::C,
    1218            7 :                             this->InletTemp,
    1219              :                             OutputProcessor::TimeStepType::System,
    1220              :                             OutputProcessor::StoreType::Average,
    1221            7 :                             this->Name);
    1222              : 
    1223           14 :         SetupOutputVariable(state,
    1224              :                             "Ice Thermal Storage Blended Outlet Temperature",
    1225              :                             Constant::Units::C,
    1226            7 :                             this->OutletTemp,
    1227              :                             OutputProcessor::TimeStepType::System,
    1228              :                             OutputProcessor::StoreType::Average,
    1229            7 :                             this->Name);
    1230              : 
    1231           14 :         SetupOutputVariable(state,
    1232              :                             "Ice Thermal Storage Tank Outlet Temperature",
    1233              :                             Constant::Units::C,
    1234            7 :                             this->TankOutletTemp,
    1235              :                             OutputProcessor::TimeStepType::System,
    1236              :                             OutputProcessor::StoreType::Average,
    1237            7 :                             this->Name);
    1238              : 
    1239           14 :         SetupOutputVariable(state,
    1240              :                             "Ice Thermal Storage Cooling Discharge Rate",
    1241              :                             Constant::Units::W,
    1242            7 :                             this->DischargingRate,
    1243              :                             OutputProcessor::TimeStepType::System,
    1244              :                             OutputProcessor::StoreType::Average,
    1245            7 :                             this->Name);
    1246              : 
    1247           14 :         SetupOutputVariable(state,
    1248              :                             "Ice Thermal Storage Cooling Discharge Energy",
    1249              :                             Constant::Units::J,
    1250            7 :                             this->DischargingEnergy,
    1251              :                             OutputProcessor::TimeStepType::System,
    1252              :                             OutputProcessor::StoreType::Sum,
    1253            7 :                             this->Name);
    1254              : 
    1255           14 :         SetupOutputVariable(state,
    1256              :                             "Ice Thermal Storage Cooling Charge Rate",
    1257              :                             Constant::Units::W,
    1258            7 :                             this->ChargingRate,
    1259              :                             OutputProcessor::TimeStepType::System,
    1260              :                             OutputProcessor::StoreType::Average,
    1261            7 :                             this->Name);
    1262              : 
    1263           14 :         SetupOutputVariable(state,
    1264              :                             "Ice Thermal Storage Cooling Charge Energy",
    1265              :                             Constant::Units::J,
    1266            7 :                             this->ChargingEnergy,
    1267              :                             OutputProcessor::TimeStepType::System,
    1268              :                             OutputProcessor::StoreType::Sum,
    1269            7 :                             this->Name);
    1270              : 
    1271           14 :         SetupOutputVariable(state,
    1272              :                             "Ice Thermal Storage Ancillary Electricity Rate",
    1273              :                             Constant::Units::W,
    1274            7 :                             this->ParasiticElecRate,
    1275              :                             OutputProcessor::TimeStepType::System,
    1276              :                             OutputProcessor::StoreType::Average,
    1277            7 :                             this->Name);
    1278              : 
    1279           14 :         SetupOutputVariable(state,
    1280              :                             "Ice Thermal Storage Ancillary Electricity Energy",
    1281              :                             Constant::Units::J,
    1282            7 :                             this->ParasiticElecEnergy,
    1283              :                             OutputProcessor::TimeStepType::System,
    1284              :                             OutputProcessor::StoreType::Sum,
    1285            7 :                             this->Name,
    1286              :                             Constant::eResource::Electricity,
    1287              :                             OutputProcessor::Group::HVAC,
    1288              :                             OutputProcessor::EndUseCat::Invalid);
    1289            7 :     }
    1290              : 
    1291       272104 :     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       272104 :         if (this->MyPlantScanFlag) {
    1307            7 :             bool errFlag = false;
    1308            7 :             PlantUtilities::ScanPlantLoopsForObject(state, this->Name, DataPlant::PlantEquipmentType::TS_IceDetailed, this->plantLoc, errFlag);
    1309              : 
    1310            7 :             if (errFlag) {
    1311            0 :                 ShowFatalError(state, "DetailedIceStorageData: oneTimeInit: Program terminated due to previous condition(s).");
    1312              :             }
    1313              : 
    1314            7 :             this->setupOutputVars(state);
    1315            7 :             this->MyPlantScanFlag = false;
    1316              :         }
    1317              : 
    1318       272104 :         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           42 :             this->IceFracChange = 0.0;
    1323           42 :             this->IceFracRemaining = 1.0;
    1324           42 :             this->IceFracOnCoil = 1.0;
    1325           42 :             this->InletTemp = 0.0;
    1326           42 :             this->OutletTemp = 0.0;
    1327           42 :             this->TankOutletTemp = 0.0;
    1328           42 :             this->DischargeIterErrors = 0;
    1329           42 :             this->ChargeIterErrors = 0;
    1330           42 :             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           42 :             PlantUtilities::InitComponentNodes(state, 0.0, this->DesignMassFlowRate, this->PlantInNodeNum, this->PlantOutNodeNum);
    1333              : 
    1334           60 :             if ((state.dataPlnt->PlantLoop(this->plantLoc.loopNum).CommonPipeType == DataPlant::CommonPipeType::TwoWay) &&
    1335           18 :                 (this->plantLoc.loopSideNum == DataPlant::LoopSideLocation::Supply)) {
    1336              :                 // up flow priority of other components on the same branch as the Ice tank
    1337           66 :                 for (int CompNum = 1; CompNum <= state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
    1338           66 :                                                      .LoopSide(DataPlant::LoopSideLocation::Supply)
    1339           66 :                                                      .Branch(this->plantLoc.branchNum)
    1340           66 :                                                      .TotalComponents;
    1341              :                      ++CompNum) {
    1342           48 :                     state.dataPlnt->PlantLoop(this->plantLoc.loopNum)
    1343           48 :                         .LoopSide(DataPlant::LoopSideLocation::Supply)
    1344           48 :                         .Branch(this->plantLoc.branchNum)
    1345           48 :                         .Comp(CompNum)
    1346           48 :                         .FlowPriority = DataPlant::LoopFlowStatus::NeedyAndTurnsLoopOn;
    1347              :                 }
    1348              :             }
    1349              : 
    1350           42 :             this->MyEnvrnFlag2 = false;
    1351              :         }
    1352       272104 :         if (!state.dataGlobal->BeginEnvrnFlag) {
    1353       269684 :             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       272104 :         this->CompLoad = 0.0;
    1359       272104 :         this->IceFracChange = 0.0;
    1360       272104 :         this->DischargingRate = 0.0;
    1361       272104 :         this->DischargingEnergy = 0.0;
    1362       272104 :         this->ChargingRate = 0.0;
    1363       272104 :         this->ChargingEnergy = 0.0;
    1364       272104 :         this->MassFlowRate = 0.0;
    1365       272104 :         this->BypassMassFlowRate = 0.0;
    1366       272104 :         this->TankMassFlowRate = 0.0;
    1367       272104 :         this->ParasiticElecRate = 0.0;
    1368       272104 :         this->ParasiticElecEnergy = 0.0;
    1369       272104 :     }
    1370              : 
    1371       103633 :     void SimpleIceStorageData::oneTimeInit(EnergyPlusData &state)
    1372              :     {
    1373              : 
    1374       103633 :         if (this->MyPlantScanFlag) {
    1375              :             // Locate the storage on the plant loops for later usage
    1376            2 :             bool errFlag = false;
    1377            4 :             PlantUtilities::ScanPlantLoopsForObject(
    1378            2 :                 state, this->Name, DataPlant::PlantEquipmentType::TS_IceSimple, this->plantLoc, errFlag, _, _, _, _, _);
    1379            2 :             if (errFlag) {
    1380            0 :                 ShowFatalError(state, "SimpleIceStorageData:oneTimeInit: Program terminated due to previous condition(s).");
    1381              :             }
    1382              : 
    1383            2 :             this->setupOutputVars(state);
    1384            2 :             this->MyPlantScanFlag = false;
    1385              :         }
    1386              : 
    1387       103633 :         if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag2) {
    1388           20 :             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           20 :             PlantUtilities::InitComponentNodes(state, 0.0, this->DesignMassFlowRate, this->PltInletNodeNum, this->PltOutletNodeNum);
    1391           20 :             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           20 :             this->MyLoad = 0.0;
    1407           20 :             this->Urate = 0.0;
    1408           20 :             this->IceFracRemain = 1.0;
    1409           20 :             this->ITSCoolingRate = 0.0;
    1410           20 :             this->ITSCoolingEnergy_rep = 0.0;
    1411           20 :             this->ITSChargingRate = 0.0;
    1412           20 :             this->ITSChargingEnergy = 0.0;
    1413           20 :             this->ITSmdot = 0.0;
    1414           20 :             this->ITSInletTemp = 0.0;
    1415           20 :             this->ITSOutletTemp = 0.0;
    1416              : 
    1417           20 :             this->MyEnvrnFlag2 = false;
    1418              :         }
    1419              : 
    1420       103633 :         if (!state.dataGlobal->BeginEnvrnFlag) {
    1421       102800 :             this->MyEnvrnFlag2 = true;
    1422              :         }
    1423       103633 :     }
    1424              : 
    1425              :     //******************************************************************************
    1426              : 
    1427        93669 :     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        93669 :         MaxCap = 0.0;
    1436        93669 :         MinCap = 0.0;
    1437        93669 :         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        93669 :         if (this->ResetXForITSFlag) {
    1442           18 :             this->XCurIceFrac = 1.0;
    1443           18 :             this->IceFracRemain = 1.0;
    1444           18 :             this->Urate = 0.0;
    1445           18 :             this->ResetXForITSFlag = false;
    1446              :         }
    1447              : 
    1448              :         // Calculate UAIceDisch[W/C] and UAIceCh[W/F] based on ONLY XCurIceFrac
    1449        93669 :         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        93669 :         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        93669 :         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        93669 :         Real64 Uact = Umin;
    1463        93669 :         Real64 ITSCoolingRateMax = std::abs(Uact * this->ITSNomCap / TimeInterval);
    1464        93669 :         Real64 ITSCoolingRateOpt = ITSCoolingRateMax;
    1465        93669 :         Real64 ITSCoolingRateMin = 0.0;
    1466              : 
    1467              :         // Define MaxCap, OptCap, and MinCap
    1468        93669 :         MaxCap = ITSCoolingRateMax;
    1469        93669 :         OptCap = ITSCoolingRateOpt;
    1470        93669 :         MinCap = ITSCoolingRateMin;
    1471        93669 :     }
    1472              : 
    1473              :     //******************************************************************************
    1474              : 
    1475         9964 :     void SimpleIceStorageData::CalcIceStorageDormant(EnergyPlusData &state)
    1476              :     {
    1477              :         // Provide output results for ITS.
    1478         9964 :         this->ITSMassFlowRate = 0.0; //[kg/s]
    1479              : 
    1480         9964 :         PlantUtilities::SetComponentFlowRate(state, this->ITSMassFlowRate, this->PltInletNodeNum, this->PltOutletNodeNum, this->plantLoc);
    1481              : 
    1482         9964 :         this->ITSInletTemp = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp; //[C]
    1483         9964 :         this->ITSOutletTemp = this->ITSInletTemp;                                   //[C]
    1484         9964 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
    1485         9964 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
    1486         9964 :             this->ITSOutletSetPointTemp = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPoint;
    1487         9964 :         } 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         9964 :         this->ITSCoolingRate = 0.0;   //[W]
    1495         9964 :         this->ITSCoolingEnergy = 0.0; //[J]
    1496              : 
    1497         9964 :         this->Urate = 0.0; //[n/a]
    1498         9964 :     }
    1499              : 
    1500              :     //******************************************************************************
    1501              : 
    1502        39773 :     void SimpleIceStorageData::CalcIceStorageCharge(EnergyPlusData &state)
    1503              :     {
    1504              :         //--------------------------------------------------------
    1505              :         // Initialize
    1506              :         //--------------------------------------------------------
    1507              :         // Below values for ITS are reported forCharging process.
    1508        39773 :         this->ITSMassFlowRate = this->DesignMassFlowRate; //[kg/s]
    1509              : 
    1510        39773 :         PlantUtilities::SetComponentFlowRate(state, this->ITSMassFlowRate, this->PltInletNodeNum, this->PltOutletNodeNum, this->plantLoc);
    1511              : 
    1512        39773 :         this->ITSInletTemp = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp; //[C]
    1513        39773 :         this->ITSOutletTemp = this->ITSInletTemp;                                   //[C]
    1514        39773 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
    1515        39773 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
    1516        39773 :             this->ITSOutletSetPointTemp = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPoint;
    1517        39773 :         } 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        39773 :         this->ITSCoolingRate = 0.0;   //[W]
    1525        39773 :         this->ITSCoolingEnergy = 0.0; //[J]
    1526              : 
    1527              :         // Initialize processed U values
    1528        39773 :         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        39773 :         this->CalcQiceChargeMaxByChiller(state, QiceMaxByChiller); //[W]
    1539              : 
    1540              :         // Chiller is remote now, so chiller out is inlet node temp
    1541        39773 :         Real64 chillerOutletTemp = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
    1542              :         // Calculate Qice charge max by ITS with ChillerOutletTemp
    1543              :         Real64 QiceMaxByITS;
    1544        39773 :         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        39773 :         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        39773 :         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        39773 :         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        39773 :         if (Umax == 0.0) { //(No Capacity of ITS), ITS is OFF.
    1564        22706 :             Uact = 0.0;
    1565              : 
    1566              :         } else { // Umax non-zero
    1567        17067 :             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        39773 :         Real64 Qice = Uact * this->ITSNomCap / TimeInterval; //[W]
    1575              :         // If Qice is equal or less than 0.0, no need to calculate anymore.
    1576        39773 :         if (Qice <= 0.0) {
    1577        22706 :             this->Urate = 0.0; //[ratio]
    1578              :         }
    1579              : 
    1580              :         // Calculate leaving water temperature
    1581        39773 :         if ((Qice <= 0.0) || (this->XCurIceFrac >= 1.0)) {
    1582        22706 :             this->ITSOutletTemp = this->ITSInletTemp;
    1583        22706 :             Qice = 0.0;
    1584        22706 :             Uact = 0.0;
    1585              :         } else {
    1586        17067 :             Real64 DeltaTemp = Qice / Psychrometrics::CPCW(this->ITSInletTemp) / this->ITSMassFlowRate;
    1587        17067 :             this->ITSOutletTemp = this->ITSInletTemp + DeltaTemp;
    1588              :             // Limit leaving temp to be no greater than setpoint or freezing temp minus 1C
    1589        17067 :             this->ITSOutletTemp = min(this->ITSOutletTemp, this->ITSOutletSetPointTemp, (FreezTemp - 1));
    1590              :             // Limit leaving temp to be no less than inlet temp
    1591        17067 :             this->ITSOutletTemp = max(this->ITSOutletTemp, this->ITSInletTemp);
    1592        17067 :             DeltaTemp = this->ITSOutletTemp - this->ITSInletTemp;
    1593        17067 :             Qice = DeltaTemp * Psychrometrics::CPCW(this->ITSInletTemp) * this->ITSMassFlowRate;
    1594        17067 :             Uact = Qice / (this->ITSNomCap / TimeInterval);
    1595              :         } // End of leaving temp checks
    1596              : 
    1597        39773 :         this->Urate = Uact;
    1598        39773 :         this->ITSCoolingRate = -Qice;
    1599        39773 :         this->ITSCoolingEnergy = this->ITSCoolingRate * state.dataHVACGlobal->TimeStepSysSec;
    1600        39773 :     }
    1601              : 
    1602              :     //******************************************************************************
    1603              : 
    1604        39773 :     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        39773 :         Real64 TchillerOut = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
    1611        39773 :         QiceMaxByChiller = this->UAIceCh * (FreezTemp - TchillerOut); //[W] = [W/degC]*[degC]
    1612              : 
    1613              :         // If it happened, it is occurred at the Discharging or Dormant process.
    1614        39773 :         if (QiceMaxByChiller <= 0.0) {
    1615        19866 :             QiceMaxByChiller = 0.0;
    1616              :         }
    1617        39773 :     }
    1618              : 
    1619        39773 :     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        39773 :         Real64 Tfr = FreezTempIP;
    1628        39773 :         Real64 ChOutletTemp = TempSItoIP(chillerOutletTemp); //[degF] = ConvertSItoIP[degC]
    1629              :         // Chiller outlet temp must be below freeze temp, or else no charge
    1630        39773 :         if (ChOutletTemp >= Tfr) {
    1631        19866 :             QiceMaxByITS = 0.0;
    1632              :         } else {
    1633              :             // Make ChillerInletTemp as almost same as ChillerOutletTemp(input data)
    1634        19907 :             Real64 ChillerInletTemp = ChOutletTemp + 0.01;
    1635              :             // ChillerInletTemp cannot be greater than or equal to freeze temp
    1636        19907 :             if (ChillerInletTemp >= Tfr) {
    1637           13 :                 ChillerInletTemp = ChOutletTemp + (Tfr - ChOutletTemp) / 2;
    1638              :             }
    1639              : 
    1640        19907 :             Real64 LogTerm = (Tfr - ChOutletTemp) / (Tfr - ChillerInletTemp);
    1641              :             // Need to protect this from LogTerm <= 0 - not sure what it should do then
    1642        19907 :             if (LogTerm <= 0.0) {
    1643            0 :                 ChillerInletTemp = ChOutletTemp;
    1644            0 :                 QiceMaxByITS = 0.0;
    1645              :             }
    1646        19907 :             QiceMaxByITS = this->UAIceCh * (TempIPtoSI(ChillerInletTemp) - TempIPtoSI(ChOutletTemp)) / std::log(LogTerm);
    1647              :         }
    1648        39773 :     }
    1649              : 
    1650        53896 :     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        53896 :         this->ITSMassFlowRate = 0.0;
    1660        53896 :         this->ITSCoolingRate = 0.0;
    1661        53896 :         this->ITSCoolingEnergy = 0.0;
    1662              : 
    1663        53896 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
    1664        53896 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
    1665        53896 :             this->ITSOutletSetPointTemp = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPoint;
    1666        53896 :         } 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        53896 :         this->Urate = 0.0;
    1676              : 
    1677              :         // If no component demand or ITS OFF, then RETURN.
    1678        53896 :         if (myLoad == 0 || !RunFlag) {
    1679           53 :             this->ITSMassFlowRate = 0.0;
    1680           53 :             this->ITSInletTemp = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
    1681           53 :             this->ITSOutletTemp = this->ITSInletTemp;
    1682           53 :             this->ITSCoolingRate = 0.0;
    1683           53 :             this->ITSCoolingEnergy = 0.0;
    1684           53 :             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        53843 :         int loopNum = this->plantLoc.loopNum;
    1692              : 
    1693              :         Real64 CpFluid =
    1694        53843 :             state.dataPlnt->PlantLoop(loopNum).glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->PltInletNodeNum).Temp, RoutineName);
    1695              : 
    1696              :         // Calculate Umyload based on MyLoad from E+
    1697        53843 :         Real64 Umyload = -myLoad * TimeInterval / this->ITSNomCap;
    1698              :         // Calculate Umax and Umin
    1699              :         // Cannot discharge more than the fraction that is left
    1700        53843 :         Real64 Umax = -this->IceFracRemain / state.dataHVACGlobal->TimeStepSys;
    1701              :         // Calculate Umin based on returned MyLoad from E+.
    1702        53843 :         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        53843 :         Real64 Uact = max(Umin, Umax);
    1706              : 
    1707              :         // Set ITSInletTemp provided by E+
    1708        53843 :         this->ITSInletTemp = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
    1709              :         // The first thing is to set the ITSMassFlowRate
    1710        53843 :         this->ITSMassFlowRate = this->DesignMassFlowRate; //[kg/s]
    1711              : 
    1712        53843 :         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        53843 :         Real64 Qice = Uact * this->ITSNomCap / TimeInterval;
    1716              :         // Qice cannot exceed MaxCap calculated by CalcIceStorageCapacity
    1717              :         // Note Qice is negative here, MaxCap is positive
    1718        53843 :         Qice = max(Qice, -MaxCap);
    1719              : 
    1720              :         // Calculate leaving water temperature
    1721        53843 :         if ((Qice >= 0.0) || (this->XCurIceFrac <= 0.0) || (this->ITSMassFlowRate < DataBranchAirLoopPlant::MassFlowTolerance)) {
    1722         8770 :             this->ITSOutletTemp = this->ITSInletTemp;
    1723         8770 :             Qice = 0.0;
    1724         8770 :             Uact = 0.0;
    1725              :         } else {
    1726        45073 :             Real64 DeltaTemp = Qice / CpFluid / this->ITSMassFlowRate;
    1727        45073 :             this->ITSOutletTemp = this->ITSInletTemp + DeltaTemp;
    1728              :             // Limit leaving temp to be no less than setpoint or freezing temp plus 1C
    1729        45073 :             this->ITSOutletTemp = max(this->ITSOutletTemp, this->ITSOutletSetPointTemp, (FreezTemp + 1));
    1730              :             // Limit leaving temp to be no greater than inlet temp
    1731        45073 :             this->ITSOutletTemp = min(this->ITSOutletTemp, this->ITSInletTemp);
    1732        45073 :             DeltaTemp = this->ITSOutletTemp - this->ITSInletTemp;
    1733        45073 :             Qice = DeltaTemp * CpFluid * this->ITSMassFlowRate;
    1734        45073 :             Uact = Qice / (this->ITSNomCap / TimeInterval);
    1735              :         } // End of leaving temp checks
    1736              : 
    1737              :         // Calculate reported U value
    1738        53843 :         this->Urate = Uact;
    1739              :         // Calculate ITSCoolingEnergy [J]
    1740        53843 :         this->ITSCoolingRate = -Qice;
    1741        53843 :         this->ITSCoolingEnergy = this->ITSCoolingRate * state.dataHVACGlobal->TimeStepSysSec;
    1742              :     }
    1743              : 
    1744        93669 :     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        93669 :         Real64 ITSInletTemp_loc = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
    1751        93669 :         Real64 ITSOutletTemp_loc = 0.0;
    1752        93669 :         switch (state.dataPlnt->PlantLoop(this->plantLoc.loopNum).LoopDemandCalcScheme) {
    1753        93669 :         case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
    1754        93669 :             ITSOutletTemp_loc = state.dataLoopNodes->Node(this->PltOutletNodeNum).TempSetPoint;
    1755        93669 :         } 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        93669 :         Real64 LogTerm = (ITSInletTemp_loc - FreezTemp) / (ITSOutletTemp_loc - FreezTemp);
    1765              : 
    1766        93669 :         if (LogTerm <= 1) {
    1767        39773 :             QiceMin = 0.0;
    1768              :         } else {
    1769        53896 :             QiceMin = this->UAIceDisCh * (ITSInletTemp_loc - ITSOutletTemp_loc) / std::log(LogTerm);
    1770              :         }
    1771        93669 :     }
    1772              : 
    1773        93669 :     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        93669 :         switch (this->ITSType_Num) {
    1787        93669 :         case ITSType::IceOnCoilInternal: {
    1788        93669 :             Real64 y = XCurIceFrac_loc;
    1789        93669 :             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        93669 :                           this->ITSNomCap / TimeInterval / 10.0; // [W/C]
    1791        93669 :             y = 1.0 - XCurIceFrac_loc;
    1792        93669 :             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        93669 :                              this->ITSNomCap / TimeInterval / 10.0; // [W/C]
    1794        93669 :             HLoss_loc = 0.0;
    1795        93669 :         } 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        93669 :     }
    1809              : 
    1810       115255 :     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       115255 :         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       115255 :         Real64 DeltaTio = std::abs(Tin - Tout); // Inlet to outlet temperature difference
    1839       115255 :         Real64 DeltaTif = std::abs(Tin - Tfr);  // Inlet to freezing temperature difference
    1840       115255 :         Real64 DeltaTof = std::abs(Tout - Tfr); // Outlet to freezing temperature difference
    1841              : 
    1842       115255 :         if (DeltaTif < DeltaTifMin) {
    1843            0 :             DeltaTif = DeltaTifMin;
    1844              :         }
    1845       115255 :         if (DeltaTof < DeltaTofMin) {
    1846           60 :             DeltaTof = DeltaTofMin;
    1847              :         }
    1848              : 
    1849       115255 :         CalcDetIceStorLMTDstar = (DeltaTio / std::log(DeltaTif / DeltaTof)) / Tnom;
    1850              : 
    1851       115255 :         return CalcDetIceStorLMTDstar;
    1852              :     }
    1853              : 
    1854       115255 :     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       115255 :         if (CurveIndVarType == CurveVars::FracChargedLMTD) {
    1866        12159 :             CalcQstar = std::abs(Curve::CurveValue(state, CurveIndex, FracCharged, LMTDstar));
    1867       103096 :         } else if (CurveIndVarType == CurveVars::FracDischargedLMTD) {
    1868        84757 :             CalcQstar = std::abs(Curve::CurveValue(state, CurveIndex, (1.0 - FracCharged), LMTDstar));
    1869        18339 :         } else if (CurveIndVarType == CurveVars::LMTDMassFlow) {
    1870        18339 :             CalcQstar = std::abs(Curve::CurveValue(state, CurveIndex, LMTDstar, MassFlowstar));
    1871            0 :         } else if (CurveIndVarType == CurveVars::LMTDFracCharged) {
    1872            0 :             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       115255 :         return CalcQstar;
    1878              :     }
    1879              : 
    1880        39773 :     Real64 TempSItoIP(Real64 const Temp)
    1881              :     {
    1882        39773 :         return (Temp * 9.0 / 5.0) + 32.0;
    1883              :     }
    1884              : 
    1885        39814 :     Real64 TempIPtoSI(Real64 const Temp)
    1886              :     {
    1887        39814 :         return (Temp - 32.0) * 5.0 / 9.0;
    1888              :     }
    1889              : 
    1890       103633 :     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       103633 :         PlantUtilities::SafeCopyPlantNode(state, this->PltInletNodeNum, this->PltOutletNodeNum);
    1898       103633 :         if (myLoad == 0 || !RunFlag) {
    1899              :             // Update Outlet Conditions so that same as Inlet, so component can be bypassed if necessary
    1900        10042 :             state.dataLoopNodes->Node(this->PltOutletNodeNum).Temp = state.dataLoopNodes->Node(this->PltInletNodeNum).Temp;
    1901              :         } else {
    1902        93591 :             state.dataLoopNodes->Node(this->PltOutletNodeNum).Temp = this->ITSOutletTemp;
    1903              :         }
    1904       103633 :     }
    1905              : 
    1906       103633 :     void SimpleIceStorageData::RecordOutput(Real64 const myLoad, bool const RunFlag)
    1907              :     {
    1908       103633 :         if (myLoad == 0 || !RunFlag) {
    1909        10042 :             this->MyLoad = myLoad;
    1910        10042 :             this->ITSCoolingRate_rep = 0.0;
    1911        10042 :             this->ITSCoolingEnergy_rep = 0.0;
    1912        10042 :             this->ITSChargingRate = 0.0;
    1913        10042 :             this->ITSChargingEnergy = 0.0;
    1914        10042 :             this->ITSmdot = 0.0;
    1915              : 
    1916              :         } else {
    1917        93591 :             this->MyLoad = myLoad;
    1918        93591 :             if (this->ITSCoolingRate > 0.0) {
    1919        45073 :                 this->ITSCoolingRate_rep = this->ITSCoolingRate;
    1920        45073 :                 this->ITSCoolingEnergy_rep = this->ITSCoolingEnergy;
    1921        45073 :                 this->ITSChargingRate = 0.0;
    1922        45073 :                 this->ITSChargingEnergy = 0.0;
    1923              :             } else {
    1924        48518 :                 this->ITSCoolingRate_rep = 0.0;
    1925        48518 :                 this->ITSCoolingEnergy_rep = 0.0;
    1926        48518 :                 this->ITSChargingRate = -this->ITSCoolingRate;
    1927        48518 :                 this->ITSChargingEnergy = -this->ITSCoolingEnergy;
    1928              :             }
    1929        93591 :             this->ITSmdot = this->ITSMassFlowRate;
    1930              :         }
    1931       103633 :     }
    1932              : 
    1933      3588830 :     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      3596529 :         for (auto &thisITS : state.dataIceThermalStorage->SimpleIceStorage) {
    1950         7699 :             thisITS.IceFracRemain += thisITS.Urate * state.dataHVACGlobal->TimeStepSys;
    1951         7699 :             if (thisITS.IceFracRemain <= 0.001) {
    1952          756 :                 thisITS.IceFracRemain = 0.0;
    1953              :             }
    1954         7699 :             if (thisITS.IceFracRemain > 1.0) {
    1955            0 :                 thisITS.IceFracRemain = 1.0;
    1956              :             }
    1957      3588830 :         }
    1958              : 
    1959      3610348 :         for (auto &thisITS : state.dataIceThermalStorage->DetailedIceStorage) {
    1960        21518 :             thisITS.IceFracRemaining += thisITS.IceFracChange - (thisITS.TankLossCoeff * state.dataHVACGlobal->TimeStepSys);
    1961        21518 :             if (thisITS.IceFracRemaining < 0.001) {
    1962          644 :                 thisITS.IceFracRemaining = 0.0;
    1963              :             }
    1964        21518 :             if (thisITS.IceFracRemaining > 1.000) {
    1965           86 :                 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        21518 :             if (thisITS.ThawProcessIndex == DetIce::InsideMelt) {
    1972         6128 :                 if (thisITS.IceFracChange < 0.0) {
    1973         1732 :                     thisITS.IceFracOnCoil = 0.0;
    1974              :                 } else {
    1975              :                     // Assume loss term does not impact ice on the coil but what is remaining
    1976         4396 :                     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         4396 :                     if (thisITS.IceFracOnCoil > thisITS.IceFracRemaining) {
    1979         3174 :                         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        15390 :                 thisITS.IceFracOnCoil = thisITS.IceFracRemaining;
    1984              :             }
    1985      3588830 :         }
    1986      3588830 :     }
    1987              : 
    1988       272104 :     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       272104 :         int InNodeNum = this->PlantInNodeNum;
    2007       272104 :         int OutNodeNum = this->PlantOutNodeNum;
    2008              : 
    2009       272104 :         PlantUtilities::SafeCopyPlantNode(state, InNodeNum, OutNodeNum);
    2010              : 
    2011       272104 :         state.dataLoopNodes->Node(OutNodeNum).Temp = this->OutletTemp;
    2012       272104 :     }
    2013              : 
    2014       272104 :     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       272104 :         Real64 constexpr LowLoadLimit(0.1); // Load below which device can be assumed off [W]
    2031              : 
    2032       272104 :         if (this->CompLoad < LowLoadLimit) { // No load condition
    2033              : 
    2034       171909 :             this->IceFracChange = 0.0;
    2035       171909 :             this->DischargingRate = 0.0;
    2036       171909 :             this->DischargingEnergy = 0.0;
    2037       171909 :             this->ChargingRate = 0.0;
    2038       171909 :             this->ChargingEnergy = 0.0;
    2039       171909 :             this->ParasiticElecRate = 0.0;
    2040       171909 :             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       100195 :             if (this->InletTemp < this->OutletTemp) { // Charging Mode
    2045              : 
    2046         8786 :                 this->ChargingRate = this->CompLoad;
    2047         8786 :                 this->ChargingEnergy = this->CompLoad * (state.dataHVACGlobal->TimeStepSysSec);
    2048         8786 :                 this->IceFracChange = this->CompLoad * state.dataHVACGlobal->TimeStepSys / this->NomCapacity;
    2049         8786 :                 this->DischargingRate = 0.0;
    2050         8786 :                 this->DischargingEnergy = 0.0;
    2051         8786 :                 this->ParasiticElecRate = this->ChargeParaElecLoad * this->CompLoad;
    2052         8786 :                 this->ParasiticElecEnergy = this->ChargeParaElecLoad * this->ChargingEnergy;
    2053              : 
    2054              :             } else { // (DetailedIceStorage(IceNum)%InletTemp < DetailedIceStorage(IceNum)%OutletTemp) Discharging Mode
    2055              : 
    2056        91409 :                 this->DischargingRate = this->CompLoad;
    2057        91409 :                 this->DischargingEnergy = this->CompLoad * (state.dataHVACGlobal->TimeStepSysSec);
    2058        91409 :                 this->IceFracChange = -this->CompLoad * state.dataHVACGlobal->TimeStepSys / this->NomCapacity;
    2059        91409 :                 this->ChargingRate = 0.0;
    2060        91409 :                 this->ChargingEnergy = 0.0;
    2061        91409 :                 this->ParasiticElecRate = this->DischargeParaElecLoad * this->CompLoad;
    2062        91409 :                 this->ParasiticElecEnergy = this->DischargeParaElecLoad * this->ChargingEnergy;
    2063              :             }
    2064              :         }
    2065       272104 :     }
    2066              : 
    2067              : } // namespace IceThermalStorage
    2068              : 
    2069              : } // namespace EnergyPlus
        

Generated by: LCOV version 2.0-1