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