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