Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cassert>
50 : #include <cmath>
51 :
52 : // ObjexxFCL Headers
53 : #include <ObjexxFCL/Array.functions.hh>
54 : #include <ObjexxFCL/Fmath.hh>
55 :
56 : // EnergyPlus Headers
57 : #include <EnergyPlus/Autosizing/Base.hh>
58 : #include <EnergyPlus/BranchNodeConnections.hh>
59 : #include <EnergyPlus/ChillerIndirectAbsorption.hh>
60 : #include <EnergyPlus/CurveManager.hh>
61 : #include <EnergyPlus/Data/EnergyPlusData.hh>
62 : #include <EnergyPlus/DataBranchAirLoopPlant.hh>
63 : #include <EnergyPlus/DataEnvironment.hh>
64 : #include <EnergyPlus/DataHVACGlobals.hh>
65 : #include <EnergyPlus/DataIPShortCuts.hh>
66 : #include <EnergyPlus/DataLoopNode.hh>
67 : #include <EnergyPlus/DataSizing.hh>
68 : #include <EnergyPlus/EMSManager.hh>
69 : #include <EnergyPlus/FaultsManager.hh>
70 : #include <EnergyPlus/FluidProperties.hh>
71 : #include <EnergyPlus/GlobalNames.hh>
72 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
73 : #include <EnergyPlus/NodeInputManager.hh>
74 : #include <EnergyPlus/OutputProcessor.hh>
75 : #include <EnergyPlus/OutputReportPredefined.hh>
76 : #include <EnergyPlus/Plant/DataPlant.hh>
77 : #include <EnergyPlus/Plant/PlantLocation.hh>
78 : #include <EnergyPlus/PlantUtilities.hh>
79 : #include <EnergyPlus/UtilityRoutines.hh>
80 :
81 : namespace EnergyPlus::ChillerIndirectAbsorption {
82 :
83 : // MODULE INFORMATION:
84 : // AUTHOR R. Raustad (FSEC)
85 : // DATE WRITTEN May 2008
86 :
87 : // PURPOSE OF THIS MODULE:
88 : // This module simulates the performance of the revised BLAST
89 : // absorbers. New curve objects are included.
90 :
91 : // METHODOLOGY EMPLOYED:
92 : // Once the PlantLoopManager determines that the revised BLAST absorber
93 : // is available to meet a loop cooling demand, it calls SimIndirectAbsorber
94 : // which in turn calls the appropriate Indirect Absorption Chiller model.
95 : // All Absorption Chiller models are based on a polynomial fit of Absorber
96 : // performance data.
97 :
98 : // REFERENCES:
99 : // 1. BLAST Users Manual
100 :
101 : // OTHER NOTES:
102 : // Manufacturers performance data can be used to generate the coefficients for the model.
103 :
104 : static constexpr std::string_view calcChillerAbsorptionIndirect("CALC Chiller:Absorption:Indirect ");
105 :
106 0 : IndirectAbsorberSpecs *IndirectAbsorberSpecs::factory(EnergyPlusData &state, std::string const &objectName)
107 : {
108 : // Process the input data
109 0 : if (state.dataChillerIndirectAbsorption->GetInput) {
110 0 : GetIndirectAbsorberInput(state);
111 0 : state.dataChillerIndirectAbsorption->GetInput = false;
112 : }
113 : // Now look for this particular object
114 0 : auto thisObj = std::find_if(state.dataChillerIndirectAbsorption->IndirectAbsorber.begin(),
115 0 : state.dataChillerIndirectAbsorption->IndirectAbsorber.end(),
116 0 : [&objectName](const IndirectAbsorberSpecs &myObj) { return myObj.Name == objectName; });
117 0 : if (thisObj != state.dataChillerIndirectAbsorption->IndirectAbsorber.end()) return thisObj;
118 : // If we didn't find it, fatal
119 : ShowFatalError(state, format("LocalIndirectAbsorptionChillerFactory: Error getting inputs for object named: {}", objectName)); // LCOV_EXCL_LINE
120 : // Shut up the compiler
121 : return nullptr; // LCOV_EXCL_LINE
122 : }
123 :
124 0 : void IndirectAbsorberSpecs::simulate(
125 : EnergyPlusData &state, const PlantLocation &calledFromLocation, bool FirstHVACIteration, Real64 &CurLoad, bool RunFlag)
126 : {
127 0 : if (calledFromLocation.loopNum == this->CWPlantLoc.loopNum) {
128 :
129 0 : this->initialize(state, RunFlag, CurLoad);
130 0 : this->calculate(state, CurLoad, RunFlag);
131 0 : this->updateRecords(state, CurLoad, RunFlag);
132 :
133 0 : } else if (calledFromLocation.loopNum == this->CDPlantLoc.loopNum) {
134 : // Called from non-dominant condenser water connection loop side
135 0 : PlantUtilities::UpdateChillerComponentCondenserSide(state,
136 0 : calledFromLocation.loopNum,
137 0 : calledFromLocation.loopSideNum,
138 : DataPlant::PlantEquipmentType::Chiller_Indirect_Absorption,
139 : this->CondInletNodeNum,
140 : this->CondOutletNodeNum,
141 : this->Report.QCond,
142 : this->Report.CondInletTemp,
143 : this->Report.CondOutletTemp,
144 : this->Report.Condmdot,
145 : FirstHVACIteration);
146 :
147 0 : } else if (calledFromLocation.loopNum == this->GenPlantLoc.loopNum) {
148 : // Called from non-dominant generator hot water or steam connection loop side
149 0 : PlantUtilities::UpdateAbsorberChillerComponentGeneratorSide(state,
150 0 : calledFromLocation.loopNum,
151 0 : calledFromLocation.loopSideNum,
152 : DataPlant::PlantEquipmentType::Chiller_Indirect_Absorption,
153 : this->GeneratorInletNodeNum,
154 : this->GeneratorOutletNodeNum,
155 : this->GenHeatSourceType,
156 : this->Report.QGenerator,
157 : this->Report.SteamMdot,
158 : FirstHVACIteration);
159 :
160 : } else {
161 0 : ShowFatalError(state,
162 0 : format("SimIndirectAbsorber: Invalid LoopNum passed={}, Unit name={}, stored chilled water loop={}, stored condenser "
163 : "water loop={}, stored generator loop={}",
164 0 : calledFromLocation.loopNum,
165 0 : this->Name,
166 0 : this->CWPlantLoc.loopNum,
167 0 : this->CDPlantLoc.loopNum,
168 0 : this->GenPlantLoc.loopNum));
169 : }
170 0 : }
171 :
172 0 : void IndirectAbsorberSpecs::getDesignCapacities(
173 : [[maybe_unused]] EnergyPlusData &state, const PlantLocation &calledFromLocation, Real64 &MaxLoad, Real64 &MinLoad, Real64 &OptLoad)
174 : {
175 0 : if (calledFromLocation.loopNum == this->CWPlantLoc.loopNum) {
176 0 : MinLoad = this->NomCap * this->MinPartLoadRat;
177 0 : MaxLoad = this->NomCap * this->MaxPartLoadRat;
178 0 : OptLoad = this->NomCap * this->OptPartLoadRat;
179 : } else {
180 0 : MinLoad = 0.0;
181 0 : MaxLoad = 0.0;
182 0 : OptLoad = 0.0;
183 : }
184 0 : }
185 :
186 0 : void IndirectAbsorberSpecs::getSizingFactor(Real64 &sizFac)
187 : {
188 0 : sizFac = this->SizFac;
189 0 : }
190 :
191 0 : void IndirectAbsorberSpecs::onInitLoopEquip(EnergyPlusData &state, const PlantLocation &calledFromLocation)
192 : {
193 0 : bool runFlag = true;
194 0 : Real64 myLoad = 0.0;
195 :
196 0 : this->initialize(state, runFlag, myLoad);
197 :
198 0 : if (calledFromLocation.loopNum == this->CWPlantLoc.loopNum) {
199 0 : this->sizeChiller(state); // only size when called from chilled water loop
200 : }
201 0 : }
202 :
203 1 : void GetIndirectAbsorberInput(EnergyPlusData &state)
204 : {
205 : // SUBROUTINE INFORMATION:
206 : // AUTHOR: R. Raustad (FSEC)
207 : // DATE WRITTEN: May 2008
208 :
209 : // PURPOSE OF THIS SUBROUTINE:
210 : // This routine will get the input
211 : // required by the Indirect Absorption chiller models as shown below:
212 :
213 : // METHODOLOGY EMPLOYED:
214 : // EnergyPlus input processor
215 :
216 : static constexpr std::string_view RoutineName("GetIndirectAbsorberInput: "); // include trailing blank space
217 :
218 1 : int AbsorberNum = 0; // Absorber counter
219 1 : int NumAlphas = 0; // Number of elements in the alpha array
220 1 : int NumNums = 0; // Number of elements in the numeric array
221 1 : int IOStat = 0; // IO Status when calling get input subroutine
222 1 : bool ErrorsFound(false);
223 :
224 1 : state.dataIPShortCut->cCurrentModuleObject = "Chiller:Absorption:Indirect";
225 1 : int NumIndirectAbsorbers = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
226 :
227 1 : if (NumIndirectAbsorbers <= 0) {
228 0 : ShowSevereError(state, format("No {} equipment specified in input file", state.dataIPShortCut->cCurrentModuleObject));
229 : // See if load distribution manager has already gotten the input
230 0 : ErrorsFound = true;
231 : }
232 :
233 1 : if (allocated(state.dataChillerIndirectAbsorption->IndirectAbsorber)) return;
234 :
235 1 : state.dataChillerIndirectAbsorption->IndirectAbsorber.allocate(NumIndirectAbsorbers);
236 :
237 : // LOAD ARRAYS WITH BLAST CURVE FIT Absorber DATA
238 2 : for (AbsorberNum = 1; AbsorberNum <= NumIndirectAbsorbers; ++AbsorberNum) {
239 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
240 1 : state.dataIPShortCut->cCurrentModuleObject,
241 : AbsorberNum,
242 1 : state.dataIPShortCut->cAlphaArgs,
243 : NumAlphas,
244 1 : state.dataIPShortCut->rNumericArgs,
245 : NumNums,
246 : IOStat,
247 1 : state.dataIPShortCut->lNumericFieldBlanks,
248 1 : state.dataIPShortCut->lAlphaFieldBlanks,
249 1 : state.dataIPShortCut->cAlphaFieldNames,
250 1 : state.dataIPShortCut->cNumericFieldNames);
251 :
252 : // ErrorsFound will be set to True if problem was found, left untouched otherwise
253 1 : GlobalNames::VerifyUniqueChillerName(state,
254 1 : state.dataIPShortCut->cCurrentModuleObject,
255 1 : state.dataIPShortCut->cAlphaArgs(1),
256 : ErrorsFound,
257 2 : state.dataIPShortCut->cCurrentModuleObject + " Name");
258 :
259 1 : auto &thisChiller = state.dataChillerIndirectAbsorption->IndirectAbsorber(AbsorberNum);
260 1 : thisChiller.Name = state.dataIPShortCut->cAlphaArgs(1);
261 1 : thisChiller.NomCap = state.dataIPShortCut->rNumericArgs(1);
262 1 : if (thisChiller.NomCap == DataSizing::AutoSize) {
263 0 : thisChiller.NomCapWasAutoSized = true;
264 : }
265 1 : thisChiller.NomPumpPower = state.dataIPShortCut->rNumericArgs(2);
266 1 : if (thisChiller.NomPumpPower == DataSizing::AutoSize) {
267 0 : thisChiller.NomPumpPowerWasAutoSized = true;
268 : }
269 1 : if (state.dataIPShortCut->rNumericArgs(1) == 0.0) {
270 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->rNumericArgs(1)));
271 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
272 0 : ErrorsFound = true;
273 : }
274 : // Assign Node Numbers to specified nodes
275 1 : thisChiller.EvapInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
276 1 : state.dataIPShortCut->cAlphaArgs(2),
277 : ErrorsFound,
278 : DataLoopNode::ConnectionObjectType::ChillerAbsorptionIndirect,
279 1 : state.dataIPShortCut->cAlphaArgs(1),
280 : DataLoopNode::NodeFluidType::Water,
281 : DataLoopNode::ConnectionType::Inlet,
282 : NodeInputManager::CompFluidStream::Primary,
283 : DataLoopNode::ObjectIsNotParent);
284 2 : thisChiller.EvapOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
285 1 : state.dataIPShortCut->cAlphaArgs(3),
286 : ErrorsFound,
287 : DataLoopNode::ConnectionObjectType::ChillerAbsorptionIndirect,
288 1 : state.dataIPShortCut->cAlphaArgs(1),
289 : DataLoopNode::NodeFluidType::Water,
290 : DataLoopNode::ConnectionType::Outlet,
291 : NodeInputManager::CompFluidStream::Primary,
292 : DataLoopNode::ObjectIsNotParent);
293 2 : BranchNodeConnections::TestCompSet(state,
294 1 : state.dataIPShortCut->cCurrentModuleObject,
295 1 : state.dataIPShortCut->cAlphaArgs(1),
296 1 : state.dataIPShortCut->cAlphaArgs(2),
297 1 : state.dataIPShortCut->cAlphaArgs(3),
298 : "Chilled Water Nodes");
299 :
300 1 : thisChiller.CondInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
301 1 : state.dataIPShortCut->cAlphaArgs(4),
302 : ErrorsFound,
303 : DataLoopNode::ConnectionObjectType::ChillerAbsorptionIndirect,
304 1 : state.dataIPShortCut->cAlphaArgs(1),
305 : DataLoopNode::NodeFluidType::Water,
306 : DataLoopNode::ConnectionType::Inlet,
307 : NodeInputManager::CompFluidStream::Secondary,
308 : DataLoopNode::ObjectIsNotParent);
309 2 : thisChiller.CondOutletNodeNum = NodeInputManager::GetOnlySingleNode(state,
310 1 : state.dataIPShortCut->cAlphaArgs(5),
311 : ErrorsFound,
312 : DataLoopNode::ConnectionObjectType::ChillerAbsorptionIndirect,
313 1 : state.dataIPShortCut->cAlphaArgs(1),
314 : DataLoopNode::NodeFluidType::Water,
315 : DataLoopNode::ConnectionType::Outlet,
316 : NodeInputManager::CompFluidStream::Secondary,
317 : DataLoopNode::ObjectIsNotParent);
318 2 : BranchNodeConnections::TestCompSet(state,
319 1 : state.dataIPShortCut->cCurrentModuleObject,
320 1 : state.dataIPShortCut->cAlphaArgs(1),
321 1 : state.dataIPShortCut->cAlphaArgs(4),
322 1 : state.dataIPShortCut->cAlphaArgs(5),
323 : "Condenser (not tested) Nodes");
324 :
325 1 : thisChiller.GeneratorInputCurvePtr = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(7));
326 1 : if (thisChiller.GeneratorInputCurvePtr > 0) {
327 : // Verify Curve Object, only legal types are Quadratic or Cubic
328 0 : ErrorsFound |= Curve::CheckCurveDims(state,
329 : thisChiller.GeneratorInputCurvePtr, // Curve index
330 : {1}, // Valid dimensions
331 : RoutineName, // Routine name
332 0 : state.dataIPShortCut->cCurrentModuleObject, // Object Type
333 : thisChiller.Name, // Object Name
334 0 : state.dataIPShortCut->cAlphaFieldNames(7)); // Field Name
335 : }
336 :
337 1 : thisChiller.PumpPowerCurvePtr = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(8));
338 1 : if (thisChiller.PumpPowerCurvePtr > 0) {
339 : // Verify Curve Object, only legal types are Quadratic or Cubic
340 0 : ErrorsFound |= Curve::CheckCurveDims(state,
341 : thisChiller.PumpPowerCurvePtr, // Curve index
342 : {1}, // Valid dimensions
343 : RoutineName, // Routine name
344 0 : state.dataIPShortCut->cCurrentModuleObject, // Object Type
345 : thisChiller.Name, // Object Name
346 0 : state.dataIPShortCut->cAlphaFieldNames(8)); // Field Name
347 : }
348 :
349 1 : if (NumAlphas > 15) {
350 2 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(16), "HotWater") ||
351 2 : Util::SameString(state.dataIPShortCut->cAlphaArgs(16), "HotWater")) {
352 0 : thisChiller.GenHeatSourceType = DataLoopNode::NodeFluidType::Water;
353 : // Default to Steam if left blank
354 1 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(16), "STEAM") || state.dataIPShortCut->cAlphaArgs(16).empty()) {
355 1 : thisChiller.GenHeatSourceType = DataLoopNode::NodeFluidType::Steam;
356 1 : thisChiller.steam = Fluid::GetSteam(state);
357 : } else {
358 0 : ShowWarningError(state, format("{}, Name={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
359 0 : ShowContinueError(state, "...Generator heat source type must be Steam or Hot Water.");
360 0 : ShowContinueError(state, format("...Entered generator heat source type = {}", state.dataIPShortCut->cAlphaArgs(16)));
361 0 : ErrorsFound = true;
362 : }
363 : } else {
364 : // Default to Steam if not entered as input
365 0 : thisChiller.GenHeatSourceType = DataLoopNode::NodeFluidType::Steam;
366 0 : thisChiller.steam = Fluid::GetSteam(state);
367 : }
368 :
369 1 : if ((!state.dataIPShortCut->cAlphaArgs(9).empty()) && (!state.dataIPShortCut->cAlphaArgs(10).empty())) {
370 1 : thisChiller.GenInputOutputNodesUsed = true;
371 1 : if (thisChiller.GenHeatSourceType == DataLoopNode::NodeFluidType::Water) {
372 0 : thisChiller.GeneratorInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
373 0 : state.dataIPShortCut->cAlphaArgs(9),
374 : ErrorsFound,
375 : DataLoopNode::ConnectionObjectType::ChillerAbsorptionIndirect,
376 0 : state.dataIPShortCut->cAlphaArgs(1),
377 : DataLoopNode::NodeFluidType::Water,
378 : DataLoopNode::ConnectionType::Inlet,
379 : NodeInputManager::CompFluidStream::Tertiary,
380 : DataLoopNode::ObjectIsNotParent);
381 0 : thisChiller.GeneratorOutletNodeNum =
382 0 : NodeInputManager::GetOnlySingleNode(state,
383 0 : state.dataIPShortCut->cAlphaArgs(10),
384 : ErrorsFound,
385 : DataLoopNode::ConnectionObjectType::ChillerAbsorptionIndirect,
386 0 : state.dataIPShortCut->cAlphaArgs(1),
387 : DataLoopNode::NodeFluidType::Water,
388 : DataLoopNode::ConnectionType::Outlet,
389 : NodeInputManager::CompFluidStream::Tertiary,
390 : DataLoopNode::ObjectIsNotParent);
391 0 : BranchNodeConnections::TestCompSet(state,
392 0 : state.dataIPShortCut->cCurrentModuleObject,
393 0 : state.dataIPShortCut->cAlphaArgs(1),
394 0 : state.dataIPShortCut->cAlphaArgs(9),
395 0 : state.dataIPShortCut->cAlphaArgs(10),
396 : "Hot Water Nodes");
397 : } else {
398 1 : if ((thisChiller.steam = Fluid::GetSteam(state)) == nullptr) {
399 0 : ShowSevereError(state, "Fluid Properties for STEAM not found.");
400 0 : ErrorsFound = true;
401 : }
402 :
403 1 : thisChiller.GeneratorInletNodeNum = NodeInputManager::GetOnlySingleNode(state,
404 1 : state.dataIPShortCut->cAlphaArgs(9),
405 : ErrorsFound,
406 : DataLoopNode::ConnectionObjectType::ChillerAbsorptionIndirect,
407 1 : state.dataIPShortCut->cAlphaArgs(1),
408 : DataLoopNode::NodeFluidType::Steam,
409 : DataLoopNode::ConnectionType::Inlet,
410 : NodeInputManager::CompFluidStream::Tertiary,
411 : DataLoopNode::ObjectIsNotParent);
412 1 : thisChiller.GeneratorOutletNodeNum =
413 2 : NodeInputManager::GetOnlySingleNode(state,
414 1 : state.dataIPShortCut->cAlphaArgs(10),
415 : ErrorsFound,
416 : DataLoopNode::ConnectionObjectType::ChillerAbsorptionIndirect,
417 1 : state.dataIPShortCut->cAlphaArgs(1),
418 : DataLoopNode::NodeFluidType::Steam,
419 : DataLoopNode::ConnectionType::Outlet,
420 : NodeInputManager::CompFluidStream::Tertiary,
421 : DataLoopNode::ObjectIsNotParent);
422 3 : BranchNodeConnections::TestCompSet(state,
423 1 : state.dataIPShortCut->cCurrentModuleObject,
424 1 : state.dataIPShortCut->cAlphaArgs(1),
425 1 : state.dataIPShortCut->cAlphaArgs(9),
426 1 : state.dataIPShortCut->cAlphaArgs(10),
427 : "Steam Nodes");
428 : }
429 0 : } else if (state.dataIPShortCut->cAlphaArgs(9).empty() != state.dataIPShortCut->cAlphaArgs(10).empty()) {
430 0 : ShowWarningError(state, format("{}, Name={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
431 0 : ShowContinueError(state, "...Generator fluid nodes must both be entered (or both left blank).");
432 0 : ShowContinueError(state, format("...Generator fluid inlet node = {}", state.dataIPShortCut->cAlphaArgs(9)));
433 0 : ShowContinueError(state, format("...Generator fluid outlet node = {}", state.dataIPShortCut->cAlphaArgs(10)));
434 0 : ErrorsFound = true;
435 : } else {
436 : // Generator fluid type must be steam if generator inlet/outlet nodes are not used
437 0 : if (thisChiller.GenHeatSourceType == DataLoopNode::NodeFluidType::Water) {
438 0 : ShowWarningError(state, format("{}, Name={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
439 0 : ShowContinueError(state, "...Generator fluid type must be Steam if generator inlet/outlet nodes are blank.");
440 0 : ShowContinueError(state, "...Generator fluid type is set to Steam and the simulation continues.");
441 0 : thisChiller.GenHeatSourceType = DataLoopNode::NodeFluidType::Steam;
442 : }
443 : }
444 :
445 : {
446 1 : thisChiller.FlowMode = static_cast<DataPlant::FlowMode>(getEnumValue(DataPlant::FlowModeNamesUC, state.dataIPShortCut->cAlphaArgs(6)));
447 1 : if (thisChiller.FlowMode == DataPlant::FlowMode::Invalid) {
448 0 : ShowSevereError(state,
449 0 : format("{}{}=\"{}\",", RoutineName, state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
450 0 : ShowContinueError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(6), state.dataIPShortCut->cAlphaArgs(6)));
451 0 : ShowContinueError(state, "Available choices are ConstantFlow, NotModulated, or LeavingSetpointModulated");
452 0 : ShowContinueError(state, "Flow mode NotModulated is assumed and the simulation continues.");
453 0 : thisChiller.FlowMode = DataPlant::FlowMode::NotModulated;
454 : };
455 : }
456 :
457 1 : thisChiller.CapFCondenserTempPtr = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(11));
458 1 : if (thisChiller.CapFCondenserTempPtr > 0) {
459 : // Verify Curve Object, only legal types are Quadratic or Cubic
460 0 : ErrorsFound |= Curve::CheckCurveDims(state,
461 : thisChiller.CapFCondenserTempPtr, // Curve index
462 : {1}, // Valid dimensions
463 : RoutineName, // Routine name
464 0 : state.dataIPShortCut->cCurrentModuleObject, // Object Type
465 : thisChiller.Name, // Object Name
466 0 : state.dataIPShortCut->cAlphaFieldNames(11)); // Field Name
467 : }
468 :
469 1 : thisChiller.CapFEvaporatorTempPtr = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(12));
470 1 : if (thisChiller.CapFEvaporatorTempPtr > 0) {
471 : // Verify Curve Object, only legal types are Quadratic or Cubic
472 0 : ErrorsFound |= Curve::CheckCurveDims(state,
473 : thisChiller.CapFEvaporatorTempPtr, // Curve index
474 : {1}, // Valid dimensions
475 : RoutineName, // Routine name
476 0 : state.dataIPShortCut->cCurrentModuleObject, // Object Type
477 : thisChiller.Name, // Object Name
478 0 : state.dataIPShortCut->cAlphaFieldNames(12)); // Field Name
479 : }
480 :
481 1 : thisChiller.CapFGeneratorTempPtr = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(13));
482 1 : if (thisChiller.CapFGeneratorTempPtr > 0) {
483 : // Verify Curve Object, only legal types are Quadratic or Cubic
484 0 : ErrorsFound |= Curve::CheckCurveDims(state,
485 : thisChiller.CapFGeneratorTempPtr, // Curve index
486 : {1}, // Valid dimensions
487 : RoutineName, // Routine name
488 0 : state.dataIPShortCut->cCurrentModuleObject, // Object Type
489 : thisChiller.Name, // Object Name
490 0 : state.dataIPShortCut->cAlphaFieldNames(13)); // Field Name
491 : }
492 :
493 1 : thisChiller.HeatInputFCondTempPtr = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(14));
494 1 : if (thisChiller.HeatInputFCondTempPtr > 0) {
495 : // Verify Curve Object, only legal types are Quadratic or Cubic
496 0 : ErrorsFound |= Curve::CheckCurveDims(state,
497 : thisChiller.HeatInputFCondTempPtr, // Curve index
498 : {1}, // Valid dimensions
499 : RoutineName, // Routine name
500 0 : state.dataIPShortCut->cCurrentModuleObject, // Object Type
501 : thisChiller.Name, // Object Name
502 0 : state.dataIPShortCut->cAlphaFieldNames(14)); // Field Name
503 : }
504 :
505 1 : thisChiller.HeatInputFEvapTempPtr = Curve::GetCurveIndex(state, state.dataIPShortCut->cAlphaArgs(15));
506 1 : if (thisChiller.HeatInputFEvapTempPtr > 0) {
507 : // Verify Curve Object, only legal types are Quadratic or Cubic
508 0 : ErrorsFound |= Curve::CheckCurveDims(state,
509 : thisChiller.HeatInputFEvapTempPtr, // Curve index
510 : {1}, // Valid dimensions
511 : RoutineName, // Routine name
512 0 : state.dataIPShortCut->cCurrentModuleObject, // Object Type
513 : thisChiller.Name, // Object Name
514 0 : state.dataIPShortCut->cAlphaFieldNames(15)); // Field Name
515 : }
516 :
517 : // Get remaining data
518 1 : thisChiller.MinPartLoadRat = state.dataIPShortCut->rNumericArgs(3);
519 1 : thisChiller.MaxPartLoadRat = state.dataIPShortCut->rNumericArgs(4);
520 1 : thisChiller.OptPartLoadRat = state.dataIPShortCut->rNumericArgs(5);
521 1 : thisChiller.TempDesCondIn = state.dataIPShortCut->rNumericArgs(6);
522 1 : thisChiller.MinCondInletTemp = state.dataIPShortCut->rNumericArgs(7);
523 1 : thisChiller.TempLowLimitEvapOut = state.dataIPShortCut->rNumericArgs(8);
524 1 : thisChiller.EvapVolFlowRate = state.dataIPShortCut->rNumericArgs(9);
525 1 : if (thisChiller.EvapVolFlowRate == DataSizing::AutoSize) {
526 0 : thisChiller.EvapVolFlowRateWasAutoSized = true;
527 : }
528 1 : thisChiller.CondVolFlowRate = state.dataIPShortCut->rNumericArgs(10);
529 1 : if (thisChiller.CondVolFlowRate == DataSizing::AutoSize) {
530 0 : thisChiller.CondVolFlowRateWasAutoSized = true;
531 : }
532 1 : if (NumNums > 10) {
533 1 : thisChiller.GeneratorVolFlowRate = state.dataIPShortCut->rNumericArgs(11);
534 1 : if (thisChiller.GeneratorVolFlowRate == DataSizing::AutoSize) {
535 1 : thisChiller.GeneratorVolFlowRateWasAutoSized = true;
536 : }
537 : }
538 :
539 1 : if (thisChiller.GeneratorVolFlowRate == 0.0 && thisChiller.GenHeatSourceType == DataLoopNode::NodeFluidType::Water) {
540 0 : ShowWarningError(state, format("{}, Name={}", state.dataIPShortCut->cCurrentModuleObject, state.dataIPShortCut->cAlphaArgs(1)));
541 0 : ShowContinueError(state, "...Generator water flow rate must be greater than 0 when absorber generator fluid type is hot water.");
542 0 : ErrorsFound = true;
543 : }
544 :
545 1 : if (NumNums > 11) {
546 1 : thisChiller.MinGeneratorInletTemp = state.dataIPShortCut->rNumericArgs(12);
547 : } else {
548 0 : thisChiller.MinGeneratorInletTemp = 0.0;
549 : }
550 :
551 1 : if (NumNums > 12) {
552 1 : thisChiller.GeneratorSubcool = state.dataIPShortCut->rNumericArgs(13);
553 : } else {
554 0 : thisChiller.GeneratorSubcool = 0.0;
555 : }
556 :
557 1 : if (NumNums > 13) {
558 1 : thisChiller.LoopSubcool = state.dataIPShortCut->rNumericArgs(14);
559 : } else {
560 0 : thisChiller.LoopSubcool = 0.0;
561 : }
562 :
563 1 : if (NumNums > 14) {
564 0 : thisChiller.SizFac = state.dataIPShortCut->rNumericArgs(15);
565 : } else {
566 1 : thisChiller.SizFac = 1.0;
567 : }
568 : }
569 :
570 1 : if (ErrorsFound) {
571 0 : ShowFatalError(state, "Errors found in getting Chiller:Absorption:Indirect");
572 : }
573 : }
574 :
575 0 : void IndirectAbsorberSpecs::setupOutputVars(EnergyPlusData &state)
576 : {
577 0 : SetupOutputVariable(state,
578 : "Chiller Electricity Rate",
579 : Constant::Units::W,
580 0 : this->Report.PumpingPower,
581 : OutputProcessor::TimeStepType::System,
582 : OutputProcessor::StoreType::Average,
583 0 : this->Name);
584 :
585 0 : SetupOutputVariable(state,
586 : "Chiller Electricity Energy",
587 : Constant::Units::J,
588 0 : this->Report.PumpingEnergy,
589 : OutputProcessor::TimeStepType::System,
590 : OutputProcessor::StoreType::Sum,
591 0 : this->Name,
592 : Constant::eResource::Electricity,
593 : OutputProcessor::Group::Plant,
594 : OutputProcessor::EndUseCat::Cooling);
595 :
596 0 : SetupOutputVariable(state,
597 : "Chiller Evaporator Cooling Rate",
598 : Constant::Units::W,
599 0 : this->Report.QEvap,
600 : OutputProcessor::TimeStepType::System,
601 : OutputProcessor::StoreType::Average,
602 0 : this->Name);
603 :
604 0 : SetupOutputVariable(state,
605 : "Chiller Evaporator Cooling Energy",
606 : Constant::Units::J,
607 0 : this->Report.EvapEnergy,
608 : OutputProcessor::TimeStepType::System,
609 : OutputProcessor::StoreType::Sum,
610 0 : this->Name,
611 : Constant::eResource::EnergyTransfer,
612 : OutputProcessor::Group::Plant,
613 : OutputProcessor::EndUseCat::Chillers);
614 :
615 0 : SetupOutputVariable(state,
616 : "Chiller Evaporator Inlet Temperature",
617 : Constant::Units::C,
618 0 : this->Report.EvapInletTemp,
619 : OutputProcessor::TimeStepType::System,
620 : OutputProcessor::StoreType::Average,
621 0 : this->Name);
622 :
623 0 : SetupOutputVariable(state,
624 : "Chiller Evaporator Outlet Temperature",
625 : Constant::Units::C,
626 0 : this->Report.EvapOutletTemp,
627 : OutputProcessor::TimeStepType::System,
628 : OutputProcessor::StoreType::Average,
629 0 : this->Name);
630 :
631 0 : SetupOutputVariable(state,
632 : "Chiller Evaporator Mass Flow Rate",
633 : Constant::Units::kg_s,
634 0 : this->Report.Evapmdot,
635 : OutputProcessor::TimeStepType::System,
636 : OutputProcessor::StoreType::Average,
637 0 : this->Name);
638 :
639 0 : SetupOutputVariable(state,
640 : "Chiller Condenser Heat Transfer Rate",
641 : Constant::Units::W,
642 0 : this->Report.QCond,
643 : OutputProcessor::TimeStepType::System,
644 : OutputProcessor::StoreType::Average,
645 0 : this->Name);
646 :
647 0 : SetupOutputVariable(state,
648 : "Chiller Condenser Heat Transfer Energy",
649 : Constant::Units::J,
650 0 : this->Report.CondEnergy,
651 : OutputProcessor::TimeStepType::System,
652 : OutputProcessor::StoreType::Sum,
653 0 : this->Name,
654 : Constant::eResource::EnergyTransfer,
655 : OutputProcessor::Group::Plant,
656 : OutputProcessor::EndUseCat::HeatRejection);
657 :
658 0 : SetupOutputVariable(state,
659 : "Chiller Condenser Inlet Temperature",
660 : Constant::Units::C,
661 0 : this->Report.CondInletTemp,
662 : OutputProcessor::TimeStepType::System,
663 : OutputProcessor::StoreType::Average,
664 0 : this->Name);
665 :
666 0 : SetupOutputVariable(state,
667 : "Chiller Condenser Outlet Temperature",
668 : Constant::Units::C,
669 0 : this->Report.CondOutletTemp,
670 : OutputProcessor::TimeStepType::System,
671 : OutputProcessor::StoreType::Average,
672 0 : this->Name);
673 :
674 0 : SetupOutputVariable(state,
675 : "Chiller Condenser Mass Flow Rate",
676 : Constant::Units::kg_s,
677 0 : this->Report.Condmdot,
678 : OutputProcessor::TimeStepType::System,
679 : OutputProcessor::StoreType::Average,
680 0 : this->Name);
681 :
682 0 : if (this->GenHeatSourceType == DataLoopNode::NodeFluidType::Water) {
683 0 : SetupOutputVariable(state,
684 : "Chiller Hot Water Consumption Rate",
685 : Constant::Units::W,
686 0 : this->Report.QGenerator,
687 : OutputProcessor::TimeStepType::System,
688 : OutputProcessor::StoreType::Average,
689 0 : this->Name);
690 :
691 0 : SetupOutputVariable(state,
692 : "Chiller Source Hot Water Energy",
693 : Constant::Units::J,
694 0 : this->Report.GeneratorEnergy,
695 : OutputProcessor::TimeStepType::System,
696 : OutputProcessor::StoreType::Sum,
697 0 : this->Name,
698 : Constant::eResource::EnergyTransfer,
699 : OutputProcessor::Group::Plant,
700 : OutputProcessor::EndUseCat::Cooling);
701 : } else {
702 0 : if (this->GenInputOutputNodesUsed) {
703 0 : SetupOutputVariable(state,
704 : "Chiller Source Steam Rate",
705 : Constant::Units::W,
706 0 : this->Report.QGenerator,
707 : OutputProcessor::TimeStepType::System,
708 : OutputProcessor::StoreType::Average,
709 0 : this->Name);
710 :
711 0 : SetupOutputVariable(state,
712 : "Chiller Source Steam Energy",
713 : Constant::Units::J,
714 0 : this->Report.GeneratorEnergy,
715 : OutputProcessor::TimeStepType::System,
716 : OutputProcessor::StoreType::Sum,
717 0 : this->Name,
718 : Constant::eResource::PlantLoopHeatingDemand,
719 : OutputProcessor::Group::Plant,
720 : OutputProcessor::EndUseCat::Chillers);
721 : } else {
722 0 : SetupOutputVariable(state,
723 : "Chiller Source Steam Rate",
724 : Constant::Units::W,
725 0 : this->Report.QGenerator,
726 : OutputProcessor::TimeStepType::System,
727 : OutputProcessor::StoreType::Average,
728 0 : this->Name);
729 :
730 0 : SetupOutputVariable(state,
731 : "Chiller Source Steam Energy",
732 : Constant::Units::J,
733 0 : this->Report.GeneratorEnergy,
734 : OutputProcessor::TimeStepType::System,
735 : OutputProcessor::StoreType::Sum,
736 0 : this->Name,
737 : Constant::eResource::DistrictHeatingSteam,
738 : OutputProcessor::Group::Plant,
739 : OutputProcessor::EndUseCat::Cooling);
740 : }
741 : }
742 :
743 0 : SetupOutputVariable(state,
744 : "Chiller COP",
745 : Constant::Units::W_W,
746 0 : this->Report.ActualCOP,
747 : OutputProcessor::TimeStepType::System,
748 : OutputProcessor::StoreType::Average,
749 0 : this->Name);
750 :
751 0 : SetupOutputVariable(state,
752 : "Chiller Part Load Ratio",
753 : Constant::Units::None,
754 0 : this->Report.ChillerPartLoadRatio,
755 : OutputProcessor::TimeStepType::System,
756 : OutputProcessor::StoreType::Average,
757 0 : this->Name);
758 :
759 0 : SetupOutputVariable(state,
760 : "Chiller Cycling Ratio",
761 : Constant::Units::None,
762 0 : this->Report.ChillerCyclingFrac,
763 : OutputProcessor::TimeStepType::System,
764 : OutputProcessor::StoreType::Average,
765 0 : this->Name);
766 :
767 0 : SetupOutputVariable(state,
768 : "Chiller Steam Heat Loss Rate",
769 : Constant::Units::W,
770 0 : this->Report.LoopLoss,
771 : OutputProcessor::TimeStepType::System,
772 : OutputProcessor::StoreType::Average,
773 0 : this->Name);
774 :
775 0 : if (state.dataGlobal->AnyEnergyManagementSystemInModel) {
776 0 : SetupEMSInternalVariable(state, "Chiller Nominal Capacity", this->Name, "[W]", this->NomCap);
777 : }
778 0 : }
779 :
780 0 : void IndirectAbsorberSpecs::oneTimeInit(EnergyPlusData &state)
781 : {
782 : // Locate the chillers on the plant loops for later usage
783 0 : bool errFlag = false;
784 0 : PlantUtilities::ScanPlantLoopsForObject(state,
785 : this->Name,
786 : DataPlant::PlantEquipmentType::Chiller_Indirect_Absorption,
787 0 : this->CWPlantLoc,
788 : errFlag,
789 0 : this->TempLowLimitEvapOut,
790 : _,
791 : _,
792 0 : this->EvapInletNodeNum,
793 : _);
794 :
795 0 : PlantUtilities::ScanPlantLoopsForObject(
796 0 : state, this->Name, DataPlant::PlantEquipmentType::Chiller_Indirect_Absorption, this->CDPlantLoc, errFlag, _, _, _, this->CondInletNodeNum, _);
797 0 : PlantUtilities::InterConnectTwoPlantLoopSides(
798 0 : state, this->CWPlantLoc, this->CDPlantLoc, DataPlant::PlantEquipmentType::Chiller_Indirect_Absorption, true);
799 :
800 0 : if (this->GeneratorInletNodeNum > 0) {
801 0 : PlantUtilities::ScanPlantLoopsForObject(state,
802 : this->Name,
803 : DataPlant::PlantEquipmentType::Chiller_Indirect_Absorption,
804 0 : this->GenPlantLoc,
805 : errFlag,
806 : _,
807 : _,
808 : _,
809 0 : this->GeneratorInletNodeNum,
810 : _);
811 0 : PlantUtilities::InterConnectTwoPlantLoopSides(
812 0 : state, this->CWPlantLoc, this->GenPlantLoc, DataPlant::PlantEquipmentType::Chiller_Indirect_Absorption, true);
813 : }
814 :
815 0 : if ((this->CondInletNodeNum > 0) && (this->GeneratorInletNodeNum > 0)) {
816 0 : PlantUtilities::InterConnectTwoPlantLoopSides(
817 0 : state, this->CDPlantLoc, this->GenPlantLoc, DataPlant::PlantEquipmentType::Chiller_Indirect_Absorption, false);
818 : }
819 0 : if (errFlag) {
820 0 : ShowFatalError(state, "InitIndirectAbsorpChiller: Program terminated due to previous condition(s).");
821 : }
822 :
823 0 : if (this->FlowMode == DataPlant::FlowMode::Constant) {
824 : // reset flow priority
825 0 : this->CWPlantLoc.comp->FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
826 : }
827 :
828 0 : if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
829 : // reset flow priority
830 0 : this->CWPlantLoc.comp->FlowPriority = DataPlant::LoopFlowStatus::NeedyIfLoopOn;
831 :
832 0 : if ((state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint == DataLoopNode::SensedNodeFlagValue) &&
833 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi == DataLoopNode::SensedNodeFlagValue)) {
834 0 : if (!state.dataGlobal->AnyEnergyManagementSystemInModel) {
835 0 : if (!this->ModulatedFlowErrDone) {
836 0 : ShowWarningError(state, format("Missing temperature setpoint for LeavingSetpointModulated mode chiller named {}", this->Name));
837 0 : ShowContinueError(
838 : state, " A temperature setpoint is needed at the outlet node of a chiller in variable flow mode, use a SetpointManager");
839 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
840 0 : this->ModulatedFlowErrDone = true;
841 : }
842 : } else {
843 : // need call to EMS to check node
844 0 : bool FatalError = false; // but not really fatal yet, but should be.
845 0 : EMSManager::CheckIfNodeSetPointManagedByEMS(state, this->EvapOutletNodeNum, HVAC::CtrlVarType::Temp, FatalError);
846 0 : state.dataLoopNodes->NodeSetpointCheck(this->EvapOutletNodeNum).needsSetpointChecking = false;
847 0 : if (FatalError) {
848 0 : if (!this->ModulatedFlowErrDone) {
849 0 : ShowWarningError(state,
850 0 : format("Missing temperature setpoint for LeavingSetpointModulated mode chiller named {}", this->Name));
851 0 : ShowContinueError(state,
852 : " A temperature setpoint is needed at the outlet node of a chiller evaporator in variable flow mode");
853 0 : ShowContinueError(state, " use a Setpoint Manager to establish a setpoint at the chiller evaporator outlet node ");
854 0 : ShowContinueError(state, " or use an EMS actuator to establish a setpoint at the outlet node ");
855 0 : ShowContinueError(state, " The overall loop setpoint will be assumed for chiller. The simulation continues ... ");
856 0 : this->ModulatedFlowErrDone = true;
857 : }
858 : }
859 : }
860 :
861 0 : this->ModulatedFlowSetToLoop = true;
862 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint =
863 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
864 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi =
865 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
866 : }
867 : }
868 0 : }
869 :
870 0 : void IndirectAbsorberSpecs::initialize(EnergyPlusData &state, bool RunFlag, Real64 MyLoad)
871 : {
872 :
873 : // SUBROUTINE INFORMATION:
874 : // AUTHOR Richard Raustad
875 : // DATE WRITTEN September 2009
876 :
877 : // PURPOSE OF THIS SUBROUTINE:
878 : // This subroutine is for initializations of the Indirect Absorption Chiller components
879 :
880 : // METHODOLOGY EMPLOYED:
881 : // Uses the status flags to trigger initializations.
882 :
883 : static constexpr std::string_view RoutineName("InitIndirectAbsorpChiller");
884 :
885 : // Init more variables
886 0 : if (this->MyOneTimeFlag) {
887 0 : this->oneTimeInit(state);
888 0 : this->setupOutputVars(state);
889 0 : this->MyOneTimeFlag = false;
890 : }
891 :
892 0 : this->EquipFlowCtrl = this->CWPlantLoc.comp->FlowCtrl;
893 :
894 : // Initialize Supply Side Variables
895 0 : if (this->MyEnvrnFlag && state.dataGlobal->BeginEnvrnFlag && (state.dataPlnt->PlantFirstSizesOkayToFinalize)) {
896 :
897 0 : Real64 rho = this->CWPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
898 :
899 0 : this->EvapMassFlowRateMax = this->EvapVolFlowRate * rho;
900 :
901 0 : PlantUtilities::InitComponentNodes(state, 0.0, this->EvapMassFlowRateMax, this->EvapInletNodeNum, this->EvapOutletNodeNum);
902 :
903 0 : rho = this->CDPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
904 :
905 0 : this->CondMassFlowRateMax = rho * this->CondVolFlowRate;
906 :
907 0 : PlantUtilities::InitComponentNodes(state, 0.0, this->CondMassFlowRateMax, this->CondInletNodeNum, this->CondOutletNodeNum);
908 :
909 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp = this->TempDesCondIn;
910 :
911 0 : if (this->GeneratorInletNodeNum > 0) {
912 :
913 0 : if (this->GenHeatSourceType == DataLoopNode::NodeFluidType::Water) {
914 :
915 0 : rho = this->GenPlantLoc.loop->glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
916 0 : this->GenMassFlowRateMax = rho * this->GeneratorVolFlowRate;
917 :
918 : } else {
919 0 : Real64 SteamDensity = this->steam->getSatDensity(
920 0 : state, state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp, 1.0, std::string{calcChillerAbsorptionIndirect} + this->Name);
921 0 : this->GenMassFlowRateMax = SteamDensity * this->GeneratorVolFlowRate;
922 : }
923 :
924 0 : PlantUtilities::InitComponentNodes(state, 0.0, this->GenMassFlowRateMax, this->GeneratorInletNodeNum, this->GeneratorOutletNodeNum);
925 : }
926 0 : this->MyEnvrnFlag = false;
927 : }
928 0 : if (!state.dataGlobal->BeginEnvrnFlag) {
929 0 : this->MyEnvrnFlag = true;
930 : }
931 :
932 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) && this->ModulatedFlowSetToLoop) {
933 : // fix for clumsy old input that worked because loop setpoint was spread.
934 : // could be removed with transition, testing , model change, period of being obsolete.
935 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint =
936 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
937 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi =
938 0 : state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
939 : }
940 :
941 0 : Real64 mdotEvap = 0.0; // local fluid mass flow rate thru evaporator
942 0 : Real64 mdotCond = 0.0; // local fluid mass flow rate thru condenser
943 0 : Real64 mdotGen = 0.0; // local fluid mass flow rate thru generator
944 :
945 0 : if ((MyLoad < 0.0) && RunFlag) {
946 0 : mdotEvap = this->EvapMassFlowRateMax;
947 0 : mdotCond = this->CondMassFlowRateMax;
948 0 : mdotGen = this->GenMassFlowRateMax;
949 : }
950 :
951 0 : PlantUtilities::SetComponentFlowRate(state, mdotEvap, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
952 :
953 0 : PlantUtilities::SetComponentFlowRate(state, mdotCond, this->CondInletNodeNum, this->CondOutletNodeNum, this->CDPlantLoc);
954 :
955 0 : if (this->GeneratorInletNodeNum > 0) {
956 :
957 0 : PlantUtilities::SetComponentFlowRate(state, mdotGen, this->GeneratorInletNodeNum, this->GeneratorOutletNodeNum, this->GenPlantLoc);
958 : }
959 0 : }
960 :
961 0 : void IndirectAbsorberSpecs::sizeChiller(EnergyPlusData &state)
962 : {
963 :
964 : // SUBROUTINE INFORMATION:
965 : // AUTHOR R. Raustad (FSEC)
966 : // DATE WRITTEN May 2008
967 : // MODIFIED November 2013 Daeho Kang, add component sizing table entries
968 :
969 : // PURPOSE OF THIS SUBROUTINE:
970 : // This subroutine is for sizing Indirect Absorption Chiller Components for which capacities and flow rates
971 : // have not been specified in the input.
972 :
973 : // METHODOLOGY EMPLOYED:
974 : // Obtains evaporator flow rate from the plant sizing array. Calculates nominal capacity from
975 : // the evaporator flow rate and the chilled water loop design delta T. The condenser flow rate
976 : // is calculated from the nominal capacity, the COP, and the condenser loop design delta T.
977 :
978 : static constexpr std::string_view RoutineName("SizeIndirectAbsorpChiller");
979 : static constexpr std::string_view SizeChillerAbsorptionIndirect("SIZE Chiller:Absorption:Indirect");
980 :
981 0 : bool LoopErrorsFound = false;
982 :
983 0 : Real64 PltSizCondNum = 0;
984 0 : Real64 PltSizHeatingNum = 0;
985 0 : Real64 PltSizSteamNum = 0;
986 0 : bool ErrorsFound = false;
987 : // init local temporary version in case of partial/mixed autosizing
988 :
989 : // local nominal capacity cooling power
990 0 : Real64 tmpNomCap = this->NomCap;
991 :
992 : // local evaporator design volume flow rate
993 0 : Real64 tmpEvapVolFlowRate = this->EvapVolFlowRate;
994 :
995 : // local condenser design volume flow rate
996 0 : Real64 tmpCondVolFlowRate = this->CondVolFlowRate;
997 :
998 : // local generator design volume flow rate
999 0 : Real64 tmpGeneratorVolFlowRate = this->GeneratorVolFlowRate;
1000 :
1001 0 : Real64 SteamInputRatNom = 1.0; // nominal energy input ratio (steam or hot water)
1002 0 : if (this->GeneratorInputCurvePtr > 0) {
1003 0 : SteamInputRatNom = Curve::CurveValue(state, this->GeneratorInputCurvePtr, 1.0);
1004 : }
1005 :
1006 : // find the appropriate Plant Sizing object
1007 0 : int PltSizNum = this->CWPlantLoc.loop->PlantSizNum;
1008 :
1009 : // IF (IndirectAbsorber(ChillNum)%CondVolFlowRate == AutoSize) THEN
1010 0 : if (PltSizNum > 0) {
1011 0 : PltSizCondNum = PlantUtilities::MyPlantSizingIndex(
1012 : state, "Chiller:Absorption:Indirect", this->Name, this->CondInletNodeNum, this->CondOutletNodeNum, LoopErrorsFound);
1013 : }
1014 :
1015 0 : if (this->GenHeatSourceType == DataLoopNode::NodeFluidType::Steam) {
1016 0 : if (this->GeneratorInletNodeNum > 0 && this->GeneratorOutletNodeNum > 0) {
1017 0 : PltSizSteamNum = PlantUtilities::MyPlantSizingIndex(
1018 : state, "Chiller:Absorption:Indirect", this->Name, this->GeneratorInletNodeNum, this->GeneratorOutletNodeNum, LoopErrorsFound);
1019 : } else {
1020 0 : for (int PltSizIndex = 1; PltSizIndex <= state.dataSize->NumPltSizInput; ++PltSizIndex) {
1021 0 : if (state.dataSize->PlantSizData(PltSizIndex).LoopType == DataSizing::TypeOfPlantLoop::Steam) {
1022 0 : PltSizSteamNum = PltSizIndex;
1023 : }
1024 : }
1025 : }
1026 : } else {
1027 0 : if (this->GeneratorInletNodeNum > 0 && this->GeneratorOutletNodeNum > 0) {
1028 0 : PltSizHeatingNum = PlantUtilities::MyPlantSizingIndex(
1029 : state, "Chiller:Absorption:Indirect", this->Name, this->GeneratorInletNodeNum, this->GeneratorOutletNodeNum, LoopErrorsFound);
1030 : } else {
1031 0 : for (int PltSizIndex = 1; PltSizIndex <= state.dataSize->NumPltSizInput; ++PltSizIndex) {
1032 0 : if (state.dataSize->PlantSizData(PltSizIndex).LoopType == DataSizing::TypeOfPlantLoop::Heating) {
1033 0 : PltSizHeatingNum = PltSizIndex;
1034 : }
1035 : }
1036 : }
1037 : }
1038 :
1039 0 : if (PltSizNum > 0) {
1040 0 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
1041 :
1042 0 : Real64 Cp = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, Constant::CWInitConvTemp, RoutineName);
1043 :
1044 0 : Real64 rho = this->CWPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
1045 0 : tmpNomCap =
1046 0 : Cp * rho * state.dataSize->PlantSizData(PltSizNum).DeltaT * state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * this->SizFac;
1047 0 : if (!this->NomCapWasAutoSized) tmpNomCap = this->NomCap;
1048 : } else {
1049 0 : if (this->NomCapWasAutoSized) tmpNomCap = 0.0;
1050 : }
1051 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1052 0 : if (this->NomCapWasAutoSized) {
1053 0 : this->NomCap = tmpNomCap;
1054 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1055 0 : BaseSizer::reportSizerOutput(state, "Chiller:Absorption:Indirect", this->Name, "Design Size Nominal Capacity [W]", tmpNomCap);
1056 : }
1057 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1058 0 : BaseSizer::reportSizerOutput(
1059 : state, "Chiller:Absorption:Indirect", this->Name, "Initial Design Size Nominal Capacity [W]", tmpNomCap);
1060 : }
1061 : } else {
1062 0 : if (this->NomCap > 0.0 && tmpNomCap > 0.0) {
1063 0 : Real64 NomCapUser = this->NomCap;
1064 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1065 0 : BaseSizer::reportSizerOutput(state,
1066 : "Chiller:Absorption:Indirect",
1067 : this->Name,
1068 : "Design Size Nominal Capacity [W]",
1069 : tmpNomCap,
1070 : "User-Specified Nominal Capacity [W]",
1071 : NomCapUser);
1072 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1073 0 : if ((std::abs(tmpNomCap - NomCapUser) / NomCapUser) > state.dataSize->AutoVsHardSizingThreshold) {
1074 0 : ShowMessage(state, format("SizeChillerAbsorptionIndirect: Potential issue with equipment sizing for {}", this->Name));
1075 0 : ShowContinueError(state, format("User-Specified Nominal Capacity of {:.2R} [W]", NomCapUser));
1076 0 : ShowContinueError(state, format("differs from Design Size Nominal Capacity of {:.2R} [W]", tmpNomCap));
1077 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1078 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1079 : }
1080 : }
1081 : }
1082 0 : tmpNomCap = NomCapUser;
1083 : }
1084 : }
1085 : }
1086 : } else {
1087 0 : if (this->NomCapWasAutoSized) {
1088 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1089 0 : ShowSevereError(state, "Autosizing of Absorption Chiller nominal capacity requires a loop Sizing:Plant object");
1090 0 : ShowContinueError(state, format("Occurs in Chiller:Absorption:Indirect object={}", this->Name));
1091 0 : ErrorsFound = true;
1092 : }
1093 : } else {
1094 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1095 0 : if (this->NomCap > 0.0) {
1096 0 : BaseSizer::reportSizerOutput(
1097 : state, "Chiller:Absorption:Indirect", this->Name, "User-Specified Nominal Capacity [W]", this->NomCap);
1098 : }
1099 : }
1100 : }
1101 : }
1102 :
1103 : // local nominal pump power
1104 0 : Real64 tmpNomPumpPower = 0.0045 * tmpNomCap;
1105 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1106 : // the DOE-2 EIR for single stage absorption chiller
1107 0 : if (this->NomPumpPowerWasAutoSized) {
1108 0 : this->NomPumpPower = tmpNomPumpPower; // 0.0045d0 * IndirectAbsorber(ChillNum)%NomCap
1109 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1110 0 : BaseSizer::reportSizerOutput(
1111 : state, "Chiller:Absorption:Indirect", this->Name, "Design Size Nominal Pumping Power [W]", tmpNomPumpPower);
1112 : }
1113 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1114 0 : BaseSizer::reportSizerOutput(
1115 : state, "Chiller:Absorption:Indirect", this->Name, "Initial Design Size Nominal Pumping Power [W]", tmpNomPumpPower);
1116 : }
1117 : } else {
1118 0 : if (this->NomPumpPower > 0.0 && tmpNomPumpPower > 0.0) {
1119 0 : Real64 NomPumpPowerUser = this->NomPumpPower;
1120 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1121 0 : BaseSizer::reportSizerOutput(state,
1122 : "Chiller:Absorption:Indirect",
1123 : this->Name,
1124 : "Design Size Nominal Pumping Power [W]",
1125 : tmpNomPumpPower,
1126 : "User-Specified Nominal Pumping Power [W]",
1127 : NomPumpPowerUser);
1128 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1129 0 : if ((std::abs(tmpNomPumpPower - NomPumpPowerUser) / NomPumpPowerUser) > state.dataSize->AutoVsHardSizingThreshold) {
1130 0 : ShowMessage(state, format("SizeChillerAbsorptionIndirect: Potential issue with equipment sizing for {}", this->Name));
1131 0 : ShowContinueError(state, format("User-Specified Nominal Pumping Power of {:.2R} [W]", NomPumpPowerUser));
1132 0 : ShowContinueError(state, format("differs from Design Size Nominal Pumping Power of {:.2R} [W]", tmpNomPumpPower));
1133 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1134 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1135 : }
1136 : }
1137 : }
1138 0 : tmpNomPumpPower = NomPumpPowerUser;
1139 : }
1140 : }
1141 : }
1142 :
1143 0 : if (PltSizNum > 0) {
1144 0 : if (state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate >= HVAC::SmallWaterVolFlow) {
1145 0 : tmpEvapVolFlowRate = state.dataSize->PlantSizData(PltSizNum).DesVolFlowRate * this->SizFac;
1146 0 : if (!this->EvapVolFlowRateWasAutoSized) tmpEvapVolFlowRate = this->EvapVolFlowRate;
1147 : } else {
1148 0 : if (this->EvapVolFlowRateWasAutoSized) tmpEvapVolFlowRate = 0.0;
1149 : }
1150 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1151 0 : if (this->EvapVolFlowRateWasAutoSized) {
1152 0 : this->EvapVolFlowRate = tmpEvapVolFlowRate;
1153 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1154 0 : BaseSizer::reportSizerOutput(
1155 : state, "Chiller:Absorption:Indirect", this->Name, "Design Size Design Chilled Water Flow Rate [m3/s]", tmpEvapVolFlowRate);
1156 : }
1157 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1158 0 : BaseSizer::reportSizerOutput(state,
1159 : "Chiller:Absorption:Indirect",
1160 : this->Name,
1161 : "Initial Design Size Design Chilled Water Flow Rate [m3/s]",
1162 : tmpEvapVolFlowRate);
1163 : }
1164 : } else {
1165 0 : if (this->EvapVolFlowRate > 0.0 && tmpEvapVolFlowRate > 0.0) {
1166 0 : Real64 EvapVolFlowRateUser = this->EvapVolFlowRate;
1167 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1168 0 : BaseSizer::reportSizerOutput(state,
1169 : "Chiller:Absorption:Indirect",
1170 : this->Name,
1171 : "Design Size Design Chilled Water Flow Rate [m3/s]",
1172 : tmpEvapVolFlowRate,
1173 : "User-Specified Design Chilled Water Flow Rate [m3/s]",
1174 : EvapVolFlowRateUser);
1175 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1176 0 : if ((std::abs(tmpEvapVolFlowRate - EvapVolFlowRateUser) / EvapVolFlowRateUser) >
1177 0 : state.dataSize->AutoVsHardSizingThreshold) {
1178 0 : ShowMessage(state, format("SizeChillerElectricIndirect: Potential issue with equipment sizing for {}", this->Name));
1179 0 : ShowContinueError(state,
1180 0 : format("User-Specified Design Chilled Water Flow Rate of {:.5R} [m3/s]", EvapVolFlowRateUser));
1181 0 : ShowContinueError(
1182 0 : state, format("differs from Design Size Design Chilled Water Flow Rate of {:.5R} [m3/s]", tmpEvapVolFlowRate));
1183 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1184 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1185 : }
1186 : }
1187 : }
1188 0 : tmpEvapVolFlowRate = EvapVolFlowRateUser;
1189 : }
1190 : }
1191 : }
1192 : } else {
1193 0 : if (this->EvapVolFlowRateWasAutoSized) {
1194 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1195 0 : ShowSevereError(state, "Autosizing of Absorption Chiller evap flow rate requires a loop Sizing:Plant object");
1196 0 : ShowContinueError(state, format("Occurs in Chiller:Absorption:Indirect object={}", this->Name));
1197 0 : ErrorsFound = true;
1198 : }
1199 : } else {
1200 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1201 0 : if (this->EvapVolFlowRate > 0.0) {
1202 0 : BaseSizer::reportSizerOutput(state,
1203 : "Chiller:Absorption:Indirect",
1204 : this->Name,
1205 : "User-Specified Design Chilled Water Flow Rate [m3/s]",
1206 : this->EvapVolFlowRate);
1207 : }
1208 : }
1209 : }
1210 : }
1211 :
1212 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1213 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->EvapInletNodeNum, this->EvapVolFlowRate);
1214 : } else {
1215 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->EvapInletNodeNum, tmpEvapVolFlowRate);
1216 : }
1217 :
1218 0 : if (PltSizCondNum > 0 && PltSizNum > 0) {
1219 0 : if (this->EvapVolFlowRate >= HVAC::SmallWaterVolFlow && tmpNomCap > 0.0) {
1220 : // QCondenser = QEvaporator + QGenerator + PumpingPower
1221 :
1222 0 : Real64 Cp = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, Constant::CWInitConvTemp, RoutineName);
1223 :
1224 0 : Real64 rho = this->CDPlantLoc.loop->glycol->getDensity(state, Constant::CWInitConvTemp, RoutineName);
1225 0 : tmpCondVolFlowRate =
1226 0 : tmpNomCap * (1.0 + SteamInputRatNom + tmpNomPumpPower / tmpNomCap) / (state.dataSize->PlantSizData(PltSizCondNum).DeltaT * Cp * rho);
1227 0 : if (!this->CondVolFlowRateWasAutoSized) tmpCondVolFlowRate = this->CondVolFlowRate;
1228 0 : } else {
1229 0 : if (this->CondVolFlowRateWasAutoSized) tmpCondVolFlowRate = 0.0;
1230 : }
1231 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1232 0 : if (this->CondVolFlowRateWasAutoSized) {
1233 0 : this->CondVolFlowRate = tmpCondVolFlowRate;
1234 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1235 0 : BaseSizer::reportSizerOutput(
1236 : state, "Chiller:Absorption:Indirect", this->Name, "Design Size Design Condenser Water Flow Rate [m3/s]", tmpCondVolFlowRate);
1237 : }
1238 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1239 0 : BaseSizer::reportSizerOutput(state,
1240 : "Chiller:Absorption:Indirect",
1241 : this->Name,
1242 : "Initial Design Size Design Condenser Water Flow Rate [m3/s]",
1243 : tmpCondVolFlowRate);
1244 : }
1245 : } else {
1246 0 : if (this->CondVolFlowRate > 0.0 && tmpCondVolFlowRate > 0.0) {
1247 0 : Real64 CondVolFlowRateUser = this->CondVolFlowRate;
1248 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1249 0 : BaseSizer::reportSizerOutput(state,
1250 : "Chiller:Absorption:Indirect",
1251 : this->Name,
1252 : "Design Size Design Condenser Water Flow Rate [m3/s]",
1253 : tmpCondVolFlowRate,
1254 : "User-Specified Design Condenser Water Flow Rate [m3/s]",
1255 : CondVolFlowRateUser);
1256 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1257 0 : if ((std::abs(tmpCondVolFlowRate - CondVolFlowRateUser) / CondVolFlowRateUser) >
1258 0 : state.dataSize->AutoVsHardSizingThreshold) {
1259 0 : ShowMessage(state, format("SizeChillerAbsorptionIndirect: Potential issue with equipment sizing for {}", this->Name));
1260 0 : ShowContinueError(state,
1261 0 : format("User-Specified Design Condenser Water Flow Rate of {:.5R} [m3/s]", CondVolFlowRateUser));
1262 0 : ShowContinueError(
1263 0 : state, format("differs from Design Size Design Condenser Water Flow Rate of {:.5R} [m3/s]", tmpCondVolFlowRate));
1264 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1265 0 : ShowContinueError(state, "Verify that the value entered is intended and is consistent with other components.");
1266 : }
1267 : }
1268 : }
1269 0 : tmpCondVolFlowRate = CondVolFlowRateUser;
1270 : }
1271 : }
1272 : }
1273 0 : } else {
1274 0 : if (this->CondVolFlowRateWasAutoSized) {
1275 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1276 0 : ShowSevereError(state, "Autosizing of Absorption Chiller condenser flow rate requires a condenser");
1277 0 : ShowContinueError(state, "loop Sizing:Plant object");
1278 0 : ShowContinueError(state, format("Occurs in Chiller:Absorption:Indirect object={}", this->Name));
1279 0 : ErrorsFound = true;
1280 : }
1281 : } else {
1282 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1283 0 : if (this->CondVolFlowRate > 0.0) {
1284 0 : BaseSizer::reportSizerOutput(state,
1285 : "Chiller:Absorption:Indirect",
1286 : this->Name,
1287 : "User-Specified Design Condenser Water Flow Rate [m3/s]",
1288 : this->CondVolFlowRate);
1289 : }
1290 : }
1291 : }
1292 : }
1293 :
1294 : // save the design condenser water volumetric flow rate for use by the condenser water loop sizing algorithms
1295 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1296 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->CondInletNodeNum, this->CondVolFlowRate);
1297 : } else {
1298 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->CondInletNodeNum, tmpCondVolFlowRate);
1299 : }
1300 :
1301 0 : if ((PltSizSteamNum > 0 && this->GenHeatSourceType == DataLoopNode::NodeFluidType::Steam) ||
1302 0 : (PltSizHeatingNum > 0 && this->GenHeatSourceType == DataLoopNode::NodeFluidType::Water)) {
1303 0 : if (this->EvapVolFlowRate >= HVAC::SmallWaterVolFlow && tmpNomCap > 0.0) {
1304 0 : if (this->GenHeatSourceType == DataLoopNode::NodeFluidType::Water) {
1305 : Real64 CpWater =
1306 0 : this->GenPlantLoc.loop->glycol->getSpecificHeat(state, state.dataSize->PlantSizData(PltSizHeatingNum).ExitTemp, RoutineName);
1307 0 : Real64 SteamDeltaT = max(0.5, state.dataSize->PlantSizData(PltSizHeatingNum).DeltaT);
1308 :
1309 0 : Real64 RhoWater = this->GenPlantLoc.loop->glycol->getDensity(
1310 0 : state, (state.dataSize->PlantSizData(PltSizHeatingNum).ExitTemp - SteamDeltaT), RoutineName);
1311 0 : tmpGeneratorVolFlowRate = (tmpNomCap * SteamInputRatNom) / (CpWater * SteamDeltaT * RhoWater);
1312 0 : if (!this->GeneratorVolFlowRateWasAutoSized) tmpGeneratorVolFlowRate = this->GeneratorVolFlowRate;
1313 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1314 0 : if (this->GeneratorVolFlowRateWasAutoSized) {
1315 0 : this->GeneratorVolFlowRate = tmpGeneratorVolFlowRate;
1316 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1317 0 : BaseSizer::reportSizerOutput(state,
1318 : "Chiller:Absorption:Indirect",
1319 : this->Name,
1320 : "Design Size Design Generator Fluid Flow Rate [m3/s]",
1321 : tmpGeneratorVolFlowRate);
1322 : }
1323 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1324 0 : BaseSizer::reportSizerOutput(state,
1325 : "Chiller:Absorption:Indirect",
1326 : this->Name,
1327 : "Initial Design Size Design Generator Fluid Flow Rate [m3/s]",
1328 : tmpGeneratorVolFlowRate);
1329 : }
1330 : } else {
1331 0 : if (this->GeneratorVolFlowRate > 0.0 && tmpGeneratorVolFlowRate > 0.0) {
1332 0 : Real64 GeneratorVolFlowRateUser = this->GeneratorVolFlowRate;
1333 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1334 0 : BaseSizer::reportSizerOutput(state,
1335 : "Chiller:Absorption:Indirect",
1336 : this->Name,
1337 : "Design Size Design Generator Fluid Flow Rate [m3/s]",
1338 : tmpGeneratorVolFlowRate,
1339 : "User-Specified Design Generator Fluid Flow Rate [m3/s]",
1340 : GeneratorVolFlowRateUser);
1341 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1342 0 : if ((std::abs(tmpGeneratorVolFlowRate - GeneratorVolFlowRateUser) / GeneratorVolFlowRateUser) >
1343 0 : state.dataSize->AutoVsHardSizingThreshold) {
1344 0 : ShowMessage(
1345 0 : state, format("SizeChillerAbsorptionIndirect: Potential issue with equipment sizing for {}", this->Name));
1346 0 : ShowContinueError(
1347 : state,
1348 0 : format("User-Specified Design Generator Fluid Flow Rate of {:.5R} [m3/s]", GeneratorVolFlowRateUser));
1349 0 : ShowContinueError(state,
1350 0 : format("differs from Design Size Design Generator Fluid Flow Rate of {:.5R} [m3/s]",
1351 : tmpGeneratorVolFlowRate));
1352 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1353 0 : ShowContinueError(state,
1354 : "Verify that the value entered is intended and is consistent with other components.");
1355 : }
1356 : }
1357 : }
1358 0 : tmpGeneratorVolFlowRate = GeneratorVolFlowRateUser;
1359 : }
1360 : }
1361 : }
1362 : } else {
1363 0 : Real64 SteamDensity = this->steam->getSatDensity(
1364 0 : state, state.dataSize->PlantSizData(PltSizSteamNum).ExitTemp, 1.0, std::string{SizeChillerAbsorptionIndirect} + this->Name);
1365 0 : Real64 SteamDeltaT = state.dataSize->PlantSizData(PltSizSteamNum).DeltaT;
1366 0 : Real64 GeneratorOutletTemp = state.dataSize->PlantSizData(PltSizSteamNum).ExitTemp - SteamDeltaT;
1367 :
1368 : // dry enthalpy of steam (quality = 1)
1369 0 : Real64 EnthSteamOutDry = this->steam->getSatEnthalpy(
1370 0 : state, state.dataSize->PlantSizData(PltSizSteamNum).ExitTemp, 1.0, std::string{SizeChillerAbsorptionIndirect} + this->Name);
1371 :
1372 : // wet enthalpy of steam (quality = 0)
1373 0 : Real64 EnthSteamOutWet = this->steam->getSatEnthalpy(
1374 0 : state, state.dataSize->PlantSizData(PltSizSteamNum).ExitTemp, 0.0, std::string{SizeChillerAbsorptionIndirect} + this->Name);
1375 :
1376 0 : auto *water = Fluid::GetWater(state);
1377 0 : Real64 CpWater = water->getSpecificHeat(state, GeneratorOutletTemp, RoutineName);
1378 0 : Real64 HfgSteam = EnthSteamOutDry - EnthSteamOutWet;
1379 : // calculate the mass flow rate through the generator
1380 0 : Real64 SteamMassFlowRate = (tmpNomCap * SteamInputRatNom) / ((HfgSteam) + (SteamDeltaT * CpWater));
1381 : // calculate the steam volumetric flow rate
1382 0 : tmpGeneratorVolFlowRate = SteamMassFlowRate / SteamDensity;
1383 0 : if (!this->GeneratorVolFlowRateWasAutoSized) tmpGeneratorVolFlowRate = this->GeneratorVolFlowRate;
1384 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1385 0 : if (this->GeneratorVolFlowRateWasAutoSized) {
1386 0 : this->GeneratorVolFlowRate = tmpGeneratorVolFlowRate;
1387 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1388 0 : BaseSizer::reportSizerOutput(state,
1389 : "Chiller:Absorption:Indirect",
1390 : this->Name,
1391 : "Design Size Design Generator Fluid Flow Rate [m3/s]",
1392 : tmpGeneratorVolFlowRate);
1393 : }
1394 0 : if (state.dataPlnt->PlantFirstSizesOkayToReport) {
1395 0 : BaseSizer::reportSizerOutput(state,
1396 : "Chiller:Absorption:Indirect",
1397 : this->Name,
1398 : "Initial Design Size Design Generator Fluid Flow Rate [m3/s]",
1399 : tmpGeneratorVolFlowRate);
1400 : }
1401 : } else {
1402 0 : if (this->GeneratorVolFlowRate > 0.0 && tmpGeneratorVolFlowRate > 0.0) {
1403 0 : Real64 GeneratorVolFlowRateUser = this->GeneratorVolFlowRate;
1404 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1405 0 : BaseSizer::reportSizerOutput(state,
1406 : "Chiller:Absorption:Indirect",
1407 : this->Name,
1408 : "Design Size Design Generator Fluid Flow Rate [m3/s]",
1409 : tmpGeneratorVolFlowRate,
1410 : "User-Specified Design Generator Fluid Flow Rate [m3/s]",
1411 : GeneratorVolFlowRateUser);
1412 0 : if (state.dataGlobal->DisplayExtraWarnings) {
1413 0 : if ((std::abs(tmpGeneratorVolFlowRate - GeneratorVolFlowRateUser) / GeneratorVolFlowRateUser) >
1414 0 : state.dataSize->AutoVsHardSizingThreshold) {
1415 0 : ShowMessage(
1416 0 : state, format("SizeChillerAbsorptionIndirect: Potential issue with equipment sizing for {}", this->Name));
1417 0 : ShowContinueError(
1418 : state,
1419 0 : format("User-Specified Design Generator Fluid Flow Rate of {:.5R} [m3/s]", GeneratorVolFlowRateUser));
1420 0 : ShowContinueError(state,
1421 0 : format("differs from Design Size Design Generator Fluid Flow Rate of {:.5R} [m3/s]",
1422 : tmpGeneratorVolFlowRate));
1423 0 : ShowContinueError(state, "This may, or may not, indicate mismatched component sizes.");
1424 0 : ShowContinueError(state,
1425 : "Verify that the value entered is intended and is consistent with other components.");
1426 : }
1427 : }
1428 : }
1429 0 : tmpGeneratorVolFlowRate = GeneratorVolFlowRateUser;
1430 : }
1431 : }
1432 : }
1433 : }
1434 0 : } else {
1435 0 : if (this->GeneratorVolFlowRateWasAutoSized) {
1436 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1437 0 : this->GeneratorVolFlowRate = 0.0;
1438 : } else {
1439 0 : tmpGeneratorVolFlowRate = 0.0;
1440 : }
1441 : }
1442 : }
1443 0 : } else {
1444 0 : if (this->GeneratorVolFlowRateWasAutoSized) {
1445 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1446 0 : ShowSevereError(state, "Autosizing of Absorption Chiller generator flow rate requires a loop Sizing:Plant object.");
1447 0 : ShowContinueError(state, " For steam loops, use a steam Sizing:Plant object.");
1448 0 : ShowContinueError(state, " For hot water loops, use a heating Sizing:Plant object.");
1449 0 : ShowContinueError(state, format("Occurs in Chiller:Absorption:Indirect object={}", this->Name));
1450 0 : ErrorsFound = true;
1451 : }
1452 : } else {
1453 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1454 0 : if (this->GeneratorVolFlowRate > 0.0) {
1455 0 : BaseSizer::reportSizerOutput(state,
1456 : "Chiller:Absorption:Indirect",
1457 : this->Name,
1458 : "User-Specified Design Generator Fluid Flow Rate [m3/s]",
1459 : this->GeneratorVolFlowRate);
1460 : }
1461 : }
1462 : }
1463 : }
1464 :
1465 : // save the design steam or hot water volumetric flow rate for use by the steam or hot water loop sizing algorithms
1466 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1467 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->GeneratorInletNodeNum, this->GeneratorVolFlowRate);
1468 : } else {
1469 0 : PlantUtilities::RegisterPlantCompDesignFlow(state, this->GeneratorInletNodeNum, tmpGeneratorVolFlowRate);
1470 : }
1471 :
1472 0 : if (this->GeneratorDeltaTempWasAutoSized) {
1473 0 : if (PltSizHeatingNum > 0 && this->GenHeatSourceType == DataLoopNode::NodeFluidType::Water) {
1474 0 : this->GeneratorDeltaTemp = max(0.5, state.dataSize->PlantSizData(PltSizHeatingNum).DeltaT);
1475 0 : } else if (this->GenHeatSourceType == DataLoopNode::NodeFluidType::Water) {
1476 0 : Real64 rho = this->GenPlantLoc.loop->glycol->getDensity(state, Constant::HWInitConvTemp, RoutineName);
1477 : Real64 CpWater =
1478 0 : this->GenPlantLoc.loop->glycol->getSpecificHeat(state, state.dataSize->PlantSizData(PltSizHeatingNum).ExitTemp, RoutineName);
1479 0 : if (state.dataPlnt->PlantFirstSizesOkayToFinalize) {
1480 0 : this->GeneratorDeltaTemp = (SteamInputRatNom * this->NomCap) / (CpWater * rho * this->GeneratorVolFlowRate);
1481 : }
1482 : }
1483 : }
1484 :
1485 0 : if (ErrorsFound) {
1486 0 : ShowFatalError(state, "Preceding sizing errors cause program termination");
1487 : }
1488 :
1489 0 : if (state.dataPlnt->PlantFinalSizesOkayToReport) {
1490 : // create predefined report
1491 0 : std::string equipName = this->Name;
1492 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechType, equipName, "Chiller:Absorption:Indirect");
1493 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomEff, equipName, "n/a");
1494 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchMechNomCap, equipName, this->NomCap);
1495 :
1496 : // std 229 new Chillers table
1497 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerType, this->Name, "Chiller:Absorption:Indirect");
1498 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefCap, this->Name, this->NomCap);
1499 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEff, this->Name, "N/A");
1500 0 : OutputReportPredefined::PreDefTableEntry(
1501 0 : state, state.dataOutRptPredefined->pdchChillerRatedCap, this->Name, this->NomCap); // did not find rated cap
1502 0 : OutputReportPredefined::PreDefTableEntry(
1503 0 : state, state.dataOutRptPredefined->pdchChillerRatedEff, this->Name, "N/A"); // did not find rated eff or cop ; also Eff == COP?
1504 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerIPLVinSI, this->Name, "N/A");
1505 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerIPLVinIP, this->Name, "N/A");
1506 0 : OutputReportPredefined::PreDefTableEntry(state,
1507 0 : state.dataOutRptPredefined->pdchChillerPlantloopName,
1508 : this->Name,
1509 0 : (this->CWPlantLoc.loop != nullptr) ? this->CWPlantLoc.loop->Name : "N/A");
1510 0 : OutputReportPredefined::PreDefTableEntry(state,
1511 0 : state.dataOutRptPredefined->pdchChillerPlantloopBranchName,
1512 : this->Name,
1513 0 : (this->CWPlantLoc.branch != nullptr) ? this->CWPlantLoc.branch->Name : "N/A");
1514 0 : OutputReportPredefined::PreDefTableEntry(state,
1515 0 : state.dataOutRptPredefined->pdchChillerCondLoopName,
1516 : this->Name,
1517 0 : (this->CDPlantLoc.loop != nullptr) ? this->CDPlantLoc.loop->Name : "N/A");
1518 0 : OutputReportPredefined::PreDefTableEntry(state,
1519 0 : state.dataOutRptPredefined->pdchChillerCondLoopBranchName,
1520 : this->Name,
1521 0 : (this->CDPlantLoc.branch != nullptr) ? this->CDPlantLoc.branch->Name : "N/A");
1522 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerMinPLR, this->Name, this->MinPartLoadRat);
1523 0 : OutputReportPredefined::PreDefTableEntry(state,
1524 0 : state.dataOutRptPredefined->pdchChillerFuelType,
1525 : this->Name,
1526 0 : DataLoopNode::NodeFluidTypeNames[static_cast<int>(this->GenHeatSourceType)]);
1527 0 : OutputReportPredefined::PreDefTableEntry(
1528 0 : state, state.dataOutRptPredefined->pdchChillerRatedEntCondTemp, this->Name, this->TempDesCondIn); // Rated==Ref?
1529 0 : OutputReportPredefined::PreDefTableEntry(
1530 0 : state, state.dataOutRptPredefined->pdchChillerRatedLevEvapTemp, this->Name, this->TempLowLimitEvapOut); // Rated==Ref?
1531 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefEntCondTemp, this->Name, this->TempDesCondIn);
1532 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRefLevEvapTemp, this->Name, this->TempLowLimitEvapOut);
1533 :
1534 0 : OutputReportPredefined::PreDefTableEntry(state,
1535 0 : state.dataOutRptPredefined->pdchChillerDesSizeRefCHWFlowRate,
1536 : this->Name,
1537 : this->EvapMassFlowRateMax); // flowrate Max==DesignSizeRef flowrate?
1538 0 : OutputReportPredefined::PreDefTableEntry(state,
1539 0 : state.dataOutRptPredefined->pdchChillerDesSizeRefCondFluidFlowRate,
1540 : this->Name,
1541 : this->CondMassFlowRateMax); // Cond flowrate Max==DesignSizeRef Cond flowrate?
1542 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerHeatRecPlantloopName, this->Name, "N/A");
1543 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerHeatRecPlantloopBranchName, this->Name, "N/A");
1544 0 : OutputReportPredefined::PreDefTableEntry(state, state.dataOutRptPredefined->pdchChillerRecRelCapFrac, this->Name, "N/A");
1545 0 : }
1546 0 : }
1547 :
1548 0 : void IndirectAbsorberSpecs::calculate(EnergyPlusData &state, Real64 MyLoad, bool const RunFlag)
1549 : {
1550 : // SUBROUTINE INFORMATION:
1551 : // AUTHOR R. Raustad (FSEC)
1552 : // DATE WRITTEN May 2008
1553 : // MODIFIED Jun. 2016, Rongpeng Zhang, Applied the chiller supply water temperature sensor fault model
1554 :
1555 : // PURPOSE OF THIS SUBROUTINE:
1556 : // simulate a vapor compression Absorber using a revised BLAST model
1557 :
1558 : // METHODOLOGY EMPLOYED:
1559 : // curve fit of performance data:
1560 :
1561 : // REFERENCES:
1562 : // 1. BLAST User Manual
1563 : // 2. Absorber User Manual
1564 :
1565 : static constexpr std::string_view RoutineName("CalcIndirectAbsorberModel");
1566 : static constexpr std::string_view LoopLossesChillerAbsorptionIndirect("Loop Losses: Chiller:Absorption:Indirect");
1567 : static constexpr std::string_view LoopLossesChillerAbsorptionIndirectSpace("Loop Losses: Chiller:Absorption:Indirect ");
1568 :
1569 0 : Real64 TempEvapOutSetPoint(0.0); // C - evaporator outlet temperature setpoint
1570 0 : Real64 EvapDeltaTemp(0.0); // C - evaporator temperature difference, water side
1571 :
1572 : // set module level inlet and outlet nodes
1573 0 : this->EvapMassFlowRate = 0.0;
1574 0 : this->CondMassFlowRate = 0.0;
1575 0 : this->GenMassFlowRate = 0.0;
1576 0 : this->QCondenser = 0.0;
1577 0 : this->QEvaporator = 0.0;
1578 0 : this->QGenerator = 0.0;
1579 0 : this->PumpingEnergy = 0.0;
1580 0 : this->CondenserEnergy = 0.0;
1581 0 : this->EvaporatorEnergy = 0.0;
1582 0 : this->GeneratorEnergy = 0.0;
1583 0 : this->PumpingPower = 0.0;
1584 0 : this->ChillerONOFFCyclingFrac = 0.0;
1585 0 : this->EnergyLossToEnvironment = 0.0;
1586 :
1587 : // If no loop demand or Absorber OFF, return
1588 0 : if (MyLoad >= 0.0 || !RunFlag) {
1589 0 : if (this->EquipFlowCtrl == DataBranchAirLoopPlant::ControlType::SeriesActive)
1590 0 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
1591 0 : return;
1592 : }
1593 :
1594 : // Warn if entering condenser water temperature is below minimum
1595 0 : if (state.dataLoopNodes->Node(this->CondInletNodeNum).Temp < this->MinCondInletTemp) {
1596 0 : if (!state.dataGlobal->WarmupFlag) {
1597 0 : if (this->MinCondInletTempCtr < 1) {
1598 0 : ++this->MinCondInletTempCtr;
1599 0 : ShowWarningError(state, format("Chiller:Absorption:Indirect \"{}\"", this->Name));
1600 0 : ShowContinueError(state,
1601 0 : format("...Entering condenser water temperature below specified minimum ({:.3R} C).", this->MinCondInletTemp));
1602 0 : ShowContinueError(
1603 0 : state, format("...Entering condenser water temperature = {:.3R} C.", state.dataLoopNodes->Node(this->CondInletNodeNum).Temp));
1604 0 : ShowContinueErrorTimeStamp(state, "...simulation continues.");
1605 : } else {
1606 0 : ShowRecurringWarningErrorAtEnd(state,
1607 : "Entering condenser water temperature below specified minimum error continues.",
1608 0 : this->MinCondInletTempIndex,
1609 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp,
1610 0 : state.dataLoopNodes->Node(this->CondInletNodeNum).Temp);
1611 : }
1612 : }
1613 : }
1614 :
1615 : // Warn if entering generator fluid temperature is below minimum
1616 0 : if (this->GeneratorInletNodeNum > 0) {
1617 0 : if (state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp < this->MinGeneratorInletTemp) {
1618 0 : if (!state.dataGlobal->WarmupFlag) {
1619 0 : if (this->MinGenInletTempCtr < 1) {
1620 0 : ++this->MinGenInletTempCtr;
1621 0 : ShowWarningError(state, format("Chiller:Absorption:Indirect \"{}\"", this->Name));
1622 0 : ShowContinueError(
1623 0 : state, format("...Entering generator fluid temperature below specified minimum ({:.3R} C).", this->MinGeneratorInletTemp));
1624 0 : ShowContinueError(
1625 : state,
1626 0 : format("...Entering generator fluid temperature = {:.3R} C.", state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp));
1627 0 : ShowContinueErrorTimeStamp(state, "...simulation continues.");
1628 : } else {
1629 0 : ShowRecurringWarningErrorAtEnd(state,
1630 : "Entering generator fluid temperature below specified minimum error continues.",
1631 0 : this->MinGenInletTempIndex,
1632 0 : state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp,
1633 0 : state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp);
1634 : }
1635 : }
1636 : }
1637 : }
1638 :
1639 : // Set module level Absorber inlet and temperature variables
1640 : // C - evaporator inlet temperature, water side
1641 0 : Real64 EvapInletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1642 :
1643 : // C - condenser inlet temperature, water side
1644 0 : Real64 CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
1645 :
1646 : // Set the condenser mass flow rates
1647 0 : this->CondMassFlowRate = state.dataLoopNodes->Node(this->CondInletNodeNum).MassFlowRate;
1648 :
1649 : // Absorber nominal capacity
1650 0 : Real64 AbsorberNomCap = this->NomCap;
1651 :
1652 : // C - (BLAST ADJTC(1)The design secondary loop fluid
1653 0 : Real64 TempCondIn = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
1654 :
1655 : // C - evaporator outlet temperature, water side
1656 0 : Real64 TempEvapOut = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
1657 :
1658 : // C - Evaporator low temp. limit cut off
1659 0 : Real64 TempLowLimitEout = this->TempLowLimitEvapOut;
1660 :
1661 0 : Real64 CpFluid = this->CWPlantLoc.loop->glycol->getSpecificHeat(state, EvapInletTemp, RoutineName);
1662 :
1663 : // If there is a fault of Chiller SWT Sensor
1664 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) && (!state.dataGlobal->KickOffSimulation)) {
1665 0 : int FaultIndex = this->FaultyChillerSWTIndex;
1666 0 : Real64 EvapOutletTemp_ff = TempEvapOut;
1667 :
1668 : // calculate the sensor offset using fault information
1669 0 : this->FaultyChillerSWTOffset = state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex).CalFaultOffsetAct(state);
1670 : // update the TempEvapOut
1671 0 : TempEvapOut = max(this->TempLowLimitEvapOut,
1672 0 : min(state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp, EvapOutletTemp_ff - this->FaultyChillerSWTOffset));
1673 0 : this->FaultyChillerSWTOffset = EvapOutletTemp_ff - TempEvapOut;
1674 : }
1675 :
1676 0 : Real64 CapacityfAbsorberTemp = 1.0; // performance curve output
1677 0 : if (this->CapFCondenserTempPtr > 0) {
1678 0 : CapacityfAbsorberTemp = Curve::CurveValue(state, this->CapFCondenserTempPtr, TempCondIn);
1679 : }
1680 :
1681 0 : Real64 CapacityfEvaporatorTemp = 1.0; // performance curve output
1682 0 : if (this->CapFEvaporatorTempPtr > 0) {
1683 0 : CapacityfEvaporatorTemp = Curve::CurveValue(state, this->CapFEvaporatorTempPtr, TempEvapOut);
1684 : }
1685 :
1686 0 : Real64 CapacityfGeneratorTemp = 1.0; // performance curve output
1687 0 : if (this->CapFGeneratorTempPtr > 0) {
1688 0 : if (this->GeneratorInletNodeNum > 0) {
1689 0 : if (this->GenHeatSourceType == DataLoopNode::NodeFluidType::Water) {
1690 : CapacityfGeneratorTemp =
1691 0 : Curve::CurveValue(state, this->CapFGeneratorTempPtr, state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp);
1692 : } else {
1693 0 : CapacityfGeneratorTemp = 1.0;
1694 : }
1695 : } else {
1696 0 : CapacityfGeneratorTemp = 1.0;
1697 : }
1698 : }
1699 :
1700 0 : AbsorberNomCap *= CapacityfAbsorberTemp * CapacityfEvaporatorTemp * CapacityfGeneratorTemp;
1701 :
1702 : // If FlowLock is True, the new resolved mdot is used to update Power, QEvap, Qcond, and
1703 : // condenser side outlet temperature.
1704 0 : if (this->CWPlantLoc.side->FlowLock == DataPlant::FlowLock::Unlocked) {
1705 0 : this->PossibleSubcooling = false;
1706 0 : this->QEvaporator = std::abs(MyLoad);
1707 :
1708 : // Either set the flow to the Constant value or calculate the flow for the variable volume
1709 0 : if ((this->FlowMode == DataPlant::FlowMode::Constant) || (this->FlowMode == DataPlant::FlowMode::NotModulated)) {
1710 0 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
1711 :
1712 0 : if (this->EvapMassFlowRate != 0.0) {
1713 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / CpFluid;
1714 : } else {
1715 0 : EvapDeltaTemp = 0.0;
1716 : }
1717 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
1718 :
1719 0 : } else if (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) {
1720 : // Calculate the Delta Temp from the inlet temp to the chiller outlet setpoint
1721 0 : switch (this->CWPlantLoc.loop->LoopDemandCalcScheme) {
1722 0 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
1723 0 : EvapDeltaTemp =
1724 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
1725 0 : } break;
1726 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
1727 0 : EvapDeltaTemp =
1728 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
1729 0 : } break;
1730 0 : default: {
1731 0 : assert(false);
1732 : } break;
1733 : }
1734 :
1735 0 : if (EvapDeltaTemp != 0) {
1736 0 : this->EvapMassFlowRate = std::abs(this->QEvaporator / CpFluid / EvapDeltaTemp);
1737 0 : if ((this->EvapMassFlowRate - this->EvapMassFlowRateMax) > DataBranchAirLoopPlant::MassFlowTolerance) this->PossibleSubcooling = true;
1738 : // Check to see if the Maximum is exceeded, if so set to maximum
1739 0 : this->EvapMassFlowRate = min(this->EvapMassFlowRateMax, this->EvapMassFlowRate);
1740 0 : PlantUtilities::SetComponentFlowRate(
1741 0 : state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
1742 0 : switch (this->CWPlantLoc.loop->LoopDemandCalcScheme) {
1743 0 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
1744 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
1745 0 : } break;
1746 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
1747 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
1748 0 : } break;
1749 0 : default:
1750 0 : break;
1751 : }
1752 : } else {
1753 0 : this->EvapMassFlowRate = 0.0;
1754 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1755 :
1756 0 : ShowRecurringWarningErrorAtEnd(state,
1757 0 : "CalcIndirectAbsorberModel: Name=\"" + this->Name +
1758 : "\" Evaporative Condenser Delta Temperature = 0 in mass flow calculation.",
1759 0 : this->ErrCount2);
1760 : }
1761 : } // End of Constant Variable Flow If Block
1762 :
1763 : // If there is a fault of Chiller SWT Sensor
1764 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
1765 0 : (!state.dataGlobal->KickOffSimulation) && (this->EvapMassFlowRate > 0)) {
1766 : // calculate directly affected variables at faulty case: EvapOutletTemp, EvapMassFlowRate, QEvaporator
1767 0 : int FaultIndex = this->FaultyChillerSWTIndex;
1768 0 : bool VarFlowFlag = (this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated);
1769 0 : state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex)
1770 0 : .CalFaultChillerSWT(VarFlowFlag,
1771 : this->FaultyChillerSWTOffset,
1772 : CpFluid,
1773 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp,
1774 0 : this->EvapOutletTemp,
1775 0 : this->EvapMassFlowRate,
1776 0 : this->QEvaporator);
1777 : // update corresponding variables at faulty case
1778 : // PartLoadRat = ( AvailChillerCap > 0.0 ) ? ( QEvaporator / AvailChillerCap ) : 0.0;
1779 : // PartLoadRat = max( 0.0, min( PartLoadRat, MaxPartLoadRat ));
1780 : // ChillerPartLoadRatio = PartLoadRat;
1781 : }
1782 :
1783 : } else { // If FlowLock is True
1784 :
1785 0 : this->EvapMassFlowRate = state.dataLoopNodes->Node(this->EvapInletNodeNum).MassFlowRate;
1786 0 : if (this->PossibleSubcooling) {
1787 0 : this->QEvaporator = std::abs(MyLoad);
1788 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / CpFluid;
1789 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
1790 : } else {
1791 0 : switch (this->CWPlantLoc.loop->LoopDemandCalcScheme) {
1792 0 : case DataPlant::LoopDemandCalcScheme::SingleSetPoint: {
1793 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
1794 0 : (this->CWPlantLoc.comp->CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) ||
1795 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint != DataLoopNode::SensedNodeFlagValue)) {
1796 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPoint;
1797 : } else {
1798 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPoint;
1799 : }
1800 0 : } break;
1801 0 : case DataPlant::LoopDemandCalcScheme::DualSetPointDeadBand: {
1802 0 : if ((this->FlowMode == DataPlant::FlowMode::LeavingSetpointModulated) ||
1803 0 : (state, this->CWPlantLoc.comp->CurOpSchemeType == DataPlant::OpScheme::CompSetPtBased) ||
1804 0 : (state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi != DataLoopNode::SensedNodeFlagValue)) {
1805 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempSetPointHi;
1806 : } else {
1807 0 : TempEvapOutSetPoint = state.dataLoopNodes->Node(this->CWPlantLoc.loop->TempSetPointNodeNum).TempSetPointHi;
1808 : }
1809 0 : } break;
1810 0 : default: {
1811 0 : assert(false);
1812 : } break;
1813 : }
1814 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - TempEvapOutSetPoint;
1815 0 : this->QEvaporator = std::abs(this->EvapMassFlowRate * CpFluid * EvapDeltaTemp);
1816 0 : this->EvapOutletTemp = TempEvapOutSetPoint;
1817 : }
1818 : // Check that the Evap outlet temp honors both plant loop temp low limit and also the chiller low limit
1819 0 : if (this->EvapOutletTemp < TempLowLimitEout) {
1820 0 : if ((state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - TempLowLimitEout) > DataPlant::DeltaTempTol) {
1821 0 : this->EvapOutletTemp = TempLowLimitEout;
1822 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
1823 0 : this->QEvaporator = this->EvapMassFlowRate * CpFluid * EvapDeltaTemp;
1824 : } else {
1825 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1826 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
1827 0 : this->QEvaporator = this->EvapMassFlowRate * CpFluid * EvapDeltaTemp;
1828 : }
1829 : }
1830 0 : if (this->EvapOutletTemp < state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) {
1831 0 : if ((state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin) >
1832 : DataPlant::DeltaTempTol) {
1833 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).TempMin;
1834 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
1835 0 : this->QEvaporator = this->EvapMassFlowRate * CpFluid * EvapDeltaTemp;
1836 : } else {
1837 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1838 0 : EvapDeltaTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - this->EvapOutletTemp;
1839 0 : this->QEvaporator = this->EvapMassFlowRate * CpFluid * EvapDeltaTemp;
1840 : }
1841 : }
1842 :
1843 : // Checks QEvaporator on the basis of the machine limits.
1844 0 : if (this->QEvaporator > std::abs(MyLoad)) {
1845 0 : if (this->EvapMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
1846 0 : this->QEvaporator = std::abs(MyLoad);
1847 0 : EvapDeltaTemp = this->QEvaporator / this->EvapMassFlowRate / CpFluid;
1848 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp - EvapDeltaTemp;
1849 : } else {
1850 0 : this->QEvaporator = 0.0;
1851 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1852 : }
1853 : }
1854 :
1855 : // If there is a fault of Chiller SWT Sensor
1856 0 : if (this->FaultyChillerSWTFlag && (!state.dataGlobal->WarmupFlag) && (!state.dataGlobal->DoingSizing) &&
1857 0 : (!state.dataGlobal->KickOffSimulation) && (this->EvapMassFlowRate > 0)) {
1858 : // calculate directly affected variables at faulty case: EvapOutletTemp, EvapMassFlowRate, QEvaporator
1859 0 : int FaultIndex = this->FaultyChillerSWTIndex;
1860 0 : bool VarFlowFlag = false;
1861 0 : state.dataFaultsMgr->FaultsChillerSWTSensor(FaultIndex)
1862 0 : .CalFaultChillerSWT(VarFlowFlag,
1863 : this->FaultyChillerSWTOffset,
1864 : CpFluid,
1865 0 : state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp,
1866 0 : this->EvapOutletTemp,
1867 0 : this->EvapMassFlowRate,
1868 0 : this->QEvaporator);
1869 : // update corresponding variables at faulty case
1870 : }
1871 :
1872 : } // This is the end of the FlowLock Block
1873 :
1874 : // Operating part load ratio
1875 0 : Real64 OperPartLoadRat = this->QEvaporator / AbsorberNomCap;
1876 :
1877 : // part load ratio for efficiency calc
1878 0 : Real64 PartLoadRat = max(this->MinPartLoadRat, OperPartLoadRat);
1879 0 : this->Report.ChillerPartLoadRatio = OperPartLoadRat;
1880 :
1881 0 : Real64 FRAC = 1.0; // fraction of time step chiller cycles
1882 0 : if (OperPartLoadRat < PartLoadRat) {
1883 0 : FRAC = min(1.0, OperPartLoadRat / this->MinPartLoadRat);
1884 : }
1885 :
1886 0 : this->ChillerONOFFCyclingFrac = FRAC;
1887 :
1888 0 : Real64 HeatInputfCondTemp = 1.0; // performance curve output
1889 0 : if (this->GeneratorInletNodeNum > 0) {
1890 0 : if (this->HeatInputFCondTempPtr > 0) {
1891 0 : HeatInputfCondTemp = Curve::CurveValue(state, this->HeatInputFCondTempPtr, state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp);
1892 : } else {
1893 0 : HeatInputfCondTemp = 1.0;
1894 : }
1895 : }
1896 :
1897 0 : Real64 HeatInputfEvapTemp = 1.0; // performance curve output
1898 0 : if (this->HeatInputFEvapTempPtr > 0) {
1899 0 : HeatInputfEvapTemp = Curve::CurveValue(state, this->HeatInputFEvapTempPtr, state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp);
1900 : }
1901 :
1902 : // Calculate steam input ratio. Include impact of generator and evaporator temperatures
1903 0 : Real64 HeatInputRat = HeatInputfCondTemp * HeatInputfEvapTemp; // generator heat input ratio
1904 0 : if (this->GeneratorInputCurvePtr > 0) {
1905 0 : HeatInputRat = Curve::CurveValue(state, this->GeneratorInputCurvePtr, PartLoadRat) * HeatInputfCondTemp * HeatInputfEvapTemp;
1906 : }
1907 :
1908 : // Calculate electric input ratio
1909 0 : Real64 ElectricInputRat = 1.0; // energy input ratio
1910 0 : if (this->PumpPowerCurvePtr > 0) {
1911 0 : ElectricInputRat = Curve::CurveValue(state, this->PumpPowerCurvePtr, PartLoadRat);
1912 : }
1913 :
1914 0 : this->QGenerator = HeatInputRat * AbsorberNomCap * FRAC;
1915 0 : this->PumpingPower = ElectricInputRat * this->NomPumpPower * FRAC;
1916 :
1917 0 : if (this->EvapMassFlowRate == 0.0) {
1918 0 : this->QGenerator = 0.0;
1919 0 : this->EvapOutletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
1920 0 : this->PumpingPower = 0.0;
1921 : }
1922 :
1923 0 : this->QCondenser = this->QEvaporator + this->QGenerator + this->PumpingPower;
1924 :
1925 0 : CpFluid = this->CDPlantLoc.loop->glycol->getSpecificHeat(state, CondInletTemp, RoutineName);
1926 :
1927 0 : if (this->CondMassFlowRate > DataBranchAirLoopPlant::MassFlowTolerance) {
1928 0 : this->CondOutletTemp = this->QCondenser / this->CondMassFlowRate / CpFluid + CondInletTemp;
1929 : } else {
1930 0 : this->CondOutletTemp = CondInletTemp;
1931 0 : this->CondMassFlowRate = 0.0;
1932 0 : this->QCondenser = 0.0;
1933 0 : MyLoad = 0.0;
1934 0 : this->EvapMassFlowRate = 0.0;
1935 0 : PlantUtilities::SetComponentFlowRate(state, this->EvapMassFlowRate, this->EvapInletNodeNum, this->EvapOutletNodeNum, this->CWPlantLoc);
1936 0 : return;
1937 : // V7 plant upgrade, no longer fatal here anymore... set some things and return
1938 : }
1939 :
1940 0 : if (this->GeneratorInletNodeNum > 0) {
1941 : // Hot water plant is used for the generator
1942 0 : if (this->GenHeatSourceType == DataLoopNode::NodeFluidType::Water) {
1943 :
1944 : CpFluid =
1945 0 : this->GenPlantLoc.loop->glycol->getSpecificHeat(state, state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp, RoutineName);
1946 0 : if ((this->FlowMode == DataPlant::FlowMode::Constant) || (this->FlowMode == DataPlant::FlowMode::NotModulated)) {
1947 0 : this->GenMassFlowRate = this->GenMassFlowRateMax;
1948 : } else {
1949 0 : this->GenMassFlowRate = this->QGenerator / CpFluid / this->GeneratorDeltaTemp;
1950 : }
1951 :
1952 0 : PlantUtilities::SetComponentFlowRate(
1953 0 : state, this->GenMassFlowRate, this->GeneratorInletNodeNum, this->GeneratorOutletNodeNum, this->GenPlantLoc);
1954 :
1955 0 : if (this->GenMassFlowRate <= 0.0) {
1956 0 : this->GenOutletTemp = state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp;
1957 0 : this->SteamOutletEnthalpy = state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Enthalpy;
1958 : } else {
1959 0 : this->GenOutletTemp =
1960 0 : state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp - this->QGenerator / (CpFluid * this->GenMassFlowRate);
1961 0 : this->SteamOutletEnthalpy =
1962 0 : state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Enthalpy - this->QGenerator / this->GenMassFlowRate;
1963 : }
1964 :
1965 : } else { // using a steam plant for the generator
1966 :
1967 : // enthalpy of dry steam at generator inlet
1968 0 : Real64 EnthSteamOutDry = this->steam->getSatEnthalpy(
1969 0 : state, state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp, 1.0, std::string{calcChillerAbsorptionIndirect} + this->Name);
1970 :
1971 : // enthalpy of wet steam at generator inlet
1972 0 : Real64 EnthSteamOutWet = this->steam->getSatEnthalpy(
1973 0 : state, state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp, 0.0, std::string{calcChillerAbsorptionIndirect} + this->Name);
1974 :
1975 : // temperature difference of fluid through generator
1976 0 : Real64 SteamDeltaT = this->GeneratorSubcool;
1977 :
1978 : // generator outlet temperature
1979 0 : Real64 SteamOutletTemp = state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp - SteamDeltaT;
1980 :
1981 : // heat of vaporization of steam
1982 0 : Real64 HfgSteam = EnthSteamOutDry - EnthSteamOutWet;
1983 0 : CpFluid = Fluid::GetWater(state)->getSpecificHeat(state, SteamOutletTemp, std::string{calcChillerAbsorptionIndirect} + this->Name);
1984 0 : this->GenMassFlowRate = this->QGenerator / (HfgSteam + CpFluid * SteamDeltaT);
1985 0 : PlantUtilities::SetComponentFlowRate(
1986 0 : state, this->GenMassFlowRate, this->GeneratorInletNodeNum, this->GeneratorOutletNodeNum, this->GenPlantLoc);
1987 :
1988 0 : if (this->GenMassFlowRate <= 0.0) {
1989 0 : this->GenOutletTemp = state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp;
1990 0 : this->SteamOutletEnthalpy = state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Enthalpy;
1991 : } else {
1992 0 : this->GenOutletTemp = state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp - SteamDeltaT;
1993 0 : this->SteamOutletEnthalpy = this->steam->getSatEnthalpy(state,
1994 0 : state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp,
1995 : 0.0,
1996 0 : std::string{LoopLossesChillerAbsorptionIndirect} + this->Name);
1997 0 : CpFluid = Fluid::GetWater(state)->getSpecificHeat(
1998 0 : state, state.dataLoopNodes->Node(this->GeneratorInletNodeNum).Temp, std::string{calcChillerAbsorptionIndirect} + this->Name);
1999 :
2000 0 : this->SteamOutletEnthalpy -= CpFluid * SteamDeltaT;
2001 :
2002 : //************************* Loop Losses *****************************
2003 :
2004 : // temperature of condensed steam leaving generator (after condensate trap)
2005 0 : Real64 TempWaterAtmPress = this->steam->getSatTemperature(
2006 0 : state, state.dataEnvrn->OutBaroPress, std::string{LoopLossesChillerAbsorptionIndirect} + this->Name);
2007 :
2008 : // enthalpy of condensed steam leaving generator (after condensate trap)
2009 : Real64 EnthAtAtmPress =
2010 0 : this->steam->getSatEnthalpy(state, TempWaterAtmPress, 0.0, std::string{LoopLossesChillerAbsorptionIndirectSpace} + this->Name);
2011 :
2012 : // Point 4 at atm - loop delta subcool during return journey back to pump
2013 :
2014 : // temperature of condensed steam entering pump (includes loop losses)
2015 0 : Real64 TempLoopOutToPump = TempWaterAtmPress - this->LoopSubcool;
2016 :
2017 : // Reported value of coil outlet enthalpy at the node to match the node outlet temperature
2018 :
2019 : // enthalpy of condensed steam entering pump (includes loop losses)
2020 0 : Real64 EnthPumpInlet = EnthAtAtmPress - CpFluid * this->LoopSubcool;
2021 :
2022 : // Point 3-Point 5,
2023 0 : this->EnergyLossToEnvironment = this->GenMassFlowRate * (this->SteamOutletEnthalpy - EnthPumpInlet);
2024 :
2025 : //************************* Loop Losses *****************************
2026 :
2027 0 : this->GenOutletTemp = TempLoopOutToPump;
2028 0 : this->SteamOutletEnthalpy = EnthPumpInlet;
2029 :
2030 : } // IF(GenMassFlowRate .LE. 0.0d0)THEN
2031 :
2032 : } // IF(IndirectAbsorber(ChillNum)%GenHeatSourceType == DataLoopNode::NodeFluidType::Water)THEN
2033 :
2034 : } // IF(GeneratorInletNode .GT. 0)THEN
2035 :
2036 : // convert power to energy
2037 0 : this->GeneratorEnergy = this->QGenerator * state.dataHVACGlobal->TimeStepSysSec;
2038 0 : this->EvaporatorEnergy = this->QEvaporator * state.dataHVACGlobal->TimeStepSysSec;
2039 0 : this->CondenserEnergy = this->QCondenser * state.dataHVACGlobal->TimeStepSysSec;
2040 0 : this->PumpingEnergy = this->PumpingPower * state.dataHVACGlobal->TimeStepSysSec;
2041 :
2042 : // ------
2043 : // / \.
2044 : // / |
2045 : // 6/-------------1 - Boiler Outlet Temp/Enthalpy/Pressure
2046 : // / / /.
2047 : // / / / . \_
2048 : // / / / . _pressure drop (PD) across steam pressure regulator
2049 : // P / / / . /
2050 : // r 5 / / .
2051 : // e / 3-2'-------------2------ - Generator Inlet Temp/Enthalpy/Pressure
2052 : // s / |/ /
2053 : // s / | PD across / 2-2' latent heat of vaporization (neglecting amount of superheat due to PD)
2054 : // u / /| condensate / 1-3 delta H in generator
2055 : // r / / | trap / 2'-3 subcooling of hot water in generator
2056 : // e 4------/--3' / 3-3' pressure drop at generator hot-water condensate trap
2057 : // / / 3-4 loop subcooling back to loop pump
2058 : // / / 4-5 pressure/temp/enthalpy increase due to loop condensate pump
2059 : // / / 5-6 heat addition in boiler to return condensate
2060 : // / / 6-1 heat of vaporization in boiler of return condensate to steam
2061 : //____________________________________
2062 : // Enthalpy (H)
2063 : }
2064 :
2065 0 : void IndirectAbsorberSpecs::updateRecords(EnergyPlusData &state, Real64 MyLoad, bool RunFlag)
2066 : {
2067 : // SUBROUTINE INFORMATION:
2068 : // AUTHOR: R. Raustad (FSEC)
2069 : // DATE WRITTEN: May 2008
2070 :
2071 : // PURPOSE OF THIS SUBROUTINE:
2072 : // reporting
2073 :
2074 0 : int CondOutletNode = this->CondOutletNodeNum;
2075 :
2076 0 : if (MyLoad >= 0 || !RunFlag) {
2077 : // set node temperature
2078 0 : PlantUtilities::SafeCopyPlantNode(state, this->EvapInletNodeNum, this->EvapOutletNodeNum);
2079 0 : PlantUtilities::SafeCopyPlantNode(state, this->CondInletNodeNum, CondOutletNode);
2080 :
2081 0 : this->Report.PumpingPower = 0.0;
2082 0 : this->Report.QEvap = 0.0;
2083 0 : this->Report.QCond = 0.0;
2084 0 : this->Report.QGenerator = 0.0;
2085 0 : this->Report.PumpingEnergy = 0.0;
2086 0 : this->Report.EvapEnergy = 0.0;
2087 0 : this->Report.CondEnergy = 0.0;
2088 0 : this->Report.GeneratorEnergy = 0.0;
2089 0 : this->Report.EvapInletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
2090 0 : this->Report.CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
2091 0 : this->Report.CondOutletTemp = state.dataLoopNodes->Node(CondOutletNode).Temp;
2092 0 : this->Report.EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
2093 0 : this->Report.Evapmdot = 0.0;
2094 0 : this->Report.Condmdot = 0.0;
2095 0 : this->Report.Genmdot = 0.0;
2096 0 : this->Report.ActualCOP = 0.0;
2097 0 : this->Report.ChillerPartLoadRatio = 0.0;
2098 0 : this->Report.LoopLoss = 0.0;
2099 0 : this->Report.ChillerCyclingFrac = 0.0;
2100 :
2101 0 : if (this->GeneratorInletNodeNum > 0) {
2102 0 : PlantUtilities::SafeCopyPlantNode(state, this->GeneratorInletNodeNum, this->GeneratorOutletNodeNum);
2103 : }
2104 :
2105 : } else {
2106 : // set node temperatures
2107 0 : PlantUtilities::SafeCopyPlantNode(state, this->EvapInletNodeNum, this->EvapOutletNodeNum);
2108 0 : PlantUtilities::SafeCopyPlantNode(state, this->CondInletNodeNum, CondOutletNode);
2109 0 : state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp = this->EvapOutletTemp;
2110 0 : state.dataLoopNodes->Node(CondOutletNode).Temp = this->CondOutletTemp;
2111 :
2112 0 : this->Report.PumpingPower = this->PumpingPower;
2113 0 : this->Report.QEvap = this->QEvaporator;
2114 0 : this->Report.QCond = this->QCondenser;
2115 0 : this->Report.QGenerator = this->QGenerator;
2116 0 : this->Report.PumpingEnergy = this->PumpingEnergy;
2117 0 : this->Report.EvapEnergy = this->EvaporatorEnergy;
2118 0 : this->Report.CondEnergy = this->CondenserEnergy;
2119 0 : this->Report.GeneratorEnergy = this->GeneratorEnergy;
2120 0 : this->Report.EvapInletTemp = state.dataLoopNodes->Node(this->EvapInletNodeNum).Temp;
2121 0 : this->Report.CondInletTemp = state.dataLoopNodes->Node(this->CondInletNodeNum).Temp;
2122 0 : this->Report.CondOutletTemp = state.dataLoopNodes->Node(CondOutletNode).Temp;
2123 0 : this->Report.EvapOutletTemp = state.dataLoopNodes->Node(this->EvapOutletNodeNum).Temp;
2124 0 : this->Report.Evapmdot = this->EvapMassFlowRate;
2125 0 : this->Report.Condmdot = this->CondMassFlowRate;
2126 0 : this->Report.Genmdot = this->GenMassFlowRate;
2127 0 : this->Report.LoopLoss = this->EnergyLossToEnvironment;
2128 0 : this->Report.ChillerCyclingFrac = this->ChillerONOFFCyclingFrac;
2129 :
2130 0 : if (this->QGenerator != 0.0) {
2131 0 : this->Report.ActualCOP = this->QEvaporator / this->QGenerator;
2132 : } else {
2133 0 : this->Report.ActualCOP = 0.0;
2134 : }
2135 :
2136 0 : if (this->GeneratorInletNodeNum > 0) {
2137 0 : PlantUtilities::SafeCopyPlantNode(state, this->GeneratorInletNodeNum, this->GeneratorOutletNodeNum);
2138 0 : state.dataLoopNodes->Node(this->GeneratorOutletNodeNum).Temp = this->GenOutletTemp;
2139 : }
2140 : }
2141 0 : }
2142 :
2143 : } // namespace EnergyPlus::ChillerIndirectAbsorption
|