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