LCOV - code coverage report
Current view: top level - EnergyPlus - IceThermalStorage.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 742 911 81.4 %
Date: 2023-01-17 19:17:23 Functions: 29 29 100.0 %

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

Generated by: LCOV version 1.13