LCOV - code coverage report
Current view: top level - EnergyPlus - IceThermalStorage.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 762 944 80.7 %
Date: 2024-08-23 23:50:59 Functions: 27 27 100.0 %

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

Generated by: LCOV version 1.14