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