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