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