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