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