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